semiotic 3.5.4 → 3.7.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/CLAUDE.md +196 -175
- package/README.md +52 -15
- package/ai/cli.js +41 -0
- package/ai/componentMetadata.cjs +11 -2
- package/ai/dist/mcp-server.js +454 -4
- package/ai/examples.md +98 -0
- package/ai/schema.json +614 -9
- package/ai/system-prompt.md +5 -2
- package/dist/components/AccessibleNavTree.d.ts +25 -0
- package/dist/components/Annotation.d.ts +40 -14
- package/dist/components/ChartContainer.d.ts +32 -2
- package/dist/components/ai/annotationProvenance.d.ts +349 -0
- package/dist/components/ai/audienceProfile.d.ts +147 -0
- package/dist/components/ai/audiences.d.ts +31 -0
- package/dist/components/ai/chartCapabilities.d.ts +55 -0
- package/dist/components/ai/chartCapabilityTypes.d.ts +254 -0
- package/dist/components/ai/chartRoles.d.ts +27 -0
- package/dist/components/ai/conversationArc.d.ts +379 -0
- package/dist/components/ai/dataScaleProfile.d.ts +320 -0
- package/dist/components/ai/describeChart.d.ts +114 -0
- package/dist/components/ai/diffProfile.d.ts +51 -0
- package/dist/components/ai/inferIntent.d.ts +24 -0
- package/dist/components/ai/intents.d.ts +34 -0
- package/dist/components/ai/navigationTree.d.ts +45 -0
- package/dist/components/ai/profileData.d.ts +16 -0
- package/dist/components/ai/qualityFixtures.d.ts +2 -0
- package/dist/components/ai/qualityScorecard.d.ts +82 -0
- package/dist/components/ai/readerGrounding.d.ts +70 -0
- package/dist/components/ai/repairChartConfig.d.ts +73 -0
- package/dist/components/ai/streamingTypes.d.ts +64 -0
- package/dist/components/ai/suggestCharts.d.ts +109 -0
- package/dist/components/ai/suggestDashboard.d.ts +92 -0
- package/dist/components/ai/suggestStreamCharts.d.ts +34 -0
- package/dist/components/ai/suggestStretchCharts.d.ts +60 -0
- package/dist/components/ai/useChartSuggestions.d.ts +22 -0
- package/dist/components/ai/useConversationArc.d.ts +89 -0
- package/dist/components/ai/useNavigationSync.d.ts +61 -0
- package/dist/components/ai/variantDiscovery.d.ts +168 -0
- package/dist/components/charts/geo/ChoroplethMap.capability.d.ts +2 -0
- package/dist/components/charts/geo/DistanceCartogram.capability.d.ts +2 -0
- package/dist/components/charts/geo/FlowMap.capability.d.ts +2 -0
- package/dist/components/charts/geo/ProportionalSymbolMap.capability.d.ts +2 -0
- package/dist/components/charts/index.d.ts +1 -1
- package/dist/components/charts/network/ChordDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/CirclePack.capability.d.ts +2 -0
- package/dist/components/charts/network/ForceDirectedGraph.capability.d.ts +2 -0
- package/dist/components/charts/network/OrbitDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/ProcessSankey.capability.d.ts +2 -0
- package/dist/components/charts/network/SankeyDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/TreeDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/Treemap.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/BarChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/BoxPlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/DonutChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/DotPlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/FunnelChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/GaugeChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/GroupedBarChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/Histogram.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/Histogram.d.ts +4 -2
- package/dist/components/charts/ordinal/LikertChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/LikertChart.d.ts +1 -1
- package/dist/components/charts/ordinal/LikertChart.defaults.d.ts +1 -0
- package/dist/components/charts/ordinal/PieChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/RidgelinePlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/StackedBarChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/SwarmPlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/SwimlaneChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/ViolinPlot.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeHeatmap.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeHeatmap.d.ts +3 -0
- package/dist/components/charts/realtime/RealtimeHistogram.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeHistogram.d.ts +3 -0
- package/dist/components/charts/realtime/RealtimeLineChart.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeLineChart.d.ts +3 -0
- package/dist/components/charts/realtime/RealtimeSwarmChart.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeSwarmChart.d.ts +3 -0
- package/dist/components/charts/realtime/RealtimeWaterfallChart.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeWaterfallChart.d.ts +3 -0
- package/dist/components/charts/realtime/TemporalHistogram.capability.d.ts +7 -0
- package/dist/components/charts/shared/annotationHierarchy.d.ts +42 -0
- package/dist/components/charts/shared/annotationResolvers.d.ts +3 -2
- package/dist/components/charts/shared/annotationRules.d.ts +16 -0
- package/dist/components/charts/shared/annotationTypes.d.ts +14 -0
- package/dist/components/charts/shared/auditAccessibility.d.ts +90 -0
- package/dist/components/charts/shared/chartSpecs.d.ts +2 -37
- package/dist/components/charts/shared/diagnoseConfig.d.ts +4 -6
- package/dist/components/charts/shared/selectionUtils.d.ts +5 -2
- package/dist/components/charts/shared/streamPropsHelpers.d.ts +2 -0
- package/dist/components/charts/shared/types.d.ts +5 -1
- package/dist/components/charts/value/BigNumber.capability.d.ts +13 -0
- package/dist/components/charts/value/BigNumber.d.ts +14 -0
- package/dist/components/charts/value/formatting.d.ts +40 -0
- package/dist/components/charts/value/thresholdSparkline.d.ts +40 -0
- package/dist/components/charts/value/types.d.ts +292 -0
- package/dist/components/charts/xy/AreaChart.capability.d.ts +10 -0
- package/dist/components/charts/xy/BubbleChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/CandlestickChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/ConnectedScatterplot.capability.d.ts +2 -0
- package/dist/components/charts/xy/DifferenceChart.capability.d.ts +8 -0
- package/dist/components/charts/xy/Heatmap.capability.d.ts +9 -0
- package/dist/components/charts/xy/LineChart.capability.d.ts +9 -0
- package/dist/components/charts/xy/MinimapChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/MultiAxisLineChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/QuadrantChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/QuadrantChart.d.ts +5 -2
- package/dist/components/charts/xy/QuadrantChart.defaults.d.ts +2 -0
- package/dist/components/charts/xy/Scatterplot.capability.d.ts +2 -0
- package/dist/components/charts/xy/StackedAreaChart.capability.d.ts +2 -0
- package/dist/components/data/DataSummarizer.d.ts +45 -0
- package/dist/components/realtime/lifecycleBands.d.ts +44 -0
- package/dist/components/realtime/types.d.ts +23 -8
- package/dist/components/recipes/annotationDensity.d.ts +69 -0
- package/dist/components/recipes/annotationLayout.d.ts +93 -0
- package/dist/components/semiotic-ai.d.ts +58 -0
- package/dist/components/semiotic-realtime.d.ts +2 -0
- package/dist/components/semiotic-recipes.d.ts +4 -0
- package/dist/components/semiotic-utils.d.ts +8 -0
- package/dist/components/semiotic-value.d.ts +55 -0
- package/dist/components/semiotic-xy.d.ts +1 -1
- package/dist/components/semiotic.d.ts +8 -1
- package/dist/components/server/staticAnnotations.d.ts +2 -0
- package/dist/components/store/useChartFocus.d.ts +43 -0
- package/dist/components/store/useChartInterrogation.d.ts +141 -0
- package/dist/components/stream/AccessibleDataTable.d.ts +10 -1
- package/dist/components/stream/NetworkSVGOverlay.d.ts +11 -5
- package/dist/components/stream/OrdinalSVGOverlay.d.ts +2 -0
- package/dist/components/stream/SVGOverlay.d.ts +2 -0
- package/dist/components/stream/geoTypes.d.ts +3 -0
- package/dist/components/stream/networkTypes.d.ts +2 -0
- package/dist/components/stream/ordinalTypes.d.ts +2 -0
- package/dist/components/stream/types.d.ts +2 -0
- package/dist/geo.min.js +1 -1
- package/dist/geo.module.min.js +1 -1
- package/dist/network.min.js +1 -1
- package/dist/network.module.min.js +1 -1
- package/dist/ordinal.min.js +1 -1
- package/dist/ordinal.module.min.js +1 -1
- package/dist/realtime.min.js +1 -1
- package/dist/realtime.module.min.js +1 -1
- package/dist/semiotic-ai.d.ts +58 -0
- package/dist/semiotic-ai.min.js +1 -1
- package/dist/semiotic-ai.module.min.js +1 -1
- package/dist/semiotic-realtime.d.ts +2 -0
- package/dist/semiotic-recipes.d.ts +4 -0
- package/dist/semiotic-recipes.min.js +1 -1
- package/dist/semiotic-recipes.module.min.js +1 -1
- package/dist/semiotic-themes.min.js +1 -1
- package/dist/semiotic-themes.module.min.js +1 -1
- package/dist/semiotic-utils.d.ts +8 -0
- package/dist/semiotic-utils.min.js +1 -1
- package/dist/semiotic-utils.module.min.js +1 -1
- package/dist/semiotic-value.d.ts +55 -0
- package/dist/semiotic-value.min.js +2 -0
- package/dist/semiotic-value.module.min.js +2 -0
- package/dist/semiotic-xy.d.ts +1 -1
- package/dist/semiotic.d.ts +8 -1
- package/dist/semiotic.min.js +1 -1
- package/dist/semiotic.module.min.js +1 -1
- package/dist/server.min.js +1 -1
- package/dist/server.module.min.js +1 -1
- package/dist/xy.min.js +1 -1
- package/dist/xy.module.min.js +1 -1
- package/package.json +28 -5
package/ai/dist/mcp-server.js
CHANGED
|
@@ -6890,7 +6890,7 @@ var require_dist = __commonJS({
|
|
|
6890
6890
|
var require_componentMetadata = __commonJS({
|
|
6891
6891
|
"ai/componentMetadata.cjs"(exports2, module2) {
|
|
6892
6892
|
"use strict";
|
|
6893
|
-
var CATEGORY_ORDER = ["xy", "ordinal", "network", "geo", "realtime"];
|
|
6893
|
+
var CATEGORY_ORDER = ["xy", "ordinal", "network", "geo", "realtime", "value"];
|
|
6894
6894
|
var COMPONENTS_BY_CATEGORY = {
|
|
6895
6895
|
xy: [
|
|
6896
6896
|
"LineChart",
|
|
@@ -6947,6 +6947,9 @@ var require_componentMetadata = __commonJS({
|
|
|
6947
6947
|
"RealtimeSwarmChart",
|
|
6948
6948
|
"RealtimeWaterfallChart",
|
|
6949
6949
|
"RealtimeHeatmap"
|
|
6950
|
+
],
|
|
6951
|
+
value: [
|
|
6952
|
+
"BigNumber"
|
|
6950
6953
|
]
|
|
6951
6954
|
};
|
|
6952
6955
|
var COMPONENT_TO_CATEGORY = /* @__PURE__ */ new Map();
|
|
@@ -6972,11 +6975,12 @@ var require_componentMetadata = __commonJS({
|
|
|
6972
6975
|
const name = typeof entryOrName === "string" ? entryOrName : entryOrName.name;
|
|
6973
6976
|
const category = categoryForComponent(name);
|
|
6974
6977
|
const isPushOnly = category === "realtime" && name.startsWith("Realtime");
|
|
6978
|
+
const isValueCategory = category === "value";
|
|
6975
6979
|
return {
|
|
6976
6980
|
name,
|
|
6977
6981
|
category,
|
|
6978
6982
|
importPath: importPathForCategory(category),
|
|
6979
|
-
renderable: !isPushOnly,
|
|
6983
|
+
renderable: !isPushOnly && !isValueCategory,
|
|
6980
6984
|
description: typeof entryOrName === "string" ? void 0 : entryOrName.description
|
|
6981
6985
|
};
|
|
6982
6986
|
}
|
|
@@ -32643,6 +32647,22 @@ ${contracts}` : msg}` }] };
|
|
|
32643
32647
|
isError: true
|
|
32644
32648
|
};
|
|
32645
32649
|
}
|
|
32650
|
+
async function auditAccessibilityHandler(args) {
|
|
32651
|
+
const component = args.component;
|
|
32652
|
+
const props = args.props ?? {};
|
|
32653
|
+
if (!component) {
|
|
32654
|
+
return {
|
|
32655
|
+
content: [{ type: "text", text: "Missing 'component' field. Provide { component: 'LineChart', props: { ... } }." }],
|
|
32656
|
+
isError: true
|
|
32657
|
+
};
|
|
32658
|
+
}
|
|
32659
|
+
const result = (0, import_ai3.auditAccessibility)(component, props, { inChartContainer: args.inChartContainer === true, describe: args.describe === true, navigable: args.navigable === true });
|
|
32660
|
+
return {
|
|
32661
|
+
content: [{ type: "text", text: (0, import_ai3.formatAccessibilityAudit)(result) }],
|
|
32662
|
+
// Only block on provable critical failures; warnings/manual items are advisory.
|
|
32663
|
+
isError: !result.ok
|
|
32664
|
+
};
|
|
32665
|
+
}
|
|
32646
32666
|
async function reportIssueHandler(args) {
|
|
32647
32667
|
const title = args.title;
|
|
32648
32668
|
const body = args.body;
|
|
@@ -32743,6 +32763,287 @@ Dark-mode presets: ${THEME_PRESET_NAMES.filter((n) => n.includes("dark")).join("
|
|
|
32743
32763
|
content: [{ type: "text", text: usage.join("\n") }]
|
|
32744
32764
|
};
|
|
32745
32765
|
}
|
|
32766
|
+
function profileInputFromVariantArgs(args) {
|
|
32767
|
+
const props = args.props ?? {};
|
|
32768
|
+
if (Array.isArray(args.data)) {
|
|
32769
|
+
return { data: args.data };
|
|
32770
|
+
}
|
|
32771
|
+
if (Array.isArray(props.data)) {
|
|
32772
|
+
return { data: props.data };
|
|
32773
|
+
}
|
|
32774
|
+
if (Array.isArray(props.nodes) && (Array.isArray(props.edges) || Array.isArray(props.links))) {
|
|
32775
|
+
return {
|
|
32776
|
+
data: [],
|
|
32777
|
+
rawInput: {
|
|
32778
|
+
nodes: props.nodes,
|
|
32779
|
+
edges: props.edges ?? props.links
|
|
32780
|
+
}
|
|
32781
|
+
};
|
|
32782
|
+
}
|
|
32783
|
+
if (props.data && typeof props.data === "object" && !Array.isArray(props.data)) {
|
|
32784
|
+
return { data: [], rawInput: props.data };
|
|
32785
|
+
}
|
|
32786
|
+
return { data: [] };
|
|
32787
|
+
}
|
|
32788
|
+
function buildVariantProposalProps(proposal, profile, audience) {
|
|
32789
|
+
if (proposal.buildProps) return proposal.buildProps(profile, audience);
|
|
32790
|
+
const capability = (0, import_ai3.getCapability)(proposal.baseComponent);
|
|
32791
|
+
const variant = proposal.variantKey ? capability?.variants?.find((v) => v.key === proposal.variantKey) : void 0;
|
|
32792
|
+
return capability ? capability.buildProps(profile, variant) : {};
|
|
32793
|
+
}
|
|
32794
|
+
async function proposeChartVariantsHandler(args) {
|
|
32795
|
+
const { component, intent, maxResults, audience } = args;
|
|
32796
|
+
const capability = (0, import_ai3.getCapability)(component);
|
|
32797
|
+
if (!capability) {
|
|
32798
|
+
return {
|
|
32799
|
+
content: [{ type: "text", text: `No chart capability registered for "${component}". Call suggestCharts first to pick from known capability components.` }],
|
|
32800
|
+
isError: true
|
|
32801
|
+
};
|
|
32802
|
+
}
|
|
32803
|
+
const { data, rawInput } = profileInputFromVariantArgs(args);
|
|
32804
|
+
const profile = (0, import_ai3.profileData)(data, { rawInput });
|
|
32805
|
+
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
32806
|
+
const fitReason = capability.fits(profile);
|
|
32807
|
+
const proposals = (0, import_ai3.proposeVariant)(component, capability, {
|
|
32808
|
+
profile,
|
|
32809
|
+
audience,
|
|
32810
|
+
intent: intentArg,
|
|
32811
|
+
existingVariants: capability.variants
|
|
32812
|
+
});
|
|
32813
|
+
const ranked = proposals.map((proposal) => {
|
|
32814
|
+
const score = (0, import_ai3.evaluateVariantProposal)(proposal, profile, audience, {
|
|
32815
|
+
intent: intentArg,
|
|
32816
|
+
baselineComponent: component
|
|
32817
|
+
});
|
|
32818
|
+
const { buildProps: _buildProps, ...proposalMeta } = proposal;
|
|
32819
|
+
return {
|
|
32820
|
+
proposal: proposalMeta,
|
|
32821
|
+
score,
|
|
32822
|
+
props: buildVariantProposalProps(proposal, profile, audience)
|
|
32823
|
+
};
|
|
32824
|
+
}).sort((a, b) => {
|
|
32825
|
+
if (b.score.fit !== a.score.fit) return b.score.fit - a.score.fit;
|
|
32826
|
+
if (a.score.risk !== b.score.risk) return a.score.risk - b.score.risk;
|
|
32827
|
+
return b.score.novelty - a.score.novelty;
|
|
32828
|
+
}).slice(0, maxResults ?? 8);
|
|
32829
|
+
const lines = [
|
|
32830
|
+
`${ranked.length} variant proposal${ranked.length === 1 ? "" : "s"} for ${component}${intentArg ? ` (intent: ${intentArg.join(", ")})` : ""}:`,
|
|
32831
|
+
...fitReason ? [`Base chart fit warning: ${fitReason}`] : [],
|
|
32832
|
+
"",
|
|
32833
|
+
...ranked.map((entry, i) => {
|
|
32834
|
+
const label = entry.proposal.label ?? entry.proposal.variantKey ?? entry.proposal.id;
|
|
32835
|
+
const tags = entry.proposal.tags?.length ? ` [${entry.proposal.tags.join(", ")}]` : "";
|
|
32836
|
+
const reasons = entry.score.reasons.length ? `
|
|
32837
|
+
${entry.score.reasons.join("; ")}` : "";
|
|
32838
|
+
return `${i + 1}. ${entry.proposal.baseComponent} / ${label}${tags} (fit ${entry.score.fit.toFixed(1)}/5, novelty ${entry.score.novelty.toFixed(2)}, risk ${entry.score.risk.toFixed(2)})${reasons}`;
|
|
32839
|
+
})
|
|
32840
|
+
];
|
|
32841
|
+
return {
|
|
32842
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32843
|
+
structuredContent: {
|
|
32844
|
+
component,
|
|
32845
|
+
profile: {
|
|
32846
|
+
rowCount: profile.rowCount,
|
|
32847
|
+
primary: profile.primary,
|
|
32848
|
+
categoryCount: profile.categoryCount ?? null,
|
|
32849
|
+
seriesCount: profile.seriesCount ?? null,
|
|
32850
|
+
hasHierarchy: profile.hasHierarchy,
|
|
32851
|
+
hasNetwork: profile.hasNetwork,
|
|
32852
|
+
hasGeo: profile.hasGeo
|
|
32853
|
+
},
|
|
32854
|
+
fitReason,
|
|
32855
|
+
proposals: ranked
|
|
32856
|
+
}
|
|
32857
|
+
};
|
|
32858
|
+
}
|
|
32859
|
+
async function suggestChartsHandler(args) {
|
|
32860
|
+
const { data, intent, maxResults, allow, deny, audience } = args;
|
|
32861
|
+
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
32862
|
+
const suggestions = (0, import_ai3.suggestCharts)(data, {
|
|
32863
|
+
intent: intentArg,
|
|
32864
|
+
allow,
|
|
32865
|
+
deny,
|
|
32866
|
+
maxResults: maxResults ?? 8,
|
|
32867
|
+
audience
|
|
32868
|
+
});
|
|
32869
|
+
const lines = [
|
|
32870
|
+
`${suggestions.length} suggestion${suggestions.length === 1 ? "" : "s"} for ${data.length} rows${intentArg ? ` (intent: ${intentArg.join(", ")})` : ""}:`,
|
|
32871
|
+
"",
|
|
32872
|
+
...suggestions.map((s, i) => {
|
|
32873
|
+
const variantTag = s.variant ? ` / ${s.variant.label}` : "";
|
|
32874
|
+
const reasons = s.reasons.length ? ` \u2014 ${s.reasons.join("; ")}` : "";
|
|
32875
|
+
const caveats = s.caveats.length ? `
|
|
32876
|
+
caveats: ${s.caveats.join("; ")}` : "";
|
|
32877
|
+
return `${i + 1}. ${s.component}${variantTag} (score ${s.score.toFixed(1)}/5, familiarity ${s.rubric.familiarity}, accuracy ${s.rubric.accuracy})${reasons}${caveats}`;
|
|
32878
|
+
})
|
|
32879
|
+
];
|
|
32880
|
+
return {
|
|
32881
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32882
|
+
structuredContent: { suggestions }
|
|
32883
|
+
};
|
|
32884
|
+
}
|
|
32885
|
+
async function suggestStreamChartsHandler(args) {
|
|
32886
|
+
const { schema: schema2, intent, maxResults } = args;
|
|
32887
|
+
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
32888
|
+
const suggestions = (0, import_ai3.suggestStreamCharts)(schema2, {
|
|
32889
|
+
intent: intentArg,
|
|
32890
|
+
maxResults: maxResults ?? 8
|
|
32891
|
+
});
|
|
32892
|
+
const lines = [
|
|
32893
|
+
`${suggestions.length} stream chart suggestion${suggestions.length === 1 ? "" : "s"}${intentArg ? ` (intent: ${intentArg.join(", ")})` : ""}`,
|
|
32894
|
+
...schema2.throughput ? [`throughput: ${schema2.throughput}`] : [],
|
|
32895
|
+
...schema2.retention ? [`retention: ${schema2.retention}`] : [],
|
|
32896
|
+
"",
|
|
32897
|
+
...suggestions.map((s, i) => {
|
|
32898
|
+
const reasons = s.reasons.length ? ` \u2014 ${s.reasons.join("; ")}` : "";
|
|
32899
|
+
const caveats = s.caveats.length ? `
|
|
32900
|
+
caveats: ${s.caveats.join("; ")}` : "";
|
|
32901
|
+
return `${i + 1}. ${s.component} (score ${s.score.toFixed(1)}/5)${reasons}${caveats}`;
|
|
32902
|
+
})
|
|
32903
|
+
];
|
|
32904
|
+
return {
|
|
32905
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32906
|
+
structuredContent: { suggestions, schema: schema2 }
|
|
32907
|
+
};
|
|
32908
|
+
}
|
|
32909
|
+
async function suggestDashboardHandler(args) {
|
|
32910
|
+
const { data, intents, maxPanels, diversifyByFamily, audience } = args;
|
|
32911
|
+
const dashboard = (0, import_ai3.suggestDashboard)(data, {
|
|
32912
|
+
intents,
|
|
32913
|
+
maxPanels: maxPanels ?? 6,
|
|
32914
|
+
diversifyByFamily: diversifyByFamily !== false,
|
|
32915
|
+
audience
|
|
32916
|
+
});
|
|
32917
|
+
const lines = [];
|
|
32918
|
+
lines.push(`Dashboard: ${dashboard.panels.length} panels covering ${dashboard.intentsCovered.join(", ") || "\u2014"}`);
|
|
32919
|
+
if (dashboard.intentsMissing.length) {
|
|
32920
|
+
lines.push(`Intents this data couldn't fill: ${dashboard.intentsMissing.join(", ")}`);
|
|
32921
|
+
}
|
|
32922
|
+
lines.push("");
|
|
32923
|
+
for (let i = 0; i < dashboard.panels.length; i++) {
|
|
32924
|
+
const { intent, suggestion } = dashboard.panels[i];
|
|
32925
|
+
const variantTag = suggestion.variant ? ` / ${suggestion.variant.label}` : "";
|
|
32926
|
+
lines.push(`${i + 1}. [${intent}] ${suggestion.component}${variantTag} (score ${suggestion.score.toFixed(1)}/5)`);
|
|
32927
|
+
if (suggestion.reasons.length) lines.push(` ${suggestion.reasons.join("; ")}`);
|
|
32928
|
+
}
|
|
32929
|
+
if (dashboard.stretchPanels.length > 0) {
|
|
32930
|
+
lines.push("");
|
|
32931
|
+
lines.push(`Stretch picks (audience-unfamiliar but fitting):`);
|
|
32932
|
+
for (const stretch of dashboard.stretchPanels) {
|
|
32933
|
+
const variantTag = stretch.suggestion.variant ? ` / ${stretch.suggestion.variant.label}` : "";
|
|
32934
|
+
lines.push(` ${stretch.suggestion.component}${variantTag} (familiarity ${stretch.familiarity}) \u2014 ${stretch.rationale}`);
|
|
32935
|
+
}
|
|
32936
|
+
}
|
|
32937
|
+
return {
|
|
32938
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32939
|
+
structuredContent: dashboard
|
|
32940
|
+
};
|
|
32941
|
+
}
|
|
32942
|
+
async function suggestStretchChartsHandler(args) {
|
|
32943
|
+
const { data, audience, intent, maxResults } = args;
|
|
32944
|
+
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
32945
|
+
const stretches = (0, import_ai3.suggestStretchCharts)(data, {
|
|
32946
|
+
audience,
|
|
32947
|
+
intent: intentArg,
|
|
32948
|
+
maxResults: maxResults ?? 5
|
|
32949
|
+
});
|
|
32950
|
+
const lines = [
|
|
32951
|
+
`${stretches.length} stretch pick${stretches.length === 1 ? "" : "s"} for "${audience.name ?? "audience"}":`,
|
|
32952
|
+
"",
|
|
32953
|
+
...stretches.map((s, i) => {
|
|
32954
|
+
const variantTag = s.suggestion.variant ? ` / ${s.suggestion.variant.label}` : "";
|
|
32955
|
+
const replacing = s.replacing ? ` (could replace ${s.replacing})` : "";
|
|
32956
|
+
return `${i + 1}. ${s.suggestion.component}${variantTag} (familiarity ${s.familiarity}/5)${replacing}
|
|
32957
|
+
${s.rationale}`;
|
|
32958
|
+
})
|
|
32959
|
+
];
|
|
32960
|
+
return {
|
|
32961
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32962
|
+
structuredContent: { stretches, audience: audience.name ?? null }
|
|
32963
|
+
};
|
|
32964
|
+
}
|
|
32965
|
+
async function repairChartConfigHandler(args) {
|
|
32966
|
+
const { component, data, intent, maxAlternatives } = args;
|
|
32967
|
+
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
32968
|
+
const result = (0, import_ai3.repairChartConfig)(component, data, {
|
|
32969
|
+
intent: intentArg,
|
|
32970
|
+
maxAlternatives: maxAlternatives ?? 3
|
|
32971
|
+
});
|
|
32972
|
+
const lines = [];
|
|
32973
|
+
if (result.status === "ok") {
|
|
32974
|
+
lines.push(`\u2705 ${component} fits this dataset \u2014 no repair needed.`);
|
|
32975
|
+
} else if (result.status === "alternative") {
|
|
32976
|
+
lines.push(`\u26A0 ${component} doesn't fit: ${result.reason}`);
|
|
32977
|
+
lines.push("");
|
|
32978
|
+
lines.push(`Alternatives that fit${intentArg ? ` (ranked by intent: ${intentArg.join(", ")})` : ""}:`);
|
|
32979
|
+
for (let i = 0; i < result.alternatives.length; i++) {
|
|
32980
|
+
const s = result.alternatives[i];
|
|
32981
|
+
const variantTag = s.variant ? ` / ${s.variant.label}` : "";
|
|
32982
|
+
const reasons = s.reasons.length ? ` \u2014 ${s.reasons.join("; ")}` : "";
|
|
32983
|
+
lines.push(`${i + 1}. ${s.component}${variantTag} (score ${s.score.toFixed(1)}/5)${reasons}`);
|
|
32984
|
+
}
|
|
32985
|
+
} else {
|
|
32986
|
+
lines.push(`\u2753 No capability registered for "${component}". Closest matches:`);
|
|
32987
|
+
for (let i = 0; i < result.alternatives.length; i++) {
|
|
32988
|
+
const s = result.alternatives[i];
|
|
32989
|
+
lines.push(`${i + 1}. ${s.component} (${s.family}, score ${s.score.toFixed(1)}/5)`);
|
|
32990
|
+
}
|
|
32991
|
+
}
|
|
32992
|
+
return {
|
|
32993
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
32994
|
+
structuredContent: result
|
|
32995
|
+
};
|
|
32996
|
+
}
|
|
32997
|
+
async function interrogateChartHandler(args) {
|
|
32998
|
+
const { component, props, query } = args;
|
|
32999
|
+
const data = props.data || props.nodes || [];
|
|
33000
|
+
const summary = (0, import_ai3.summarizeData)(data);
|
|
33001
|
+
const content = [
|
|
33002
|
+
{ type: "text", text: `Statistical summary for ${component}:
|
|
33003
|
+
${JSON.stringify(summary, null, 2)}` }
|
|
33004
|
+
];
|
|
33005
|
+
if (query) {
|
|
33006
|
+
content.push({
|
|
33007
|
+
type: "text",
|
|
33008
|
+
text: `User Question: "${query}"
|
|
33009
|
+
|
|
33010
|
+
Contextual instructions:
|
|
33011
|
+
1. Analyze the statistical summary to answer the question.
|
|
33012
|
+
2. Return a natural language response.
|
|
33013
|
+
3. Optionally suggest a JSON array of Semiotic annotations to visually highlight the answer on the chart (e.g. { type: "callout", x: "Mar", y: 1500, label: "Peak month" }).
|
|
33014
|
+
4. Use the accessor names from the provided props (e.g. xAccessor, yAccessor).`
|
|
33015
|
+
});
|
|
33016
|
+
}
|
|
33017
|
+
return { content, structuredContent: { summary, component, props } };
|
|
33018
|
+
}
|
|
33019
|
+
async function groundChartHandler(args) {
|
|
33020
|
+
const component = args.component;
|
|
33021
|
+
const props = args.props ?? {};
|
|
33022
|
+
if (!component) {
|
|
33023
|
+
return {
|
|
33024
|
+
content: [{ type: "text", text: "Missing 'component' field. Provide { component: 'LineChart', props: { ... } }." }],
|
|
33025
|
+
isError: true
|
|
33026
|
+
};
|
|
33027
|
+
}
|
|
33028
|
+
const capability = (0, import_ai3.getCapability)(component);
|
|
33029
|
+
const grounding = (0, import_ai3.buildReaderGrounding)(component, props, { capability });
|
|
33030
|
+
const nodeCount = grounding.structure ? (0, import_ai3.countNodes)(grounding.structure) : 0;
|
|
33031
|
+
const lines = [
|
|
33032
|
+
`Reader grounding for ${component} \u2014 the payload an agent reads to interpret this chart without seeing it:`,
|
|
33033
|
+
"",
|
|
33034
|
+
`L1\u2013L3 (description): ${grounding.description.text}`,
|
|
33035
|
+
grounding.intent ? `L4 (intent \xB7 ${grounding.intent.act}): ${grounding.intent.sentence}` : "L4 (intent): not resolved (no capability for this component).",
|
|
33036
|
+
"",
|
|
33037
|
+
`Structure: ${nodeCount} navigable node(s) (chart \u2192 axes/series \u2192 datum) in structuredContent.structure.`,
|
|
33038
|
+
"",
|
|
33039
|
+
"Combined text:",
|
|
33040
|
+
grounding.text
|
|
33041
|
+
];
|
|
33042
|
+
return {
|
|
33043
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
33044
|
+
structuredContent: grounding
|
|
33045
|
+
};
|
|
33046
|
+
}
|
|
32746
33047
|
function createServer2() {
|
|
32747
33048
|
const srv = new McpServer({
|
|
32748
33049
|
name: "semiotic",
|
|
@@ -32822,7 +33123,7 @@ function createServer2() {
|
|
|
32822
33123
|
"Use this MCP workflow:",
|
|
32823
33124
|
"1. Read semiotic://system-prompt for compact API rules and pitfalls.",
|
|
32824
33125
|
"2. Read semiotic://behavior-contracts for semantic rules that schema shape alone cannot express.",
|
|
32825
|
-
"3. If no component is specified, call
|
|
33126
|
+
"3. If no component is specified, call suggestCharts with representative rows and the intent.",
|
|
32826
33127
|
"4. Call getSchema for the selected component before writing JSX or renderChart props.",
|
|
32827
33128
|
'5. Call diagnoseConfig with usageMode="static" for renderChart/static data, or usageMode="push" for ref-based React code that intentionally omits data.',
|
|
32828
33129
|
"6. Fix all diagnoseConfig errors before presenting code.",
|
|
@@ -32909,6 +33210,18 @@ function createServer2() {
|
|
|
32909
33210
|
},
|
|
32910
33211
|
diagnoseConfigHandler
|
|
32911
33212
|
);
|
|
33213
|
+
srv.tool(
|
|
33214
|
+
"auditAccessibility",
|
|
33215
|
+
"Audit a Semiotic chart configuration against the Chartability (POUR-CAF) accessibility framework \u2014 Perceivable, Operable, Understandable, Robust, Compromising, Assistive, Flexible. Statically grades the config (no DOM/AT): credits the built-ins every HOC ships (keyboard nav, focus ring, skip link, screen-reader data table, reduced-motion + forced-colors, shareable state), flags author-actionable gaps (missing title/description/summary, low contrast, small text, color-only encoding, undescribed trends, data density), and routes everything that needs real assistive-technology testing to a 'manual' item. Returns a per-principle report with the 14 critical heuristics marked. Pass inChartContainer=true to credit data-download/share affordances. Pair with manual NVDA/JAWS/VoiceOver testing \u2014 Chartability is not a pass/fail certification.",
|
|
33216
|
+
{
|
|
33217
|
+
component: external_exports3.string().describe("Chart component name, e.g. 'LineChart'"),
|
|
33218
|
+
props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).optional().describe("Chart props object, e.g. { data: [...], xAccessor: 'x', title: '...' }."),
|
|
33219
|
+
inChartContainer: external_exports3.boolean().optional().describe("True if the chart is (or will be) wrapped in a ChartContainer exposing data-download/copy-config actions."),
|
|
33220
|
+
describe: external_exports3.boolean().optional().describe("True if ChartContainer's describe option (auto-generated L1\u2013L3 description via describeChart) is enabled \u2014 passes the 'features described' heuristic."),
|
|
33221
|
+
navigable: external_exports3.boolean().optional().describe("True if ChartContainer's navigable option (structured navigation tree via buildNavigationTree) is enabled \u2014 passes the 'navigable structure' heuristic.")
|
|
33222
|
+
},
|
|
33223
|
+
auditAccessibilityHandler
|
|
33224
|
+
);
|
|
32912
33225
|
srv.tool(
|
|
32913
33226
|
"reportIssue",
|
|
32914
33227
|
"Generate a GitHub issue URL for Semiotic bug reports or feature requests. Returns a URL the user can open to submit. For rendering bugs, include the component name, props summary, and any diagnoseConfig output in the body.",
|
|
@@ -32927,6 +33240,143 @@ function createServer2() {
|
|
|
32927
33240
|
},
|
|
32928
33241
|
applyThemeHandler
|
|
32929
33242
|
);
|
|
33243
|
+
srv.tool(
|
|
33244
|
+
"interrogateChart",
|
|
33245
|
+
"Conversational interrogation of a Semiotic chart. Extract a statistical summary and answer natural language questions about the data, trends, and outliers. Returns a summary and guidance for an AI to generate a textual answer and visual annotations.",
|
|
33246
|
+
{
|
|
33247
|
+
component: external_exports3.string().describe("Chart component name, e.g. 'LineChart'"),
|
|
33248
|
+
props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).describe("The full chart props including data"),
|
|
33249
|
+
query: external_exports3.string().optional().describe("A natural language question about the chart data")
|
|
33250
|
+
},
|
|
33251
|
+
interrogateChartHandler
|
|
33252
|
+
);
|
|
33253
|
+
srv.tool(
|
|
33254
|
+
"groundChart",
|
|
33255
|
+
"Build the agent-reader grounding payload for a Semiotic chart: the layered L1\u2013L3 natural-language description, the L4 communicative-act sentence (what the chart is asking the reader to do \u2014 'this is an alerting chart; the spike warrants a closer look'), and a structured navigation tree (chart \u2192 axes/series \u2192 datum). This is the documented thing an LLM reads to interpret a chart faithfully without seeing the pixels \u2014 the reader-side complement to a capability descriptor. The L4 act is resolved from the chart's registered capability. Returns prose plus the full structured payload (description/intent/structure/text).",
|
|
33256
|
+
{
|
|
33257
|
+
component: external_exports3.string().describe("Chart component name, e.g. 'LineChart'"),
|
|
33258
|
+
props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).describe("The full chart props including data")
|
|
33259
|
+
},
|
|
33260
|
+
groundChartHandler
|
|
33261
|
+
);
|
|
33262
|
+
srv.tool(
|
|
33263
|
+
"suggestStreamCharts",
|
|
33264
|
+
"Recommend realtime/streaming Semiotic charts for a schema (not row data). Pass a schema describing field types plus optional throughput ('low'|'medium'|'high') and retention ('windowed'|'cumulative') hints; the engine ranks realtime charts (RealtimeLineChart, RealtimeHistogram, RealtimeHeatmap, RealtimeWaterfallChart, RealtimeSwarmChart, TemporalHistogram) by their fit. Use when the user is wiring up a live dashboard or monitoring view rather than visualizing a bounded dataset.",
|
|
33265
|
+
{
|
|
33266
|
+
schema: external_exports3.object({
|
|
33267
|
+
fields: external_exports3.array(
|
|
33268
|
+
external_exports3.object({
|
|
33269
|
+
name: external_exports3.string(),
|
|
33270
|
+
kind: external_exports3.enum(["numeric", "categorical", "date", "boolean"]),
|
|
33271
|
+
role: external_exports3.enum(["x", "y", "value", "category", "series", "size"]).optional()
|
|
33272
|
+
})
|
|
33273
|
+
),
|
|
33274
|
+
throughput: external_exports3.enum(["low", "medium", "high"]).optional(),
|
|
33275
|
+
retention: external_exports3.enum(["windowed", "cumulative"]).optional()
|
|
33276
|
+
}).describe("Stream schema \u2014 fields plus throughput/retention hints. No row data."),
|
|
33277
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional().describe("Ranking intent."),
|
|
33278
|
+
maxResults: external_exports3.number().int().min(1).max(20).optional()
|
|
33279
|
+
},
|
|
33280
|
+
suggestStreamChartsHandler
|
|
33281
|
+
);
|
|
33282
|
+
srv.tool(
|
|
33283
|
+
"suggestDashboard",
|
|
33284
|
+
"Generate a dashboard of complementary chart panels for a dataset \u2014 each panel answers a distinct analytical intent (trend, rank, distribution, correlation, etc.) and the engine diversifies by chart family by default. Heuristic only; no LLM call. Use when the user asks 'show me this data' or 'build me a dashboard' rather than picking one chart.",
|
|
33285
|
+
{
|
|
33286
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
|
|
33287
|
+
intents: external_exports3.array(external_exports3.string()).optional().describe("Intents to cover. Omit to let the engine pick based on the data shape."),
|
|
33288
|
+
maxPanels: external_exports3.number().int().min(1).max(12).optional().describe("Maximum panels (default 6)."),
|
|
33289
|
+
diversifyByFamily: external_exports3.boolean().optional().describe("Prefer not to repeat chart families across panels (default true).")
|
|
33290
|
+
},
|
|
33291
|
+
suggestDashboardHandler
|
|
33292
|
+
);
|
|
33293
|
+
srv.tool(
|
|
33294
|
+
"suggestStretchCharts",
|
|
33295
|
+
"Recommend literacy-growth chart picks for a dataset given an AudienceProfile. Returns charts the data supports but the audience is unfamiliar with (familiarity \u2264 3, or \u2264 4 at exposureLevel 2), each paired with the familiar chart it could substitute for and a rationale. Use when the consumer wants to gently expose users to less familiar but more analytically appropriate visualizations.",
|
|
33296
|
+
{
|
|
33297
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data."),
|
|
33298
|
+
audience: external_exports3.object({
|
|
33299
|
+
name: external_exports3.string().optional(),
|
|
33300
|
+
familiarity: external_exports3.record(external_exports3.string(), external_exports3.number()).optional(),
|
|
33301
|
+
targets: external_exports3.record(
|
|
33302
|
+
external_exports3.string(),
|
|
33303
|
+
external_exports3.object({
|
|
33304
|
+
direction: external_exports3.enum(["increase", "decrease"]),
|
|
33305
|
+
weight: external_exports3.number().int().min(1).max(3).optional(),
|
|
33306
|
+
reason: external_exports3.string().optional()
|
|
33307
|
+
})
|
|
33308
|
+
).optional(),
|
|
33309
|
+
exposureLevel: external_exports3.union([external_exports3.literal(0), external_exports3.literal(1), external_exports3.literal(2)]).optional(),
|
|
33310
|
+
receptionModality: external_exports3.enum(["visual", "screen-reader", "sonified", "agent"]).optional().describe("Reception channel \u2014 see suggestCharts.")
|
|
33311
|
+
}).describe("Audience profile \u2014 familiarity, targets, exposure level, reception modality."),
|
|
33312
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional(),
|
|
33313
|
+
maxResults: external_exports3.number().int().min(1).max(20).optional()
|
|
33314
|
+
},
|
|
33315
|
+
suggestStretchChartsHandler
|
|
33316
|
+
);
|
|
33317
|
+
srv.tool(
|
|
33318
|
+
"repairChartConfig",
|
|
33319
|
+
"Validate that a chart component is a sensible choice for a dataset, and if not, propose alternatives that fit. Use when a user asks for a specific chart and you want to confirm it's appropriate, or when you've drafted a config and want to verify it. Returns either ok (no change needed), alternative (chart doesn't fit; here are ranked replacements with rationale), or unknown (no capability registered).",
|
|
33320
|
+
{
|
|
33321
|
+
component: external_exports3.string().describe("Chart component name to validate, e.g. 'PieChart'"),
|
|
33322
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
|
|
33323
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional().describe("User intent \u2014 informs ranking of alternatives when the chart doesn't fit."),
|
|
33324
|
+
maxAlternatives: external_exports3.number().int().min(1).max(10).optional().describe("Cap on alternatives returned (default 3).")
|
|
33325
|
+
},
|
|
33326
|
+
repairChartConfigHandler
|
|
33327
|
+
);
|
|
33328
|
+
srv.tool(
|
|
33329
|
+
"proposeChartVariants",
|
|
33330
|
+
"Propose and score chart variants for a selected Semiotic component. Uses the capability registry plus heuristic variant discovery: registered variants, conservative transforms, and same-intent cross-family alternatives. Returns ranked proposals with fit/novelty/risk scores, rationale, and ready-to-use props. Use after suggestCharts when an agent wants to actively explore variants rather than stop at the first chart recommendation.",
|
|
33331
|
+
{
|
|
33332
|
+
component: external_exports3.string().describe("Base chart component to vary, e.g. 'LineChart', 'BarChart', or 'BoxPlot'."),
|
|
33333
|
+
props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).optional().describe("Existing chart props. If props.data is present it is profiled; network/hierarchy/geo object data can be passed here as raw input."),
|
|
33334
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).optional().describe("Row data to profile. Overrides props.data when present."),
|
|
33335
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional().describe("Ranking intent(s), e.g. trend, distribution, rank, compare-categories, composition-over-time."),
|
|
33336
|
+
maxResults: external_exports3.number().int().min(1).max(20).optional().describe("Cap on proposals returned (default 8)."),
|
|
33337
|
+
audience: external_exports3.object({
|
|
33338
|
+
name: external_exports3.string().optional(),
|
|
33339
|
+
familiarity: external_exports3.record(external_exports3.string(), external_exports3.number()).optional(),
|
|
33340
|
+
targets: external_exports3.record(
|
|
33341
|
+
external_exports3.string(),
|
|
33342
|
+
external_exports3.object({
|
|
33343
|
+
direction: external_exports3.enum(["increase", "decrease"]),
|
|
33344
|
+
weight: external_exports3.number().int().min(1).max(3).optional(),
|
|
33345
|
+
reason: external_exports3.string().optional()
|
|
33346
|
+
})
|
|
33347
|
+
).optional(),
|
|
33348
|
+
exposureLevel: external_exports3.union([external_exports3.literal(0), external_exports3.literal(1), external_exports3.literal(2)]).optional(),
|
|
33349
|
+
receptionModality: external_exports3.enum(["visual", "screen-reader", "sonified", "agent"]).optional().describe("Reception channel \u2014 see suggestCharts.")
|
|
33350
|
+
}).optional().describe("Audience profile \u2014 familiarity, adoption targets, exposure level, and reception modality.")
|
|
33351
|
+
},
|
|
33352
|
+
proposeChartVariantsHandler
|
|
33353
|
+
);
|
|
33354
|
+
srv.tool(
|
|
33355
|
+
"suggestCharts",
|
|
33356
|
+
"Recommend Semiotic charts for a dataset using heuristic capability descriptors. Each chart declares which data shapes it serves and which intents (trend, compare-categories, distribution, correlation, part-to-whole, etc.) it answers \u2014 the engine returns a ranked list with scores, reasons, caveats, and ready-to-use props. Heuristic only; no LLM call. Use the result as structured context when answering 'what chart should I use?' or generating chart code.",
|
|
33357
|
+
{
|
|
33358
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
|
|
33359
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional().describe("Ranking intent. One of: trend, compare-series, compare-categories, rank, part-to-whole, distribution, correlation, flow, hierarchy, geo, outlier-detection, composition-over-time, change-detection. Custom intents accepted."),
|
|
33360
|
+
maxResults: external_exports3.number().int().min(1).max(40).optional().describe("Cap on suggestions returned (default 8)."),
|
|
33361
|
+
allow: external_exports3.array(external_exports3.string()).optional().describe("Restrict to these component names."),
|
|
33362
|
+
deny: external_exports3.array(external_exports3.string()).optional().describe("Exclude these component names."),
|
|
33363
|
+
audience: external_exports3.object({
|
|
33364
|
+
name: external_exports3.string().optional(),
|
|
33365
|
+
familiarity: external_exports3.record(external_exports3.string(), external_exports3.number()).optional(),
|
|
33366
|
+
targets: external_exports3.record(
|
|
33367
|
+
external_exports3.string(),
|
|
33368
|
+
external_exports3.object({
|
|
33369
|
+
direction: external_exports3.enum(["increase", "decrease"]),
|
|
33370
|
+
weight: external_exports3.number().int().min(1).max(3).optional(),
|
|
33371
|
+
reason: external_exports3.string().optional()
|
|
33372
|
+
})
|
|
33373
|
+
).optional(),
|
|
33374
|
+
exposureLevel: external_exports3.union([external_exports3.literal(0), external_exports3.literal(1), external_exports3.literal(2)]).optional(),
|
|
33375
|
+
receptionModality: external_exports3.enum(["visual", "screen-reader", "sonified", "agent"]).optional().describe("Reception channel. A non-visual value down-ranks charts the audience can't receive in that channel (e.g. a many-slice pie for a screen reader) and adds receivability caveats.")
|
|
33376
|
+
}).optional().describe("Audience profile \u2014 familiarity, adoption targets, exposure level, and reception modality.")
|
|
33377
|
+
},
|
|
33378
|
+
suggestChartsHandler
|
|
33379
|
+
);
|
|
32930
33380
|
return srv;
|
|
32931
33381
|
}
|
|
32932
33382
|
var cliArgs = process.argv.slice(2);
|
|
@@ -32973,7 +33423,7 @@ async function main() {
|
|
|
32973
33423
|
});
|
|
32974
33424
|
httpServer.listen(port, () => {
|
|
32975
33425
|
console.error(`Semiotic MCP server (HTTP) listening on http://localhost:${port}`);
|
|
32976
|
-
console.error("Tools: getSchema, suggestChart, renderChart, diagnoseConfig, reportIssue, applyTheme");
|
|
33426
|
+
console.error("Tools: getSchema, suggestChart, suggestCharts, proposeChartVariants, suggestStreamCharts, suggestDashboard, suggestStretchCharts, repairChartConfig, renderChart, interrogateChart, groundChart, diagnoseConfig, auditAccessibility, reportIssue, applyTheme");
|
|
32977
33427
|
console.error("Resources: semiotic://schema, semiotic://components, semiotic://behavior-contracts, semiotic://system-prompt, semiotic://examples");
|
|
32978
33428
|
});
|
|
32979
33429
|
} else {
|
package/ai/examples.md
CHANGED
|
@@ -1181,3 +1181,101 @@ import { BarChart } from "semiotic/ai"
|
|
|
1181
1181
|
```
|
|
1182
1182
|
|
|
1183
1183
|
Key props: `y-threshold` works on vertical ordinal charts. `category-highlight` highlights a category column. `labelPosition` controls label placement.
|
|
1184
|
+
|
|
1185
|
+
---
|
|
1186
|
+
|
|
1187
|
+
## Value Charts — One Number Is The Visualization
|
|
1188
|
+
|
|
1189
|
+
### BigNumber (KPI tile — comparison + target + threshold zones)
|
|
1190
|
+
|
|
1191
|
+
```jsx
|
|
1192
|
+
import { BigNumber } from "semiotic/value"
|
|
1193
|
+
|
|
1194
|
+
<BigNumber
|
|
1195
|
+
value={1284900}
|
|
1196
|
+
label="Q3 Revenue"
|
|
1197
|
+
caption="Year-to-date bookings"
|
|
1198
|
+
format="currency"
|
|
1199
|
+
precision={0}
|
|
1200
|
+
comparison={{ value: 980000, label: "vs Q2" }}
|
|
1201
|
+
target={{ value: 1500000, label: "Q3 plan" }}
|
|
1202
|
+
thresholds={[
|
|
1203
|
+
{ at: -Infinity, level: "danger" },
|
|
1204
|
+
{ at: 1000000, level: "warning" },
|
|
1205
|
+
{ at: 1300000, level: "success" },
|
|
1206
|
+
]}
|
|
1207
|
+
/>
|
|
1208
|
+
```
|
|
1209
|
+
|
|
1210
|
+
Key props: `value` (the one number), `format` ("number"|"currency"|"percent"|"compact"|"duration"|fn), `comparison` derives a delta with auto-sentiment, `target` renders "X% of goal", `thresholds` map value to a semantic theme role (`--semiotic-{success|warning|danger|info}`). Suppress chrome via `mode="thumbnail"` for dense grids or `mode="inline"` for prose. Stream via `ref.current.push({ value, time })` — pair with `stalenessThreshold` to dim the card when updates stop.
|
|
1211
|
+
|
|
1212
|
+
### BigNumber with a Semiotic chart embedded via `trendSlot` (wide / rectangular)
|
|
1213
|
+
|
|
1214
|
+
```jsx
|
|
1215
|
+
import { BigNumber } from "semiotic/value"
|
|
1216
|
+
import { LineChart } from "semiotic/xy"
|
|
1217
|
+
|
|
1218
|
+
<BigNumber
|
|
1219
|
+
value={1284900}
|
|
1220
|
+
label="Q3 Revenue"
|
|
1221
|
+
format="currency"
|
|
1222
|
+
comparison={{ value: 980000, label: "vs Q2" }}
|
|
1223
|
+
trendSlot={(ctx) => (
|
|
1224
|
+
<LineChart
|
|
1225
|
+
data={[820000, 870000, 920000, 1010000, 1120000, 1284900].map((y, x) => ({ x, y }))}
|
|
1226
|
+
xAccessor="x"
|
|
1227
|
+
yAccessor="y"
|
|
1228
|
+
mode="sparkline"
|
|
1229
|
+
width={260}
|
|
1230
|
+
height={32}
|
|
1231
|
+
color={ctx.color}
|
|
1232
|
+
/>
|
|
1233
|
+
)}
|
|
1234
|
+
/>
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
Key props: BigNumber ships NO built-in chart renderer. `trendSlot` accepts any ReactNode (or `(ctx) => ReactNode`); pass a `LineChart`/`AreaChart` in `mode="sparkline"` for wide / rectangular charts. The slot context exposes `ctx.color` (resolved threshold colour) so the embedded chart picks up the BigNumber's level for cohesive theming.
|
|
1238
|
+
|
|
1239
|
+
### BigNumber with a square Semiotic chart via `chartSlot`
|
|
1240
|
+
|
|
1241
|
+
```jsx
|
|
1242
|
+
import { BigNumber } from "semiotic/value"
|
|
1243
|
+
import { DonutChart } from "semiotic/ordinal"
|
|
1244
|
+
|
|
1245
|
+
<BigNumber
|
|
1246
|
+
value={1284900}
|
|
1247
|
+
label="Q3 Revenue by region"
|
|
1248
|
+
format="currency"
|
|
1249
|
+
chartSlot={
|
|
1250
|
+
<DonutChart
|
|
1251
|
+
data={[
|
|
1252
|
+
{ region: "NA", revenue: 540000 },
|
|
1253
|
+
{ region: "EU", revenue: 420000 },
|
|
1254
|
+
{ region: "APAC", revenue: 324900 },
|
|
1255
|
+
]}
|
|
1256
|
+
categoryAccessor="region"
|
|
1257
|
+
valueAccessor="revenue"
|
|
1258
|
+
width={120}
|
|
1259
|
+
height={120}
|
|
1260
|
+
innerRadius={32}
|
|
1261
|
+
/>
|
|
1262
|
+
}
|
|
1263
|
+
/>
|
|
1264
|
+
```
|
|
1265
|
+
|
|
1266
|
+
Key props: `chartSlot` is the square-aspect counterpart to `trendSlot`. The card splits horizontally — text content on the left, square chart on the right (DonutChart / PieChart / Scatterplot / Treemap / CirclePack). Pass both `trendSlot` and `chartSlot` to get the square chart on the right and the wide sparkline at the bottom.
|
|
1267
|
+
|
|
1268
|
+
### BigNumber (inverted direction — lower is better)
|
|
1269
|
+
|
|
1270
|
+
```jsx
|
|
1271
|
+
import { BigNumber } from "semiotic/value"
|
|
1272
|
+
|
|
1273
|
+
<BigNumber
|
|
1274
|
+
value={486}
|
|
1275
|
+
label="P99 latency"
|
|
1276
|
+
suffix=" ms"
|
|
1277
|
+
comparison={{ value: 410, label: "vs last week", direction: "lower-is-better" }}
|
|
1278
|
+
/>
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
Key props: `direction: "lower-is-better"` flips sentiment colouring — a value that went UP now reads as negative (danger). Same pattern for error rate, churn, complaint count, etc.
|