graphein-mcp 0.19.0 → 0.20.0
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 +6 -0
- package/dist/{chunk-CODCFNDV.js → chunk-7DJMHUCG.js} +129 -31
- package/dist/chunk-7DJMHUCG.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/server.js +1 -1
- package/package.json +6 -5
- package/resources/agent-guide.md +22 -0
- package/resources/chart-spec.schema.json +15 -8
- package/resources/spec-reference.md +108 -29
- package/dist/chunk-CODCFNDV.js.map +0 -1
package/README.md
CHANGED
|
@@ -47,6 +47,12 @@ npm install -g graphein-mcp # then: graphein-mcp
|
|
|
47
47
|
`dpr`, `repair` (default `true`), `repairLevel` (`'safe'` default; `'data'` explicitly
|
|
48
48
|
permits data-aware authoring inference), and `quality`. Every type rasterizes — kpi, table, matrix, slicers and dashboard render
|
|
49
49
|
a static canvas snapshot, so the whole catalog returns an image + report.
|
|
50
|
+
`width`/`height` are limited to 1–8192 CSS pixels, `dpr` to 0.25–4, and the
|
|
51
|
+
rasterized canvas to 67,108,864 pixels; invalid sizes return a structured tool
|
|
52
|
+
error instead of allocating an unsafe canvas.
|
|
53
|
+
CSV/TSV parsing keeps a column as strings unless every value converts losslessly,
|
|
54
|
+
so leading-zero identifiers stay identifiers. Bundled resources are served only
|
|
55
|
+
from the package's committed resource set.
|
|
50
56
|
|
|
51
57
|
### Opt-in presentation improvement
|
|
52
58
|
|
|
@@ -28,14 +28,26 @@ function detectDelimiter(text2) {
|
|
|
28
28
|
}
|
|
29
29
|
return tab > comma ? " " : ",";
|
|
30
30
|
}
|
|
31
|
-
function
|
|
31
|
+
function coerceLosslessNumber(value) {
|
|
32
32
|
const trimmed = value.trim();
|
|
33
|
-
if (
|
|
33
|
+
if (/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/.test(trimmed)) {
|
|
34
34
|
const n = Number(trimmed);
|
|
35
35
|
if (Number.isFinite(n)) return n;
|
|
36
36
|
}
|
|
37
37
|
return value;
|
|
38
38
|
}
|
|
39
|
+
function coerceColumns(records, headers) {
|
|
40
|
+
const columnsAsNumbers = headers.map(
|
|
41
|
+
(_, i) => records.every((record) => typeof coerceLosslessNumber(record[i].value) === "number")
|
|
42
|
+
);
|
|
43
|
+
return records.map((record) => {
|
|
44
|
+
const row = {};
|
|
45
|
+
for (let i = 0; i < headers.length; i++) {
|
|
46
|
+
row[headers[i]] = columnsAsNumbers[i] ? coerceLosslessNumber(record[i].value) : record[i].value;
|
|
47
|
+
}
|
|
48
|
+
return row;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
39
51
|
function parseRecords(text2, delimiter) {
|
|
40
52
|
const records = [];
|
|
41
53
|
let record = [];
|
|
@@ -102,16 +114,15 @@ function parseTabularText(text2) {
|
|
|
102
114
|
if (new Set(headers).size !== headers.length) {
|
|
103
115
|
throw new TabularParseError("CSV/TSV header row must not contain duplicate column names.");
|
|
104
116
|
}
|
|
105
|
-
|
|
117
|
+
const dataRecords = records.slice(1);
|
|
118
|
+
for (const [rowIndex, record] of dataRecords.entries()) {
|
|
106
119
|
if (record.length !== headers.length) {
|
|
107
120
|
throw new TabularParseError(
|
|
108
121
|
`Row ${rowIndex + 2} has ${record.length} cells, expected ${headers.length}.`
|
|
109
122
|
);
|
|
110
123
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return row;
|
|
114
|
-
});
|
|
124
|
+
}
|
|
125
|
+
return coerceColumns(dataRecords, headers);
|
|
115
126
|
}
|
|
116
127
|
function parseInlineData(value) {
|
|
117
128
|
if (Array.isArray(value)) return value.map(parseInlineData);
|
|
@@ -133,7 +144,7 @@ import {
|
|
|
133
144
|
listChartTypes,
|
|
134
145
|
summarize
|
|
135
146
|
} from "graphein";
|
|
136
|
-
import { NodeRenderError, renderChart } from "@graphein/node";
|
|
147
|
+
import { NodeRenderError, renderChart, validateRenderImageOptions } from "@graphein/node";
|
|
137
148
|
function text(value) {
|
|
138
149
|
return { type: "text", text: value };
|
|
139
150
|
}
|
|
@@ -162,6 +173,22 @@ function parseErrorResult(e, quality) {
|
|
|
162
173
|
structuredContent: payload
|
|
163
174
|
};
|
|
164
175
|
}
|
|
176
|
+
function optionErrorResult(e, quality) {
|
|
177
|
+
const payload = {
|
|
178
|
+
ok: false,
|
|
179
|
+
rendered: false,
|
|
180
|
+
stage: "options",
|
|
181
|
+
message: e instanceof Error ? e.message : String(e),
|
|
182
|
+
...quality ? {
|
|
183
|
+
quality: draft(void 0, { repair: false, quality }).quality
|
|
184
|
+
} : {}
|
|
185
|
+
};
|
|
186
|
+
return {
|
|
187
|
+
isError: true,
|
|
188
|
+
content: [json(payload)],
|
|
189
|
+
structuredContent: payload
|
|
190
|
+
};
|
|
191
|
+
}
|
|
165
192
|
function specWithParsedData(spec) {
|
|
166
193
|
return parseInlineData(spec);
|
|
167
194
|
}
|
|
@@ -202,6 +229,11 @@ function critiqueChartHandler(args) {
|
|
|
202
229
|
}
|
|
203
230
|
function renderOrCritique(args, includeImage) {
|
|
204
231
|
const { spec, width, height, dpr, repair = true, repairLevel, quality } = args;
|
|
232
|
+
try {
|
|
233
|
+
validateRenderImageOptions({ width, height, dpr });
|
|
234
|
+
} catch (e) {
|
|
235
|
+
return optionErrorResult(e, quality);
|
|
236
|
+
}
|
|
205
237
|
let working;
|
|
206
238
|
try {
|
|
207
239
|
working = specWithParsedData(spec);
|
|
@@ -418,7 +450,11 @@ var RESOURCES = [
|
|
|
418
450
|
}
|
|
419
451
|
];
|
|
420
452
|
var cache = /* @__PURE__ */ new Map();
|
|
453
|
+
var allowedResourceFiles = new Set(RESOURCES.map((r) => r.file));
|
|
421
454
|
function readResourceFile(file) {
|
|
455
|
+
if (!allowedResourceFiles.has(file)) {
|
|
456
|
+
throw new Error(`Unknown Graphein MCP resource "${file}".`);
|
|
457
|
+
}
|
|
422
458
|
const hit = cache.get(file);
|
|
423
459
|
if (hit !== void 0) return hit;
|
|
424
460
|
const url = new URL(`../resources/${file}`, import.meta.url);
|
|
@@ -432,8 +468,55 @@ function resourceByUri(uri) {
|
|
|
432
468
|
|
|
433
469
|
// src/create-server.ts
|
|
434
470
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
471
|
+
import { RENDER_LIMITS } from "@graphein/node";
|
|
435
472
|
import { z } from "zod";
|
|
436
|
-
|
|
473
|
+
|
|
474
|
+
// src/toolMetadata.ts
|
|
475
|
+
var MCP_TOOL_METADATA = Object.freeze([
|
|
476
|
+
{
|
|
477
|
+
name: "render_chart",
|
|
478
|
+
title: "Render a Graphein chart",
|
|
479
|
+
description: "The one-call loop: validate a ChartSpec, auto-repair safe mistakes, render it to a PNG, and return the image plus a vision-free critique (render report, lint warnings, repairs applied). If the spec cannot be made valid, returns structured errors with JSON-Patch fixes instead of an image. Every type rasterizes headlessly \u2014 kpi, table, matrix, slicers and dashboard render static canvas snapshots."
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
name: "critique_chart",
|
|
483
|
+
title: "Critique a Graphein chart without an image",
|
|
484
|
+
description: "Validate a ChartSpec, auto-repair safe mistakes, render it headlessly, and return only the RenderReport, deterministic summary, lint warnings, and repairs applied \u2014 no base64 PNG. Use this when you need diagnostics but not an image."
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
name: "validate_chart",
|
|
488
|
+
title: "Validate a Graphein chart spec",
|
|
489
|
+
description: "Validate a ChartSpec without rendering. Returns structural errors (each with a JSON-Patch fix when unambiguous, plus did-you-mean suggestions) and best-practice lint warnings. Fast feedback before rendering."
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
name: "recommend_chart",
|
|
493
|
+
title: "Recommend Graphein chart specs",
|
|
494
|
+
description: "Profile tidy rows and return ranked ChartSpecs with rationale, profile evidence, alternatives, and explicit needs-decision/no-candidate findings. Use this before guessing a chart type or encoding; no supplied data is changed."
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
name: "repair_chart",
|
|
498
|
+
title: "Repair a Graphein chart spec",
|
|
499
|
+
description: `Apply Graphein repairs and return the corrected spec, JSON Patch ops, per-patch rationales, and whether it is now valid. The default safe level applies validator-provided fixes; level "data" may infer missing encodings and field-name typo fixes from the spec's own data.`
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: "list_chart_types",
|
|
503
|
+
title: "List Graphein chart types",
|
|
504
|
+
description: "Return every supported chart type with purpose, required channels/properties, field roles, aggregation semantics, cardinality guidance, supported features, and a minimal runnable starter. Use this before reading the full schema."
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
name: "summarize_chart",
|
|
508
|
+
title: "Summarize a Graphein chart",
|
|
509
|
+
description: `Return a deterministic, plain-English description of what the chart's data shows (e.g. "Users grew 46% over six months, peaking in June"). Doubles as alt-text; needs no LLM.`
|
|
510
|
+
}
|
|
511
|
+
]);
|
|
512
|
+
function mcpToolMetadata(name) {
|
|
513
|
+
const tool = MCP_TOOL_METADATA.find((item) => item.name === name);
|
|
514
|
+
if (!tool) throw new Error(`Unknown Graphein MCP tool: ${name}`);
|
|
515
|
+
return tool;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// src/create-server.ts
|
|
519
|
+
var VERSION = "0.20.0";
|
|
437
520
|
var SERVER_INSTRUCTIONS = `Graphein is an agent-first data-visualization library: you describe a chart as one JSON ChartSpec ({ type, data, encoding, ... }) and it renders. This server lets you build correct charts without prior knowledge of the API.
|
|
438
521
|
|
|
439
522
|
Workflow:
|
|
@@ -462,21 +545,37 @@ var qualitySchema = z.union([
|
|
|
462
545
|
"Opt in to bounded presentation-default improvement. Default false: one render. Never alters data, encodings, explicit palettes/domains, or other caller settings. Returns effectiveSpec and quality history. Mutable targets reserve a rollback pass."
|
|
463
546
|
);
|
|
464
547
|
var repairLevelSchema = z.enum(["safe", "data"]).optional().describe("Independent repair policy: safe (default), or explicitly opt in to data-aware field/encoding inference.");
|
|
548
|
+
var widthSchema = z.number().min(RENDER_LIMITS.minWidth).max(RENDER_LIMITS.maxWidth).optional().describe(`Logical width in CSS px (default 800; ${RENDER_LIMITS.minWidth}-${RENDER_LIMITS.maxWidth}).`);
|
|
549
|
+
var heightSchema = z.number().min(RENDER_LIMITS.minHeight).max(RENDER_LIMITS.maxHeight).optional().describe(`Logical height in CSS px (default 500; ${RENDER_LIMITS.minHeight}-${RENDER_LIMITS.maxHeight}).`);
|
|
550
|
+
var dprSchema = z.number().min(RENDER_LIMITS.minDpr).max(RENDER_LIMITS.maxDpr).optional().describe(`Device pixel ratio for crisp output (default 2; ${RENDER_LIMITS.minDpr}-${RENDER_LIMITS.maxDpr}; total raster pixels capped at ${RENDER_LIMITS.maxPixels.toLocaleString("en-US")}).`);
|
|
551
|
+
var toolOptions = (name) => {
|
|
552
|
+
const { title, description } = mcpToolMetadata(name);
|
|
553
|
+
return { title, description };
|
|
554
|
+
};
|
|
465
555
|
function createServer() {
|
|
466
556
|
const server = new McpServer(
|
|
467
557
|
{ name: "graphein-mcp", version: VERSION },
|
|
468
558
|
{ instructions: SERVER_INSTRUCTIONS }
|
|
469
559
|
);
|
|
560
|
+
registerTools(server);
|
|
561
|
+
registerResources(server);
|
|
562
|
+
registerCreateChartPrompt(server);
|
|
563
|
+
return server;
|
|
564
|
+
}
|
|
565
|
+
function registerTools(server) {
|
|
566
|
+
registerRenderTools(server);
|
|
567
|
+
registerSpecTools(server);
|
|
568
|
+
}
|
|
569
|
+
function registerRenderTools(server) {
|
|
470
570
|
server.registerTool(
|
|
471
571
|
"render_chart",
|
|
472
572
|
{
|
|
473
|
-
|
|
474
|
-
description: "The one-call loop: validate a ChartSpec, auto-repair safe mistakes, render it to a PNG, and return the image plus a vision-free critique (render report, lint warnings, repairs applied). If the spec cannot be made valid, returns structured errors with JSON-Patch fixes instead of an image. Every type rasterizes headlessly \u2014 kpi, table, matrix, slicers and dashboard render static canvas snapshots.",
|
|
573
|
+
...toolOptions("render_chart"),
|
|
475
574
|
inputSchema: {
|
|
476
575
|
spec: specSchema,
|
|
477
|
-
width:
|
|
478
|
-
height:
|
|
479
|
-
dpr:
|
|
576
|
+
width: widthSchema,
|
|
577
|
+
height: heightSchema,
|
|
578
|
+
dpr: dprSchema,
|
|
480
579
|
repair: z.boolean().optional().describe("Auto-apply safe repairs before rendering when the spec is invalid (default true)."),
|
|
481
580
|
repairLevel: repairLevelSchema,
|
|
482
581
|
quality: qualitySchema
|
|
@@ -487,13 +586,12 @@ function createServer() {
|
|
|
487
586
|
server.registerTool(
|
|
488
587
|
"critique_chart",
|
|
489
588
|
{
|
|
490
|
-
|
|
491
|
-
description: "Validate a ChartSpec, auto-repair safe mistakes, render it headlessly, and return only the RenderReport, deterministic summary, lint warnings, and repairs applied \u2014 no base64 PNG. Use this when you need diagnostics but not an image.",
|
|
589
|
+
...toolOptions("critique_chart"),
|
|
492
590
|
inputSchema: {
|
|
493
591
|
spec: specSchema,
|
|
494
|
-
width:
|
|
495
|
-
height:
|
|
496
|
-
dpr:
|
|
592
|
+
width: widthSchema,
|
|
593
|
+
height: heightSchema,
|
|
594
|
+
dpr: dprSchema,
|
|
497
595
|
repair: z.boolean().optional().describe("Auto-apply safe repairs before rendering when the spec is invalid (default true)."),
|
|
498
596
|
repairLevel: repairLevelSchema,
|
|
499
597
|
quality: qualitySchema
|
|
@@ -501,11 +599,12 @@ function createServer() {
|
|
|
501
599
|
},
|
|
502
600
|
async (args) => critiqueChartHandler(args)
|
|
503
601
|
);
|
|
602
|
+
}
|
|
603
|
+
function registerSpecTools(server) {
|
|
504
604
|
server.registerTool(
|
|
505
605
|
"validate_chart",
|
|
506
606
|
{
|
|
507
|
-
|
|
508
|
-
description: 'Validate a ChartSpec without rendering. Returns structural errors (each with a JSON-Patch `fix` when unambiguous, plus "did you mean" suggestions) and best-practice lint warnings. Fast feedback before rendering.',
|
|
607
|
+
...toolOptions("validate_chart"),
|
|
509
608
|
inputSchema: { spec: specSchema }
|
|
510
609
|
},
|
|
511
610
|
async (args) => validateChartHandler(args)
|
|
@@ -513,8 +612,7 @@ function createServer() {
|
|
|
513
612
|
server.registerTool(
|
|
514
613
|
"recommend_chart",
|
|
515
614
|
{
|
|
516
|
-
|
|
517
|
-
description: "Profile tidy rows and return ranked ChartSpecs with rationale, profile evidence, alternatives, and explicit needs-decision/no-candidate findings. Use this before guessing a chart type or encoding; no supplied data is changed.",
|
|
615
|
+
...toolOptions("recommend_chart"),
|
|
518
616
|
inputSchema: {
|
|
519
617
|
data: dataRowsSchema,
|
|
520
618
|
intent: intentSchema,
|
|
@@ -530,8 +628,7 @@ function createServer() {
|
|
|
530
628
|
server.registerTool(
|
|
531
629
|
"repair_chart",
|
|
532
630
|
{
|
|
533
|
-
|
|
534
|
-
description: `Apply Graphein repairs and return the corrected spec, JSON Patch ops, per-patch rationales, and whether it is now valid. The default safe level applies validator-provided fixes; level "data" may infer missing encodings and field-name typo fixes from the spec's own data.`,
|
|
631
|
+
...toolOptions("repair_chart"),
|
|
535
632
|
inputSchema: {
|
|
536
633
|
spec: specSchema,
|
|
537
634
|
level: z.enum(["safe", "data"]).optional().describe('Repair aggressiveness. "safe" is default; "data" also infers from the spec data.')
|
|
@@ -542,8 +639,7 @@ function createServer() {
|
|
|
542
639
|
server.registerTool(
|
|
543
640
|
"list_chart_types",
|
|
544
641
|
{
|
|
545
|
-
|
|
546
|
-
description: "Return every supported chart type with purpose, required channels/properties, field roles, aggregation semantics, cardinality guidance, supported features, and a minimal runnable starter. Use this before reading the full schema.",
|
|
642
|
+
...toolOptions("list_chart_types"),
|
|
547
643
|
inputSchema: {}
|
|
548
644
|
},
|
|
549
645
|
async () => listChartTypesHandler()
|
|
@@ -551,12 +647,13 @@ function createServer() {
|
|
|
551
647
|
server.registerTool(
|
|
552
648
|
"summarize_chart",
|
|
553
649
|
{
|
|
554
|
-
|
|
555
|
-
description: `Return a deterministic, plain-English description of what the chart's data shows (e.g. "Users grew 46% over six months, peaking in June"). Doubles as alt-text; needs no LLM.`,
|
|
650
|
+
...toolOptions("summarize_chart"),
|
|
556
651
|
inputSchema: { spec: specSchema }
|
|
557
652
|
},
|
|
558
653
|
async (args) => summarizeChartHandler(args)
|
|
559
654
|
);
|
|
655
|
+
}
|
|
656
|
+
function registerResources(server) {
|
|
560
657
|
for (const r of RESOURCES) {
|
|
561
658
|
server.registerResource(
|
|
562
659
|
r.name,
|
|
@@ -567,6 +664,8 @@ function createServer() {
|
|
|
567
664
|
})
|
|
568
665
|
);
|
|
569
666
|
}
|
|
667
|
+
}
|
|
668
|
+
function registerCreateChartPrompt(server) {
|
|
570
669
|
server.registerPrompt(
|
|
571
670
|
"create_chart",
|
|
572
671
|
{
|
|
@@ -601,7 +700,6 @@ Steps:
|
|
|
601
700
|
]
|
|
602
701
|
})
|
|
603
702
|
);
|
|
604
|
-
return server;
|
|
605
703
|
}
|
|
606
704
|
|
|
607
705
|
export {
|
|
@@ -621,4 +719,4 @@ export {
|
|
|
621
719
|
VERSION,
|
|
622
720
|
createServer
|
|
623
721
|
};
|
|
624
|
-
//# sourceMappingURL=chunk-
|
|
722
|
+
//# sourceMappingURL=chunk-7DJMHUCG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tabular.ts","../src/handlers.ts","../src/resources.ts","../src/create-server.ts","../src/toolMetadata.ts"],"sourcesContent":["/** A tidy row parsed from CSV/TSV text. */\nexport type TabularRow = Record<string, number | string>;\n\n/** Error thrown when CSV/TSV text is malformed. */\nexport class TabularParseError extends Error {\n /** Create a parse error with a human-readable message. */\n constructor(message: string) {\n super(message);\n this.name = 'TabularParseError';\n }\n}\n\ninterface Cell {\n value: string;\n}\n\nfunction detectDelimiter(text: string): ',' | '\\t' {\n let comma = 0;\n let tab = 0;\n let quoted = false;\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (ch === '\"') {\n if (quoted && text[i + 1] === '\"') {\n i++;\n } else {\n quoted = !quoted;\n }\n } else if (!quoted && (ch === '\\n' || ch === '\\r')) {\n break;\n } else if (!quoted && ch === ',') {\n comma++;\n } else if (!quoted && ch === '\\t') {\n tab++;\n }\n }\n\n return tab > comma ? '\\t' : ',';\n}\n\nfunction coerceLosslessNumber(value: string): number | string {\n const trimmed = value.trim();\n if (/^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$/.test(trimmed)) {\n const n = Number(trimmed);\n if (Number.isFinite(n)) return n;\n }\n return value;\n}\n\nfunction coerceColumns(records: Cell[][], headers: string[]): TabularRow[] {\n const columnsAsNumbers = headers.map((_, i) =>\n records.every((record) => typeof coerceLosslessNumber(record[i].value) === 'number'),\n );\n return records.map((record) => {\n const row: TabularRow = {};\n for (let i = 0; i < headers.length; i++) {\n row[headers[i]] = columnsAsNumbers[i] ? coerceLosslessNumber(record[i].value) : record[i].value;\n }\n return row;\n });\n}\n\nfunction parseRecords(text: string, delimiter: ',' | '\\t'): Cell[][] {\n const records: Cell[][] = [];\n let record: Cell[] = [];\n let value = '';\n let quoted = false;\n let afterQuote = false;\n\n const pushCell = () => {\n record.push({ value });\n value = '';\n afterQuote = false;\n };\n const pushRecord = () => {\n pushCell();\n records.push(record);\n record = [];\n };\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n\n if (quoted) {\n if (ch === '\"') {\n if (text[i + 1] === '\"') {\n value += '\"';\n i++;\n } else {\n quoted = false;\n afterQuote = true;\n }\n } else {\n value += ch;\n }\n continue;\n }\n\n if (afterQuote && ch !== delimiter && ch !== '\\n' && ch !== '\\r') {\n if (/\\s/.test(ch)) continue;\n throw new TabularParseError(`Unexpected character '${ch}' after closing quote.`);\n }\n\n if (ch === '\"') {\n if (value.length > 0) throw new TabularParseError('Unexpected quote in an unquoted field.');\n quoted = true;\n } else if (ch === delimiter) {\n pushCell();\n } else if (ch === '\\n') {\n pushRecord();\n } else if (ch === '\\r') {\n pushRecord();\n if (text[i + 1] === '\\n') i++;\n } else {\n value += ch;\n }\n }\n\n if (quoted) throw new TabularParseError('Unclosed quoted field.');\n if (value.length > 0 || record.length > 0 || text.endsWith(String(delimiter))) pushRecord();\n return records.filter((r) => r.some((cell) => cell.value.length > 0));\n}\n\n/**\n * Parse CSV or TSV text with a header row into tidy data rows. Handles quoted\n * fields, escaped quotes, embedded delimiters, and embedded newlines.\n */\nexport function parseTabularText(text: string): TabularRow[] {\n const trimmed = text.replace(/^\\uFEFF/, '');\n const delimiter = detectDelimiter(trimmed);\n const records = parseRecords(trimmed, delimiter);\n if (records.length === 0) return [];\n\n const headers = records[0].map((cell) => cell.value.trim());\n if (headers.some((h) => h.length === 0)) {\n throw new TabularParseError('CSV/TSV header row must not contain empty column names.');\n }\n if (new Set(headers).size !== headers.length) {\n throw new TabularParseError('CSV/TSV header row must not contain duplicate column names.');\n }\n\n const dataRecords = records.slice(1);\n for (const [rowIndex, record] of dataRecords.entries()) {\n if (record.length !== headers.length) {\n throw new TabularParseError(\n `Row ${rowIndex + 2} has ${record.length} cells, expected ${headers.length}.`,\n );\n }\n }\n return coerceColumns(dataRecords, headers);\n}\n\n/**\n * Return a copy of a spec-like value with any `data: \"csv/tsv...\"` properties\n * parsed into tidy rows. Non-spec values are returned unchanged.\n */\nexport function parseInlineData(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(parseInlineData);\n if (typeof value !== 'object' || value === null) return value;\n\n const out: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n out[key] = key === 'data' && typeof child === 'string' ? parseTabularText(child) : parseInlineData(child);\n }\n return out;\n}\n","/**\n * Pure tool handlers — the generate → validate → repair → render → critique loop\n * exposed as plain functions so they can be unit-tested without a transport. Each\n * returns MCP-shaped content (`text` and/or `image` blocks). `createServer` wires\n * these into the `McpServer`.\n *\n * The handlers wrap `graphein`'s self-validating / self-repairing / self-explaining\n * core (`validateSpec`, `repairSpec`, `summarize`) and `@graphein/node`'s headless\n * `renderChart`, so an agent gets the chart **plus** a vision-free critique in one\n * call — and a one-step repair when its spec is slightly wrong.\n */\nimport {\n validateSpec,\n draft,\n repairSpec,\n recommendChart,\n profileData,\n listChartTypes,\n summarize,\n type AnySpec,\n type QualityOptions,\n type RecommendOptions,\n type RepairOptions,\n type ValidationError,\n} from 'graphein';\nimport { NodeRenderError, renderChart, validateRenderImageOptions } from '@graphein/node';\nimport { parseInlineData, parseTabularText } from './tabular.js';\n\n/** A subset of MCP content blocks the handlers emit. */\nexport type McpContent =\n | { type: 'text'; text: string }\n | { type: 'image'; data: string; mimeType: string };\n\n/**\n * The shape every handler returns — assignable to the SDK's `CallToolResult`\n * (which is an open/passthrough type, hence the index signature).\n */\nexport interface ToolResult {\n content: McpContent[];\n structuredContent?: Record<string, unknown>;\n isError?: boolean;\n [key: string]: unknown;\n}\n\n/** Options accepted by {@link renderChartHandler}. */\nexport interface RenderArgs {\n spec: unknown;\n width?: number;\n height?: number;\n dpr?: number;\n /** Auto-apply safe repairs before rendering when the spec is invalid. Default true. */\n repair?: boolean;\n /** Independent structural/data repair policy; defaults to safe. */\n repairLevel?: RepairOptions['level'];\n /** Opt-in presentation-default improvement, capped at three whole-visual renders. */\n quality?: boolean | QualityOptions;\n}\n\n/** Options accepted by {@link critiqueChartHandler}. */\nexport type CritiqueArgs = RenderArgs;\n\nexport interface RecommendChartArgs {\n data: Record<string, unknown>[] | string;\n intent?: string;\n maxResults?: number;\n /** Layout guidance only; never filters/groups the supplied rows to fit. */\n targetSize?: RecommendOptions['targetSize'];\n}\n\n/** Options accepted by {@link repairChartHandler}. */\nexport interface RepairChartArgs {\n spec: unknown;\n /** Repair level: safe fixes by default, or data-aware inference from inline rows. */\n level?: RepairOptions['level'];\n}\n\nfunction text(value: string): McpContent {\n return { type: 'text', text: value };\n}\n\nfunction json(value: unknown): McpContent {\n return text(JSON.stringify(value, null, 2));\n}\n\nfunction specType(spec: unknown): string {\n return typeof spec === 'object' && spec !== null && 'type' in spec\n ? String((spec as { type: unknown }).type)\n : '(missing)';\n}\n\nfunction isRecommendIntent(value: string | undefined): value is RecommendOptions['intent'] {\n return (\n value === undefined ||\n value === 'trend' ||\n value === 'comparison' ||\n value === 'distribution' ||\n value === 'relationship' ||\n value === 'composition'\n );\n}\n\nfunction parseErrorResult(e: unknown, quality?: RenderArgs['quality']): ToolResult {\n const payload = {\n ok: false,\n stage: 'parse-data',\n message: e instanceof Error ? e.message : String(e),\n ...(quality ? {\n rendered: false,\n quality: draft(undefined, { repair: false, quality }).quality,\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n}\n\nfunction optionErrorResult(e: unknown, quality?: RenderArgs['quality']): ToolResult {\n const payload = {\n ok: false,\n rendered: false,\n stage: 'options',\n message: e instanceof Error ? e.message : String(e),\n ...(quality ? {\n quality: draft(undefined, { repair: false, quality }).quality,\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n}\n\nfunction specWithParsedData(spec: unknown): unknown {\n return parseInlineData(spec);\n}\n\nfunction rowsWithParsedData(data: RecommendChartArgs['data']): Record<string, unknown>[] {\n return (typeof data === 'string' ? parseTabularText(data) : data) as Record<string, unknown>[];\n}\n\n/** Slim a validation error for an agent payload (drops nothing useful). */\nfunction tidyError(e: ValidationError) {\n const out: Record<string, unknown> = { path: e.path, message: e.message };\n if (e.rule) out.rule = e.rule;\n if (e.severity) out.severity = e.severity;\n if (e.fix) out.fix = e.fix;\n if (e.suggestion) out.suggestion = e.suggestion;\n if (e.evidence) out.evidence = e.evidence;\n if (e.requiresDecision !== undefined) out.requiresDecision = e.requiresDecision;\n return out;\n}\n\nfunction authoringMetadata(spec: AnySpec) {\n const types = listChartTypes();\n const capabilities = (type: AnySpec['type']) => types.find((t) => t.type === type)?.capabilities;\n if (spec.type !== 'dashboard') {\n return { profile: profileData(spec.data ?? []), capabilities: capabilities(spec.type) };\n }\n return {\n ...(spec.data ? { profile: profileData(spec.data) } : {}),\n capabilities: capabilities(spec.type),\n views: spec.views.map((view) => ({\n id: view.id,\n capabilities: capabilities(view.spec.type),\n ...(view.spec.data\n ? { profile: profileData(view.spec.data) }\n : { inheritsSharedData: true }),\n })),\n };\n}\n\n/**\n * **The flagship.** Validate a spec, auto-repair it if it's safely fixable, render\n * it to a PNG headless, and return the image alongside a machine-readable critique\n * (the render report + lint warnings + any repairs applied). When the spec can't be\n * made valid, returns the structured errors and JSON-Patch fixes instead of an image\n * so the agent corrects in one step rather than regenerating.\n */\nexport function renderChartHandler(args: RenderArgs): ToolResult {\n return renderOrCritique(args, true);\n}\n\n/**\n * Validate, optionally repair, render, and return only the machine-readable\n * render report + summary. This avoids sending a base64 PNG when an agent only\n * needs diagnostics.\n */\nexport function critiqueChartHandler(args: CritiqueArgs): ToolResult {\n return renderOrCritique(args, false);\n}\n\nfunction renderOrCritique(args: RenderArgs, includeImage: boolean): ToolResult {\n const { spec, width, height, dpr, repair = true, repairLevel, quality } = args;\n try {\n validateRenderImageOptions({ width, height, dpr });\n } catch (e) {\n return optionErrorResult(e, quality);\n }\n let working: unknown;\n try {\n working = specWithParsedData(spec);\n } catch (e) {\n return parseErrorResult(e, quality);\n }\n const prepared = draft(working, { repair, repairLevel, quality });\n const type = specType(prepared.spec);\n if (!prepared.valid) {\n const payload = {\n ok: false, rendered: false, stage: 'validate', type,\n errors: prepared.errors.map(tidyError),\n lint: prepared.warnings.map(tidyError),\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? { effectiveSpec: prepared.spec, quality: prepared.quality } : {}),\n hint: `Apply each error.fix JSON Patch (or the repair_chart tool), then call ${includeImage ? 'render_chart' : 'critique_chart'} again. See the graphein://agent-guide and graphein://schema resources.`,\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n }\n\n try {\n const rendered = renderChart(prepared.spec as AnySpec, { width, height, dpr, quality });\n const { report } = rendered;\n const payload = {\n ok: report.ok, rendered: true, type,\n pixelSize: { width: rendered.width, height: rendered.height },\n summary: report.summary,\n ...(includeImage ? {\n marks: report.markCount, series: report.seriesCount, colors: report.colorCount,\n diagnostics: report.diagnostics,\n } : {}),\n report,\n lint: validateSpec(rendered.spec).warnings.map(tidyError),\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? {\n effectiveSpec: rendered.spec, quality: rendered.quality,\n authoring: authoringMetadata(rendered.spec),\n } : {}),\n };\n return {\n isError: false,\n content: [\n ...(includeImage ? [{ type: 'image' as const, data: rendered.png.toString('base64'), mimeType: 'image/png' }] : []),\n json(payload),\n ],\n structuredContent: payload,\n };\n } catch (e) {\n const failed = e instanceof NodeRenderError ? e.result : undefined;\n const payload = {\n ok: false, rendered: false, stage: 'render', type,\n message: e instanceof Error ? e.message : String(e),\n summary: prepared.summary,\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? {\n effectiveSpec: failed?.spec ?? prepared.spec,\n quality: failed?.quality ?? { ...prepared.quality, stopReason: 'render-failed' },\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n }\n}\n\n/**\n * Validate a spec without rendering — fast structural + best-practice feedback.\n * Returns errors (each with a JSON-Patch `fix` when unambiguous and \"did you mean\"\n * suggestions) and lint `warnings`.\n */\nexport function validateChartHandler(args: { spec: unknown }): ToolResult {\n let spec: unknown;\n try {\n spec = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const result = validateSpec(spec);\n return {\n isError: false,\n content: [\n json({\n valid: result.valid,\n type: specType(spec),\n errors: result.errors.map(tidyError),\n warnings: result.warnings.map(tidyError),\n }),\n ],\n };\n}\n\n/** Recommend ready-to-render ChartSpecs from tidy rows and an optional intent. */\nexport function recommendChartHandler(args: RecommendChartArgs): ToolResult {\n if (!isRecommendIntent(args.intent)) {\n return {\n isError: true,\n content: [\n json({\n ok: false,\n message: 'Unsupported intent. Expected trend, comparison, distribution, relationship, or composition.',\n }),\n ],\n };\n }\n let data: Record<string, unknown>[];\n try {\n data = rowsWithParsedData(args.data);\n } catch (e) {\n return parseErrorResult(e);\n }\n const recommendations = recommendChart(data, {\n intent: args.intent, maxResults: args.maxResults, targetSize: args.targetSize, detailed: true,\n });\n const payload = { ok: true, ...recommendations };\n return { isError: false, content: [json(payload)], structuredContent: payload };\n}\n\n/**\n * List every supported chart family with its purpose, required channels, and a\n * minimal runnable starter spec.\n */\nexport function listChartTypesHandler(): ToolResult {\n const payload = { ok: true, chartTypes: listChartTypes() };\n return { isError: false, content: [json(payload)], structuredContent: payload };\n}\n\n/**\n * Apply every safe, unambiguous repair Graphein proposes and return the corrected\n * spec, the JSON Patch operations applied, and whether it is now valid.\n */\nexport function repairChartHandler(args: RepairChartArgs): ToolResult {\n let input: unknown;\n try {\n input = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const { spec, applied, appliedDetails, remaining } = repairSpec(input, { level: args.level ?? 'safe' });\n return {\n isError: false,\n content: [\n json({\n valid: remaining.length === 0,\n level: args.level ?? 'safe',\n applied,\n appliedDetails,\n remaining: remaining.map(tidyError),\n spec,\n }),\n ],\n };\n}\n\n/**\n * Return a deterministic, plain-English summary of what the chart's data shows —\n * doubles as alt-text, needs no LLM.\n */\nexport function summarizeChartHandler(args: { spec: unknown }): ToolResult {\n let spec: unknown;\n try {\n spec = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const result = validateSpec(spec);\n if (!result.valid) {\n return {\n isError: true,\n content: [\n json({\n summary: null,\n reason: 'Spec is invalid; fix it first (validate_chart / repair_chart).',\n errors: result.errors.map(tidyError),\n }),\n ],\n };\n }\n const validSpec = spec as AnySpec;\n const summary = validSpec.type === 'dashboard' ? undefined : summarize(validSpec);\n return {\n isError: false,\n content: [\n text(summary || `(No narrative summary is available for a '${specType(args.spec)}' chart.)`),\n ],\n };\n}\n","/**\n * The agent-facing knowledge Graphein serves as MCP **resources** — the schema\n * and the prose guides — so a model that has never seen Graphein's API can read\n * the contract at runtime instead of relying on training data. This is the core\n * of the MCP server's \"neutralize the training-data gap\" purpose.\n *\n * The files live in `../resources/` (committed copies of the repo's `docs/`, kept\n * in sync by `scripts/sync-resources.mjs`). They are read lazily and cached so the\n * server pays nothing until an agent actually asks for one.\n */\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\n/** Metadata describing one served resource. */\nexport interface GrapheinResource {\n /** Short registration name. */\n name: string;\n /** Stable `graphein://…` URI an agent reads. */\n uri: string;\n /** Human title. */\n title: string;\n /** What the resource is and when to read it. */\n description: string;\n /** IANA media type. */\n mimeType: string;\n /** File under `resources/`. */\n file: string;\n}\n\n/** Every resource the server exposes, in the order they should be advertised. */\nexport const RESOURCES: GrapheinResource[] = [\n {\n name: 'schema',\n uri: 'graphein://schema',\n title: 'Graphein ChartSpec JSON Schema',\n description:\n 'The machine-readable JSON Schema for every Graphein ChartSpec and DashboardSpec field — chart types, channels, transforms, annotations, and required properties. Generate or check a spec against this.',\n mimeType: 'application/json',\n file: 'chart-spec.schema.json',\n },\n {\n name: 'agent-guide',\n uri: 'graphein://agent-guide',\n title: 'Graphein Agent Guide',\n description:\n 'A task-oriented guide for producing correct Graphein charts: the one-rule workflow, choosing a chart type, encodings, transforms, the validate → repair → render → critique loop, and worked recipes. Read this first.',\n mimeType: 'text/markdown',\n file: 'agent-guide.md',\n },\n {\n name: 'spec-reference',\n uri: 'graphein://spec-reference',\n title: 'Graphein Spec Reference',\n description:\n 'The exhaustive field-by-field reference for every chart type, channel, transform, annotation, and modifier. Consult this for the precise shape of a specific field.',\n mimeType: 'text/markdown',\n file: 'spec-reference.md',\n },\n];\n\nconst cache = new Map<string, string>();\nconst allowedResourceFiles = new Set(RESOURCES.map((r) => r.file));\n\n/**\n * Read a bundled resource file's text, cached. Resolved relative to this module\n * so it works both from `dist/` (published) and `src/` (tests) — the committed\n * `resources/` dir always sits one level up from either.\n */\nexport function readResourceFile(file: string): string {\n if (!allowedResourceFiles.has(file)) {\n throw new Error(`Unknown Graphein MCP resource \"${file}\".`);\n }\n const hit = cache.get(file);\n if (hit !== undefined) return hit;\n const url = new URL(`../resources/${file}`, import.meta.url);\n const text = readFileSync(fileURLToPath(url), 'utf8');\n cache.set(file, text);\n return text;\n}\n\n/** Look up a resource by its `graphein://…` URI. */\nexport function resourceByUri(uri: string): GrapheinResource | undefined {\n return RESOURCES.find((r) => r.uri === uri);\n}\n","/**\n * `createServer()` — builds the Graphein MCP server: the generate → validate →\n * repair → render → critique loop as four tools, the schema + guides as resources,\n * and a `create_chart` prompt that teaches the workflow. Split from the stdio\n * entry point (`server.ts`) so it can be driven over any transport — including the\n * in-memory transport in tests.\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { RENDER_LIMITS } from '@graphein/node';\nimport { z } from 'zod';\nimport {\n critiqueChartHandler,\n listChartTypesHandler,\n renderChartHandler,\n validateChartHandler,\n repairChartHandler,\n recommendChartHandler,\n summarizeChartHandler,\n} from './handlers.js';\nimport { RESOURCES, readResourceFile } from './resources.js';\nimport { mcpToolMetadata } from './toolMetadata.js';\n\n/** Package version, surfaced as the MCP server version. */\nexport const VERSION = '0.20.0';\n\nconst SERVER_INSTRUCTIONS = `Graphein is an agent-first data-visualization library: you describe a chart as one JSON ChartSpec ({ type, data, encoding, ... }) and it renders. This server lets you build correct charts without prior knowledge of the API.\n\nWorkflow:\n1. Call list_chart_types to see every supported chart type with required channels, field roles, aggregation behavior, cardinality caveats, and starter specs; read graphein://agent-guide (and graphein://schema for exact fields) only when you need deeper detail.\n2. Shape data as tidy rows — one row per observation, one column per variable. Tools that accept rows also accept CSV/TSV text with a header row.\n3. Use recommend_chart when you want ranked specs from data, or start from a list_chart_types starter. Inspect profile, findings, and status: needs-decision/no-candidate are not permission to guess aggregation, date roles, missing values, or geometry.\n4. Emit a ChartSpec and call critique_chart for report-only diagnostics, or render_chart when you need the PNG plus critique. Both validate, auto-repair safe mistakes, render headlessly once by default, and return lint/report feedback. Opt in with quality:true for presentation-default improvements within three TOTAL whole-visual renders, including restoration. Read effectiveSpec, quality history and unresolved diagnostics; the loop never changes data or explicit settings.\n5. If a spec is invalid, validate_chart, critique_chart, and render_chart return structured errors with JSON-Patch fixes. Apply them or call repair_chart; use repair_chart level \"data\" to infer missing encodings or close field-name typos from the spec's own data.\nUse summarize_chart for deterministic alt-text. Every type rasterizes headlessly, including kpi, table, matrix, slicers and dashboard (static canvas snapshots).`;\n\n/** A permissive object schema for a Graphein spec — validateSpec does the real checking. */\nconst specSchema = z\n .record(z.string(), z.unknown())\n .describe(\n 'A Graphein ChartSpec or DashboardSpec object, e.g. { \"type\": \"line\", \"data\": [...], \"encoding\": {...} }. Any data property may be tidy rows or CSV/TSV text with a header row. See the graphein://schema and graphein://agent-guide resources.',\n );\n\nconst dataRowsSchema = z.union([\n z.array(z.record(z.string(), z.any())),\n z.string().describe('CSV or TSV text with a header row; quoted delimiters, quotes, and newlines are supported.'),\n]);\n\nconst intentSchema = z\n .enum(['trend', 'comparison', 'distribution', 'relationship', 'composition'])\n .optional()\n .describe(\n 'Optional analytical intent used to rank recommendations: trend, comparison, distribution, relationship, or composition.',\n );\n\nconst qualitySchema = z.union([\n z.boolean(),\n z.object({\n maxPasses: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional()\n .describe('Total whole-visual render ceiling including initial and rollback passes (default 3).'),\n }).strict(),\n]).optional().describe(\n 'Opt in to bounded presentation-default improvement. Default false: one render. Never alters data, encodings, explicit palettes/domains, or other caller settings. Returns effectiveSpec and quality history. Mutable targets reserve a rollback pass.',\n);\n\nconst repairLevelSchema = z.enum(['safe', 'data']).optional()\n .describe('Independent repair policy: safe (default), or explicitly opt in to data-aware field/encoding inference.');\nconst widthSchema = z.number().min(RENDER_LIMITS.minWidth).max(RENDER_LIMITS.maxWidth).optional()\n .describe(`Logical width in CSS px (default 800; ${RENDER_LIMITS.minWidth}-${RENDER_LIMITS.maxWidth}).`);\nconst heightSchema = z.number().min(RENDER_LIMITS.minHeight).max(RENDER_LIMITS.maxHeight).optional()\n .describe(`Logical height in CSS px (default 500; ${RENDER_LIMITS.minHeight}-${RENDER_LIMITS.maxHeight}).`);\nconst dprSchema = z.number().min(RENDER_LIMITS.minDpr).max(RENDER_LIMITS.maxDpr).optional()\n .describe(`Device pixel ratio for crisp output (default 2; ${RENDER_LIMITS.minDpr}-${RENDER_LIMITS.maxDpr}; total raster pixels capped at ${RENDER_LIMITS.maxPixels.toLocaleString('en-US')}).`);\n\nconst toolOptions = (name: string): { title: string; description: string } => {\n const { title, description } = mcpToolMetadata(name);\n return { title, description };\n};\n\n/**\n * Build a fully-configured Graphein MCP server. The caller connects it to a\n * transport (`server.connect(transport)`).\n */\nexport function createServer(): McpServer {\n const server = new McpServer(\n { name: 'graphein-mcp', version: VERSION },\n { instructions: SERVER_INSTRUCTIONS },\n );\n registerTools(server);\n registerResources(server);\n registerCreateChartPrompt(server);\n return server;\n}\n\nfunction registerTools(server: McpServer): void {\n // --- Tools: the runtime loop -------------------------------------------------\n registerRenderTools(server);\n registerSpecTools(server);\n}\n\nfunction registerRenderTools(server: McpServer): void {\n server.registerTool(\n 'render_chart',\n {\n ...toolOptions('render_chart'),\n inputSchema: {\n spec: specSchema,\n width: widthSchema,\n height: heightSchema,\n dpr: dprSchema,\n repair: z\n .boolean()\n .optional()\n .describe('Auto-apply safe repairs before rendering when the spec is invalid (default true).'),\n repairLevel: repairLevelSchema,\n quality: qualitySchema,\n },\n },\n async (args) => renderChartHandler(args),\n );\n\n server.registerTool(\n 'critique_chart',\n {\n ...toolOptions('critique_chart'),\n inputSchema: {\n spec: specSchema,\n width: widthSchema,\n height: heightSchema,\n dpr: dprSchema,\n repair: z\n .boolean()\n .optional()\n .describe('Auto-apply safe repairs before rendering when the spec is invalid (default true).'),\n repairLevel: repairLevelSchema,\n quality: qualitySchema,\n },\n },\n async (args) => critiqueChartHandler(args),\n );\n}\n\nfunction registerSpecTools(server: McpServer): void {\n server.registerTool(\n 'validate_chart',\n {\n ...toolOptions('validate_chart'),\n inputSchema: { spec: specSchema },\n },\n async (args) => validateChartHandler(args),\n );\n\n server.registerTool(\n 'recommend_chart',\n {\n ...toolOptions('recommend_chart'),\n inputSchema: {\n data: dataRowsSchema,\n intent: intentSchema,\n maxResults: z.number().int().positive().optional(),\n targetSize: z.object({\n width: z.number().positive(),\n height: z.number().positive(),\n }).optional().describe('Optional target CSS-pixel size for layout guidance only; does not filter or group data.'),\n },\n },\n async (args) => recommendChartHandler(args),\n );\n\n server.registerTool(\n 'repair_chart',\n {\n ...toolOptions('repair_chart'),\n inputSchema: {\n spec: specSchema,\n level: z\n .enum(['safe', 'data'])\n .optional()\n .describe('Repair aggressiveness. \"safe\" is default; \"data\" also infers from the spec data.'),\n },\n },\n async (args) => repairChartHandler(args),\n );\n\n server.registerTool(\n 'list_chart_types',\n {\n ...toolOptions('list_chart_types'),\n inputSchema: {},\n },\n async () => listChartTypesHandler(),\n );\n\n server.registerTool(\n 'summarize_chart',\n {\n ...toolOptions('summarize_chart'),\n inputSchema: { spec: specSchema },\n },\n async (args) => summarizeChartHandler(args),\n );\n}\n\nfunction registerResources(server: McpServer): void {\n\n // --- Resources: deliver the API knowledge at runtime -------------------------\n for (const r of RESOURCES) {\n server.registerResource(\n r.name,\n r.uri,\n { title: r.title, description: r.description, mimeType: r.mimeType },\n async (uri) => ({\n contents: [{ uri: uri.href, mimeType: r.mimeType, text: readResourceFile(r.file) }],\n }),\n );\n }\n}\n\nfunction registerCreateChartPrompt(server: McpServer): void {\n\n // --- Prompt: teach the workflow ---------------------------------------------\n server.registerPrompt(\n 'create_chart',\n {\n title: 'Create a Graphein chart',\n description:\n 'Scaffold the workflow for building a validated Graphein chart from a goal (and optional data).',\n argsSchema: {\n goal: z.string().describe('What the chart should show, e.g. \"monthly active users over the last year\".'),\n data: z\n .string()\n .optional()\n .describe('Optional: the data as a JSON array, or a description of the columns available.'),\n },\n },\n ({ goal, data }) => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Build a Graphein chart for this goal:\\n\\n${goal}\\n${\n data ? `\\nData:\\n${data}\\n` : ''\n }\\nSteps:\\n1. Call list_chart_types for available chart families and starter specs; read graphein://agent-guide or graphein://schema only for deeper details.\\n2. Shape the data as tidy rows — one row per observation, one column per variable. CSV/TSV text with a header row is accepted anywhere data rows are accepted.\\n3. Choose a chart type (or call recommend_chart) and write a single ChartSpec ({ type, data, encoding, title }).\\n4. Call critique_chart for report-only feedback or render_chart when you need the PNG too. Read the returned render report + lint to confirm it looks right.\\n5. If it reports errors, apply each error.fix patch (or call repair_chart, using level \"data\" when field/encoding inference from data is useful) and render again — do not regenerate from scratch.`,\n },\n },\n ],\n }),\n );\n}\n","export interface McpToolMetadata {\n readonly name: string;\n readonly title: string;\n readonly description: string;\n}\n\nexport const MCP_TOOL_METADATA = Object.freeze([\n {\n name: 'render_chart',\n title: 'Render a Graphein chart',\n description: 'The one-call loop: validate a ChartSpec, auto-repair safe mistakes, render it to a PNG, and return the image plus a vision-free critique (render report, lint warnings, repairs applied). If the spec cannot be made valid, returns structured errors with JSON-Patch fixes instead of an image. Every type rasterizes headlessly — kpi, table, matrix, slicers and dashboard render static canvas snapshots.',\n },\n {\n name: 'critique_chart',\n title: 'Critique a Graphein chart without an image',\n description: 'Validate a ChartSpec, auto-repair safe mistakes, render it headlessly, and return only the RenderReport, deterministic summary, lint warnings, and repairs applied — no base64 PNG. Use this when you need diagnostics but not an image.',\n },\n {\n name: 'validate_chart',\n title: 'Validate a Graphein chart spec',\n description: 'Validate a ChartSpec without rendering. Returns structural errors (each with a JSON-Patch fix when unambiguous, plus did-you-mean suggestions) and best-practice lint warnings. Fast feedback before rendering.',\n },\n {\n name: 'recommend_chart',\n title: 'Recommend Graphein chart specs',\n description: 'Profile tidy rows and return ranked ChartSpecs with rationale, profile evidence, alternatives, and explicit needs-decision/no-candidate findings. Use this before guessing a chart type or encoding; no supplied data is changed.',\n },\n {\n name: 'repair_chart',\n title: 'Repair a Graphein chart spec',\n description: 'Apply Graphein repairs and return the corrected spec, JSON Patch ops, per-patch rationales, and whether it is now valid. The default safe level applies validator-provided fixes; level \"data\" may infer missing encodings and field-name typo fixes from the spec\\'s own data.',\n },\n {\n name: 'list_chart_types',\n title: 'List Graphein chart types',\n description: 'Return every supported chart type with purpose, required channels/properties, field roles, aggregation semantics, cardinality guidance, supported features, and a minimal runnable starter. Use this before reading the full schema.',\n },\n {\n name: 'summarize_chart',\n title: 'Summarize a Graphein chart',\n description: 'Return a deterministic, plain-English description of what the chart\\'s data shows (e.g. \"Users grew 46% over six months, peaking in June\"). Doubles as alt-text; needs no LLM.',\n },\n] satisfies readonly McpToolMetadata[]);\n\nexport function mcpToolMetadata(name: string): McpToolMetadata {\n const tool = MCP_TOOL_METADATA.find((item) => item.name === name);\n if (!tool) throw new Error(`Unknown Graphein MCP tool: ${name}`);\n return tool;\n}\n"],"mappings":";AAIO,IAAM,oBAAN,cAAgC,MAAM;AAAA;AAAA,EAE3C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAMA,SAAS,gBAAgBA,OAA0B;AACjD,MAAI,QAAQ;AACZ,MAAI,MAAM;AACV,MAAI,SAAS;AAEb,WAAS,IAAI,GAAG,IAAIA,MAAK,QAAQ,KAAK;AACpC,UAAM,KAAKA,MAAK,CAAC;AACjB,QAAI,OAAO,KAAK;AACd,UAAI,UAAUA,MAAK,IAAI,CAAC,MAAM,KAAK;AACjC;AAAA,MACF,OAAO;AACL,iBAAS,CAAC;AAAA,MACZ;AAAA,IACF,WAAW,CAAC,WAAW,OAAO,QAAQ,OAAO,OAAO;AAClD;AAAA,IACF,WAAW,CAAC,UAAU,OAAO,KAAK;AAChC;AAAA,IACF,WAAW,CAAC,UAAU,OAAO,KAAM;AACjC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,QAAQ,MAAO;AAC9B;AAEA,SAAS,qBAAqB,OAAgC;AAC5D,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,+BAA+B,KAAK,OAAO,GAAG;AAChD,UAAM,IAAI,OAAO,OAAO;AACxB,QAAI,OAAO,SAAS,CAAC,EAAG,QAAO;AAAA,EACjC;AACA,SAAO;AACT;AAEA,SAAS,cAAc,SAAmB,SAAiC;AACzE,QAAM,mBAAmB,QAAQ;AAAA,IAAI,CAAC,GAAG,MACvC,QAAQ,MAAM,CAAC,WAAW,OAAO,qBAAqB,OAAO,CAAC,EAAE,KAAK,MAAM,QAAQ;AAAA,EACrF;AACA,SAAO,QAAQ,IAAI,CAAC,WAAW;AAC7B,UAAM,MAAkB,CAAC;AACzB,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAI,QAAQ,CAAC,CAAC,IAAI,iBAAiB,CAAC,IAAI,qBAAqB,OAAO,CAAC,EAAE,KAAK,IAAI,OAAO,CAAC,EAAE;AAAA,IAC5F;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,aAAaA,OAAc,WAAiC;AACnE,QAAM,UAAoB,CAAC;AAC3B,MAAI,SAAiB,CAAC;AACtB,MAAI,QAAQ;AACZ,MAAI,SAAS;AACb,MAAI,aAAa;AAEjB,QAAM,WAAW,MAAM;AACrB,WAAO,KAAK,EAAE,MAAM,CAAC;AACrB,YAAQ;AACR,iBAAa;AAAA,EACf;AACA,QAAM,aAAa,MAAM;AACvB,aAAS;AACT,YAAQ,KAAK,MAAM;AACnB,aAAS,CAAC;AAAA,EACZ;AAEA,WAAS,IAAI,GAAG,IAAIA,MAAK,QAAQ,KAAK;AACpC,UAAM,KAAKA,MAAK,CAAC;AAEjB,QAAI,QAAQ;AACV,UAAI,OAAO,KAAK;AACd,YAAIA,MAAK,IAAI,CAAC,MAAM,KAAK;AACvB,mBAAS;AACT;AAAA,QACF,OAAO;AACL,mBAAS;AACT,uBAAa;AAAA,QACf;AAAA,MACF,OAAO;AACL,iBAAS;AAAA,MACX;AACA;AAAA,IACF;AAEA,QAAI,cAAc,OAAO,aAAa,OAAO,QAAQ,OAAO,MAAM;AAChE,UAAI,KAAK,KAAK,EAAE,EAAG;AACnB,YAAM,IAAI,kBAAkB,yBAAyB,EAAE,wBAAwB;AAAA,IACjF;AAEA,QAAI,OAAO,KAAK;AACd,UAAI,MAAM,SAAS,EAAG,OAAM,IAAI,kBAAkB,wCAAwC;AAC1F,eAAS;AAAA,IACX,WAAW,OAAO,WAAW;AAC3B,eAAS;AAAA,IACX,WAAW,OAAO,MAAM;AACtB,iBAAW;AAAA,IACb,WAAW,OAAO,MAAM;AACtB,iBAAW;AACX,UAAIA,MAAK,IAAI,CAAC,MAAM,KAAM;AAAA,IAC5B,OAAO;AACL,eAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI,OAAQ,OAAM,IAAI,kBAAkB,wBAAwB;AAChE,MAAI,MAAM,SAAS,KAAK,OAAO,SAAS,KAAKA,MAAK,SAAS,OAAO,SAAS,CAAC,EAAG,YAAW;AAC1F,SAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,KAAK,MAAM,SAAS,CAAC,CAAC;AACtE;AAMO,SAAS,iBAAiBA,OAA4B;AAC3D,QAAM,UAAUA,MAAK,QAAQ,WAAW,EAAE;AAC1C,QAAM,YAAY,gBAAgB,OAAO;AACzC,QAAM,UAAU,aAAa,SAAS,SAAS;AAC/C,MAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAElC,QAAM,UAAU,QAAQ,CAAC,EAAE,IAAI,CAAC,SAAS,KAAK,MAAM,KAAK,CAAC;AAC1D,MAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG;AACvC,UAAM,IAAI,kBAAkB,yDAAyD;AAAA,EACvF;AACA,MAAI,IAAI,IAAI,OAAO,EAAE,SAAS,QAAQ,QAAQ;AAC5C,UAAM,IAAI,kBAAkB,6DAA6D;AAAA,EAC3F;AAEA,QAAM,cAAc,QAAQ,MAAM,CAAC;AACnC,aAAW,CAAC,UAAU,MAAM,KAAK,YAAY,QAAQ,GAAG;AACtD,QAAI,OAAO,WAAW,QAAQ,QAAQ;AACpC,YAAM,IAAI;AAAA,QACR,OAAO,WAAW,CAAC,QAAQ,OAAO,MAAM,oBAAoB,QAAQ,MAAM;AAAA,MAC5E;AAAA,IACF;AAAA,EACF;AACA,SAAO,cAAc,aAAa,OAAO;AAC3C;AAMO,SAAS,gBAAgB,OAAyB;AACvD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,eAAe;AAC1D,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AAExD,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,GAAG,IAAI,QAAQ,UAAU,OAAO,UAAU,WAAW,iBAAiB,KAAK,IAAI,gBAAgB,KAAK;AAAA,EAC1G;AACA,SAAO;AACT;;;AC3JA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AACP,SAAS,iBAAiB,aAAa,kCAAkC;AAmDzE,SAAS,KAAK,OAA2B;AACvC,SAAO,EAAE,MAAM,QAAQ,MAAM,MAAM;AACrC;AAEA,SAAS,KAAK,OAA4B;AACxC,SAAO,KAAK,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAC5C;AAEA,SAAS,SAAS,MAAuB;AACvC,SAAO,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU,OAC1D,OAAQ,KAA2B,IAAI,IACvC;AACN;AAEA,SAAS,kBAAkB,OAAgE;AACzF,SACE,UAAU,UACV,UAAU,WACV,UAAU,gBACV,UAAU,kBACV,UAAU,kBACV,UAAU;AAEd;AAEA,SAAS,iBAAiB,GAAY,SAA6C;AACjF,QAAM,UAAU;AAAA,IACd,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,SAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAAA,IAClD,GAAI,UAAU;AAAA,MACZ,UAAU;AAAA,MACV,SAAS,MAAM,QAAW,EAAE,QAAQ,OAAO,QAAQ,CAAC,EAAE;AAAA,IACxD,IAAI,CAAC;AAAA,EACP;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IAAM,SAAS,CAAC,KAAK,OAAO,CAAC;AAAA,IAAG,mBAAmB;AAAA,EAC9D;AACF;AAEA,SAAS,kBAAkB,GAAY,SAA6C;AAClF,QAAM,UAAU;AAAA,IACd,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAAA,IAClD,GAAI,UAAU;AAAA,MACZ,SAAS,MAAM,QAAW,EAAE,QAAQ,OAAO,QAAQ,CAAC,EAAE;AAAA,IACxD,IAAI,CAAC;AAAA,EACP;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IAAM,SAAS,CAAC,KAAK,OAAO,CAAC;AAAA,IAAG,mBAAmB;AAAA,EAC9D;AACF;AAEA,SAAS,mBAAmB,MAAwB;AAClD,SAAO,gBAAgB,IAAI;AAC7B;AAEA,SAAS,mBAAmB,MAA6D;AACvF,SAAQ,OAAO,SAAS,WAAW,iBAAiB,IAAI,IAAI;AAC9D;AAGA,SAAS,UAAU,GAAoB;AACrC,QAAM,MAA+B,EAAE,MAAM,EAAE,MAAM,SAAS,EAAE,QAAQ;AACxE,MAAI,EAAE,KAAM,KAAI,OAAO,EAAE;AACzB,MAAI,EAAE,SAAU,KAAI,WAAW,EAAE;AACjC,MAAI,EAAE,IAAK,KAAI,MAAM,EAAE;AACvB,MAAI,EAAE,WAAY,KAAI,aAAa,EAAE;AACrC,MAAI,EAAE,SAAU,KAAI,WAAW,EAAE;AACjC,MAAI,EAAE,qBAAqB,OAAW,KAAI,mBAAmB,EAAE;AAC/D,SAAO;AACT;AAEA,SAAS,kBAAkB,MAAe;AACxC,QAAM,QAAQ,eAAe;AAC7B,QAAM,eAAe,CAAC,SAA0B,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,GAAG;AACpF,MAAI,KAAK,SAAS,aAAa;AAC7B,WAAO,EAAE,SAAS,YAAY,KAAK,QAAQ,CAAC,CAAC,GAAG,cAAc,aAAa,KAAK,IAAI,EAAE;AAAA,EACxF;AACA,SAAO;AAAA,IACL,GAAI,KAAK,OAAO,EAAE,SAAS,YAAY,KAAK,IAAI,EAAE,IAAI,CAAC;AAAA,IACvD,cAAc,aAAa,KAAK,IAAI;AAAA,IACpC,OAAO,KAAK,MAAM,IAAI,CAAC,UAAU;AAAA,MAC/B,IAAI,KAAK;AAAA,MACT,cAAc,aAAa,KAAK,KAAK,IAAI;AAAA,MACzC,GAAI,KAAK,KAAK,OACV,EAAE,SAAS,YAAY,KAAK,KAAK,IAAI,EAAE,IACvC,EAAE,oBAAoB,KAAK;AAAA,IACjC,EAAE;AAAA,EACJ;AACF;AASO,SAAS,mBAAmB,MAA8B;AAC/D,SAAO,iBAAiB,MAAM,IAAI;AACpC;AAOO,SAAS,qBAAqB,MAAgC;AACnE,SAAO,iBAAiB,MAAM,KAAK;AACrC;AAEA,SAAS,iBAAiB,MAAkB,cAAmC;AAC7E,QAAM,EAAE,MAAM,OAAO,QAAQ,KAAK,SAAS,MAAM,aAAa,QAAQ,IAAI;AAC1E,MAAI;AACF,+BAA2B,EAAE,OAAO,QAAQ,IAAI,CAAC;AAAA,EACnD,SAAS,GAAG;AACV,WAAO,kBAAkB,GAAG,OAAO;AAAA,EACrC;AACA,MAAI;AACJ,MAAI;AACF,cAAU,mBAAmB,IAAI;AAAA,EACnC,SAAS,GAAG;AACV,WAAO,iBAAiB,GAAG,OAAO;AAAA,EACpC;AACA,QAAM,WAAW,MAAM,SAAS,EAAE,QAAQ,aAAa,QAAQ,CAAC;AAChE,QAAM,OAAO,SAAS,SAAS,IAAI;AACnC,MAAI,CAAC,SAAS,OAAO;AACnB,UAAM,UAAU;AAAA,MACd,IAAI;AAAA,MAAO,UAAU;AAAA,MAAO,OAAO;AAAA,MAAY;AAAA,MAC/C,QAAQ,SAAS,OAAO,IAAI,SAAS;AAAA,MACrC,MAAM,SAAS,SAAS,IAAI,SAAS;AAAA,MACrC,gBAAgB,SAAS;AAAA,MACzB,eAAe,SAAS;AAAA,MACxB,GAAI,UAAU,EAAE,eAAe,SAAS,MAAM,SAAS,SAAS,QAAQ,IAAI,CAAC;AAAA,MAC7E,MAAM,yEAAyE,eAAe,iBAAiB,gBAAgB;AAAA,IACjI;AACA,WAAO;AAAA,MACL,SAAS;AAAA,MAAM,SAAS,CAAC,KAAK,OAAO,CAAC;AAAA,MAAG,mBAAmB;AAAA,IAC9D;AAAA,EACF;AAEA,MAAI;AACF,UAAM,WAAW,YAAY,SAAS,MAAiB,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC;AACtF,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU;AAAA,MACd,IAAI,OAAO;AAAA,MAAI,UAAU;AAAA,MAAM;AAAA,MAC/B,WAAW,EAAE,OAAO,SAAS,OAAO,QAAQ,SAAS,OAAO;AAAA,MAC5D,SAAS,OAAO;AAAA,MAChB,GAAI,eAAe;AAAA,QACjB,OAAO,OAAO;AAAA,QAAW,QAAQ,OAAO;AAAA,QAAa,QAAQ,OAAO;AAAA,QACpE,aAAa,OAAO;AAAA,MACtB,IAAI,CAAC;AAAA,MACL;AAAA,MACA,MAAM,aAAa,SAAS,IAAI,EAAE,SAAS,IAAI,SAAS;AAAA,MACxD,gBAAgB,SAAS;AAAA,MACzB,eAAe,SAAS;AAAA,MACxB,GAAI,UAAU;AAAA,QACZ,eAAe,SAAS;AAAA,QAAM,SAAS,SAAS;AAAA,QAChD,WAAW,kBAAkB,SAAS,IAAI;AAAA,MAC5C,IAAI,CAAC;AAAA,IACP;AACA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,QACP,GAAI,eAAe,CAAC,EAAE,MAAM,SAAkB,MAAM,SAAS,IAAI,SAAS,QAAQ,GAAG,UAAU,YAAY,CAAC,IAAI,CAAC;AAAA,QACjH,KAAK,OAAO;AAAA,MACd;AAAA,MACA,mBAAmB;AAAA,IACrB;AAAA,EACF,SAAS,GAAG;AACV,UAAM,SAAS,aAAa,kBAAkB,EAAE,SAAS;AACzD,UAAM,UAAU;AAAA,MACd,IAAI;AAAA,MAAO,UAAU;AAAA,MAAO,OAAO;AAAA,MAAU;AAAA,MAC7C,SAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAAA,MAClD,SAAS,SAAS;AAAA,MAClB,gBAAgB,SAAS;AAAA,MACzB,eAAe,SAAS;AAAA,MACxB,GAAI,UAAU;AAAA,QACZ,eAAe,QAAQ,QAAQ,SAAS;AAAA,QACxC,SAAS,QAAQ,WAAW,EAAE,GAAG,SAAS,SAAS,YAAY,gBAAgB;AAAA,MACjF,IAAI,CAAC;AAAA,IACP;AACA,WAAO;AAAA,MACL,SAAS;AAAA,MAAM,SAAS,CAAC,KAAK,OAAO,CAAC;AAAA,MAAG,mBAAmB;AAAA,IAC9D;AAAA,EACF;AACF;AAOO,SAAS,qBAAqB,MAAqC;AACxE,MAAI;AACJ,MAAI;AACF,WAAO,mBAAmB,KAAK,IAAI;AAAA,EACrC,SAAS,GAAG;AACV,WAAO,iBAAiB,CAAC;AAAA,EAC3B;AACA,QAAM,SAAS,aAAa,IAAI;AAChC,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,MACP,KAAK;AAAA,QACH,OAAO,OAAO;AAAA,QACd,MAAM,SAAS,IAAI;AAAA,QACnB,QAAQ,OAAO,OAAO,IAAI,SAAS;AAAA,QACnC,UAAU,OAAO,SAAS,IAAI,SAAS;AAAA,MACzC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAGO,SAAS,sBAAsB,MAAsC;AAC1E,MAAI,CAAC,kBAAkB,KAAK,MAAM,GAAG;AACnC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,QACP,KAAK;AAAA,UACH,IAAI;AAAA,UACJ,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,MAAI;AACJ,MAAI;AACF,WAAO,mBAAmB,KAAK,IAAI;AAAA,EACrC,SAAS,GAAG;AACV,WAAO,iBAAiB,CAAC;AAAA,EAC3B;AACA,QAAM,kBAAkB,eAAe,MAAM;AAAA,IAC3C,QAAQ,KAAK;AAAA,IAAQ,YAAY,KAAK;AAAA,IAAY,YAAY,KAAK;AAAA,IAAY,UAAU;AAAA,EAC3F,CAAC;AACD,QAAM,UAAU,EAAE,IAAI,MAAM,GAAG,gBAAgB;AAC/C,SAAO,EAAE,SAAS,OAAO,SAAS,CAAC,KAAK,OAAO,CAAC,GAAG,mBAAmB,QAAQ;AAChF;AAMO,SAAS,wBAAoC;AAClD,QAAM,UAAU,EAAE,IAAI,MAAM,YAAY,eAAe,EAAE;AACzD,SAAO,EAAE,SAAS,OAAO,SAAS,CAAC,KAAK,OAAO,CAAC,GAAG,mBAAmB,QAAQ;AAChF;AAMO,SAAS,mBAAmB,MAAmC;AACpE,MAAI;AACJ,MAAI;AACF,YAAQ,mBAAmB,KAAK,IAAI;AAAA,EACtC,SAAS,GAAG;AACV,WAAO,iBAAiB,CAAC;AAAA,EAC3B;AACA,QAAM,EAAE,MAAM,SAAS,gBAAgB,UAAU,IAAI,WAAW,OAAO,EAAE,OAAO,KAAK,SAAS,OAAO,CAAC;AACtG,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,MACP,KAAK;AAAA,QACH,OAAO,UAAU,WAAW;AAAA,QAC5B,OAAO,KAAK,SAAS;AAAA,QACrB;AAAA,QACA;AAAA,QACA,WAAW,UAAU,IAAI,SAAS;AAAA,QAClC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAMO,SAAS,sBAAsB,MAAqC;AACzE,MAAI;AACJ,MAAI;AACF,WAAO,mBAAmB,KAAK,IAAI;AAAA,EACrC,SAAS,GAAG;AACV,WAAO,iBAAiB,CAAC;AAAA,EAC3B;AACA,QAAM,SAAS,aAAa,IAAI;AAChC,MAAI,CAAC,OAAO,OAAO;AACjB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,QACP,KAAK;AAAA,UACH,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ,OAAO,OAAO,IAAI,SAAS;AAAA,QACrC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,QAAM,YAAY;AAClB,QAAM,UAAU,UAAU,SAAS,cAAc,SAAY,UAAU,SAAS;AAChF,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,MACP,KAAK,WAAW,6CAA6C,SAAS,KAAK,IAAI,CAAC,WAAW;AAAA,IAC7F;AAAA,EACF;AACF;;;ACzXA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAmBvB,IAAM,YAAgC;AAAA,EAC3C;AAAA,IACE,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,aACE;AAAA,IACF,UAAU;AAAA,IACV,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,aACE;AAAA,IACF,UAAU;AAAA,IACV,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,aACE;AAAA,IACF,UAAU;AAAA,IACV,MAAM;AAAA,EACR;AACF;AAEA,IAAM,QAAQ,oBAAI,IAAoB;AACtC,IAAM,uBAAuB,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAO1D,SAAS,iBAAiB,MAAsB;AACrD,MAAI,CAAC,qBAAqB,IAAI,IAAI,GAAG;AACnC,UAAM,IAAI,MAAM,kCAAkC,IAAI,IAAI;AAAA,EAC5D;AACA,QAAM,MAAM,MAAM,IAAI,IAAI;AAC1B,MAAI,QAAQ,OAAW,QAAO;AAC9B,QAAM,MAAM,IAAI,IAAI,gBAAgB,IAAI,IAAI,YAAY,GAAG;AAC3D,QAAMC,QAAO,aAAa,cAAc,GAAG,GAAG,MAAM;AACpD,QAAM,IAAI,MAAMA,KAAI;AACpB,SAAOA;AACT;AAGO,SAAS,cAAc,KAA2C;AACvE,SAAO,UAAU,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG;AAC5C;;;AC5EA,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB;AAC9B,SAAS,SAAS;;;ACHX,IAAM,oBAAoB,OAAO,OAAO;AAAA,EAC7C;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AACF,CAAsC;AAE/B,SAAS,gBAAgB,MAA+B;AAC7D,QAAM,OAAO,kBAAkB,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI;AAChE,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,8BAA8B,IAAI,EAAE;AAC/D,SAAO;AACT;;;ADzBO,IAAM,UAAU;AAEvB,IAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAW5B,IAAM,aAAa,EAChB,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAC9B;AAAA,EACC;AACF;AAEF,IAAM,iBAAiB,EAAE,MAAM;AAAA,EAC7B,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,IAAI,CAAC,CAAC;AAAA,EACrC,EAAE,OAAO,EAAE,SAAS,2FAA2F;AACjH,CAAC;AAED,IAAM,eAAe,EAClB,KAAK,CAAC,SAAS,cAAc,gBAAgB,gBAAgB,aAAa,CAAC,EAC3E,SAAS,EACT;AAAA,EACC;AACF;AAEF,IAAM,gBAAgB,EAAE,MAAM;AAAA,EAC5B,EAAE,QAAQ;AAAA,EACV,EAAE,OAAO;AAAA,IACP,WAAW,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EACrE,SAAS,sFAAsF;AAAA,EACpG,CAAC,EAAE,OAAO;AACZ,CAAC,EAAE,SAAS,EAAE;AAAA,EACZ;AACF;AAEA,IAAM,oBAAoB,EAAE,KAAK,CAAC,QAAQ,MAAM,CAAC,EAAE,SAAS,EACzD,SAAS,yGAAyG;AACrH,IAAM,cAAc,EAAE,OAAO,EAAE,IAAI,cAAc,QAAQ,EAAE,IAAI,cAAc,QAAQ,EAAE,SAAS,EAC7F,SAAS,yCAAyC,cAAc,QAAQ,IAAI,cAAc,QAAQ,IAAI;AACzG,IAAM,eAAe,EAAE,OAAO,EAAE,IAAI,cAAc,SAAS,EAAE,IAAI,cAAc,SAAS,EAAE,SAAS,EAChG,SAAS,0CAA0C,cAAc,SAAS,IAAI,cAAc,SAAS,IAAI;AAC5G,IAAM,YAAY,EAAE,OAAO,EAAE,IAAI,cAAc,MAAM,EAAE,IAAI,cAAc,MAAM,EAAE,SAAS,EACvF,SAAS,mDAAmD,cAAc,MAAM,IAAI,cAAc,MAAM,mCAAmC,cAAc,UAAU,eAAe,OAAO,CAAC,IAAI;AAEjM,IAAM,cAAc,CAAC,SAAyD;AAC5E,QAAM,EAAE,OAAO,YAAY,IAAI,gBAAgB,IAAI;AACnD,SAAO,EAAE,OAAO,YAAY;AAC9B;AAMO,SAAS,eAA0B;AACxC,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,gBAAgB,SAAS,QAAQ;AAAA,IACzC,EAAE,cAAc,oBAAoB;AAAA,EACtC;AACA,gBAAc,MAAM;AACpB,oBAAkB,MAAM;AACxB,4BAA0B,MAAM;AAChC,SAAO;AACT;AAEA,SAAS,cAAc,QAAyB;AAE9C,sBAAoB,MAAM;AAC1B,oBAAkB,MAAM;AAC1B;AAEA,SAAS,oBAAoB,QAAyB;AACpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,GAAG,YAAY,cAAc;AAAA,MAC7B,aAAa;AAAA,QACX,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,QAAQ,EACL,QAAQ,EACR,SAAS,EACT,SAAS,mFAAmF;AAAA,QAC/F,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,OAAO,SAAS,mBAAmB,IAAI;AAAA,EACzC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,GAAG,YAAY,gBAAgB;AAAA,MAC/B,aAAa;AAAA,QACX,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,QAAQ,EACL,QAAQ,EACR,SAAS,EACT,SAAS,mFAAmF;AAAA,QAC/F,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,OAAO,SAAS,qBAAqB,IAAI;AAAA,EAC3C;AACF;AAEA,SAAS,kBAAkB,QAAyB;AAClD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,GAAG,YAAY,gBAAgB;AAAA,MAC/B,aAAa,EAAE,MAAM,WAAW;AAAA,IAClC;AAAA,IACA,OAAO,SAAS,qBAAqB,IAAI;AAAA,EAC3C;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,GAAG,YAAY,iBAAiB;AAAA,MAChC,aAAa;AAAA,QACX,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,QACjD,YAAY,EAAE,OAAO;AAAA,UACnB,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,UAC3B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,QAC9B,CAAC,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,MAClH;AAAA,IACF;AAAA,IACA,OAAO,SAAS,sBAAsB,IAAI;AAAA,EAC5C;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,GAAG,YAAY,cAAc;AAAA,MAC7B,aAAa;AAAA,QACX,MAAM;AAAA,QACN,OAAO,EACJ,KAAK,CAAC,QAAQ,MAAM,CAAC,EACrB,SAAS,EACT,SAAS,kFAAkF;AAAA,MAChG;AAAA,IACF;AAAA,IACA,OAAO,SAAS,mBAAmB,IAAI;AAAA,EACzC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,GAAG,YAAY,kBAAkB;AAAA,MACjC,aAAa,CAAC;AAAA,IAChB;AAAA,IACA,YAAY,sBAAsB;AAAA,EACpC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,GAAG,YAAY,iBAAiB;AAAA,MAChC,aAAa,EAAE,MAAM,WAAW;AAAA,IAClC;AAAA,IACA,OAAO,SAAS,sBAAsB,IAAI;AAAA,EAC5C;AACF;AAEA,SAAS,kBAAkB,QAAyB;AAGlD,aAAW,KAAK,WAAW;AACzB,WAAO;AAAA,MACL,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE,OAAO,EAAE,OAAO,aAAa,EAAE,aAAa,UAAU,EAAE,SAAS;AAAA,MACnE,OAAO,SAAS;AAAA,QACd,UAAU,CAAC,EAAE,KAAK,IAAI,MAAM,UAAU,EAAE,UAAU,MAAM,iBAAiB,EAAE,IAAI,EAAE,CAAC;AAAA,MACpF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,0BAA0B,QAAyB;AAG1D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,aACE;AAAA,MACF,YAAY;AAAA,QACV,MAAM,EAAE,OAAO,EAAE,SAAS,6EAA6E;AAAA,QACvG,MAAM,EACH,OAAO,EACP,SAAS,EACT,SAAS,gFAAgF;AAAA,MAC9F;AAAA,IACF;AAAA,IACA,CAAC,EAAE,MAAM,KAAK,OAAO;AAAA,MACnB,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,YACP,MAAM;AAAA,YACN,MAAM;AAAA;AAAA,EAA4C,IAAI;AAAA,EACpD,OAAO;AAAA;AAAA,EAAY,IAAI;AAAA,IAAO,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":["text","text"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export { AnyRenderReport, AnySpec, ChartCapabilities, ChartSpec, DashboardRender
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
/** Package version, surfaced as the MCP server version. */
|
|
14
|
-
declare const VERSION = "0.
|
|
14
|
+
declare const VERSION = "0.20.0";
|
|
15
15
|
/**
|
|
16
16
|
* Build a fully-configured Graphein MCP server. The caller connects it to a
|
|
17
17
|
* transport (`server.connect(transport)`).
|
package/dist/index.js
CHANGED
package/dist/server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphein-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Model Context Protocol server for Graphein — wraps generate → validate → repair → render → critique into one tool call, and serves Graphein's schema + agent guide as resources so a model that never saw the API can still build correct charts.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,18 +52,19 @@
|
|
|
52
52
|
"access": "public"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
|
-
"
|
|
55
|
+
"sync:version": "node ../core/scripts/sync-version.mjs .",
|
|
56
|
+
"build": "npm run sync:version && tsup",
|
|
56
57
|
"dev": "tsup --watch",
|
|
57
58
|
"start": "node dist/server.js",
|
|
58
59
|
"sync:resources": "node scripts/sync-resources.mjs",
|
|
59
60
|
"test": "vitest run",
|
|
60
61
|
"typecheck": "tsc --noEmit",
|
|
61
|
-
"prepack": "tsup"
|
|
62
|
+
"prepack": "npm run sync:version && tsup"
|
|
62
63
|
},
|
|
63
64
|
"dependencies": {
|
|
64
|
-
"@graphein/node": "^0.
|
|
65
|
+
"@graphein/node": "^0.20.0",
|
|
65
66
|
"@modelcontextprotocol/sdk": "^1.20.0",
|
|
66
|
-
"graphein": "^0.
|
|
67
|
+
"graphein": "^0.20.0",
|
|
67
68
|
"zod": "^3.23.0"
|
|
68
69
|
}
|
|
69
70
|
}
|
package/resources/agent-guide.md
CHANGED
|
@@ -88,6 +88,28 @@ mark** (cartesian charts plot rows as‑is); reach for `fold` instead of pre‑p
|
|
|
88
88
|
filter in the spec so the same raw `data` can feed several views. Full field‑by‑field
|
|
89
89
|
reference: [spec-reference → Transforms](./spec-reference.md#transforms).
|
|
90
90
|
|
|
91
|
+
### Current semantics agents should rely on
|
|
92
|
+
|
|
93
|
+
- Validation is total for JSON inputs: `validateSpec` / `validateDashboard` return errors
|
|
94
|
+
instead of throwing, shape-check nested encodings/scales/ValueRefs, flag unknown nested
|
|
95
|
+
properties with suggestions, and validate `calculate` length/depth/functions/arity,
|
|
96
|
+
filter leaves, bin params, and KPI/gauge/bullet aggregates before rendering. Repair
|
|
97
|
+
skips unsafe or unresolvable JSON Patch ops and rejects prototype paths.
|
|
98
|
+
- One data classifier is shared by render, validate, lint, repair, profile, recommend and
|
|
99
|
+
insights. Numeric strings are numbers first (`"2019"` is quantitative), quantitative or
|
|
100
|
+
temporal inference needs at least 80% usable sampled values, calendar dates are strict,
|
|
101
|
+
and dot-path fields work in accessors and aggregate transforms.
|
|
102
|
+
- Bare temporal strings use local time; `YYYY`, `YYYY-MM`, and date-only range bounds use
|
|
103
|
+
local calendar periods. A max bound like `"2024-01-31"` includes that whole day, and
|
|
104
|
+
dateRange slicers step by local calendar days across DST.
|
|
105
|
+
- Selections compare temporal values by instant and publish raw row values. Heatmap and
|
|
106
|
+
calendarHeatmap picks keep `Date` objects; histogram picks publish interval/range
|
|
107
|
+
selections; multi-series cartesian dashboard picks publish `[x, series]` tuples.
|
|
108
|
+
- Chart instances are lifecycle-safe: after `destroy()` mutations are no-ops and
|
|
109
|
+
`report()` returns the last report; `update()` re-runs transforms even after in-place
|
|
110
|
+
data mutation; DPR changes redraw; selection redraws are coalesced and flushed by
|
|
111
|
+
`report()` / `getSelection()`. `SelectionStore.batch(fn)` coalesces notifications.
|
|
112
|
+
|
|
91
113
|
## Picking a chart type
|
|
92
114
|
|
|
93
115
|
| Goal | Use | Key channels |
|
|
@@ -2499,7 +2499,7 @@
|
|
|
2499
2499
|
}
|
|
2500
2500
|
}
|
|
2501
2501
|
],
|
|
2502
|
-
"description": "Cross-interaction policy:\n- 'auto' (default):
|
|
2502
|
+
"description": "Cross-interaction policy:\n- 'auto' (default): compatible sources cross-filter the page — slicers and chart clicks subset peer views that share their dataset, or peer views on separate data only when those views explicitly reference the selected field (encodings, value refs, table/matrix fields, facets, etc.). The clicked chart dims its own unpicked marks instead of hiding them.\n- 'none': views are laid out but not linked.\n- an array of InteractionLink: explicit wiring (replaces auto)."
|
|
2503
2503
|
}
|
|
2504
2504
|
},
|
|
2505
2505
|
"required": [
|
|
@@ -7786,7 +7786,8 @@
|
|
|
7786
7786
|
"description": "Negative / down semantics."
|
|
7787
7787
|
}
|
|
7788
7788
|
},
|
|
7789
|
-
"additionalProperties": false
|
|
7789
|
+
"additionalProperties": false,
|
|
7790
|
+
"description": "Deep-partial token overrides: arrays replace wholesale, nested objects merge key by key."
|
|
7790
7791
|
},
|
|
7791
7792
|
"ThemeFontOverrides": {
|
|
7792
7793
|
"type": "object",
|
|
@@ -7801,7 +7802,8 @@
|
|
|
7801
7802
|
"$ref": "#/$defs/ThemeFontWeightsOverrides"
|
|
7802
7803
|
}
|
|
7803
7804
|
},
|
|
7804
|
-
"additionalProperties": false
|
|
7805
|
+
"additionalProperties": false,
|
|
7806
|
+
"description": "Deep-partial token overrides: arrays replace wholesale, nested objects merge key by key."
|
|
7805
7807
|
},
|
|
7806
7808
|
"ThemeFontSizesOverrides": {
|
|
7807
7809
|
"type": "object",
|
|
@@ -7822,7 +7824,8 @@
|
|
|
7822
7824
|
"type": "number"
|
|
7823
7825
|
}
|
|
7824
7826
|
},
|
|
7825
|
-
"additionalProperties": false
|
|
7827
|
+
"additionalProperties": false,
|
|
7828
|
+
"description": "Deep-partial token overrides: arrays replace wholesale, nested objects merge key by key."
|
|
7826
7829
|
},
|
|
7827
7830
|
"ThemeFontWeightsOverrides": {
|
|
7828
7831
|
"type": "object",
|
|
@@ -7837,7 +7840,8 @@
|
|
|
7837
7840
|
"type": "number"
|
|
7838
7841
|
}
|
|
7839
7842
|
},
|
|
7840
|
-
"additionalProperties": false
|
|
7843
|
+
"additionalProperties": false,
|
|
7844
|
+
"description": "Deep-partial token overrides: arrays replace wholesale, nested objects merge key by key."
|
|
7841
7845
|
},
|
|
7842
7846
|
"ThemeInput": {
|
|
7843
7847
|
"anyOf": [
|
|
@@ -7890,7 +7894,8 @@
|
|
|
7890
7894
|
"type": "number"
|
|
7891
7895
|
}
|
|
7892
7896
|
},
|
|
7893
|
-
"additionalProperties": false
|
|
7897
|
+
"additionalProperties": false,
|
|
7898
|
+
"description": "Deep-partial token overrides: arrays replace wholesale, nested objects merge key by key."
|
|
7894
7899
|
},
|
|
7895
7900
|
"ThemeSpacingOverrides": {
|
|
7896
7901
|
"type": "object",
|
|
@@ -7911,7 +7916,8 @@
|
|
|
7911
7916
|
"type": "number"
|
|
7912
7917
|
}
|
|
7913
7918
|
},
|
|
7914
|
-
"additionalProperties": false
|
|
7919
|
+
"additionalProperties": false,
|
|
7920
|
+
"description": "Deep-partial token overrides: arrays replace wholesale, nested objects merge key by key."
|
|
7915
7921
|
},
|
|
7916
7922
|
"ThemeStrokesOverrides": {
|
|
7917
7923
|
"type": "object",
|
|
@@ -7926,7 +7932,8 @@
|
|
|
7926
7932
|
"type": "number"
|
|
7927
7933
|
}
|
|
7928
7934
|
},
|
|
7929
|
-
"additionalProperties": false
|
|
7935
|
+
"additionalProperties": false,
|
|
7936
|
+
"description": "Deep-partial token overrides: arrays replace wholesale, nested objects merge key by key."
|
|
7930
7937
|
},
|
|
7931
7938
|
"TimeUnit": {
|
|
7932
7939
|
"type": "string",
|
|
@@ -17,8 +17,11 @@ const instance = render('#chart', {
|
|
|
17
17
|
});
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
- **`type`** is the discriminator. One of:
|
|
21
|
-
`line`, `area`, `bar`, `scatter`, `
|
|
20
|
+
- **`type`** is the discriminator. One of 27 chart and slicer types:
|
|
21
|
+
`line`, `area`, `bar`, `scatter`, `combo`, `histogram`, `pie`, `heatmap`, `funnel`,
|
|
22
|
+
`kpi`, `treemap`, `gauge`, `bullet`, `calendarHeatmap`, `waterfall`, `slope`,
|
|
23
|
+
`dumbbell`, `table`, `matrix`, `box`, `sankey`, `choropleth`, `dropdown`,
|
|
24
|
+
`search`, `list`, `range`, `dateRange`.
|
|
22
25
|
- **`data`** is a tidy/row‑oriented array of records (`Array<Record<string, unknown>>`).
|
|
23
26
|
The same long‑format table feeds every chart; you select fields via `encoding`
|
|
24
27
|
(cartesian charts) or via explicit field lists (`table`, `matrix`).
|
|
@@ -65,7 +68,7 @@ Shared by **all** chart types.
|
|
|
65
68
|
|
|
66
69
|
| Field | Type | Default | Notes |
|
|
67
70
|
| --- | --- | --- | --- |
|
|
68
|
-
| `data` | `Datum[]` | — | Row‑oriented records. Required for
|
|
71
|
+
| `data` | `Datum[]` | — | Row‑oriented records. Required for data-backed charts/tables; optional for literal-value `kpi`, `gauge`, and `bullet` specs. |
|
|
69
72
|
| `transform` | `Transform[]` | — | Declarative pipeline that reshapes `data` **before** charting (aggregate, bin, filter, fold, timeUnit). See [Transforms](#transforms). |
|
|
70
73
|
| `theme` | `'light' \| 'dark' \| ThemeOverride` | `'light'` | Theme name or a partial override (see [Themes](#themes)). |
|
|
71
74
|
| `palette` | `'graphein' \| 'colorblind' \| 'bright' \| 'muted' \| string[]` | theme palette | Categorical series palette selector, or explicit colors cycled across series. |
|
|
@@ -222,6 +225,11 @@ columns onto visual **channels** through `encoding`.
|
|
|
222
225
|
> **Temporal fields:** JSON has no `Date` type, so pass dates as ISO‑ish strings
|
|
223
226
|
> (`"2024-01-15"`, `"2024-01"`) or epoch milliseconds. Graphein parses them for time
|
|
224
227
|
> axes, and `%` date formats coerce date strings for display in tables.
|
|
228
|
+
> Numeric evidence wins inference first, so a year-like string such as `"2019"`
|
|
229
|
+
> is quantitative unless you set `type:'temporal'`. Temporal strings without
|
|
230
|
+
> `Z`/offset parse in local time; `YYYY` is local Jan 1. Date-only range bounds
|
|
231
|
+
> cover whole local periods, so `max:"2024-01-31"` includes all of Jan 31.
|
|
232
|
+
> Strict calendar validation rejects impossible dates such as `"2024-02-30"`.
|
|
225
233
|
|
|
226
234
|
---
|
|
227
235
|
|
|
@@ -331,6 +339,8 @@ Supported:
|
|
|
331
339
|
max number isFinite isNaN str lower upper trim length substring replace contains
|
|
332
340
|
startsWith endsWith concat coalesce if year month day hours minutes`. No
|
|
333
341
|
`now()`/`random()` — transforms stay deterministic.
|
|
342
|
+
- **Limits:** expressions may be at most 10,000 characters and 100 nested levels.
|
|
343
|
+
Unknown functions and wrong arity are validation errors, not render-time throws.
|
|
334
344
|
|
|
335
345
|
> **Note:** Aggregation is chart-specific. KPI/gauge/bullet ValueRefs aggregate
|
|
336
346
|
> values (sum by default); matrix uses `values[].op`; pie honors
|
|
@@ -338,6 +348,16 @@ Supported:
|
|
|
338
348
|
> Cartesian channels plot rows as supplied: use an explicit `transform`
|
|
339
349
|
> `aggregate` step when you want one row per mark.
|
|
340
350
|
|
|
351
|
+
Validation also shape-checks every present encoding channel, FieldDef, scale and
|
|
352
|
+
ValueRef; unknown nested property names are warnings with did-you-mean guidance.
|
|
353
|
+
`filter` leaves may contain only one comparison operator (use `range` or compose
|
|
354
|
+
with `and`), bin params require integer `maxbins >= 1`, finite positive `step`, and
|
|
355
|
+
finite increasing `extent`, and ValueRef aggregates for `kpi`/`gauge`/`bullet` use
|
|
356
|
+
the same aggregate-op enum as other value references. `validateSpec` and
|
|
357
|
+
`validateDashboard` return structured failures for any JSON input rather than
|
|
358
|
+
throwing. Repair JSON Patches follow RFC 6901/6902 index rules, reject
|
|
359
|
+
`__proto__`/`constructor`/`prototype` path segments, and skip unresolvable ops.
|
|
360
|
+
|
|
341
361
|
---
|
|
342
362
|
|
|
343
363
|
## Annotations (reference lines, bands, zones, points)
|
|
@@ -492,6 +512,38 @@ remaining information does not fit.
|
|
|
492
512
|
|
|
493
513
|
## Chart types
|
|
494
514
|
|
|
515
|
+
<!-- generated:chart-types:start -->
|
|
516
|
+
| Type | Label | Purpose | Required channels/properties |
|
|
517
|
+
| --- | --- | --- | --- |
|
|
518
|
+
| `line` | Line chart | Trend over time | `x`, `y` |
|
|
519
|
+
| `area` | Area chart | Part-to-whole or filled trend over time | `x`, `y` |
|
|
520
|
+
| `bar` | Bar chart | Compare categories | `x`, `y` |
|
|
521
|
+
| `scatter` | Scatter plot | Correlation or distribution across two measures | `x`, `y` |
|
|
522
|
+
| `combo` | Combo chart | Two measures or mark types on a shared axis | `x` |
|
|
523
|
+
| `histogram` | Histogram | Distribution of one quantitative measure | `x` |
|
|
524
|
+
| `pie` | Pie chart | Composition of a total | `theta`, `color` |
|
|
525
|
+
| `heatmap` | Heatmap | Density across two categories | `x`, `y`, `color` |
|
|
526
|
+
| `funnel` | Funnel chart | Conversion through stages | `stage`, `value` |
|
|
527
|
+
| `kpi` | KPI card | Single headline value or compact scorecard | — |
|
|
528
|
+
| `treemap` | Treemap | Hierarchical or categorical part-to-whole | `category`, `value` |
|
|
529
|
+
| `gauge` | Gauge | Single value against a scale | — |
|
|
530
|
+
| `bullet` | Bullet graph | Compact KPI versus a target | — |
|
|
531
|
+
| `calendarHeatmap` | Calendar heatmap | Daily values over a year | `date`, `color` |
|
|
532
|
+
| `waterfall` | Waterfall chart | Running total or bridge of signed deltas | `stage`, `value` |
|
|
533
|
+
| `slope` | Slope chart | Before/after change across series | `x`, `y`, `series` |
|
|
534
|
+
| `dumbbell` | Dumbbell plot | Gap between two groups by category | `category`, `value`, `group` |
|
|
535
|
+
| `table` | Data table | Tabular detail | — |
|
|
536
|
+
| `matrix` | Pivot matrix | Pivot or cross-tab summary | — |
|
|
537
|
+
| `box` | Box plot | Spread and distribution by group | `x`, `y` |
|
|
538
|
+
| `sankey` | Sankey diagram | Flows between nodes | `source`, `target`, `value` |
|
|
539
|
+
| `choropleth` | Choropleth map | Values over map regions | `geo`, `key`, `color`, `featureId` |
|
|
540
|
+
| `dropdown` | Dropdown filter | Single- or multi-select field filter | `field` |
|
|
541
|
+
| `search` | Search filter | Text search filter for a field | `field` |
|
|
542
|
+
| `list` | List filter | Checkbox list filter for a field | `field` |
|
|
543
|
+
| `range` | Range filter | Numeric range filter for a field | `field` |
|
|
544
|
+
| `dateRange` | Date range filter | Temporal range filter for a field | `field` |
|
|
545
|
+
<!-- generated:chart-types:end -->
|
|
546
|
+
|
|
495
547
|
### line
|
|
496
548
|
|
|
497
549
|
Time/continuous series with optional multi‑series, markers, and area fill.
|
|
@@ -1559,6 +1611,10 @@ Inspect these fields rather than assuming input rows equal visible data:
|
|
|
1559
1611
|
nominal backdrop, not a pixel-level account of overlapping marks. Samples with
|
|
1560
1612
|
`intentionalDim:true` retain their actual opacity but are not treated as contrast
|
|
1561
1613
|
defects caused by deliberate cross-highlighting.
|
|
1614
|
+
- `backingStore:{requestedDpr,effectiveDpr,pixelWidth,pixelHeight,clamped}` appears
|
|
1615
|
+
when a renderer can report canvas allocation. If `clamped` is true, the report
|
|
1616
|
+
includes `backing-store-clamped` info because Graphein lowered DPR to keep the
|
|
1617
|
+
raster within safe browser/headless limits while preserving CSS layout size.
|
|
1562
1618
|
|
|
1563
1619
|
Dashboards expose `views:[{id,index,report}]` with each child's own size/evidence.
|
|
1564
1620
|
Aggregate diagnostic paths and `viewId` identify the affected view. Both
|
|
@@ -1574,32 +1630,55 @@ that static-output limitation rather than counting off-page marks as visible.
|
|
|
1574
1630
|
|
|
1575
1631
|
**Diagnostic codes**
|
|
1576
1632
|
|
|
1577
|
-
|
|
1578
|
-
|
|
|
1579
|
-
|
|
|
1580
|
-
| `
|
|
1581
|
-
| `
|
|
1582
|
-
| `
|
|
1583
|
-
| `
|
|
1584
|
-
| `
|
|
1585
|
-
| `
|
|
1586
|
-
| `
|
|
1587
|
-
| `
|
|
1588
|
-
| `
|
|
1589
|
-
| `
|
|
1590
|
-
| `
|
|
1591
|
-
| `
|
|
1592
|
-
| `
|
|
1593
|
-
| `
|
|
1594
|
-
| `
|
|
1595
|
-
| `
|
|
1596
|
-
| `invalid-
|
|
1597
|
-
| `
|
|
1598
|
-
| `
|
|
1599
|
-
| `
|
|
1600
|
-
| `
|
|
1601
|
-
|
|
1602
|
-
|
|
1633
|
+
<!-- generated:diagnostics:start -->
|
|
1634
|
+
| `code` | Severity | Meaning | What to do |
|
|
1635
|
+
| --- | --- | --- | --- |
|
|
1636
|
+
| `ambiguous-type` | info | A profiled field has mixed evidence and no single type dominates. | Choose the field type explicitly in the encoding or clean the source values. |
|
|
1637
|
+
| `annotation-clipped` | warning | Point annotation markers or labels overflow the plot. | Increase the chart size, shorten labels, or remove optional annotation labels/insights. |
|
|
1638
|
+
| `axis-label-overlap` | warning | Not every x-axis category label can be shown readably. | Widen the chart, rotate labels, facet, filter, or aggregate the long tail. |
|
|
1639
|
+
| `backing-store-clamped` | info | The requested canvas DPR was lowered to keep the backing store within safe limits. | Reduce the chart dimensions or requested DPR if you require the exact raster scale. |
|
|
1640
|
+
| `dashboard-placement-adjusted` | warning | A dashboard view could not keep its requested grid placement. | Review the view span, row pin, and dashboard column count. |
|
|
1641
|
+
| `degenerate-axis` | warning / info | An axis collapsed to one value or too few ticks. | Check constant data, explicit domains, or use a mark type that better suits a single value. |
|
|
1642
|
+
| `duplicate-keys` | info | Profiled rows contain repeated keys for a candidate encoding. | Decide whether to aggregate, preserve repeated rows, or add a series/detail field. |
|
|
1643
|
+
| `empty-dashboard` | warning | A dashboard has no views. | Add at least one view. |
|
|
1644
|
+
| `empty-data` | warning | No rows remain to render. | Check data, transforms, filters, and selection state. |
|
|
1645
|
+
| `empty-plot` | error / warning | The plotting area collapsed or every series resolved to zero rows. | Increase size, reduce chrome, or fix encoding field names. |
|
|
1646
|
+
| `empty-view` | error | A dashboard child view collapsed to an unusable size. | Increase the view span/page size or reduce card chrome. |
|
|
1647
|
+
| `flow-cycle` | warning | A recommended Sankey contains feedback/cyclic flow that cannot be fully laid out. | Remove feedback links, split the flow into stages, or expect omitted links. |
|
|
1648
|
+
| `font-fallback` | warning | A requested Node font could not be registered. | Supply a readable font file registered under the family used by the theme. |
|
|
1649
|
+
| `invalid-label-geometry` | error | A label reached reporting with non-finite or invalid bounds. | Fix invalid data/geometry or report a renderer bug with the spec. |
|
|
1650
|
+
| `invalid-mark-geometry` | error | A logical mark reached drawing with non-finite or negative geometry. | Check invalid values, scale domains, and renderer evidence. |
|
|
1651
|
+
| `invalid-rows` | warning | Profiling skipped non-object rows. | Pass tidy row objects or parse tabular data before profiling/recommendation. |
|
|
1652
|
+
| `invalid-values` | warning | A profiled field contains values that do not fit its inferred role. | Clean/coerce the field or set the intended type explicitly. |
|
|
1653
|
+
| `label-collision` | warning | Drawn labels overlap. | Give the chart more room or reduce optional labels while preserving identifiers. |
|
|
1654
|
+
| `label-collision-coverage` | warning | The bounded label collision scan was incomplete. | Do not treat the absence of detected collisions as proof of readability; simplify or enlarge the chart. |
|
|
1655
|
+
| `labels-suppressed` | warning / info | Some required or optional labels were intentionally not drawn. | Provide more room or choose a presentation that can show the identifiers. |
|
|
1656
|
+
| `legend-overflow` | warning | The legend was truncated to fit. | Move the legend to top/bottom, increase height, filter series, or facet. |
|
|
1657
|
+
| `low-contrast-fill` | info | A pale fill relies on a contrasting perimeter for identification. | Keep the boundary visible or choose stronger fills/backgrounds. |
|
|
1658
|
+
| `low-contrast-mark` | warning | Recorded mark paints have low contrast against their backgrounds. | Choose palette/background changes explicitly. |
|
|
1659
|
+
| `low-contrast-text` | warning | Recorded text fails the 4.5:1 contrast target. | Adjust theme text colors or background. |
|
|
1660
|
+
| `marks-clipped` | warning | Data falls outside an explicit value-axis range and is clipped. | Drop or widen the manual scale domain after reviewing the semantic impact. |
|
|
1661
|
+
| `missing-maximum` | warning | A bounded value chart recommendation lacks a finite maximum. | Supply a meaningful max/range rather than inferring one from the data alone. |
|
|
1662
|
+
| `missing-values` | info | A profiled field has missing values. | Decide whether missingness is acceptable, should be filtered, or needs imputation outside the spec. |
|
|
1663
|
+
| `no-visible-marks` | warning | Rows or literal values exist, but no visible finite logical marks were observed. | Inspect encoded values, chart size, explicit domains, and render evidence. |
|
|
1664
|
+
| `nonfinite-values` | warning | A profiled field contains non-finite numeric values. | Remove or replace NaN/Infinity before rendering quantitative marks. |
|
|
1665
|
+
| `render-evidence-incomplete` | warning | Renderer evidence is incomplete. | Do not infer visual success from row counts; inspect available evidence and renderer coverage. |
|
|
1666
|
+
| `sampled-data` | info | Profiling sampled a large dataset. | Treat profile counts as sample evidence unless you profile the full data yourself. |
|
|
1667
|
+
| `scatter-quantized` | info | Dense scatter rendering reduced drawn points for performance. | Filter, aggregate, resize, or accept quantization while using full data for interaction. |
|
|
1668
|
+
| `signed-composition` | warning | A composition recommendation found negative or mixed-sign values. | Use a signed chart type or explicitly transform values before part-to-whole charts. |
|
|
1669
|
+
| `sparse-combinations` | info | Profiled categorical combinations are sparse. | Decide whether absent combinations are meaningful gaps or just missing rows. |
|
|
1670
|
+
| `structured-values` | warning | A profiled field contains arrays/objects. | Flatten or stringify the values deliberately before encoding. |
|
|
1671
|
+
| `text-clipped` | info / warning | Text was shortened to fit; severe truncation is a warning. | Widen the chart, shorten source labels, or move space-consuming chrome. |
|
|
1672
|
+
| `text-occluded` | warning | Text extends past the visible boundary. | Increase chart size or reduce competing chrome. |
|
|
1673
|
+
| `too-many-categories` | info | A categorical axis has more bands than are individually readable. | Aggregate, filter to top-N, or choose a different visual. |
|
|
1674
|
+
| `too-many-colors` | info | Too many series share one discrete color scale. | Facet, filter/group the long tail, or use the colorblind palette. |
|
|
1675
|
+
| `truncated-baseline` | warning | A bar value axis starts above zero. | Remove the truncated domain unless the semantic distortion is intentional and disclosed. |
|
|
1676
|
+
| `unrepresented-data` | warning | Some effective rows were omitted rather than represented. | Inspect missing values, joins, unsupported values, and duplicate positions. |
|
|
1677
|
+
| `view-clipped` | warning | A headless dashboard view extends beyond the static viewport. | Increase the page size or reduce/reflow dashboard content for static output. |
|
|
1678
|
+
| `view-render-error` | error | A dashboard child view threw while rendering. | Inspect the scoped viewId/path and fix that child spec. |
|
|
1679
|
+
<!-- generated:diagnostics:end -->
|
|
1680
|
+
|
|
1681
|
+
The text and label diagnostics come from a ledger of the text each renderer actually drew, so they
|
|
1603
1682
|
apply to **every** chart type — a pie callout, a sankey node name or a treemap tile
|
|
1604
1683
|
label is checked exactly like an axis tick. Mild `text-clipped` is a healthy outcome
|
|
1605
1684
|
(it is how the layout stays intact); treat it as a prompt to widen the chart or shorten
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tabular.ts","../src/handlers.ts","../src/resources.ts","../src/create-server.ts"],"sourcesContent":["/** A tidy row parsed from CSV/TSV text. */\nexport type TabularRow = Record<string, number | string>;\n\n/** Error thrown when CSV/TSV text is malformed. */\nexport class TabularParseError extends Error {\n /** Create a parse error with a human-readable message. */\n constructor(message: string) {\n super(message);\n this.name = 'TabularParseError';\n }\n}\n\ninterface Cell {\n value: string;\n}\n\nfunction detectDelimiter(text: string): ',' | '\\t' {\n let comma = 0;\n let tab = 0;\n let quoted = false;\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (ch === '\"') {\n if (quoted && text[i + 1] === '\"') {\n i++;\n } else {\n quoted = !quoted;\n }\n } else if (!quoted && (ch === '\\n' || ch === '\\r')) {\n break;\n } else if (!quoted && ch === ',') {\n comma++;\n } else if (!quoted && ch === '\\t') {\n tab++;\n }\n }\n\n return tab > comma ? '\\t' : ',';\n}\n\nfunction coerce(value: string): number | string {\n const trimmed = value.trim();\n if (/^[+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?$/.test(trimmed)) {\n const n = Number(trimmed);\n if (Number.isFinite(n)) return n;\n }\n return value;\n}\n\nfunction parseRecords(text: string, delimiter: ',' | '\\t'): Cell[][] {\n const records: Cell[][] = [];\n let record: Cell[] = [];\n let value = '';\n let quoted = false;\n let afterQuote = false;\n\n const pushCell = () => {\n record.push({ value });\n value = '';\n afterQuote = false;\n };\n const pushRecord = () => {\n pushCell();\n records.push(record);\n record = [];\n };\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n\n if (quoted) {\n if (ch === '\"') {\n if (text[i + 1] === '\"') {\n value += '\"';\n i++;\n } else {\n quoted = false;\n afterQuote = true;\n }\n } else {\n value += ch;\n }\n continue;\n }\n\n if (afterQuote && ch !== delimiter && ch !== '\\n' && ch !== '\\r') {\n if (/\\s/.test(ch)) continue;\n throw new TabularParseError(`Unexpected character '${ch}' after closing quote.`);\n }\n\n if (ch === '\"') {\n if (value.length > 0) throw new TabularParseError('Unexpected quote in an unquoted field.');\n quoted = true;\n } else if (ch === delimiter) {\n pushCell();\n } else if (ch === '\\n') {\n pushRecord();\n } else if (ch === '\\r') {\n pushRecord();\n if (text[i + 1] === '\\n') i++;\n } else {\n value += ch;\n }\n }\n\n if (quoted) throw new TabularParseError('Unclosed quoted field.');\n if (value.length > 0 || record.length > 0 || text.endsWith(String(delimiter))) pushRecord();\n return records.filter((r) => r.some((cell) => cell.value.length > 0));\n}\n\n/**\n * Parse CSV or TSV text with a header row into tidy data rows. Handles quoted\n * fields, escaped quotes, embedded delimiters, and embedded newlines.\n */\nexport function parseTabularText(text: string): TabularRow[] {\n const trimmed = text.replace(/^\\uFEFF/, '');\n const delimiter = detectDelimiter(trimmed);\n const records = parseRecords(trimmed, delimiter);\n if (records.length === 0) return [];\n\n const headers = records[0].map((cell) => cell.value.trim());\n if (headers.some((h) => h.length === 0)) {\n throw new TabularParseError('CSV/TSV header row must not contain empty column names.');\n }\n if (new Set(headers).size !== headers.length) {\n throw new TabularParseError('CSV/TSV header row must not contain duplicate column names.');\n }\n\n return records.slice(1).map((record, rowIndex) => {\n if (record.length !== headers.length) {\n throw new TabularParseError(\n `Row ${rowIndex + 2} has ${record.length} cells, expected ${headers.length}.`,\n );\n }\n const row: TabularRow = {};\n for (let i = 0; i < headers.length; i++) row[headers[i]] = coerce(record[i].value);\n return row;\n });\n}\n\n/**\n * Return a copy of a spec-like value with any `data: \"csv/tsv...\"` properties\n * parsed into tidy rows. Non-spec values are returned unchanged.\n */\nexport function parseInlineData(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(parseInlineData);\n if (typeof value !== 'object' || value === null) return value;\n\n const out: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n out[key] = key === 'data' && typeof child === 'string' ? parseTabularText(child) : parseInlineData(child);\n }\n return out;\n}\n","/**\n * Pure tool handlers — the generate → validate → repair → render → critique loop\n * exposed as plain functions so they can be unit-tested without a transport. Each\n * returns MCP-shaped content (`text` and/or `image` blocks). `createServer` wires\n * these into the `McpServer`.\n *\n * The handlers wrap `graphein`'s self-validating / self-repairing / self-explaining\n * core (`validateSpec`, `repairSpec`, `summarize`) and `@graphein/node`'s headless\n * `renderChart`, so an agent gets the chart **plus** a vision-free critique in one\n * call — and a one-step repair when its spec is slightly wrong.\n */\nimport {\n validateSpec,\n draft,\n repairSpec,\n recommendChart,\n profileData,\n listChartTypes,\n summarize,\n type AnySpec,\n type QualityOptions,\n type RecommendOptions,\n type RepairOptions,\n type ValidationError,\n} from 'graphein';\nimport { NodeRenderError, renderChart } from '@graphein/node';\nimport { parseInlineData, parseTabularText } from './tabular.js';\n\n/** A subset of MCP content blocks the handlers emit. */\nexport type McpContent =\n | { type: 'text'; text: string }\n | { type: 'image'; data: string; mimeType: string };\n\n/**\n * The shape every handler returns — assignable to the SDK's `CallToolResult`\n * (which is an open/passthrough type, hence the index signature).\n */\nexport interface ToolResult {\n content: McpContent[];\n structuredContent?: Record<string, unknown>;\n isError?: boolean;\n [key: string]: unknown;\n}\n\n/** Options accepted by {@link renderChartHandler}. */\nexport interface RenderArgs {\n spec: unknown;\n width?: number;\n height?: number;\n dpr?: number;\n /** Auto-apply safe repairs before rendering when the spec is invalid. Default true. */\n repair?: boolean;\n /** Independent structural/data repair policy; defaults to safe. */\n repairLevel?: RepairOptions['level'];\n /** Opt-in presentation-default improvement, capped at three whole-visual renders. */\n quality?: boolean | QualityOptions;\n}\n\n/** Options accepted by {@link critiqueChartHandler}. */\nexport type CritiqueArgs = RenderArgs;\n\nexport interface RecommendChartArgs {\n data: Record<string, unknown>[] | string;\n intent?: string;\n maxResults?: number;\n /** Layout guidance only; never filters/groups the supplied rows to fit. */\n targetSize?: RecommendOptions['targetSize'];\n}\n\n/** Options accepted by {@link repairChartHandler}. */\nexport interface RepairChartArgs {\n spec: unknown;\n /** Repair level: safe fixes by default, or data-aware inference from inline rows. */\n level?: RepairOptions['level'];\n}\n\nfunction text(value: string): McpContent {\n return { type: 'text', text: value };\n}\n\nfunction json(value: unknown): McpContent {\n return text(JSON.stringify(value, null, 2));\n}\n\nfunction specType(spec: unknown): string {\n return typeof spec === 'object' && spec !== null && 'type' in spec\n ? String((spec as { type: unknown }).type)\n : '(missing)';\n}\n\nfunction isRecommendIntent(value: string | undefined): value is RecommendOptions['intent'] {\n return (\n value === undefined ||\n value === 'trend' ||\n value === 'comparison' ||\n value === 'distribution' ||\n value === 'relationship' ||\n value === 'composition'\n );\n}\n\nfunction parseErrorResult(e: unknown, quality?: RenderArgs['quality']): ToolResult {\n const payload = {\n ok: false,\n stage: 'parse-data',\n message: e instanceof Error ? e.message : String(e),\n ...(quality ? {\n rendered: false,\n quality: draft(undefined, { repair: false, quality }).quality,\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n}\n\nfunction specWithParsedData(spec: unknown): unknown {\n return parseInlineData(spec);\n}\n\nfunction rowsWithParsedData(data: RecommendChartArgs['data']): Record<string, unknown>[] {\n return (typeof data === 'string' ? parseTabularText(data) : data) as Record<string, unknown>[];\n}\n\n/** Slim a validation error for an agent payload (drops nothing useful). */\nfunction tidyError(e: ValidationError) {\n const out: Record<string, unknown> = { path: e.path, message: e.message };\n if (e.rule) out.rule = e.rule;\n if (e.severity) out.severity = e.severity;\n if (e.fix) out.fix = e.fix;\n if (e.suggestion) out.suggestion = e.suggestion;\n if (e.evidence) out.evidence = e.evidence;\n if (e.requiresDecision !== undefined) out.requiresDecision = e.requiresDecision;\n return out;\n}\n\nfunction authoringMetadata(spec: AnySpec) {\n const types = listChartTypes();\n const capabilities = (type: AnySpec['type']) => types.find((t) => t.type === type)?.capabilities;\n if (spec.type !== 'dashboard') {\n return { profile: profileData(spec.data ?? []), capabilities: capabilities(spec.type) };\n }\n return {\n ...(spec.data ? { profile: profileData(spec.data) } : {}),\n capabilities: capabilities(spec.type),\n views: spec.views.map((view) => ({\n id: view.id,\n capabilities: capabilities(view.spec.type),\n ...(view.spec.data\n ? { profile: profileData(view.spec.data) }\n : { inheritsSharedData: true }),\n })),\n };\n}\n\n/**\n * **The flagship.** Validate a spec, auto-repair it if it's safely fixable, render\n * it to a PNG headless, and return the image alongside a machine-readable critique\n * (the render report + lint warnings + any repairs applied). When the spec can't be\n * made valid, returns the structured errors and JSON-Patch fixes instead of an image\n * so the agent corrects in one step rather than regenerating.\n */\nexport function renderChartHandler(args: RenderArgs): ToolResult {\n return renderOrCritique(args, true);\n}\n\n/**\n * Validate, optionally repair, render, and return only the machine-readable\n * render report + summary. This avoids sending a base64 PNG when an agent only\n * needs diagnostics.\n */\nexport function critiqueChartHandler(args: CritiqueArgs): ToolResult {\n return renderOrCritique(args, false);\n}\n\nfunction renderOrCritique(args: RenderArgs, includeImage: boolean): ToolResult {\n const { spec, width, height, dpr, repair = true, repairLevel, quality } = args;\n let working: unknown;\n try {\n working = specWithParsedData(spec);\n } catch (e) {\n return parseErrorResult(e, quality);\n }\n const prepared = draft(working, { repair, repairLevel, quality });\n const type = specType(prepared.spec);\n if (!prepared.valid) {\n const payload = {\n ok: false, rendered: false, stage: 'validate', type,\n errors: prepared.errors.map(tidyError),\n lint: prepared.warnings.map(tidyError),\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? { effectiveSpec: prepared.spec, quality: prepared.quality } : {}),\n hint: `Apply each error.fix JSON Patch (or the repair_chart tool), then call ${includeImage ? 'render_chart' : 'critique_chart'} again. See the graphein://agent-guide and graphein://schema resources.`,\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n }\n\n try {\n const rendered = renderChart(prepared.spec as AnySpec, { width, height, dpr, quality });\n const { report } = rendered;\n const payload = {\n ok: report.ok, rendered: true, type,\n pixelSize: { width: rendered.width, height: rendered.height },\n summary: report.summary,\n ...(includeImage ? {\n marks: report.markCount, series: report.seriesCount, colors: report.colorCount,\n diagnostics: report.diagnostics,\n } : {}),\n report,\n lint: validateSpec(rendered.spec).warnings.map(tidyError),\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? {\n effectiveSpec: rendered.spec, quality: rendered.quality,\n authoring: authoringMetadata(rendered.spec),\n } : {}),\n };\n return {\n isError: false,\n content: [\n ...(includeImage ? [{ type: 'image' as const, data: rendered.png.toString('base64'), mimeType: 'image/png' }] : []),\n json(payload),\n ],\n structuredContent: payload,\n };\n } catch (e) {\n const failed = e instanceof NodeRenderError ? e.result : undefined;\n const payload = {\n ok: false, rendered: false, stage: 'render', type,\n message: e instanceof Error ? e.message : String(e),\n summary: prepared.summary,\n repairsApplied: prepared.patches,\n repairDetails: prepared.repairs,\n ...(quality ? {\n effectiveSpec: failed?.spec ?? prepared.spec,\n quality: failed?.quality ?? { ...prepared.quality, stopReason: 'render-failed' },\n } : {}),\n };\n return {\n isError: true, content: [json(payload)], structuredContent: payload,\n };\n }\n}\n\n/**\n * Validate a spec without rendering — fast structural + best-practice feedback.\n * Returns errors (each with a JSON-Patch `fix` when unambiguous and \"did you mean\"\n * suggestions) and lint `warnings`.\n */\nexport function validateChartHandler(args: { spec: unknown }): ToolResult {\n let spec: unknown;\n try {\n spec = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const result = validateSpec(spec);\n return {\n isError: false,\n content: [\n json({\n valid: result.valid,\n type: specType(spec),\n errors: result.errors.map(tidyError),\n warnings: result.warnings.map(tidyError),\n }),\n ],\n };\n}\n\n/** Recommend ready-to-render ChartSpecs from tidy rows and an optional intent. */\nexport function recommendChartHandler(args: RecommendChartArgs): ToolResult {\n if (!isRecommendIntent(args.intent)) {\n return {\n isError: true,\n content: [\n json({\n ok: false,\n message: 'Unsupported intent. Expected trend, comparison, distribution, relationship, or composition.',\n }),\n ],\n };\n }\n let data: Record<string, unknown>[];\n try {\n data = rowsWithParsedData(args.data);\n } catch (e) {\n return parseErrorResult(e);\n }\n const recommendations = recommendChart(data, {\n intent: args.intent, maxResults: args.maxResults, targetSize: args.targetSize, detailed: true,\n });\n const payload = { ok: true, ...recommendations };\n return { isError: false, content: [json(payload)], structuredContent: payload };\n}\n\n/**\n * List every supported chart family with its purpose, required channels, and a\n * minimal runnable starter spec.\n */\nexport function listChartTypesHandler(): ToolResult {\n const payload = { ok: true, chartTypes: listChartTypes() };\n return { isError: false, content: [json(payload)], structuredContent: payload };\n}\n\n/**\n * Apply every safe, unambiguous repair Graphein proposes and return the corrected\n * spec, the JSON Patch operations applied, and whether it is now valid.\n */\nexport function repairChartHandler(args: RepairChartArgs): ToolResult {\n let input: unknown;\n try {\n input = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const { spec, applied, appliedDetails, remaining } = repairSpec(input, { level: args.level ?? 'safe' });\n return {\n isError: false,\n content: [\n json({\n valid: remaining.length === 0,\n level: args.level ?? 'safe',\n applied,\n appliedDetails,\n remaining: remaining.map(tidyError),\n spec,\n }),\n ],\n };\n}\n\n/**\n * Return a deterministic, plain-English summary of what the chart's data shows —\n * doubles as alt-text, needs no LLM.\n */\nexport function summarizeChartHandler(args: { spec: unknown }): ToolResult {\n let spec: unknown;\n try {\n spec = specWithParsedData(args.spec);\n } catch (e) {\n return parseErrorResult(e);\n }\n const result = validateSpec(spec);\n if (!result.valid) {\n return {\n isError: true,\n content: [\n json({\n summary: null,\n reason: 'Spec is invalid; fix it first (validate_chart / repair_chart).',\n errors: result.errors.map(tidyError),\n }),\n ],\n };\n }\n const validSpec = spec as AnySpec;\n const summary = validSpec.type === 'dashboard' ? undefined : summarize(validSpec);\n return {\n isError: false,\n content: [\n text(summary || `(No narrative summary is available for a '${specType(args.spec)}' chart.)`),\n ],\n };\n}\n","/**\n * The agent-facing knowledge Graphein serves as MCP **resources** — the schema\n * and the prose guides — so a model that has never seen Graphein's API can read\n * the contract at runtime instead of relying on training data. This is the core\n * of the MCP server's \"neutralize the training-data gap\" purpose.\n *\n * The files live in `../resources/` (committed copies of the repo's `docs/`, kept\n * in sync by `scripts/sync-resources.mjs`). They are read lazily and cached so the\n * server pays nothing until an agent actually asks for one.\n */\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\n/** Metadata describing one served resource. */\nexport interface GrapheinResource {\n /** Short registration name. */\n name: string;\n /** Stable `graphein://…` URI an agent reads. */\n uri: string;\n /** Human title. */\n title: string;\n /** What the resource is and when to read it. */\n description: string;\n /** IANA media type. */\n mimeType: string;\n /** File under `resources/`. */\n file: string;\n}\n\n/** Every resource the server exposes, in the order they should be advertised. */\nexport const RESOURCES: GrapheinResource[] = [\n {\n name: 'schema',\n uri: 'graphein://schema',\n title: 'Graphein ChartSpec JSON Schema',\n description:\n 'The machine-readable JSON Schema for every Graphein ChartSpec and DashboardSpec field — chart types, channels, transforms, annotations, and required properties. Generate or check a spec against this.',\n mimeType: 'application/json',\n file: 'chart-spec.schema.json',\n },\n {\n name: 'agent-guide',\n uri: 'graphein://agent-guide',\n title: 'Graphein Agent Guide',\n description:\n 'A task-oriented guide for producing correct Graphein charts: the one-rule workflow, choosing a chart type, encodings, transforms, the validate → repair → render → critique loop, and worked recipes. Read this first.',\n mimeType: 'text/markdown',\n file: 'agent-guide.md',\n },\n {\n name: 'spec-reference',\n uri: 'graphein://spec-reference',\n title: 'Graphein Spec Reference',\n description:\n 'The exhaustive field-by-field reference for every chart type, channel, transform, annotation, and modifier. Consult this for the precise shape of a specific field.',\n mimeType: 'text/markdown',\n file: 'spec-reference.md',\n },\n];\n\nconst cache = new Map<string, string>();\n\n/**\n * Read a bundled resource file's text, cached. Resolved relative to this module\n * so it works both from `dist/` (published) and `src/` (tests) — the committed\n * `resources/` dir always sits one level up from either.\n */\nexport function readResourceFile(file: string): string {\n const hit = cache.get(file);\n if (hit !== undefined) return hit;\n const url = new URL(`../resources/${file}`, import.meta.url);\n const text = readFileSync(fileURLToPath(url), 'utf8');\n cache.set(file, text);\n return text;\n}\n\n/** Look up a resource by its `graphein://…` URI. */\nexport function resourceByUri(uri: string): GrapheinResource | undefined {\n return RESOURCES.find((r) => r.uri === uri);\n}\n","/**\n * `createServer()` — builds the Graphein MCP server: the generate → validate →\n * repair → render → critique loop as four tools, the schema + guides as resources,\n * and a `create_chart` prompt that teaches the workflow. Split from the stdio\n * entry point (`server.ts`) so it can be driven over any transport — including the\n * in-memory transport in tests.\n */\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport {\n critiqueChartHandler,\n listChartTypesHandler,\n renderChartHandler,\n validateChartHandler,\n repairChartHandler,\n recommendChartHandler,\n summarizeChartHandler,\n} from './handlers.js';\nimport { RESOURCES, readResourceFile } from './resources.js';\n\n/** Package version, surfaced as the MCP server version. */\nexport const VERSION = '0.3.0';\n\nconst SERVER_INSTRUCTIONS = `Graphein is an agent-first data-visualization library: you describe a chart as one JSON ChartSpec ({ type, data, encoding, ... }) and it renders. This server lets you build correct charts without prior knowledge of the API.\n\nWorkflow:\n1. Call list_chart_types to see every supported chart type with required channels, field roles, aggregation behavior, cardinality caveats, and starter specs; read graphein://agent-guide (and graphein://schema for exact fields) only when you need deeper detail.\n2. Shape data as tidy rows — one row per observation, one column per variable. Tools that accept rows also accept CSV/TSV text with a header row.\n3. Use recommend_chart when you want ranked specs from data, or start from a list_chart_types starter. Inspect profile, findings, and status: needs-decision/no-candidate are not permission to guess aggregation, date roles, missing values, or geometry.\n4. Emit a ChartSpec and call critique_chart for report-only diagnostics, or render_chart when you need the PNG plus critique. Both validate, auto-repair safe mistakes, render headlessly once by default, and return lint/report feedback. Opt in with quality:true for presentation-default improvements within three TOTAL whole-visual renders, including restoration. Read effectiveSpec, quality history and unresolved diagnostics; the loop never changes data or explicit settings.\n5. If a spec is invalid, validate_chart, critique_chart, and render_chart return structured errors with JSON-Patch fixes. Apply them or call repair_chart; use repair_chart level \"data\" to infer missing encodings or close field-name typos from the spec's own data.\nUse summarize_chart for deterministic alt-text. Every type rasterizes headlessly, including kpi, table, matrix, slicers and dashboard (static canvas snapshots).`;\n\n/** A permissive object schema for a Graphein spec — validateSpec does the real checking. */\nconst specSchema = z\n .record(z.string(), z.unknown())\n .describe(\n 'A Graphein ChartSpec or DashboardSpec object, e.g. { \"type\": \"line\", \"data\": [...], \"encoding\": {...} }. Any data property may be tidy rows or CSV/TSV text with a header row. See the graphein://schema and graphein://agent-guide resources.',\n );\n\nconst dataRowsSchema = z.union([\n z.array(z.record(z.string(), z.any())),\n z.string().describe('CSV or TSV text with a header row; quoted delimiters, quotes, and newlines are supported.'),\n]);\n\nconst intentSchema = z\n .enum(['trend', 'comparison', 'distribution', 'relationship', 'composition'])\n .optional()\n .describe(\n 'Optional analytical intent used to rank recommendations: trend, comparison, distribution, relationship, or composition.',\n );\n\nconst qualitySchema = z.union([\n z.boolean(),\n z.object({\n maxPasses: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional()\n .describe('Total whole-visual render ceiling including initial and rollback passes (default 3).'),\n }).strict(),\n]).optional().describe(\n 'Opt in to bounded presentation-default improvement. Default false: one render. Never alters data, encodings, explicit palettes/domains, or other caller settings. Returns effectiveSpec and quality history. Mutable targets reserve a rollback pass.',\n);\n\nconst repairLevelSchema = z.enum(['safe', 'data']).optional()\n .describe('Independent repair policy: safe (default), or explicitly opt in to data-aware field/encoding inference.');\n\n/**\n * Build a fully-configured Graphein MCP server. The caller connects it to a\n * transport (`server.connect(transport)`).\n */\nexport function createServer(): McpServer {\n const server = new McpServer(\n { name: 'graphein-mcp', version: VERSION },\n { instructions: SERVER_INSTRUCTIONS },\n );\n\n // --- Tools: the runtime loop -------------------------------------------------\n\n server.registerTool(\n 'render_chart',\n {\n title: 'Render a Graphein chart',\n description:\n 'The one-call loop: validate a ChartSpec, auto-repair safe mistakes, render it to a PNG, and return the image plus a vision-free critique (render report, lint warnings, repairs applied). If the spec cannot be made valid, returns structured errors with JSON-Patch fixes instead of an image. Every type rasterizes headlessly — kpi, table, matrix, slicers and dashboard render static canvas snapshots.',\n inputSchema: {\n spec: specSchema,\n width: z.number().int().positive().optional().describe('Logical width in CSS px (default 800).'),\n height: z.number().int().positive().optional().describe('Logical height in CSS px (default 500).'),\n dpr: z.number().positive().optional().describe('Device pixel ratio for crisp output (default 2).'),\n repair: z\n .boolean()\n .optional()\n .describe('Auto-apply safe repairs before rendering when the spec is invalid (default true).'),\n repairLevel: repairLevelSchema,\n quality: qualitySchema,\n },\n },\n async (args) => renderChartHandler(args),\n );\n\n server.registerTool(\n 'critique_chart',\n {\n title: 'Critique a Graphein chart without an image',\n description:\n 'Validate a ChartSpec, auto-repair safe mistakes, render it headlessly, and return only the RenderReport, deterministic summary, lint warnings, and repairs applied — no base64 PNG. Use this when you need diagnostics but not an image.',\n inputSchema: {\n spec: specSchema,\n width: z.number().int().positive().optional().describe('Logical width in CSS px (default 800).'),\n height: z.number().int().positive().optional().describe('Logical height in CSS px (default 500).'),\n dpr: z.number().positive().optional().describe('Device pixel ratio for layout parity (default 2).'),\n repair: z\n .boolean()\n .optional()\n .describe('Auto-apply safe repairs before rendering when the spec is invalid (default true).'),\n repairLevel: repairLevelSchema,\n quality: qualitySchema,\n },\n },\n async (args) => critiqueChartHandler(args),\n );\n\n server.registerTool(\n 'validate_chart',\n {\n title: 'Validate a Graphein chart spec',\n description:\n 'Validate a ChartSpec without rendering. Returns structural errors (each with a JSON-Patch `fix` when unambiguous, plus \"did you mean\" suggestions) and best-practice lint warnings. Fast feedback before rendering.',\n inputSchema: { spec: specSchema },\n },\n async (args) => validateChartHandler(args),\n );\n\n server.registerTool(\n 'recommend_chart',\n {\n title: 'Recommend Graphein chart specs',\n description:\n 'Profile tidy rows and return ranked ChartSpecs with rationale, profile evidence, alternatives, and explicit needs-decision/no-candidate findings. Use this before guessing a chart type or encoding; no supplied data is changed.',\n inputSchema: {\n data: dataRowsSchema,\n intent: intentSchema,\n maxResults: z.number().int().positive().optional(),\n targetSize: z.object({\n width: z.number().positive(),\n height: z.number().positive(),\n }).optional().describe('Optional target CSS-pixel size for layout guidance only; does not filter or group data.'),\n },\n },\n async (args) => recommendChartHandler(args),\n );\n\n server.registerTool(\n 'repair_chart',\n {\n title: 'Repair a Graphein chart spec',\n description:\n 'Apply Graphein repairs and return the corrected spec, JSON Patch ops, per-patch rationales, and whether it is now valid. The default safe level applies validator-provided fixes; level \"data\" may infer missing encodings and field-name typo fixes from the spec\\'s own data.',\n inputSchema: {\n spec: specSchema,\n level: z\n .enum(['safe', 'data'])\n .optional()\n .describe('Repair aggressiveness. \"safe\" is default; \"data\" also infers from the spec data.'),\n },\n },\n async (args) => repairChartHandler(args),\n );\n\n server.registerTool(\n 'list_chart_types',\n {\n title: 'List Graphein chart types',\n description:\n 'Return every supported chart type with purpose, required channels/properties, field roles, aggregation semantics, cardinality guidance, supported features, and a minimal runnable starter. Use this before reading the full schema.',\n inputSchema: {},\n },\n async () => listChartTypesHandler(),\n );\n\n server.registerTool(\n 'summarize_chart',\n {\n title: 'Summarize a Graphein chart',\n description:\n 'Return a deterministic, plain-English description of what the chart\\'s data shows (e.g. \"Users grew 46% over six months, peaking in June\"). Doubles as alt-text; needs no LLM.',\n inputSchema: { spec: specSchema },\n },\n async (args) => summarizeChartHandler(args),\n );\n\n // --- Resources: deliver the API knowledge at runtime -------------------------\n\n for (const r of RESOURCES) {\n server.registerResource(\n r.name,\n r.uri,\n { title: r.title, description: r.description, mimeType: r.mimeType },\n async (uri) => ({\n contents: [{ uri: uri.href, mimeType: r.mimeType, text: readResourceFile(r.file) }],\n }),\n );\n }\n\n // --- Prompt: teach the workflow ---------------------------------------------\n\n server.registerPrompt(\n 'create_chart',\n {\n title: 'Create a Graphein chart',\n description:\n 'Scaffold the workflow for building a validated Graphein chart from a goal (and optional data).',\n argsSchema: {\n goal: z.string().describe('What the chart should show, e.g. \"monthly active users over the last year\".'),\n data: z\n .string()\n .optional()\n .describe('Optional: the data as a JSON array, or a description of the columns available.'),\n },\n },\n ({ goal, data }) => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Build a Graphein chart for this goal:\\n\\n${goal}\\n${\n data ? `\\nData:\\n${data}\\n` : ''\n }\\nSteps:\\n1. Call list_chart_types for available chart families and starter specs; read graphein://agent-guide or graphein://schema only for deeper details.\\n2. Shape the data as tidy rows — one row per observation, one column per variable. CSV/TSV text with a header row is accepted anywhere data rows are accepted.\\n3. Choose a chart type (or call recommend_chart) and write a single ChartSpec ({ type, data, encoding, title }).\\n4. Call critique_chart for report-only feedback or render_chart when you need the PNG too. Read the returned render report + lint to confirm it looks right.\\n5. If it reports errors, apply each error.fix patch (or call repair_chart, using level \"data\" when field/encoding inference from data is useful) and render again — do not regenerate from scratch.`,\n },\n },\n ],\n }),\n );\n\n return server;\n}\n"],"mappings":"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","names":["text","text"]}
|