semiotic 3.7.5 → 3.8.1
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 +63 -18
- package/README.md +121 -27
- package/agent-skill/semiotic-charts/SKILL.md +146 -0
- package/ai/cli.js +133 -45
- package/ai/componentMetadata.cjs +6 -1
- package/ai/dist/mcp-server.js +1741 -163
- package/ai/examples.md +174 -0
- package/ai/schema.json +2733 -536
- package/ai/surface-manifest.json +201 -0
- package/ai/system-prompt.md +20 -4
- package/dist/__tests__/scenarios/mcpProtocolTypes.d.ts +20 -0
- package/dist/components/AccessibleNavTree.d.ts +7 -1
- package/dist/components/CategoryColors.d.ts +1 -1
- package/dist/components/ChartContainer.d.ts +91 -0
- package/dist/components/ChartGrid.d.ts +11 -1
- package/dist/components/CircularBrush.d.ts +61 -0
- package/dist/components/ContextLayout.d.ts +5 -1
- package/dist/components/DirectManipulationControl.d.ts +63 -0
- package/dist/components/LinkedCharts.d.ts +3 -1
- package/dist/components/MobileAnnotationCalloutList.d.ts +13 -0
- package/dist/components/MobileChartContainer.d.ts +51 -0
- package/dist/components/MobileStandardControls.d.ts +68 -0
- package/dist/components/SmallMultipleChart.d.ts +84 -0
- package/dist/components/Tooltip/FlippingTooltip.d.ts +21 -0
- package/dist/components/ai/ChartRecipe.d.ts +16 -0
- package/dist/components/ai/IntentMark.d.ts +15 -0
- package/dist/components/ai/chartCapabilities.d.ts +8 -1
- package/dist/components/ai/chartCapabilityTypes.d.ts +26 -1
- package/dist/components/ai/chartClinic.d.ts +91 -0
- package/dist/components/ai/chartClinicMetadata.generated.d.ts +15 -0
- package/dist/components/ai/chartRecipeRegistry.d.ts +14 -0
- package/dist/components/ai/chartRecipes.d.ts +278 -0
- package/dist/components/ai/dataPitfallsBridge.d.ts +102 -0
- package/dist/components/ai/describeChart.d.ts +7 -0
- package/dist/components/ai/describeRecipeChart.d.ts +16 -0
- package/dist/components/ai/generativeChart.d.ts +28 -3
- package/dist/components/ai/intentManifest.d.ts +62 -0
- package/dist/components/ai/navigationTree.d.ts +3 -0
- package/dist/components/ai/observedSceneAudit.d.ts +72 -0
- package/dist/components/ai/readerGrounding.d.ts +83 -0
- package/dist/components/ai/recipeCapability.d.ts +8 -0
- package/dist/components/ai/recipeNavigation.d.ts +13 -0
- package/dist/components/ai/recipeSemantics.d.ts +11 -0
- package/dist/components/ai/repairChartConfig.d.ts +9 -0
- package/dist/components/ai/suggestCharts.d.ts +11 -1
- package/dist/components/ai/useNavigationSync.d.ts +17 -2
- package/dist/components/chartContainerMobile.d.ts +9 -0
- package/dist/components/charts/custom/GeoCustomChart.d.ts +48 -0
- package/dist/components/charts/custom/NetworkCustomChart.d.ts +8 -2
- package/dist/components/charts/custom/OrdinalCustomChart.d.ts +8 -2
- package/dist/components/charts/custom/XYCustomChart.d.ts +11 -2
- package/dist/components/charts/geo/ChoroplethMap.d.ts +19 -2
- package/dist/components/charts/geo/DistanceCartogram.d.ts +15 -3
- package/dist/components/charts/geo/FlowMap.d.ts +11 -7
- package/dist/components/charts/geo/ProportionalSymbolMap.d.ts +15 -3
- package/dist/components/charts/geo/index.d.ts +2 -0
- package/dist/components/charts/index.d.ts +35 -1
- package/dist/components/charts/network/ChordDiagram.d.ts +10 -2
- package/dist/components/charts/network/CirclePack.d.ts +1 -1
- package/dist/components/charts/network/ForceDirectedGraph.d.ts +26 -5
- package/dist/components/charts/network/OrbitDiagram.d.ts +1 -1
- package/dist/components/charts/network/ProcessSankey.d.ts +1 -1
- package/dist/components/charts/network/SankeyDiagram.d.ts +10 -2
- package/dist/components/charts/network/TreeDiagram.d.ts +1 -1
- package/dist/components/charts/network/Treemap.d.ts +1 -1
- package/dist/components/charts/network/useForceLayout.d.ts +17 -0
- package/dist/components/charts/ordinal/BarChart.d.ts +22 -1
- package/dist/components/charts/ordinal/BoxPlot.d.ts +1 -1
- package/dist/components/charts/ordinal/DonutChart.d.ts +1 -1
- package/dist/components/charts/ordinal/DotPlot.d.ts +1 -1
- package/dist/components/charts/ordinal/FunnelChart.d.ts +1 -1
- package/dist/components/charts/ordinal/GroupedBarChart.d.ts +12 -1
- package/dist/components/charts/ordinal/Histogram.d.ts +1 -1
- package/dist/components/charts/ordinal/PieChart.d.ts +1 -1
- package/dist/components/charts/ordinal/RidgelinePlot.d.ts +1 -1
- package/dist/components/charts/ordinal/StackedBarChart.d.ts +12 -1
- package/dist/components/charts/ordinal/SwarmPlot.d.ts +1 -1
- package/dist/components/charts/ordinal/SwimlaneChart.d.ts +1 -1
- package/dist/components/charts/ordinal/ViolinPlot.d.ts +1 -1
- package/dist/components/charts/physics/ChainReactionChart.d.ts +9 -0
- package/dist/components/charts/physics/CollisionSwarmChart.capability.d.ts +2 -0
- package/dist/components/charts/physics/CollisionSwarmChart.d.ts +54 -0
- package/dist/components/charts/physics/EventDropChart.capability.d.ts +2 -0
- package/dist/components/charts/physics/EventDropChart.d.ts +60 -0
- package/dist/components/charts/physics/GaltonBoardChart.capability.d.ts +2 -0
- package/dist/components/charts/physics/GaltonBoardChart.d.ts +74 -0
- package/dist/components/charts/physics/GauntletChart.capability.d.ts +2 -0
- package/dist/components/charts/physics/GauntletChart.d.ts +73 -0
- package/dist/components/charts/physics/PhysicalFlowChart.capability.d.ts +2 -0
- package/dist/components/charts/physics/PhysicalFlowChart.d.ts +63 -0
- package/dist/components/charts/physics/PhysicsCustomChart.d.ts +99 -0
- package/dist/components/charts/physics/PhysicsPileChart.capability.d.ts +2 -0
- package/dist/components/charts/physics/PhysicsPileChart.d.ts +60 -0
- package/dist/components/charts/physics/ProcessFlowChart.capability.d.ts +2 -0
- package/dist/components/charts/physics/ProcessFlowChart.d.ts +96 -0
- package/dist/components/charts/physics/chainReactionOverlay.d.ts +22 -0
- package/dist/components/charts/physics/chainReactionRuntime.d.ts +37 -0
- package/dist/components/charts/physics/chainReactionTypes.d.ts +97 -0
- package/dist/components/charts/physics/collisionSwarmPhysics.d.ts +27 -0
- package/dist/components/charts/physics/dependencyMachine.d.ts +188 -0
- package/dist/components/charts/physics/eventDropPhysics.d.ts +64 -0
- package/dist/components/charts/physics/galtonBoardPhysics.d.ts +28 -0
- package/dist/components/charts/physics/gauntletChartProps.d.ts +67 -0
- package/dist/components/charts/physics/gauntletChrome.d.ts +33 -0
- package/dist/components/charts/physics/gauntletController.d.ts +73 -0
- package/dist/components/charts/physics/gauntletEffects.d.ts +36 -0
- package/dist/components/charts/physics/gauntletPhysics.d.ts +71 -0
- package/dist/components/charts/physics/gauntletRuntime.d.ts +42 -0
- package/dist/components/charts/physics/gauntletTypes.d.ts +213 -0
- package/dist/components/charts/physics/physicalFlowPhysics.d.ts +57 -0
- package/dist/components/charts/physics/physicsChartShared.d.ts +57 -0
- package/dist/components/charts/physics/physicsChartUtils.d.ts +18 -0
- package/dist/components/charts/physics/physicsCustomLayout.d.ts +32 -0
- package/dist/components/charts/physics/physicsEncoding.d.ts +142 -0
- package/dist/components/charts/physics/physicsHocHandle.d.ts +53 -0
- package/dist/components/charts/physics/physicsHocUtils.d.ts +128 -0
- package/dist/components/charts/physics/physicsPilePhysics.d.ts +41 -0
- package/dist/components/charts/physics/physicsProcessPrimitives.d.ts +38 -0
- package/dist/components/charts/physics/processFlowPhysics.d.ts +97 -0
- package/dist/components/charts/realtime/RealtimeHeatmap.d.ts +9 -1
- package/dist/components/charts/realtime/RealtimeHistogram.d.ts +9 -1
- package/dist/components/charts/realtime/RealtimeLineChart.d.ts +9 -1
- package/dist/components/charts/realtime/RealtimeSwarmChart.d.ts +16 -2
- package/dist/components/charts/realtime/RealtimeWaterfallChart.d.ts +9 -1
- package/dist/components/charts/shared/AnnotationLabel.d.ts +88 -0
- package/dist/components/charts/shared/annotationActivation.d.ts +35 -0
- package/dist/components/charts/shared/annotationLabelLayout.d.ts +5 -0
- package/dist/components/charts/shared/annotationRules.d.ts +2 -1
- package/dist/components/charts/shared/auditMobileVisualization.d.ts +91 -0
- package/dist/components/charts/shared/chartDefinitionPilot.d.ts +145 -0
- package/dist/components/charts/shared/chartFamilySets.d.ts +20 -0
- package/dist/components/charts/shared/chartSelectionUtils.d.ts +4 -0
- package/dist/components/charts/shared/chartSpecCore.d.ts +165 -0
- package/dist/components/charts/shared/chartSpecs.d.ts +8 -127
- package/dist/components/charts/shared/chartSpecsGeo.d.ts +2 -0
- package/dist/components/charts/shared/chartSpecsNetwork.d.ts +2 -0
- package/dist/components/charts/shared/chartSpecsOrdinal.d.ts +2 -0
- package/dist/components/charts/shared/chartSpecsPhysics.d.ts +2 -0
- package/dist/components/charts/shared/chartSpecsRealtime.d.ts +2 -0
- package/dist/components/charts/shared/chartSpecsValue.d.ts +2 -0
- package/dist/components/charts/shared/chartSpecsXY.d.ts +2 -0
- package/dist/components/charts/shared/colorContrast.d.ts +3 -0
- package/dist/components/charts/shared/colorUtils.d.ts +16 -1
- package/dist/components/charts/shared/datumTypes.d.ts +2 -0
- package/dist/components/charts/shared/diagnoseAnnotationChecks.d.ts +6 -0
- package/dist/components/charts/shared/diagnoseConfig.d.ts +9 -14
- package/dist/components/charts/shared/diagnoseMisleadingChecks.d.ts +9 -0
- package/dist/components/charts/shared/diagnosePhysicsChecks.d.ts +3 -0
- package/dist/components/charts/shared/diagnoseTypes.d.ts +10 -0
- package/dist/components/charts/shared/formatUtils.d.ts +3 -3
- package/dist/components/charts/shared/hatchFill.d.ts +87 -0
- package/dist/components/charts/shared/hooks.d.ts +34 -10
- package/dist/components/charts/shared/knownChartComponents.d.ts +9 -0
- package/dist/components/charts/shared/leastSquaresRegression.d.ts +16 -0
- package/dist/components/charts/shared/mergeShapeStyle.d.ts +3 -2
- package/dist/components/charts/shared/motionEncoding.d.ts +145 -0
- package/dist/components/charts/shared/responsiveRules.d.ts +56 -0
- package/dist/components/charts/shared/semanticInteractions.d.ts +42 -0
- package/dist/components/charts/shared/sparseArray.d.ts +1 -1
- package/dist/components/charts/shared/streamPropsHelpers.d.ts +17 -5
- package/dist/components/charts/shared/styleRules.d.ts +205 -0
- package/dist/components/charts/shared/temporalStrings.d.ts +7 -0
- package/dist/components/charts/shared/tooltipUtils.d.ts +22 -9
- package/dist/components/charts/shared/types.d.ts +58 -7
- package/dist/components/charts/shared/useAreaSeriesSetup.d.ts +16 -2
- package/dist/components/charts/shared/useChartSetup.d.ts +11 -4
- package/dist/components/charts/shared/useCustomChartSetup.d.ts +17 -5
- package/dist/components/charts/shared/useFrameImperativeHandle.d.ts +1 -2
- package/dist/components/charts/shared/useLikertAggregation.d.ts +4 -4
- package/dist/components/charts/shared/useNetworkChartSetup.d.ts +6 -2
- package/dist/components/charts/shared/useOrdinalBrush.d.ts +2 -1
- package/dist/components/charts/shared/useOrdinalPieceStyle.d.ts +25 -2
- package/dist/components/charts/shared/useStreamingLegend.d.ts +2 -2
- package/dist/components/charts/shared/useSyncedPushData.d.ts +49 -0
- package/dist/components/charts/shared/useXYLineStyle.d.ts +10 -0
- package/dist/components/charts/shared/useXYPointStyle.d.ts +19 -1
- package/dist/components/charts/shared/validateChartData.d.ts +7 -5
- package/dist/components/charts/shared/validationMap.d.ts +7 -9
- package/dist/components/charts/shared/validationMap.generated.d.ts +6 -0
- package/dist/components/charts/shared/withChartWrapper.d.ts +4 -3
- package/dist/components/charts/value/targetPresentation.d.ts +22 -0
- package/dist/components/charts/value/types.d.ts +5 -6
- package/dist/components/charts/xy/AreaChart.d.ts +9 -1
- package/dist/components/charts/xy/BubbleChart.d.ts +10 -1
- package/dist/components/charts/xy/ConnectedScatterplot.d.ts +7 -0
- package/dist/components/charts/xy/DifferenceChart.d.ts +1 -52
- package/dist/components/charts/xy/Heatmap.d.ts +2 -2
- package/dist/components/charts/xy/LineChart.d.ts +12 -1
- package/dist/components/charts/xy/MinimapChart.d.ts +1 -1
- package/dist/components/charts/xy/MultiAxisLineChart.d.ts +2 -2
- package/dist/components/charts/xy/QuadrantChart.d.ts +8 -1
- package/dist/components/charts/xy/Scatterplot.d.ts +11 -1
- package/dist/components/charts/xy/ScatterplotMatrix.d.ts +11 -1
- package/dist/components/charts/xy/StackedAreaChart.d.ts +16 -4
- package/dist/components/charts/xy/differenceSegments.d.ts +49 -0
- package/dist/components/charts/xy/scatterplotMatrixInteractionTypes.d.ts +12 -0
- package/dist/components/controls/SentenceFilter.d.ts +97 -0
- package/dist/components/controls/controlAudit.d.ts +24 -0
- package/dist/components/controls/controlContract.d.ts +57 -0
- package/dist/components/data/fromFlintChart.d.ts +74 -0
- package/dist/components/data/fromVegaLite.d.ts +46 -9
- package/dist/components/data/portability/index.d.ts +6 -3
- package/dist/components/data/portability/result.d.ts +52 -0
- package/dist/components/data/portability/spec.d.ts +31 -0
- package/dist/components/data/portability/vegaLite.d.ts +24 -6
- package/dist/components/export/chartConfig.d.ts +11 -0
- package/dist/components/realtime/types.d.ts +11 -0
- package/dist/components/recipes/annotationLayout.d.ts +29 -0
- package/dist/components/recipes/axisFixedForce.d.ts +119 -0
- package/dist/components/recipes/{gofishBoba.d.ts → boba.d.ts} +2 -2
- package/dist/components/recipes/cyclical.d.ts +39 -0
- package/dist/components/recipes/edgeRouter.d.ts +103 -0
- package/dist/components/recipes/forceLayout.d.ts +48 -0
- package/dist/components/recipes/forceLayoutAsync.d.ts +17 -0
- package/dist/components/recipes/gofishBobaHandwritten.d.ts +3 -0
- package/dist/components/recipes/gofishDisplayListFixtures.generated.d.ts +37 -0
- package/dist/components/recipes/gofishIR.d.ts +178 -132
- package/dist/components/recipes/gofishIRExamples.d.ts +30 -81
- package/dist/components/recipes/intervalLanes.d.ts +87 -0
- package/dist/components/recipes/intervals.d.ts +80 -0
- package/dist/components/recipes/isometricLandmarks.d.ts +88 -0
- package/dist/components/recipes/isotypeGlyphs.d.ts +17 -0
- package/dist/components/recipes/mobileAnnotationStrategy.d.ts +48 -0
- package/dist/components/recipes/mobileChartFamilyRecipes.d.ts +59 -0
- package/dist/components/recipes/networkAnalysis.d.ts +102 -0
- package/dist/components/recipes/networkLayouts.d.ts +83 -0
- package/dist/components/recipes/physics.d.ts +122 -0
- package/dist/components/recipes/physicsReference.d.ts +102 -0
- package/dist/components/recipes/processAggregates.d.ts +32 -0
- package/dist/components/recipes/processChrome.d.ts +67 -0
- package/dist/components/recipes/processJourney.d.ts +54 -0
- package/dist/components/recipes/processPhysics.d.ts +300 -0
- package/dist/components/recipes/processVolumeGeometry.d.ts +28 -0
- package/dist/components/recipes/radialCoords.d.ts +69 -0
- package/dist/components/recipes/random.d.ts +2 -0
- package/dist/components/recipes/recipeChrome.d.ts +91 -0
- package/dist/components/recipes/recipeGlyph.d.ts +42 -0
- package/dist/components/recipes/recipeLegend.d.ts +53 -1
- package/dist/components/recipes/recipeUtils.d.ts +52 -0
- package/dist/components/recipes/runs.d.ts +59 -0
- package/dist/components/recipes/tokenEncoding.d.ts +157 -0
- package/dist/components/recipes/tokenLayer.d.ts +79 -0
- package/dist/components/recipes/unitize.d.ts +108 -0
- package/dist/components/recipes/vector.d.ts +28 -0
- package/dist/components/recipes/waffle.d.ts +43 -0
- package/dist/components/rough/createRoughRenderMode.d.ts +46 -0
- package/dist/components/semiotic-ai-core.d.ts +47 -0
- package/dist/components/semiotic-ai.d.ts +53 -9
- package/dist/components/semiotic-controls.d.ts +20 -0
- package/dist/components/semiotic-experimental.d.ts +38 -9
- package/dist/components/semiotic-geo.d.ts +15 -0
- package/dist/components/semiotic-network.d.ts +15 -0
- package/dist/components/semiotic-ordinal.d.ts +14 -0
- package/dist/components/semiotic-physics-matter.d.ts +10 -0
- package/dist/components/semiotic-physics-rapier.d.ts +9 -0
- package/dist/components/semiotic-physics.d.ts +60 -0
- package/dist/components/semiotic-realtime-core.d.ts +34 -0
- package/dist/components/semiotic-realtime-react.d.ts +10 -0
- package/dist/components/semiotic-realtime.d.ts +4 -30
- package/dist/components/semiotic-recipes-core.d.ts +92 -0
- package/dist/components/semiotic-recipes-react.d.ts +7 -0
- package/dist/components/semiotic-recipes.d.ts +4 -43
- package/dist/components/semiotic-rough.d.ts +4 -0
- package/dist/components/semiotic-server-edge.d.ts +8 -0
- package/dist/components/semiotic-server-node.d.ts +5 -0
- package/dist/components/semiotic-server.d.ts +2 -2
- package/dist/components/semiotic-themes-core.d.ts +53 -0
- package/dist/components/semiotic-themes-react.d.ts +4 -0
- package/dist/components/semiotic-themes.d.ts +6 -76
- package/dist/components/semiotic-utils-core.d.ts +50 -0
- package/dist/components/semiotic-utils-react.d.ts +5 -0
- package/dist/components/semiotic-utils.d.ts +3 -39
- package/dist/components/semiotic-xy.d.ts +12 -0
- package/dist/components/semiotic.d.ts +44 -8
- package/dist/components/server/animatedGif.d.ts +36 -0
- package/dist/components/server/optionalImageTypes.d.ts +37 -0
- package/dist/components/server/renderEvidence.d.ts +1 -1
- package/dist/components/server/renderToStaticSVG.d.ts +3 -35
- package/dist/components/server/serverChartConfigShared.d.ts +21 -0
- package/dist/components/server/serverChartConfigs.d.ts +22 -12
- package/dist/components/server/serverChartConfigsCustom.d.ts +5 -0
- package/dist/components/server/serverChartConfigsGeo.d.ts +9 -0
- package/dist/components/server/serverChartConfigsNetwork.d.ts +8 -0
- package/dist/components/server/serverChartConfigsOrdinal.d.ts +16 -0
- package/dist/components/server/serverChartConfigsPhysics.d.ts +9 -0
- package/dist/components/server/serverChartConfigsXY.d.ts +11 -0
- package/dist/components/server/staticAnnotations.d.ts +6 -3
- package/dist/components/server/staticGeo.d.ts +4 -0
- package/dist/components/server/staticLegend.d.ts +2 -2
- package/dist/components/server/staticNetwork.d.ts +8 -0
- package/dist/components/server/staticOrdinal.d.ts +11 -0
- package/dist/components/server/staticPhysics.d.ts +3 -0
- package/dist/components/server/staticSVGChrome.d.ts +110 -0
- package/dist/components/server/staticXY.d.ts +4 -0
- package/dist/components/store/ObservationStore.d.ts +23 -2
- package/dist/components/store/themeSerialization.d.ts +32 -0
- package/dist/components/store/useChartInterrogation.d.ts +9 -0
- package/dist/components/stream/AccessibleDataTable.d.ts +7 -23
- package/dist/components/stream/AriaLiveTooltip.d.ts +9 -0
- package/dist/components/stream/CanvasHitTester.d.ts +4 -4
- package/dist/components/stream/DataSourceAdapter.d.ts +1 -1
- package/dist/components/stream/FocusRing.d.ts +4 -2
- package/dist/components/stream/FrameRuntime.d.ts +57 -0
- package/dist/components/stream/GeoCanvasHitTester.d.ts +1 -1
- package/dist/components/stream/GeoParticlePool.d.ts +1 -1
- package/dist/components/stream/GeoPipelineStore.d.ts +62 -3
- package/dist/components/stream/GeoSVGOverlay.d.ts +64 -0
- package/dist/components/stream/NetworkCanvasHitTester.d.ts +2 -1
- package/dist/components/stream/NetworkPipelineStore.d.ts +44 -36
- package/dist/components/stream/NetworkSSRFrame.d.ts +17 -0
- package/dist/components/stream/NetworkSVGOverlay.d.ts +10 -1
- package/dist/components/stream/OrdinalCanvasHitTester.d.ts +2 -2
- package/dist/components/stream/OrdinalPipelineStore.d.ts +55 -11
- package/dist/components/stream/OrdinalSVGOverlay.d.ts +9 -1
- package/dist/components/stream/OrdinalStyleResolver.d.ts +12 -0
- package/dist/components/stream/ParticlePool.d.ts +1 -1
- package/dist/components/stream/PipelineStore.d.ts +81 -174
- package/dist/components/stream/SVGOverlay.d.ts +6 -0
- package/dist/components/stream/SceneGraph.d.ts +12 -4
- package/dist/components/stream/StreamGeoFrame.d.ts +1 -1
- package/dist/components/stream/StreamNetworkFrame.d.ts +1 -1
- package/dist/components/stream/StreamOrdinalFrame.d.ts +1 -1
- package/dist/components/stream/StreamXYFrame.d.ts +2 -18
- package/dist/components/stream/accessibleDataRows.d.ts +33 -0
- package/dist/components/stream/accessorUtils.d.ts +25 -12
- package/dist/components/stream/annotationAccessorResolver.d.ts +2 -2
- package/dist/components/stream/brushAccessibility.d.ts +25 -0
- package/dist/components/stream/canvasBackground.d.ts +24 -0
- package/dist/components/stream/canvasSetup.d.ts +4 -1
- package/dist/components/stream/customLayoutFailure.d.ts +33 -0
- package/dist/components/stream/customLayoutPalette.d.ts +19 -9
- package/dist/components/stream/frameGraphics.d.ts +4 -0
- package/dist/components/stream/frameKeyboardNavigation.d.ts +45 -0
- package/dist/components/stream/frameThemeColors.d.ts +24 -0
- package/dist/components/stream/geoAnnotationAnchors.d.ts +14 -0
- package/dist/components/stream/geoCartogram.d.ts +17 -0
- package/dist/components/stream/geoCustomLayout.d.ts +59 -0
- package/dist/components/stream/geoDefaultTooltip.d.ts +11 -0
- package/dist/components/stream/geoFrameHelpers.d.ts +34 -0
- package/dist/components/stream/geoPipelineHelpers.d.ts +46 -0
- package/dist/components/stream/geoPipelineUpdateResults.d.ts +34 -0
- package/dist/components/stream/geoSceneBuilder.d.ts +16 -0
- package/dist/components/stream/geoTypes.d.ts +97 -15
- package/dist/components/stream/glyphDef.d.ts +98 -0
- package/dist/components/stream/hitTarget.d.ts +170 -0
- package/dist/components/stream/hitTestUtils.d.ts +2 -2
- package/dist/components/stream/hoverUtils.d.ts +7 -2
- package/dist/components/stream/keyboardNav.d.ts +4 -1
- package/dist/components/stream/layouts/forceLayoutPlugin.d.ts +9 -1
- package/dist/components/stream/layouts/forceLayoutWorkerClient.d.ts +58 -0
- package/dist/components/stream/layouts/hierarchyUtils.d.ts +2 -2
- package/dist/components/stream/networkBezier.d.ts +10 -0
- package/dist/components/stream/networkColorAccessors.d.ts +49 -0
- package/dist/components/stream/networkCustomLayoutRunner.d.ts +23 -0
- package/dist/components/stream/networkCustomRestyle.d.ts +15 -0
- package/dist/components/stream/networkDefaultTooltip.d.ts +10 -0
- package/dist/components/stream/networkFrameAnimation.d.ts +7 -0
- package/dist/components/stream/networkFrameHandleTypes.d.ts +39 -0
- package/dist/components/stream/networkFrameInteraction.d.ts +37 -0
- package/dist/components/stream/networkFrameObservations.d.ts +15 -0
- package/dist/components/stream/networkFramePaint.d.ts +52 -0
- package/dist/components/stream/networkInteractionTypes.d.ts +26 -0
- package/dist/components/stream/networkPipelineConfig.d.ts +22 -0
- package/dist/components/stream/networkPipelineHelpers.d.ts +12 -0
- package/dist/components/stream/networkPipelineUpdateResults.d.ts +38 -0
- package/dist/components/stream/networkRealtimeEncoding.d.ts +41 -0
- package/dist/components/stream/networkTypes.d.ts +103 -51
- package/dist/components/stream/ordinalCanvasRenderers.d.ts +7 -0
- package/dist/components/stream/ordinalDataIndex.d.ts +5 -0
- package/dist/components/stream/ordinalDefaultTooltip.d.ts +10 -0
- package/dist/components/stream/ordinalDomain.d.ts +38 -0
- package/dist/components/stream/ordinalPipelineUpdateResults.d.ts +31 -0
- package/dist/components/stream/ordinalPulse.d.ts +10 -0
- package/dist/components/stream/ordinalPulseResources.d.ts +3 -0
- package/dist/components/stream/ordinalSceneBuilders/sceneBuilderMap.d.ts +5 -0
- package/dist/components/stream/ordinalSceneBuilders/types.d.ts +2 -2
- package/dist/components/stream/ordinalSpatialIndex.d.ts +9 -0
- package/dist/components/stream/ordinalTypes.d.ts +68 -9
- package/dist/components/stream/paintNeeds.d.ts +31 -0
- package/dist/components/stream/physics/CapacityQueueController.d.ts +5 -0
- package/dist/components/stream/physics/CapacityQueueTypes.d.ts +134 -0
- package/dist/components/stream/physics/MatterPhysicsEngineAdapter.d.ts +42 -0
- package/dist/components/stream/physics/PhysicsAccessibility.d.ts +48 -0
- package/dist/components/stream/physics/PhysicsAnnotations.d.ts +58 -0
- package/dist/components/stream/physics/PhysicsBodyBudget.d.ts +26 -0
- package/dist/components/stream/physics/PhysicsBodySpatialIndex.d.ts +10 -0
- package/dist/components/stream/physics/PhysicsCanvasTheme.d.ts +26 -0
- package/dist/components/stream/physics/PhysicsControllers.d.ts +75 -0
- package/dist/components/stream/physics/PhysicsEngineAdapter.d.ts +59 -0
- package/dist/components/stream/physics/PhysicsEngineConformance.d.ts +23 -0
- package/dist/components/stream/physics/PhysicsEvidence.d.ts +25 -0
- package/dist/components/stream/physics/PhysicsKernel.d.ts +207 -0
- package/dist/components/stream/physics/PhysicsOptionalEngineAdapters.d.ts +12 -0
- package/dist/components/stream/physics/PhysicsPipelineStore.d.ts +86 -0
- package/dist/components/stream/physics/PhysicsPipelineTypes.d.ts +181 -0
- package/dist/components/stream/physics/PhysicsSVGOverlay.d.ts +78 -0
- package/dist/components/stream/physics/PhysicsSediment.d.ts +69 -0
- package/dist/components/stream/physics/PhysicsSettledSVG.d.ts +18 -0
- package/dist/components/stream/physics/PhysicsSettledScene.d.ts +21 -0
- package/dist/components/stream/physics/PhysicsWorkerClient.d.ts +24 -0
- package/dist/components/stream/physics/PhysicsWorkerProtocol.d.ts +101 -0
- package/dist/components/stream/physics/PhysicsWorkerRuntime.d.ts +5 -0
- package/dist/components/stream/physics/RapierPhysicsEngineAdapter.d.ts +18 -0
- package/dist/components/stream/physics/ServiceOperationsControllers.d.ts +27 -0
- package/dist/components/stream/physics/ServiceOperationsTypes.d.ts +89 -0
- package/dist/components/stream/physics/StreamPhysicsFrame.d.ts +6 -0
- package/dist/components/stream/physics/StreamPhysicsTypes.d.ts +317 -0
- package/dist/components/stream/physics/physicsBodyCanvas.d.ts +27 -0
- package/dist/components/stream/physics/physicsFrameObservations.d.ts +19 -0
- package/dist/components/stream/physics/physicsFrameSetup.d.ts +4 -0
- package/dist/components/stream/physics/physicsPipelineControls.d.ts +4 -0
- package/dist/components/stream/physics/physicsPipelineHelpers.d.ts +41 -0
- package/dist/components/stream/physics/physicsPipelineObservations.d.ts +14 -0
- package/dist/components/stream/physics/physicsPipelineUpdateResults.d.ts +27 -0
- package/dist/components/stream/physics/physicsRegionRuntime.d.ts +54 -0
- package/dist/components/stream/physics/physicsSemanticUI.d.ts +20 -0
- package/dist/components/stream/physics/usePhysicsFrameLifecyclePolicy.d.ts +18 -0
- package/dist/components/stream/pipelineBufferUtils.d.ts +26 -0
- package/dist/components/stream/pipelineConfig.d.ts +179 -0
- package/dist/components/stream/pipelineDecay.d.ts +21 -3
- package/dist/components/stream/pipelineDomainResolution.d.ts +62 -0
- package/dist/components/stream/pipelineIdentityOps.d.ts +26 -0
- package/dist/components/stream/pipelinePulse.d.ts +17 -3
- package/dist/components/stream/pipelineRibbons.d.ts +41 -0
- package/dist/components/stream/pipelineSpatialIndex.d.ts +12 -0
- package/dist/components/stream/pipelineStoreUpdateResults.d.ts +33 -0
- package/dist/components/stream/pipelineStyleResolvers.d.ts +46 -0
- package/dist/components/stream/pipelineTransitions.d.ts +3 -1
- package/dist/components/stream/pipelineUpdateContract.d.ts +69 -0
- package/dist/components/stream/pipelineUpdateStore.d.ts +21 -0
- package/dist/components/stream/pulseFrameRefresh.d.ts +22 -0
- package/dist/components/stream/renderBackend.d.ts +27 -0
- package/dist/components/stream/renderers/canvasRenderHelpers.d.ts +15 -1
- package/dist/components/stream/renderers/geoCanvasRenderer.d.ts +3 -2
- package/dist/components/stream/renderers/glyphCanvasRenderer.d.ts +6 -0
- package/dist/components/stream/renderers/networkParticleRenderer.d.ts +1 -1
- package/dist/components/stream/renderers/resolveCSSColor.d.ts +6 -0
- package/dist/components/stream/sceneRenderBackendTypes.d.ts +28 -0
- package/dist/components/stream/sceneRevisionDiagnostics.d.ts +45 -0
- package/dist/components/stream/streamSemanticTypes.d.ts +16 -0
- package/dist/components/stream/streamStoreSync.d.ts +37 -0
- package/dist/components/stream/streamThemeTypes.d.ts +14 -0
- package/dist/components/stream/svgOverlayUtils.d.ts +10 -0
- package/dist/components/stream/test-utils/frameScheduler.d.ts +12 -0
- package/dist/components/stream/test-utils/revisionConsumption.d.ts +13 -0
- package/dist/components/stream/titleLayout.d.ts +31 -0
- package/dist/components/stream/types.d.ts +165 -72
- package/dist/components/stream/useCanvasFrameHost.d.ts +71 -0
- package/dist/components/stream/useFrame.d.ts +44 -2
- package/dist/components/stream/useHydration.d.ts +6 -0
- package/dist/components/stream/useLegendCategoryEmission.d.ts +5 -0
- package/dist/components/stream/useSemanticFrameInteractions.d.ts +22 -0
- package/dist/components/stream/useUpdateResultSnapshot.d.ts +7 -0
- package/dist/components/stream/workerModuleUrl.d.ts +10 -0
- package/dist/components/stream/xyAnnotationAnchors.d.ts +13 -0
- package/dist/components/stream/xyCanvasRenderers.d.ts +7 -0
- package/dist/components/stream/xyCrosshair.d.ts +11 -0
- package/dist/components/stream/xyDateTicks.d.ts +9 -0
- package/dist/components/stream/xyDefaultTooltip.d.ts +10 -0
- package/dist/components/stream/xyFrameAxisTypes.d.ts +50 -0
- package/dist/components/stream/xySceneBuilders/types.d.ts +10 -9
- package/dist/controls.min.js +2 -0
- package/dist/controls.module.min.js +2 -0
- package/dist/forceLayoutWorker.js +1 -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/physics-matter.min.js +1 -0
- package/dist/physics-matter.module.min.js +1 -0
- package/dist/physics-rapier.min.js +1 -0
- package/dist/physics-rapier.module.min.js +1 -0
- package/dist/physics.min.js +2 -0
- package/dist/physics.module.min.js +2 -0
- package/dist/physicsWorker.js +1 -0
- package/dist/realtime.min.js +1 -1
- package/dist/realtime.module.min.js +1 -1
- package/dist/rough.min.js +1 -0
- package/dist/rough.module.min.js +1 -0
- package/dist/semiotic-ai-chunk-OG7BQUUW.module.min.js +2 -0
- package/dist/semiotic-ai-core.d.ts +47 -0
- package/dist/semiotic-ai-core.min.js +1 -0
- package/dist/semiotic-ai-core.module.min.js +1 -0
- package/dist/semiotic-ai-statisticalOverlays-CY4WKR4A.module.min.js +2 -0
- package/dist/semiotic-ai.d.ts +53 -9
- package/dist/semiotic-ai.min.js +1 -1
- package/dist/semiotic-ai.module.min.js +1 -1
- package/dist/semiotic-chunk-3FSVZ46U.module.min.js +2 -0
- package/dist/semiotic-controls.d.ts +20 -0
- package/dist/semiotic-data.min.js +1 -1
- package/dist/semiotic-data.module.min.js +1 -1
- package/dist/semiotic-experimental.d.ts +38 -9
- package/dist/semiotic-experimental.min.js +1 -1
- package/dist/semiotic-experimental.module.min.js +1 -1
- package/dist/semiotic-geo.d.ts +15 -0
- package/dist/semiotic-network.d.ts +15 -0
- package/dist/semiotic-ordinal.d.ts +14 -0
- package/dist/semiotic-physics-matter.d.ts +10 -0
- package/dist/semiotic-physics-rapier.d.ts +9 -0
- package/dist/semiotic-physics.d.ts +60 -0
- package/dist/semiotic-realtime-core.d.ts +34 -0
- package/dist/semiotic-realtime-core.min.js +1 -0
- package/dist/semiotic-realtime-core.module.min.js +1 -0
- package/dist/semiotic-realtime-react.d.ts +10 -0
- package/dist/semiotic-realtime-react.min.js +2 -0
- package/dist/semiotic-realtime-react.module.min.js +2 -0
- package/dist/semiotic-realtime.d.ts +4 -30
- package/dist/semiotic-recipes-core.d.ts +92 -0
- package/dist/semiotic-recipes-core.min.js +1 -0
- package/dist/semiotic-recipes-core.module.min.js +1 -0
- package/dist/semiotic-recipes-react.d.ts +7 -0
- package/dist/semiotic-recipes-react.min.js +2 -0
- package/dist/semiotic-recipes-react.module.min.js +2 -0
- package/dist/semiotic-recipes.d.ts +4 -43
- package/dist/semiotic-recipes.min.js +1 -1
- package/dist/semiotic-recipes.module.min.js +1 -1
- package/dist/semiotic-rough.d.ts +4 -0
- package/dist/semiotic-server-edge.d.ts +8 -0
- package/dist/semiotic-server-edge.min.js +1 -0
- package/dist/semiotic-server-edge.module.min.js +1 -0
- package/dist/semiotic-server-node.d.ts +5 -0
- package/dist/semiotic-server-node.min.js +1 -0
- package/dist/semiotic-server-node.module.min.js +1 -0
- package/dist/semiotic-server.d.ts +2 -2
- package/dist/semiotic-statisticalOverlays-UOMSFKVJ.module.min.js +2 -0
- package/dist/semiotic-themes-core.d.ts +53 -0
- package/dist/semiotic-themes-core.min.js +1 -0
- package/dist/semiotic-themes-core.module.min.js +1 -0
- package/dist/semiotic-themes-react.d.ts +4 -0
- package/dist/semiotic-themes-react.min.js +2 -0
- package/dist/semiotic-themes-react.module.min.js +2 -0
- package/dist/semiotic-themes.d.ts +6 -76
- package/dist/semiotic-themes.min.js +1 -2
- package/dist/semiotic-themes.module.min.js +1 -2
- package/dist/semiotic-utils-core.d.ts +50 -0
- package/dist/semiotic-utils-core.min.js +1 -0
- package/dist/semiotic-utils-core.module.min.js +1 -0
- package/dist/semiotic-utils-react.d.ts +5 -0
- package/dist/semiotic-utils-react.min.js +2 -0
- package/dist/semiotic-utils-react.module.min.js +2 -0
- package/dist/semiotic-utils.d.ts +3 -39
- package/dist/semiotic-utils.min.js +1 -2
- package/dist/semiotic-utils.module.min.js +1 -2
- package/dist/semiotic-value.min.js +1 -1
- package/dist/semiotic-value.module.min.js +1 -1
- package/dist/semiotic-xy.d.ts +12 -0
- package/dist/semiotic.d.ts +44 -8
- 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/test-utils/capturedFrameProps.d.ts +67 -0
- package/dist/test-utils/frameMock.d.ts +12 -9
- package/dist/xy-chunk-IWD6IB6V.module.min.js +2 -0
- package/dist/xy-statisticalOverlays-7RWG6LJT.module.min.js +2 -0
- package/dist/xy.min.js +1 -1
- package/dist/xy.module.min.js +1 -1
- package/package.json +259 -88
- package/spec/README.md +152 -0
- package/spec/bindings/README.md +35 -0
- package/spec/bindings/vega-lite.mjs +112 -0
- package/spec/v0.1/annotation-provenance.schema.json +127 -0
- package/spec/v0.1/audience-profile.schema.json +67 -0
- package/spec/v0.1/chart-capability.schema.json +186 -0
- package/dist/components/recipes/gofish.d.ts +0 -207
- package/dist/components/recipes/gofishInterpreter.d.ts +0 -52
- package/dist/components/recipes/gofishLambdas.d.ts +0 -145
- package/dist/semiotic-ai-semiotic-ai-u954ylUn.js +0 -2
- package/dist/semiotic-ai-statisticalOverlays-CU7jW05Q.js +0 -1
- package/dist/semiotic-semiotic-BmrYbi99.js +0 -2
- package/dist/semiotic-statisticalOverlays-IjZw8Lsu.js +0 -1
- package/dist/xy-semiotic-xy-Dufu3D0-.js +0 -2
- package/dist/xy-statisticalOverlays-3Ni9bRph.js +0 -1
package/ai/dist/mcp-server.js
CHANGED
|
@@ -3206,11 +3206,11 @@ var require_utils = __commonJS({
|
|
|
3206
3206
|
output.address = address.join("");
|
|
3207
3207
|
return output;
|
|
3208
3208
|
}
|
|
3209
|
-
function normalizeIPv6(
|
|
3210
|
-
if (findToken(
|
|
3211
|
-
return { host, isIPV6: false };
|
|
3209
|
+
function normalizeIPv6(host2) {
|
|
3210
|
+
if (findToken(host2, ":") < 2) {
|
|
3211
|
+
return { host: host2, isIPV6: false };
|
|
3212
3212
|
}
|
|
3213
|
-
const ipv63 = getIPV6(
|
|
3213
|
+
const ipv63 = getIPV6(host2);
|
|
3214
3214
|
if (!ipv63.error) {
|
|
3215
3215
|
let newHost = ipv63.address;
|
|
3216
3216
|
let escapedHost = ipv63.address;
|
|
@@ -3220,7 +3220,7 @@ var require_utils = __commonJS({
|
|
|
3220
3220
|
}
|
|
3221
3221
|
return { host: newHost, isIPV6: true, escapedHost };
|
|
3222
3222
|
} else {
|
|
3223
|
-
return { host, isIPV6: false };
|
|
3223
|
+
return { host: host2, isIPV6: false };
|
|
3224
3224
|
}
|
|
3225
3225
|
}
|
|
3226
3226
|
function findToken(str, token) {
|
|
@@ -3308,10 +3308,10 @@ var require_utils = __commonJS({
|
|
|
3308
3308
|
var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
|
|
3309
3309
|
var HOST_DELIM_RE = /[@/?#:]/g;
|
|
3310
3310
|
var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
3311
|
-
function reescapeHostDelimiters(
|
|
3311
|
+
function reescapeHostDelimiters(host2, isIP) {
|
|
3312
3312
|
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
3313
3313
|
re.lastIndex = 0;
|
|
3314
|
-
return
|
|
3314
|
+
return host2.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
3315
3315
|
}
|
|
3316
3316
|
function normalizePercentEncoding(input, decodeUnreserved = false) {
|
|
3317
3317
|
if (input.indexOf("%") === -1) {
|
|
@@ -3384,16 +3384,16 @@ var require_utils = __commonJS({
|
|
|
3384
3384
|
uriTokens.push("@");
|
|
3385
3385
|
}
|
|
3386
3386
|
if (component.host !== void 0) {
|
|
3387
|
-
let
|
|
3388
|
-
if (!isIPv4(
|
|
3389
|
-
const ipV6res = normalizeIPv6(
|
|
3387
|
+
let host2 = unescape(component.host);
|
|
3388
|
+
if (!isIPv4(host2)) {
|
|
3389
|
+
const ipV6res = normalizeIPv6(host2);
|
|
3390
3390
|
if (ipV6res.isIPV6 === true) {
|
|
3391
|
-
|
|
3391
|
+
host2 = `[${ipV6res.escapedHost}]`;
|
|
3392
3392
|
} else {
|
|
3393
|
-
|
|
3393
|
+
host2 = reescapeHostDelimiters(host2, false);
|
|
3394
3394
|
}
|
|
3395
3395
|
}
|
|
3396
|
-
uriTokens.push(
|
|
3396
|
+
uriTokens.push(host2);
|
|
3397
3397
|
}
|
|
3398
3398
|
if (typeof component.port === "number" || typeof component.port === "string") {
|
|
3399
3399
|
uriTokens.push(":");
|
|
@@ -4036,7 +4036,7 @@ var require_core = __commonJS({
|
|
|
4036
4036
|
constructor(opts = {}) {
|
|
4037
4037
|
this.schemas = {};
|
|
4038
4038
|
this.refs = {};
|
|
4039
|
-
this.formats =
|
|
4039
|
+
this.formats = /* @__PURE__ */ Object.create(null);
|
|
4040
4040
|
this._compilations = /* @__PURE__ */ new Set();
|
|
4041
4041
|
this._loading = {};
|
|
4042
4042
|
this._cache = /* @__PURE__ */ new Map();
|
|
@@ -6894,7 +6894,7 @@ var require_dist = __commonJS({
|
|
|
6894
6894
|
var require_componentMetadata = __commonJS({
|
|
6895
6895
|
"ai/componentMetadata.cjs"(exports2, module2) {
|
|
6896
6896
|
"use strict";
|
|
6897
|
-
var CATEGORY_ORDER = ["xy", "ordinal", "network", "geo", "realtime", "value"];
|
|
6897
|
+
var CATEGORY_ORDER = ["xy", "ordinal", "network", "geo", "realtime", "physics", "value"];
|
|
6898
6898
|
var COMPONENTS_BY_CATEGORY = {
|
|
6899
6899
|
xy: [
|
|
6900
6900
|
"LineChart",
|
|
@@ -6952,6 +6952,15 @@ var require_componentMetadata = __commonJS({
|
|
|
6952
6952
|
"RealtimeWaterfallChart",
|
|
6953
6953
|
"RealtimeHeatmap"
|
|
6954
6954
|
],
|
|
6955
|
+
physics: [
|
|
6956
|
+
"GaltonBoardChart",
|
|
6957
|
+
"EventDropChart",
|
|
6958
|
+
"PhysicsPileChart",
|
|
6959
|
+
"CollisionSwarmChart",
|
|
6960
|
+
"PhysicalFlowChart",
|
|
6961
|
+
"ProcessFlowChart",
|
|
6962
|
+
"GauntletChart"
|
|
6963
|
+
],
|
|
6955
6964
|
value: [
|
|
6956
6965
|
"BigNumber"
|
|
6957
6966
|
]
|
|
@@ -6973,6 +6982,7 @@ var require_componentMetadata = __commonJS({
|
|
|
6973
6982
|
return category;
|
|
6974
6983
|
}
|
|
6975
6984
|
function importPathForCategory(category) {
|
|
6985
|
+
if (category === "physics") return "semiotic/physics";
|
|
6976
6986
|
return category === "geo" ? "semiotic/geo" : `semiotic/${category}`;
|
|
6977
6987
|
}
|
|
6978
6988
|
function metadataForComponent2(entryOrName) {
|
|
@@ -14325,13 +14335,13 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
14325
14335
|
}
|
|
14326
14336
|
return propValues;
|
|
14327
14337
|
});
|
|
14328
|
-
const
|
|
14338
|
+
const isObject3 = isObject;
|
|
14329
14339
|
const catchall = def.catchall;
|
|
14330
14340
|
let value;
|
|
14331
14341
|
inst._zod.parse = (payload, ctx) => {
|
|
14332
14342
|
value ?? (value = _normalized.value);
|
|
14333
14343
|
const input = payload.value;
|
|
14334
|
-
if (!
|
|
14344
|
+
if (!isObject3(input)) {
|
|
14335
14345
|
payload.issues.push({
|
|
14336
14346
|
expected: "object",
|
|
14337
14347
|
code: "invalid_type",
|
|
@@ -14429,7 +14439,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
14429
14439
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
14430
14440
|
};
|
|
14431
14441
|
let fastpass;
|
|
14432
|
-
const
|
|
14442
|
+
const isObject3 = isObject;
|
|
14433
14443
|
const jit = !globalConfig.jitless;
|
|
14434
14444
|
const allowsEval2 = allowsEval;
|
|
14435
14445
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -14438,7 +14448,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
14438
14448
|
inst._zod.parse = (payload, ctx) => {
|
|
14439
14449
|
value ?? (value = _normalized.value);
|
|
14440
14450
|
const input = payload.value;
|
|
14441
|
-
if (!
|
|
14451
|
+
if (!isObject3(input)) {
|
|
14442
14452
|
payload.issues.push({
|
|
14443
14453
|
expected: "object",
|
|
14444
14454
|
code: "invalid_type",
|
|
@@ -31204,8 +31214,8 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
31204
31214
|
}
|
|
31205
31215
|
return req;
|
|
31206
31216
|
}
|
|
31207
|
-
const
|
|
31208
|
-
if (!
|
|
31217
|
+
const host2 = (incoming instanceof import_http22.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
|
31218
|
+
if (!host2) {
|
|
31209
31219
|
throw new RequestError("Missing host header");
|
|
31210
31220
|
}
|
|
31211
31221
|
let scheme;
|
|
@@ -31217,8 +31227,8 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
31217
31227
|
} else {
|
|
31218
31228
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
31219
31229
|
}
|
|
31220
|
-
const url2 = new URL(`${scheme}://${
|
|
31221
|
-
if (url2.hostname.length !==
|
|
31230
|
+
const url2 = new URL(`${scheme}://${host2}${incomingUrl}`);
|
|
31231
|
+
if (url2.hostname.length !== host2.length && url2.hostname !== host2.replace(/:\d+$/, "")) {
|
|
31222
31232
|
throw new RequestError("Invalid host header");
|
|
31223
31233
|
}
|
|
31224
31234
|
req[urlKey] = url2.href;
|
|
@@ -32356,6 +32366,636 @@ var fs = __toESM(require("fs"));
|
|
|
32356
32366
|
var path = __toESM(require("path"));
|
|
32357
32367
|
var http = __toESM(require("http"));
|
|
32358
32368
|
|
|
32369
|
+
// ai/mcp-server-options.ts
|
|
32370
|
+
var DEFAULT_HTTP_HOST = "127.0.0.1";
|
|
32371
|
+
function getFlagValue(args, flag) {
|
|
32372
|
+
const inlinePrefix = `${flag}=`;
|
|
32373
|
+
for (let index = 0; index < args.length; index++) {
|
|
32374
|
+
const argument = args[index];
|
|
32375
|
+
if (argument.startsWith(inlinePrefix)) return argument.slice(inlinePrefix.length);
|
|
32376
|
+
if (argument !== flag) continue;
|
|
32377
|
+
const next = args[index + 1];
|
|
32378
|
+
return next && !next.startsWith("--") ? next : void 0;
|
|
32379
|
+
}
|
|
32380
|
+
return void 0;
|
|
32381
|
+
}
|
|
32382
|
+
function resolveHTTPListenHost(args, env = process.env) {
|
|
32383
|
+
return getFlagValue(args, "--host")?.trim() || env.MCP_HOST?.trim() || DEFAULT_HTTP_HOST;
|
|
32384
|
+
}
|
|
32385
|
+
|
|
32386
|
+
// ai/mcp-request-cancellation.ts
|
|
32387
|
+
function createMcpRequestCancellationSignal(req, res) {
|
|
32388
|
+
const controller = new AbortController();
|
|
32389
|
+
const abort = () => controller.abort();
|
|
32390
|
+
req.once("aborted", abort);
|
|
32391
|
+
req.once("close", () => {
|
|
32392
|
+
if (!req.complete) abort();
|
|
32393
|
+
});
|
|
32394
|
+
res.once("close", () => {
|
|
32395
|
+
if (!res.writableFinished) abort();
|
|
32396
|
+
});
|
|
32397
|
+
return controller.signal;
|
|
32398
|
+
}
|
|
32399
|
+
|
|
32400
|
+
// ai/mcp-build-info.ts
|
|
32401
|
+
function nonEmptyEnvValue(env, name) {
|
|
32402
|
+
const value = env[name]?.trim();
|
|
32403
|
+
return value || void 0;
|
|
32404
|
+
}
|
|
32405
|
+
function normalizeGitSha(value) {
|
|
32406
|
+
return value && /^[0-9a-f]{40,128}$/i.test(value) ? value.toLowerCase() : void 0;
|
|
32407
|
+
}
|
|
32408
|
+
function resolveDeploymentChannel(value) {
|
|
32409
|
+
return value?.toLowerCase() === "nightly" ? "nightly" : "stable";
|
|
32410
|
+
}
|
|
32411
|
+
function resolveSemioticBuildInfo(options) {
|
|
32412
|
+
const env = options.env ?? process.env;
|
|
32413
|
+
const commitSha = normalizeGitSha(nonEmptyEnvValue(env, "SEMIOTIC_GIT_SHA"));
|
|
32414
|
+
return {
|
|
32415
|
+
channel: resolveDeploymentChannel(
|
|
32416
|
+
nonEmptyEnvValue(env, "SEMIOTIC_DEPLOYMENT_CHANNEL")
|
|
32417
|
+
),
|
|
32418
|
+
packageVersion: options.packageVersion,
|
|
32419
|
+
surfaceVersion: options.surfaceVersion,
|
|
32420
|
+
...commitSha ? { commitSha, shortCommitSha: commitSha.slice(0, 7) } : {},
|
|
32421
|
+
...nonEmptyEnvValue(env, "SEMIOTIC_BUILD_ID") ? { buildId: nonEmptyEnvValue(env, "SEMIOTIC_BUILD_ID") } : {},
|
|
32422
|
+
...nonEmptyEnvValue(env, "SEMIOTIC_BUILD_TIME") ? { builtAt: nonEmptyEnvValue(env, "SEMIOTIC_BUILD_TIME") } : {},
|
|
32423
|
+
toolProfile: options.toolProfile,
|
|
32424
|
+
nodeVersion: options.nodeVersion ?? process.version
|
|
32425
|
+
};
|
|
32426
|
+
}
|
|
32427
|
+
function mcpServerInfoForBuild(buildInfo) {
|
|
32428
|
+
if (buildInfo.channel !== "nightly") {
|
|
32429
|
+
return { name: "semiotic", version: buildInfo.packageVersion };
|
|
32430
|
+
}
|
|
32431
|
+
const packageVersion = buildInfo.packageVersion.split("+", 1)[0];
|
|
32432
|
+
const nightlyVersion = packageVersion.includes("-nightly") ? packageVersion : `${packageVersion}-nightly`;
|
|
32433
|
+
return {
|
|
32434
|
+
name: "semiotic-nightly",
|
|
32435
|
+
version: `${nightlyVersion}+${buildInfo.shortCommitSha || "unknown"}`
|
|
32436
|
+
};
|
|
32437
|
+
}
|
|
32438
|
+
|
|
32439
|
+
// ai/mcp-logging.ts
|
|
32440
|
+
var DEFAULT_MCP_LOG_LEVEL = "info";
|
|
32441
|
+
var DEFAULT_MCP_LOG_RETENTION_DAYS = 30;
|
|
32442
|
+
var DEFAULT_MCP_LOG_MAX_EVENT_BYTES = 1024;
|
|
32443
|
+
var MIN_MCP_LOG_MAX_EVENT_BYTES = 256;
|
|
32444
|
+
var MAX_MCP_LOG_MAX_EVENT_BYTES = 4096;
|
|
32445
|
+
var MAX_MCP_LOG_RETENTION_DAYS = 90;
|
|
32446
|
+
var LEVEL_RANK = {
|
|
32447
|
+
error: 0,
|
|
32448
|
+
warn: 1,
|
|
32449
|
+
info: 2
|
|
32450
|
+
};
|
|
32451
|
+
var SAFE_EVENTS = /* @__PURE__ */ new Set([
|
|
32452
|
+
"request_completed",
|
|
32453
|
+
"request_failed",
|
|
32454
|
+
"request_rejected",
|
|
32455
|
+
"service_fatal",
|
|
32456
|
+
"service_started",
|
|
32457
|
+
"log_event_truncated"
|
|
32458
|
+
]);
|
|
32459
|
+
var SAFE_REASONS = /* @__PURE__ */ new Set([
|
|
32460
|
+
"forbidden_host",
|
|
32461
|
+
"forbidden_origin",
|
|
32462
|
+
"invalid_json",
|
|
32463
|
+
"operation_limit",
|
|
32464
|
+
"request_body_too_large",
|
|
32465
|
+
"request_concurrency",
|
|
32466
|
+
"request_handler_error",
|
|
32467
|
+
"request_rate",
|
|
32468
|
+
"request_stream_error",
|
|
32469
|
+
"service_startup_failure",
|
|
32470
|
+
"unauthorized",
|
|
32471
|
+
"unsupported_accept",
|
|
32472
|
+
"unsupported_protocol_version"
|
|
32473
|
+
]);
|
|
32474
|
+
var SAFE_ROUTES = /* @__PURE__ */ new Set([
|
|
32475
|
+
"/",
|
|
32476
|
+
"/mcp",
|
|
32477
|
+
"/health",
|
|
32478
|
+
"/.well-known/openai-apps-challenge"
|
|
32479
|
+
]);
|
|
32480
|
+
function boundedPositiveInteger(value, fallback, min, max) {
|
|
32481
|
+
const parsed = Number(value);
|
|
32482
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0) return fallback;
|
|
32483
|
+
return Math.min(max, Math.max(min, parsed));
|
|
32484
|
+
}
|
|
32485
|
+
function resolveMcpLoggingPolicy(env = process.env) {
|
|
32486
|
+
const requestedLevel = env.MCP_LOG_LEVEL?.trim().toLowerCase();
|
|
32487
|
+
const level = requestedLevel === "silent" || requestedLevel === "error" || requestedLevel === "warn" || requestedLevel === "info" ? requestedLevel : DEFAULT_MCP_LOG_LEVEL;
|
|
32488
|
+
return {
|
|
32489
|
+
level,
|
|
32490
|
+
retentionDays: boundedPositiveInteger(
|
|
32491
|
+
env.MCP_LOG_RETENTION_DAYS,
|
|
32492
|
+
DEFAULT_MCP_LOG_RETENTION_DAYS,
|
|
32493
|
+
1,
|
|
32494
|
+
MAX_MCP_LOG_RETENTION_DAYS
|
|
32495
|
+
),
|
|
32496
|
+
maxEventBytes: boundedPositiveInteger(
|
|
32497
|
+
env.MCP_LOG_MAX_EVENT_BYTES,
|
|
32498
|
+
DEFAULT_MCP_LOG_MAX_EVENT_BYTES,
|
|
32499
|
+
MIN_MCP_LOG_MAX_EVENT_BYTES,
|
|
32500
|
+
MAX_MCP_LOG_MAX_EVENT_BYTES
|
|
32501
|
+
)
|
|
32502
|
+
};
|
|
32503
|
+
}
|
|
32504
|
+
function safeMethod(value) {
|
|
32505
|
+
if (typeof value !== "string") return "other";
|
|
32506
|
+
const upper = value.toUpperCase();
|
|
32507
|
+
return upper === "GET" || upper === "POST" || upper === "OPTIONS" ? upper : "other";
|
|
32508
|
+
}
|
|
32509
|
+
function safeRoute(value) {
|
|
32510
|
+
return typeof value === "string" && SAFE_ROUTES.has(value) ? value : "other";
|
|
32511
|
+
}
|
|
32512
|
+
function safeCode(value, allowlist) {
|
|
32513
|
+
return typeof value === "string" && allowlist.has(value) ? value : "other";
|
|
32514
|
+
}
|
|
32515
|
+
function safeInteger(value, min, max) {
|
|
32516
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= min && value <= max ? value : void 0;
|
|
32517
|
+
}
|
|
32518
|
+
function sanitizeMcpLogMetadata(input = {}) {
|
|
32519
|
+
const metadata = {};
|
|
32520
|
+
if (input.method !== void 0) metadata.method = safeMethod(input.method);
|
|
32521
|
+
if (input.route !== void 0) metadata.route = safeRoute(input.route);
|
|
32522
|
+
const status = safeInteger(input.status, 100, 599);
|
|
32523
|
+
if (status !== void 0) metadata.status = status;
|
|
32524
|
+
if (input.reason !== void 0) metadata.reason = safeCode(input.reason, SAFE_REASONS);
|
|
32525
|
+
const durationMs = safeInteger(input.durationMs, 0, 864e5);
|
|
32526
|
+
if (durationMs !== void 0) metadata.durationMs = durationMs;
|
|
32527
|
+
const bodyBytes = safeInteger(input.bodyBytes, 0, 1073741824);
|
|
32528
|
+
if (bodyBytes !== void 0) metadata.bodyBytes = bodyBytes;
|
|
32529
|
+
if (input.profile !== void 0) {
|
|
32530
|
+
metadata.profile = input.profile === "public" || input.profile === "developer" ? input.profile : "other";
|
|
32531
|
+
}
|
|
32532
|
+
const retentionDays = safeInteger(input.retentionDays, 1, MAX_MCP_LOG_RETENTION_DAYS);
|
|
32533
|
+
if (retentionDays !== void 0) metadata.retentionDays = retentionDays;
|
|
32534
|
+
if (typeof input.protocolVersionPresent === "boolean") {
|
|
32535
|
+
metadata.protocolVersionPresent = input.protocolVersionPresent;
|
|
32536
|
+
}
|
|
32537
|
+
return metadata;
|
|
32538
|
+
}
|
|
32539
|
+
function defaultMcpLogWriter(_severity, line) {
|
|
32540
|
+
process.stderr.write(`${line}
|
|
32541
|
+
`);
|
|
32542
|
+
}
|
|
32543
|
+
function serializeBoundedRecord(record2, maxEventBytes) {
|
|
32544
|
+
const serialized = JSON.stringify(record2);
|
|
32545
|
+
if (Buffer.byteLength(serialized, "utf8") <= maxEventBytes) return serialized;
|
|
32546
|
+
return JSON.stringify({
|
|
32547
|
+
schema: "semiotic-mcp-log/v1",
|
|
32548
|
+
service: "semiotic-mcp",
|
|
32549
|
+
timestamp: record2.timestamp,
|
|
32550
|
+
severity: record2.severity,
|
|
32551
|
+
event: "log_event_truncated",
|
|
32552
|
+
metadata: {}
|
|
32553
|
+
});
|
|
32554
|
+
}
|
|
32555
|
+
function createMcpMetadataLogger(policy = resolveMcpLoggingPolicy(), writer = defaultMcpLogWriter) {
|
|
32556
|
+
const emit = (severity, event, metadata = {}) => {
|
|
32557
|
+
if (policy.level === "silent" || LEVEL_RANK[severity] > LEVEL_RANK[policy.level]) return;
|
|
32558
|
+
const record2 = {
|
|
32559
|
+
schema: "semiotic-mcp-log/v1",
|
|
32560
|
+
service: "semiotic-mcp",
|
|
32561
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32562
|
+
severity: severity.toUpperCase(),
|
|
32563
|
+
event: safeCode(event, SAFE_EVENTS),
|
|
32564
|
+
metadata: sanitizeMcpLogMetadata(metadata)
|
|
32565
|
+
};
|
|
32566
|
+
try {
|
|
32567
|
+
writer(severity, serializeBoundedRecord(record2, policy.maxEventBytes));
|
|
32568
|
+
} catch {
|
|
32569
|
+
}
|
|
32570
|
+
};
|
|
32571
|
+
return {
|
|
32572
|
+
error: (event, metadata) => emit("error", event, metadata),
|
|
32573
|
+
warn: (event, metadata) => emit("warn", event, metadata),
|
|
32574
|
+
info: (event, metadata) => emit("info", event, metadata)
|
|
32575
|
+
};
|
|
32576
|
+
}
|
|
32577
|
+
|
|
32578
|
+
// ai/mcp-request-limits.ts
|
|
32579
|
+
var DEFAULT_MCP_MAX_CONCURRENT_REQUESTS = 16;
|
|
32580
|
+
var DEFAULT_MCP_MAX_REQUESTS_PER_WINDOW = 240;
|
|
32581
|
+
var DEFAULT_MCP_REQUEST_WINDOW_MS = 6e4;
|
|
32582
|
+
function positiveInteger(value, fallback) {
|
|
32583
|
+
const parsed = Number.parseInt(value || "", 10);
|
|
32584
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
32585
|
+
}
|
|
32586
|
+
function resolveMcpRequestLimits(env = process.env) {
|
|
32587
|
+
return {
|
|
32588
|
+
maxConcurrentRequests: positiveInteger(
|
|
32589
|
+
env.MCP_MAX_CONCURRENT_REQUESTS,
|
|
32590
|
+
DEFAULT_MCP_MAX_CONCURRENT_REQUESTS
|
|
32591
|
+
),
|
|
32592
|
+
maxRequestsPerWindow: positiveInteger(
|
|
32593
|
+
env.MCP_MAX_REQUESTS_PER_WINDOW,
|
|
32594
|
+
DEFAULT_MCP_MAX_REQUESTS_PER_WINDOW
|
|
32595
|
+
),
|
|
32596
|
+
requestWindowMs: positiveInteger(env.MCP_REQUEST_WINDOW_MS, DEFAULT_MCP_REQUEST_WINDOW_MS)
|
|
32597
|
+
};
|
|
32598
|
+
}
|
|
32599
|
+
function defaultWindowStart(now) {
|
|
32600
|
+
return now <= 0 ? 1 : now;
|
|
32601
|
+
}
|
|
32602
|
+
function createMcpRequestLimiter(limits) {
|
|
32603
|
+
let activeRequests = 0;
|
|
32604
|
+
let requestWindowStart = defaultWindowStart(Date.now());
|
|
32605
|
+
let requestsInWindow = 0;
|
|
32606
|
+
const resetWindowIfExpired = (now) => {
|
|
32607
|
+
const elapsed = now - requestWindowStart;
|
|
32608
|
+
if (elapsed >= limits.requestWindowMs || elapsed < 0) {
|
|
32609
|
+
requestWindowStart = now;
|
|
32610
|
+
requestsInWindow = 0;
|
|
32611
|
+
}
|
|
32612
|
+
};
|
|
32613
|
+
const snapshot = () => ({
|
|
32614
|
+
activeRequests,
|
|
32615
|
+
requestWindowStart,
|
|
32616
|
+
requestsInWindow
|
|
32617
|
+
});
|
|
32618
|
+
const tryAcquire = (now = Date.now()) => {
|
|
32619
|
+
resetWindowIfExpired(now);
|
|
32620
|
+
if (activeRequests >= limits.maxConcurrentRequests) {
|
|
32621
|
+
return {
|
|
32622
|
+
ok: false,
|
|
32623
|
+
code: "MCP_REQUEST_CONCURRENCY",
|
|
32624
|
+
message: `Request concurrency limit exceeded. Set MCP_MAX_CONCURRENT_REQUESTS to raise the live limit.`,
|
|
32625
|
+
retryAfterMs: 1e3
|
|
32626
|
+
};
|
|
32627
|
+
}
|
|
32628
|
+
if (requestsInWindow >= limits.maxRequestsPerWindow) {
|
|
32629
|
+
const retryAfterMs = Math.max(
|
|
32630
|
+
0,
|
|
32631
|
+
requestWindowStart + limits.requestWindowMs - now
|
|
32632
|
+
);
|
|
32633
|
+
return {
|
|
32634
|
+
ok: false,
|
|
32635
|
+
code: "MCP_REQUEST_RATE",
|
|
32636
|
+
message: `Request rate limit exceeded. Set MCP_MAX_REQUESTS_PER_WINDOW / MCP_REQUEST_WINDOW_MS to raise the rate window/capacity.`,
|
|
32637
|
+
retryAfterMs
|
|
32638
|
+
};
|
|
32639
|
+
}
|
|
32640
|
+
activeRequests++;
|
|
32641
|
+
requestsInWindow++;
|
|
32642
|
+
let released = false;
|
|
32643
|
+
return {
|
|
32644
|
+
ok: true,
|
|
32645
|
+
release: () => {
|
|
32646
|
+
if (released) return;
|
|
32647
|
+
released = true;
|
|
32648
|
+
activeRequests = Math.max(0, activeRequests - 1);
|
|
32649
|
+
}
|
|
32650
|
+
};
|
|
32651
|
+
};
|
|
32652
|
+
return {
|
|
32653
|
+
snapshot,
|
|
32654
|
+
tryAcquire
|
|
32655
|
+
};
|
|
32656
|
+
}
|
|
32657
|
+
|
|
32658
|
+
// ai/mcp-operation-limits.ts
|
|
32659
|
+
var DEFAULT_MCP_MAX_ROWS = 1e4;
|
|
32660
|
+
var DEFAULT_MCP_MAX_CELLS = 1e5;
|
|
32661
|
+
var DEFAULT_MCP_MAX_NESTING_DEPTH = 64;
|
|
32662
|
+
function positiveInteger2(value, fallback) {
|
|
32663
|
+
const parsed = Number.parseInt(value || "", 10);
|
|
32664
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
32665
|
+
}
|
|
32666
|
+
function resolveMcpOperationLimits(env = process.env) {
|
|
32667
|
+
return {
|
|
32668
|
+
maxRows: positiveInteger2(env.MCP_MAX_ROWS, DEFAULT_MCP_MAX_ROWS),
|
|
32669
|
+
maxCells: positiveInteger2(env.MCP_MAX_CELLS, DEFAULT_MCP_MAX_CELLS),
|
|
32670
|
+
maxNestingDepth: positiveInteger2(
|
|
32671
|
+
env.MCP_MAX_NESTING_DEPTH,
|
|
32672
|
+
DEFAULT_MCP_MAX_NESTING_DEPTH
|
|
32673
|
+
)
|
|
32674
|
+
};
|
|
32675
|
+
}
|
|
32676
|
+
function isObject2(value) {
|
|
32677
|
+
return value !== null && typeof value === "object";
|
|
32678
|
+
}
|
|
32679
|
+
function inspectMcpOperationInput(input, limits) {
|
|
32680
|
+
let rows = 0;
|
|
32681
|
+
let cells = 0;
|
|
32682
|
+
let nestingDepth = 0;
|
|
32683
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
32684
|
+
const stack = [{ value: input, depth: 0 }];
|
|
32685
|
+
while (stack.length > 0) {
|
|
32686
|
+
const current = stack.pop();
|
|
32687
|
+
const { value, depth } = current;
|
|
32688
|
+
if (!isObject2(value) || seen.has(value)) continue;
|
|
32689
|
+
seen.add(value);
|
|
32690
|
+
nestingDepth = Math.max(nestingDepth, depth);
|
|
32691
|
+
if (nestingDepth > limits.maxNestingDepth) {
|
|
32692
|
+
return {
|
|
32693
|
+
ok: false,
|
|
32694
|
+
limit: "nestingDepth",
|
|
32695
|
+
observed: nestingDepth,
|
|
32696
|
+
maximum: limits.maxNestingDepth
|
|
32697
|
+
};
|
|
32698
|
+
}
|
|
32699
|
+
if (Array.isArray(value)) {
|
|
32700
|
+
rows += value.length;
|
|
32701
|
+
if (rows > limits.maxRows) {
|
|
32702
|
+
return { ok: false, limit: "rows", observed: rows, maximum: limits.maxRows };
|
|
32703
|
+
}
|
|
32704
|
+
for (let index = value.length - 1; index >= 0; index--) {
|
|
32705
|
+
stack.push({ value: value[index], depth: depth + 1 });
|
|
32706
|
+
}
|
|
32707
|
+
continue;
|
|
32708
|
+
}
|
|
32709
|
+
const keys = Object.keys(value);
|
|
32710
|
+
cells += keys.length;
|
|
32711
|
+
if (cells > limits.maxCells) {
|
|
32712
|
+
return { ok: false, limit: "cells", observed: cells, maximum: limits.maxCells };
|
|
32713
|
+
}
|
|
32714
|
+
for (let index = keys.length - 1; index >= 0; index--) {
|
|
32715
|
+
stack.push({ value: value[keys[index]], depth: depth + 1 });
|
|
32716
|
+
}
|
|
32717
|
+
}
|
|
32718
|
+
return { ok: true, rows, cells, nestingDepth };
|
|
32719
|
+
}
|
|
32720
|
+
function formatMcpOperationLimitError(result) {
|
|
32721
|
+
if (result.ok) return "";
|
|
32722
|
+
switch (result.limit) {
|
|
32723
|
+
case "rows":
|
|
32724
|
+
return `Tool arguments exceed the collection-entry limit (${result.observed} > ${result.maximum}; set MCP_MAX_ROWS to adjust).`;
|
|
32725
|
+
case "cells":
|
|
32726
|
+
return `Tool arguments exceed the object-field limit (${result.observed} > ${result.maximum}; set MCP_MAX_CELLS to adjust).`;
|
|
32727
|
+
case "nestingDepth":
|
|
32728
|
+
return `Tool arguments exceed the nesting-depth limit (${result.observed} > ${result.maximum}; set MCP_MAX_NESTING_DEPTH to adjust).`;
|
|
32729
|
+
}
|
|
32730
|
+
}
|
|
32731
|
+
|
|
32732
|
+
// ai/mcp-render-output-limits.ts
|
|
32733
|
+
var DEFAULT_MCP_MAX_RENDER_OUTPUT_BYTES = 2 * 1024 * 1024;
|
|
32734
|
+
var DEFAULT_MCP_MAX_WIDGET_OUTPUT_BYTES = 2 * 1024 * 1024;
|
|
32735
|
+
var DEFAULT_MCP_MAX_WIDGET_METADATA_BYTES = 64 * 1024;
|
|
32736
|
+
var DEFAULT_MCP_MAX_WIDGET_ROWS = 50;
|
|
32737
|
+
var DEFAULT_MCP_MAX_WIDGET_COLUMNS = 16;
|
|
32738
|
+
var DEFAULT_MCP_MAX_WIDGET_VALUE_BYTES = 256;
|
|
32739
|
+
var WIDGET_COLUMN_LABEL_BYTES = 96;
|
|
32740
|
+
var WIDGET_EVIDENCE_ARRAY_ITEMS = 32;
|
|
32741
|
+
var WIDGET_EVIDENCE_OBJECT_KEYS = 16;
|
|
32742
|
+
function positiveInteger3(value, fallback) {
|
|
32743
|
+
const parsed = Number.parseInt(value || "", 10);
|
|
32744
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
32745
|
+
}
|
|
32746
|
+
function resolveMcpRenderOutputLimits(env = process.env) {
|
|
32747
|
+
return {
|
|
32748
|
+
maxRenderOutputBytes: positiveInteger3(
|
|
32749
|
+
env.MCP_MAX_RENDER_OUTPUT_BYTES,
|
|
32750
|
+
DEFAULT_MCP_MAX_RENDER_OUTPUT_BYTES
|
|
32751
|
+
),
|
|
32752
|
+
maxWidgetOutputBytes: positiveInteger3(
|
|
32753
|
+
env.MCP_MAX_WIDGET_OUTPUT_BYTES,
|
|
32754
|
+
DEFAULT_MCP_MAX_WIDGET_OUTPUT_BYTES
|
|
32755
|
+
),
|
|
32756
|
+
maxWidgetMetadataBytes: positiveInteger3(
|
|
32757
|
+
env.MCP_MAX_WIDGET_METADATA_BYTES,
|
|
32758
|
+
DEFAULT_MCP_MAX_WIDGET_METADATA_BYTES
|
|
32759
|
+
),
|
|
32760
|
+
maxWidgetRows: positiveInteger3(env.MCP_MAX_WIDGET_ROWS, DEFAULT_MCP_MAX_WIDGET_ROWS),
|
|
32761
|
+
maxWidgetColumns: positiveInteger3(env.MCP_MAX_WIDGET_COLUMNS, DEFAULT_MCP_MAX_WIDGET_COLUMNS),
|
|
32762
|
+
maxWidgetValueBytes: positiveInteger3(
|
|
32763
|
+
env.MCP_MAX_WIDGET_VALUE_BYTES,
|
|
32764
|
+
DEFAULT_MCP_MAX_WIDGET_VALUE_BYTES
|
|
32765
|
+
)
|
|
32766
|
+
};
|
|
32767
|
+
}
|
|
32768
|
+
function utf8ByteLength(value) {
|
|
32769
|
+
return Buffer.byteLength(value, "utf8");
|
|
32770
|
+
}
|
|
32771
|
+
function serializedMcpOutputBytes(value) {
|
|
32772
|
+
const serialized = JSON.stringify(value);
|
|
32773
|
+
return utf8ByteLength(serialized === void 0 ? "" : serialized);
|
|
32774
|
+
}
|
|
32775
|
+
function truncateUtf8(value, maximumBytes) {
|
|
32776
|
+
if (maximumBytes <= 0 || !value) return "";
|
|
32777
|
+
if (utf8ByteLength(value) <= maximumBytes) return value;
|
|
32778
|
+
const marker = "\u2026";
|
|
32779
|
+
const markerBytes = utf8ByteLength(marker);
|
|
32780
|
+
if (maximumBytes < markerBytes) return "";
|
|
32781
|
+
const targetBytes = maximumBytes - markerBytes;
|
|
32782
|
+
let output = "";
|
|
32783
|
+
let usedBytes = 0;
|
|
32784
|
+
for (const character of value) {
|
|
32785
|
+
const characterBytes = utf8ByteLength(character);
|
|
32786
|
+
if (usedBytes + characterBytes > targetBytes) break;
|
|
32787
|
+
output += character;
|
|
32788
|
+
usedBytes += characterBytes;
|
|
32789
|
+
}
|
|
32790
|
+
return `${output}${marker}`;
|
|
32791
|
+
}
|
|
32792
|
+
function inspectMcpOutputLimit(value, maximum) {
|
|
32793
|
+
const observed = serializedMcpOutputBytes(value);
|
|
32794
|
+
return observed <= maximum ? { ok: true, observed, maximum } : { ok: false, observed, maximum };
|
|
32795
|
+
}
|
|
32796
|
+
function formatMcpOutputLimitError(args) {
|
|
32797
|
+
return `${args.label} output exceeds the configured response limit (${args.limit.observed} > ${args.limit.maximum} bytes; set ${args.setting} to adjust). Reduce chart data or request a smaller render.`;
|
|
32798
|
+
}
|
|
32799
|
+
function isRecord(value) {
|
|
32800
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
32801
|
+
}
|
|
32802
|
+
function isSensitiveField(name) {
|
|
32803
|
+
return /password|passwd|secret|token|api[-_]?key|authorization|cookie|credential|private[-_]?key/i.test(name);
|
|
32804
|
+
}
|
|
32805
|
+
function previewColumnLabel(key, used) {
|
|
32806
|
+
const base = truncateUtf8(key || "value", WIDGET_COLUMN_LABEL_BYTES) || "value";
|
|
32807
|
+
let label = base;
|
|
32808
|
+
let suffix = 2;
|
|
32809
|
+
while (used.has(label)) {
|
|
32810
|
+
label = `${base} (${suffix})`;
|
|
32811
|
+
suffix += 1;
|
|
32812
|
+
}
|
|
32813
|
+
used.add(label);
|
|
32814
|
+
return label;
|
|
32815
|
+
}
|
|
32816
|
+
function selectPreviewCollection(props) {
|
|
32817
|
+
for (const collection of ["data", "nodes", "edges", "links"]) {
|
|
32818
|
+
if (Array.isArray(props[collection])) {
|
|
32819
|
+
return { collection, rows: props[collection] };
|
|
32820
|
+
}
|
|
32821
|
+
}
|
|
32822
|
+
return { collection: null, rows: [] };
|
|
32823
|
+
}
|
|
32824
|
+
function collectPreviewColumns(rows, limits) {
|
|
32825
|
+
const keys = [];
|
|
32826
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32827
|
+
let truncated = false;
|
|
32828
|
+
for (const row of rows) {
|
|
32829
|
+
if (isRecord(row)) {
|
|
32830
|
+
for (const key of Object.keys(row)) {
|
|
32831
|
+
if (seen.has(key)) continue;
|
|
32832
|
+
if (keys.length >= limits.maxWidgetColumns) {
|
|
32833
|
+
truncated = true;
|
|
32834
|
+
break;
|
|
32835
|
+
}
|
|
32836
|
+
seen.add(key);
|
|
32837
|
+
keys.push(key);
|
|
32838
|
+
}
|
|
32839
|
+
} else if (!seen.has("value")) {
|
|
32840
|
+
if (keys.length >= limits.maxWidgetColumns) {
|
|
32841
|
+
truncated = true;
|
|
32842
|
+
} else {
|
|
32843
|
+
seen.add("value");
|
|
32844
|
+
keys.push("value");
|
|
32845
|
+
}
|
|
32846
|
+
}
|
|
32847
|
+
if (keys.length >= limits.maxWidgetColumns && truncated) break;
|
|
32848
|
+
}
|
|
32849
|
+
const usedLabels = /* @__PURE__ */ new Set();
|
|
32850
|
+
return {
|
|
32851
|
+
columns: keys.map((key) => ({ key, label: previewColumnLabel(key, usedLabels) })),
|
|
32852
|
+
truncated
|
|
32853
|
+
};
|
|
32854
|
+
}
|
|
32855
|
+
function previewCell(value, fieldName, limits) {
|
|
32856
|
+
if (isSensitiveField(fieldName)) {
|
|
32857
|
+
return { value: "[redacted]", redacted: true, truncated: false };
|
|
32858
|
+
}
|
|
32859
|
+
if (value === null || value === void 0) {
|
|
32860
|
+
return { value: null, redacted: false, truncated: false };
|
|
32861
|
+
}
|
|
32862
|
+
if (typeof value === "string") {
|
|
32863
|
+
const bounded = truncateUtf8(value, limits.maxWidgetValueBytes);
|
|
32864
|
+
return { value: bounded, redacted: false, truncated: bounded !== value };
|
|
32865
|
+
}
|
|
32866
|
+
if (typeof value === "number") {
|
|
32867
|
+
return Number.isFinite(value) ? { value, redacted: false, truncated: false } : { value: String(value), redacted: false, truncated: false };
|
|
32868
|
+
}
|
|
32869
|
+
if (typeof value === "boolean") return { value, redacted: false, truncated: false };
|
|
32870
|
+
if (Array.isArray(value)) {
|
|
32871
|
+
return { value: `[array: ${value.length} items]`, redacted: false, truncated: true };
|
|
32872
|
+
}
|
|
32873
|
+
if (typeof value === "object") {
|
|
32874
|
+
return { value: "[object]", redacted: false, truncated: true };
|
|
32875
|
+
}
|
|
32876
|
+
return {
|
|
32877
|
+
value: truncateUtf8(String(value), limits.maxWidgetValueBytes),
|
|
32878
|
+
redacted: false,
|
|
32879
|
+
truncated: true
|
|
32880
|
+
};
|
|
32881
|
+
}
|
|
32882
|
+
function createWidgetDataPreview(props, limits = resolveMcpRenderOutputLimits()) {
|
|
32883
|
+
const selected = selectPreviewCollection(props);
|
|
32884
|
+
const inputRows = selected.rows.slice(0, limits.maxWidgetRows);
|
|
32885
|
+
const columnSelection = collectPreviewColumns(inputRows, limits);
|
|
32886
|
+
const rows = [];
|
|
32887
|
+
let redactedFields = 0;
|
|
32888
|
+
let truncatedValues = 0;
|
|
32889
|
+
let metadataBoundReached = false;
|
|
32890
|
+
for (const input of inputRows) {
|
|
32891
|
+
const row = {};
|
|
32892
|
+
let rowRedactedFields = 0;
|
|
32893
|
+
let rowTruncatedValues = 0;
|
|
32894
|
+
for (const column of columnSelection.columns) {
|
|
32895
|
+
const hasValue = isRecord(input) ? Object.prototype.hasOwnProperty.call(input, column.key) : column.key === "value";
|
|
32896
|
+
const value = isRecord(input) ? input[column.key] : input;
|
|
32897
|
+
if (!hasValue) {
|
|
32898
|
+
row[column.label] = null;
|
|
32899
|
+
continue;
|
|
32900
|
+
}
|
|
32901
|
+
const cell = previewCell(value, column.key, limits);
|
|
32902
|
+
row[column.label] = cell.value;
|
|
32903
|
+
if (cell.redacted) rowRedactedFields += 1;
|
|
32904
|
+
if (cell.truncated) rowTruncatedValues += 1;
|
|
32905
|
+
}
|
|
32906
|
+
const candidate = {
|
|
32907
|
+
collection: selected.collection,
|
|
32908
|
+
totalRows: selected.rows.length,
|
|
32909
|
+
returnedRows: rows.length + 1,
|
|
32910
|
+
returnedColumns: columnSelection.columns.length,
|
|
32911
|
+
rows: [...rows, row],
|
|
32912
|
+
redactedFields: redactedFields + rowRedactedFields,
|
|
32913
|
+
truncatedValues: truncatedValues + rowTruncatedValues,
|
|
32914
|
+
truncated: true
|
|
32915
|
+
};
|
|
32916
|
+
if (serializedMcpOutputBytes(candidate) > limits.maxWidgetMetadataBytes) {
|
|
32917
|
+
metadataBoundReached = true;
|
|
32918
|
+
break;
|
|
32919
|
+
}
|
|
32920
|
+
rows.push(row);
|
|
32921
|
+
redactedFields += rowRedactedFields;
|
|
32922
|
+
truncatedValues += rowTruncatedValues;
|
|
32923
|
+
}
|
|
32924
|
+
const truncated = metadataBoundReached || columnSelection.truncated || selected.rows.length > rows.length || truncatedValues > 0;
|
|
32925
|
+
return {
|
|
32926
|
+
collection: selected.collection,
|
|
32927
|
+
totalRows: selected.rows.length,
|
|
32928
|
+
returnedRows: rows.length,
|
|
32929
|
+
returnedColumns: columnSelection.columns.length,
|
|
32930
|
+
rows,
|
|
32931
|
+
redactedFields,
|
|
32932
|
+
truncatedValues,
|
|
32933
|
+
truncated
|
|
32934
|
+
};
|
|
32935
|
+
}
|
|
32936
|
+
function finiteNumber(value) {
|
|
32937
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
32938
|
+
}
|
|
32939
|
+
function boundedEvidenceStrings(value, limits) {
|
|
32940
|
+
if (!Array.isArray(value)) return void 0;
|
|
32941
|
+
const values = value.slice(0, WIDGET_EVIDENCE_ARRAY_ITEMS).map((item) => truncateUtf8(String(item), limits.maxWidgetValueBytes));
|
|
32942
|
+
return { values, truncated: value.length > values.length };
|
|
32943
|
+
}
|
|
32944
|
+
function createWidgetEvidencePreview(evidence, limits = resolveMcpRenderOutputLimits()) {
|
|
32945
|
+
if (!evidence) return null;
|
|
32946
|
+
const preview = {};
|
|
32947
|
+
for (const key of ["component", "frameType", "status", "ariaLabel"]) {
|
|
32948
|
+
if (typeof evidence[key] === "string") {
|
|
32949
|
+
preview[key] = truncateUtf8(evidence[key], limits.maxWidgetValueBytes);
|
|
32950
|
+
}
|
|
32951
|
+
}
|
|
32952
|
+
if (typeof evidence.empty === "boolean") preview.empty = evidence.empty;
|
|
32953
|
+
for (const key of [
|
|
32954
|
+
"markCount",
|
|
32955
|
+
"width",
|
|
32956
|
+
"height",
|
|
32957
|
+
"nodeCount",
|
|
32958
|
+
"edgeCount",
|
|
32959
|
+
"legendItems",
|
|
32960
|
+
"annotationCount"
|
|
32961
|
+
]) {
|
|
32962
|
+
const value = finiteNumber(evidence[key]);
|
|
32963
|
+
if (value !== void 0) preview[key] = value;
|
|
32964
|
+
}
|
|
32965
|
+
for (const key of ["xDomain", "yDomain"]) {
|
|
32966
|
+
const domain2 = evidence[key];
|
|
32967
|
+
if (Array.isArray(domain2) && domain2.length === 2) {
|
|
32968
|
+
const values = domain2.map(finiteNumber);
|
|
32969
|
+
if (values[0] !== void 0 && values[1] !== void 0) preview[key] = values;
|
|
32970
|
+
}
|
|
32971
|
+
}
|
|
32972
|
+
const categories = boundedEvidenceStrings(evidence.categories, limits);
|
|
32973
|
+
if (categories) {
|
|
32974
|
+
preview.categories = categories.values;
|
|
32975
|
+
if (categories.truncated) preview.categoriesTruncated = true;
|
|
32976
|
+
}
|
|
32977
|
+
const warnings = boundedEvidenceStrings(evidence.warnings, limits);
|
|
32978
|
+
if (warnings) {
|
|
32979
|
+
preview.warnings = warnings.values;
|
|
32980
|
+
if (warnings.truncated) preview.warningsTruncated = true;
|
|
32981
|
+
}
|
|
32982
|
+
if (isRecord(evidence.markCountByType)) {
|
|
32983
|
+
const markCountByType = {};
|
|
32984
|
+
const entries = Object.entries(evidence.markCountByType).sort(([left], [right]) => left.localeCompare(right)).slice(0, WIDGET_EVIDENCE_OBJECT_KEYS);
|
|
32985
|
+
for (const [key, value] of entries) {
|
|
32986
|
+
const count = finiteNumber(value);
|
|
32987
|
+
if (count !== void 0) {
|
|
32988
|
+
markCountByType[truncateUtf8(key, WIDGET_COLUMN_LABEL_BYTES)] = count;
|
|
32989
|
+
}
|
|
32990
|
+
}
|
|
32991
|
+
preview.markCountByType = markCountByType;
|
|
32992
|
+
if (Object.keys(evidence.markCountByType).length > entries.length) {
|
|
32993
|
+
preview.markCountByTypeTruncated = true;
|
|
32994
|
+
}
|
|
32995
|
+
}
|
|
32996
|
+
return preview;
|
|
32997
|
+
}
|
|
32998
|
+
|
|
32359
32999
|
// ai/renderHOCToSVG.tsx
|
|
32360
33000
|
var React = __toESM(require("react"));
|
|
32361
33001
|
var ReactDOMServer = __toESM(require("react-dom/server"));
|
|
@@ -32404,7 +33044,14 @@ var COMPONENT_REGISTRY = {
|
|
|
32404
33044
|
ChoroplethMap: { component: import_geo.ChoroplethMap, category: "geo" },
|
|
32405
33045
|
ProportionalSymbolMap: { component: import_geo.ProportionalSymbolMap, category: "geo" },
|
|
32406
33046
|
FlowMap: { component: import_geo.FlowMap, category: "geo" },
|
|
32407
|
-
DistanceCartogram: { component: import_geo.DistanceCartogram, category: "geo" }
|
|
33047
|
+
DistanceCartogram: { component: import_geo.DistanceCartogram, category: "geo" },
|
|
33048
|
+
GaltonBoardChart: { component: import_ai.GaltonBoardChart, category: "physics" },
|
|
33049
|
+
EventDropChart: { component: import_ai.EventDropChart, category: "physics" },
|
|
33050
|
+
PhysicsPileChart: { component: import_ai.PhysicsPileChart, category: "physics" },
|
|
33051
|
+
CollisionSwarmChart: { component: import_ai.CollisionSwarmChart, category: "physics" },
|
|
33052
|
+
PhysicalFlowChart: { component: import_ai.PhysicalFlowChart, category: "physics" },
|
|
33053
|
+
ProcessFlowChart: { component: import_ai.ProcessFlowChart, category: "physics" },
|
|
33054
|
+
GauntletChart: { component: import_ai.GauntletChart, category: "physics" }
|
|
32408
33055
|
};
|
|
32409
33056
|
|
|
32410
33057
|
// ai/renderHOCToSVG.tsx
|
|
@@ -32464,6 +33111,12 @@ var {
|
|
|
32464
33111
|
} = import_behaviorContracts.default;
|
|
32465
33112
|
var schemaPath = path.resolve(__dirname, "../schema.json");
|
|
32466
33113
|
var schema = JSON.parse(fs.readFileSync(schemaPath, "utf-8"));
|
|
33114
|
+
var packageManifestPath = path.resolve(__dirname, "../../package.json");
|
|
33115
|
+
var packageManifest = JSON.parse(fs.readFileSync(packageManifestPath, "utf-8"));
|
|
33116
|
+
if (typeof packageManifest.version !== "string" || !packageManifest.version) {
|
|
33117
|
+
throw new Error("Semiotic package.json must provide a package version");
|
|
33118
|
+
}
|
|
33119
|
+
var PACKAGE_VERSION = packageManifest.version;
|
|
32467
33120
|
var schemaByComponent = {};
|
|
32468
33121
|
for (const tool of schema.tools) {
|
|
32469
33122
|
schemaByComponent[tool.function.name] = tool.function;
|
|
@@ -32473,6 +33126,79 @@ var componentNames = Object.keys(COMPONENT_REGISTRY).sort();
|
|
|
32473
33126
|
var REPO = "nteract/semiotic";
|
|
32474
33127
|
var SEMIOTIC_CHART_WIDGET_URI = "ui://semiotic/chart-widget.html";
|
|
32475
33128
|
var MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
|
|
33129
|
+
var DEFAULT_MCP_SUPPORTED_PROTOCOL_VERSION = "2024-11-05";
|
|
33130
|
+
var DEFAULT_MCP_MAX_RENDER_WORK_MS = 2500;
|
|
33131
|
+
var DEFAULT_MCP_MAX_PNG_CONVERSION_MS = 4e3;
|
|
33132
|
+
var DEFAULT_MCP_MAX_INTERACTIVE_SVG_SANITIZE_MS = 3e3;
|
|
33133
|
+
var mcpLoggingPolicy = resolveMcpLoggingPolicy();
|
|
33134
|
+
var mcpLogger = createMcpMetadataLogger(mcpLoggingPolicy);
|
|
33135
|
+
function writeJsonRpcError(res, status, code, message) {
|
|
33136
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
33137
|
+
res.end(JSON.stringify({
|
|
33138
|
+
jsonrpc: "2.0",
|
|
33139
|
+
error: { code, message },
|
|
33140
|
+
id: null
|
|
33141
|
+
}));
|
|
33142
|
+
}
|
|
33143
|
+
function isAuthorizedRequest(req, token, scheme) {
|
|
33144
|
+
if (!token) return true;
|
|
33145
|
+
const authorization = req.headers.authorization;
|
|
33146
|
+
if (typeof authorization !== "string") return false;
|
|
33147
|
+
const [providedScheme, providedToken] = authorization.split(/\s+/, 2);
|
|
33148
|
+
return providedScheme?.toLowerCase() === scheme.toLowerCase() && Boolean(providedToken) && providedToken === token;
|
|
33149
|
+
}
|
|
33150
|
+
function hasSupportedAccept(acceptHeader) {
|
|
33151
|
+
if (!acceptHeader) return true;
|
|
33152
|
+
const lower = acceptHeader.toLowerCase();
|
|
33153
|
+
return lower.includes("*/*") || lower.includes("application/json") || lower.includes("text/event-stream");
|
|
33154
|
+
}
|
|
33155
|
+
function isSupportedProtocolVersion(protocolVersion, supported) {
|
|
33156
|
+
if (!protocolVersion || supported.length === 0) return true;
|
|
33157
|
+
return supported.includes(protocolVersion);
|
|
33158
|
+
}
|
|
33159
|
+
function parsePositiveInteger(value, fallback) {
|
|
33160
|
+
const parsed = Number.parseInt(value || "", 10);
|
|
33161
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
33162
|
+
}
|
|
33163
|
+
function resolveMcpRenderExecutionLimits(env = process.env) {
|
|
33164
|
+
return {
|
|
33165
|
+
maxRenderWorkMs: parsePositiveInteger(env.MCP_MAX_RENDER_WORK_MS, DEFAULT_MCP_MAX_RENDER_WORK_MS),
|
|
33166
|
+
maxPngConversionMs: parsePositiveInteger(env.MCP_MAX_PNG_CONVERSION_MS, DEFAULT_MCP_MAX_PNG_CONVERSION_MS),
|
|
33167
|
+
maxInteractiveSanitizeMs: parsePositiveInteger(env.MCP_MAX_INTERACTIVE_SVG_SANITIZE_MS, DEFAULT_MCP_MAX_INTERACTIVE_SVG_SANITIZE_MS)
|
|
33168
|
+
};
|
|
33169
|
+
}
|
|
33170
|
+
function makeRenderExecutionError(code, label, limitMs, observedMs) {
|
|
33171
|
+
const text = code === "MCP_RENDER_TIMEOUT" ? `${label} exceeded ${limitMs} ms timeout budget (${observedMs ?? 0} ms). Set ${label === "PNG conversion" ? "MCP_MAX_PNG_CONVERSION_MS" : label.includes("sanitize") ? "MCP_MAX_INTERACTIVE_SVG_SANITIZE_MS" : "MCP_MAX_RENDER_WORK_MS"} to adjust.` : `${label} was canceled before completion.`;
|
|
33172
|
+
const error48 = new Error(text);
|
|
33173
|
+
error48.code = code;
|
|
33174
|
+
return error48;
|
|
33175
|
+
}
|
|
33176
|
+
function throwIfRequestCanceled(signal, label = "render work") {
|
|
33177
|
+
if (signal?.aborted) {
|
|
33178
|
+
throw makeRenderExecutionError("MCP_RENDER_CANCELLED", label, 0);
|
|
33179
|
+
}
|
|
33180
|
+
}
|
|
33181
|
+
async function runRenderStep(label, limitMs, signal, work) {
|
|
33182
|
+
throwIfRequestCanceled(signal, label);
|
|
33183
|
+
const started = Date.now();
|
|
33184
|
+
const result = await Promise.resolve(work());
|
|
33185
|
+
if (signal?.aborted) throw makeRenderExecutionError("MCP_RENDER_CANCELLED", label, 0);
|
|
33186
|
+
const elapsed = Date.now() - started;
|
|
33187
|
+
if (limitMs > 0 && elapsed > limitMs) {
|
|
33188
|
+
throw makeRenderExecutionError("MCP_RENDER_TIMEOUT", label, limitMs, elapsed);
|
|
33189
|
+
}
|
|
33190
|
+
return result;
|
|
33191
|
+
}
|
|
33192
|
+
function isRenderExecutionError(error48) {
|
|
33193
|
+
return !!error48 && typeof error48 === "object" && (error48.code === "MCP_RENDER_TIMEOUT" || error48.code === "MCP_RENDER_CANCELLED");
|
|
33194
|
+
}
|
|
33195
|
+
function renderExecutionErrorResult(message, code) {
|
|
33196
|
+
return {
|
|
33197
|
+
content: [{ type: "text", text: message }],
|
|
33198
|
+
isError: true,
|
|
33199
|
+
structuredContent: { code }
|
|
33200
|
+
};
|
|
33201
|
+
}
|
|
32476
33202
|
function aiFilePath(fileName) {
|
|
32477
33203
|
return path.resolve(__dirname, "..", fileName);
|
|
32478
33204
|
}
|
|
@@ -32526,11 +33252,203 @@ function promptMessage(text) {
|
|
|
32526
33252
|
}]
|
|
32527
33253
|
};
|
|
32528
33254
|
}
|
|
32529
|
-
|
|
32530
|
-
|
|
33255
|
+
var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
33256
|
+
var SAFE_SVG_ELEMENTS = /* @__PURE__ */ new Set([
|
|
33257
|
+
"svg",
|
|
33258
|
+
"g",
|
|
33259
|
+
"path",
|
|
33260
|
+
"line",
|
|
33261
|
+
"polyline",
|
|
33262
|
+
"polygon",
|
|
33263
|
+
"rect",
|
|
33264
|
+
"circle",
|
|
33265
|
+
"ellipse",
|
|
33266
|
+
"text",
|
|
33267
|
+
"tspan",
|
|
33268
|
+
"title",
|
|
33269
|
+
"desc",
|
|
33270
|
+
"defs",
|
|
33271
|
+
"style",
|
|
33272
|
+
"linearGradient",
|
|
33273
|
+
"radialGradient",
|
|
33274
|
+
"stop",
|
|
33275
|
+
"clipPath",
|
|
33276
|
+
"mask",
|
|
33277
|
+
"pattern",
|
|
33278
|
+
"filter",
|
|
33279
|
+
"marker",
|
|
33280
|
+
"use",
|
|
33281
|
+
"symbol"
|
|
33282
|
+
]);
|
|
33283
|
+
var SAFE_SVG_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
33284
|
+
"alignment-baseline",
|
|
33285
|
+
"alignmentadjust",
|
|
33286
|
+
"aria-hidden",
|
|
33287
|
+
"aria-label",
|
|
33288
|
+
"aria-labelledby",
|
|
33289
|
+
"aria-describedby",
|
|
33290
|
+
"clip-path",
|
|
33291
|
+
"cx",
|
|
33292
|
+
"cy",
|
|
33293
|
+
"d",
|
|
33294
|
+
"dx",
|
|
33295
|
+
"dy",
|
|
33296
|
+
"dominant-baseline",
|
|
33297
|
+
"fill",
|
|
33298
|
+
"fill-opacity",
|
|
33299
|
+
"fill-rule",
|
|
33300
|
+
"font-family",
|
|
33301
|
+
"font-size",
|
|
33302
|
+
"font-style",
|
|
33303
|
+
"font-weight",
|
|
33304
|
+
"gradientunits",
|
|
33305
|
+
"gradienttransform",
|
|
33306
|
+
"height",
|
|
33307
|
+
"id",
|
|
33308
|
+
"marker-height",
|
|
33309
|
+
"marker-units",
|
|
33310
|
+
"marker-width",
|
|
33311
|
+
"marker-end",
|
|
33312
|
+
"marker-mid",
|
|
33313
|
+
"marker-start",
|
|
33314
|
+
"offset",
|
|
33315
|
+
"opacity",
|
|
33316
|
+
"orientation",
|
|
33317
|
+
"pattern-content-units",
|
|
33318
|
+
"pattern-transform",
|
|
33319
|
+
"pattern-units",
|
|
33320
|
+
"preserveaspectratio",
|
|
33321
|
+
"r",
|
|
33322
|
+
"rx",
|
|
33323
|
+
"ry",
|
|
33324
|
+
"role",
|
|
33325
|
+
"shape-rendering",
|
|
33326
|
+
"spreadmethod",
|
|
33327
|
+
"startoffset",
|
|
33328
|
+
"stroke",
|
|
33329
|
+
"stroke-linecap",
|
|
33330
|
+
"stroke-linejoin",
|
|
33331
|
+
"stroke-opacity",
|
|
33332
|
+
"stroke-width",
|
|
33333
|
+
"style",
|
|
33334
|
+
"text-anchor",
|
|
33335
|
+
"transform",
|
|
33336
|
+
"viewbox",
|
|
33337
|
+
"width",
|
|
33338
|
+
"x",
|
|
33339
|
+
"x1",
|
|
33340
|
+
"x2",
|
|
33341
|
+
"xmlns",
|
|
33342
|
+
"xmlns:xlink",
|
|
33343
|
+
"y",
|
|
33344
|
+
"y1",
|
|
33345
|
+
"y2",
|
|
33346
|
+
"xml:space",
|
|
33347
|
+
"class"
|
|
33348
|
+
]);
|
|
33349
|
+
var SAFE_URL_ATTR_PREFIXES = [
|
|
33350
|
+
"http://",
|
|
33351
|
+
"https://",
|
|
33352
|
+
"#",
|
|
33353
|
+
"/",
|
|
33354
|
+
"./",
|
|
33355
|
+
"../",
|
|
33356
|
+
"mailto:",
|
|
33357
|
+
"tel:",
|
|
33358
|
+
"data:image/"
|
|
33359
|
+
];
|
|
33360
|
+
function isSafeUrlValue(value) {
|
|
33361
|
+
const trimmed = value.trim().toLowerCase();
|
|
33362
|
+
if (!trimmed) return true;
|
|
33363
|
+
if (/^(javascript|vbscript|file):/i.test(trimmed)) return false;
|
|
33364
|
+
return SAFE_URL_ATTR_PREFIXES.some((prefix) => trimmed.startsWith(prefix));
|
|
33365
|
+
}
|
|
33366
|
+
function sanitizeStyleValue(value) {
|
|
33367
|
+
return value.replace(/\/\*[\s\S]*?\*\//g, "").replace(/@import[^;]*;/gi, "").replace(/expression\s*\([^)]*\)/gi, "").replace(/url\(\s*["']?\s*([^)"']+)\s*["']?\s*\)/gi, (_match, rawUrl) => {
|
|
33368
|
+
const safeUrl = String(rawUrl || "").trim().toLowerCase();
|
|
33369
|
+
if (safeUrl && !isSafeUrlValue(safeUrl)) return "url()";
|
|
33370
|
+
return `url(${rawUrl})`;
|
|
33371
|
+
});
|
|
33372
|
+
}
|
|
33373
|
+
function isAllowedSvgAttribute(name) {
|
|
33374
|
+
const lower = name.toLowerCase();
|
|
33375
|
+
if (lower.startsWith("on")) return false;
|
|
33376
|
+
if (lower.startsWith("data-")) return true;
|
|
33377
|
+
if (lower.startsWith("aria-")) return true;
|
|
33378
|
+
if (lower.startsWith("xml:")) return true;
|
|
33379
|
+
if (lower === "xmlns" || lower.startsWith("xmlns:")) return true;
|
|
33380
|
+
if (SAFE_SVG_ATTRIBUTES.has(lower)) return true;
|
|
33381
|
+
return /^[a-z][a-z0-9-_:.]*$/.test(lower);
|
|
33382
|
+
}
|
|
33383
|
+
function sanitizeSvgAttribute(name, value) {
|
|
33384
|
+
const lower = name.toLowerCase();
|
|
33385
|
+
if (!isAllowedSvgAttribute(name)) return null;
|
|
33386
|
+
if ((lower === "href" || lower === "xlink:href" || lower === "src") && !isSafeUrlValue(value)) {
|
|
33387
|
+
return null;
|
|
33388
|
+
}
|
|
33389
|
+
if (lower === "style") return sanitizeStyleValue(value);
|
|
33390
|
+
return value;
|
|
33391
|
+
}
|
|
33392
|
+
function sanitizeSvgNode(node, doc) {
|
|
33393
|
+
if (node.nodeType === 3 || node.nodeType === 4) {
|
|
33394
|
+
const text = node.textContent ?? "";
|
|
33395
|
+
return text ? doc.createTextNode(text) : null;
|
|
33396
|
+
}
|
|
33397
|
+
if (node.nodeType !== 1) return null;
|
|
33398
|
+
const source = node;
|
|
33399
|
+
const tag = source.tagName;
|
|
33400
|
+
if (!SAFE_SVG_ELEMENTS.has(tag)) return null;
|
|
33401
|
+
const safe = doc.createElementNS(SVG_NAMESPACE, tag);
|
|
33402
|
+
const isStyleTag = tag === "style";
|
|
33403
|
+
if (!isStyleTag) {
|
|
33404
|
+
for (const attribute of Array.from(source.attributes)) {
|
|
33405
|
+
const safeValue = sanitizeSvgAttribute(attribute.name, attribute.value);
|
|
33406
|
+
if (safeValue == null) continue;
|
|
33407
|
+
safe.setAttribute(attribute.name, safeValue);
|
|
33408
|
+
}
|
|
33409
|
+
} else {
|
|
33410
|
+
const styleText = sanitizeStyleValue(source.textContent ?? "");
|
|
33411
|
+
if (styleText) {
|
|
33412
|
+
safe.appendChild(doc.createTextNode(styleText));
|
|
33413
|
+
}
|
|
33414
|
+
return safe;
|
|
33415
|
+
}
|
|
33416
|
+
for (const child of Array.from(source.childNodes)) {
|
|
33417
|
+
const sanitized = sanitizeSvgNode(child, doc);
|
|
33418
|
+
if (sanitized) safe.appendChild(sanitized);
|
|
33419
|
+
}
|
|
33420
|
+
return safe;
|
|
33421
|
+
}
|
|
33422
|
+
var jsdomModulePromise = null;
|
|
33423
|
+
function loadJsdomModule() {
|
|
33424
|
+
if (!jsdomModulePromise) jsdomModulePromise = import("jsdom");
|
|
33425
|
+
return jsdomModulePromise;
|
|
33426
|
+
}
|
|
33427
|
+
void loadJsdomModule().catch(() => {
|
|
33428
|
+
});
|
|
33429
|
+
async function sanitizeSvgForWidget(svg) {
|
|
33430
|
+
const trimmed = svg.trim();
|
|
33431
|
+
if (!trimmed) return "";
|
|
33432
|
+
try {
|
|
33433
|
+
const { JSDOM } = await loadJsdomModule();
|
|
33434
|
+
const parsed = new JSDOM(trimmed, { contentType: "image/svg+xml" });
|
|
33435
|
+
const parsedDocument = parsed.window.document;
|
|
33436
|
+
const sourceRoot = parsedDocument.documentElement;
|
|
33437
|
+
if (!sourceRoot || sourceRoot.tagName.toLowerCase() !== "svg") return "";
|
|
33438
|
+
if (parsedDocument.getElementsByTagName("parsererror")[0]) return "";
|
|
33439
|
+
const cleanDocument = parsedDocument.implementation.createDocument(SVG_NAMESPACE, null, null);
|
|
33440
|
+
const safeRoot = sanitizeSvgNode(sourceRoot, cleanDocument);
|
|
33441
|
+
if (!safeRoot) return "";
|
|
33442
|
+
cleanDocument.appendChild(safeRoot);
|
|
33443
|
+
return new parsed.window.XMLSerializer().serializeToString(safeRoot);
|
|
33444
|
+
} catch {
|
|
33445
|
+
return "";
|
|
33446
|
+
}
|
|
32531
33447
|
}
|
|
32532
33448
|
function parseRenderEvidence(result) {
|
|
32533
|
-
const evidenceText = result.content.find(
|
|
33449
|
+
const evidenceText = result.content.find(
|
|
33450
|
+
(block) => block.type === "text" && block.text.startsWith("Render evidence:\n")
|
|
33451
|
+
)?.text;
|
|
32534
33452
|
if (!evidenceText) return null;
|
|
32535
33453
|
try {
|
|
32536
33454
|
return JSON.parse(evidenceText.replace(/^Render evidence:\n/, ""));
|
|
@@ -32539,7 +33457,8 @@ function parseRenderEvidence(result) {
|
|
|
32539
33457
|
}
|
|
32540
33458
|
}
|
|
32541
33459
|
function chartTitleFromProps(component, props) {
|
|
32542
|
-
|
|
33460
|
+
const title = typeof props.title === "string" && props.title.trim() ? props.title.trim() : component;
|
|
33461
|
+
return truncateUtf8(title, resolveMcpRenderOutputLimits().maxWidgetValueBytes);
|
|
32543
33462
|
}
|
|
32544
33463
|
function chartDatumCount(props) {
|
|
32545
33464
|
if (Array.isArray(props.data)) return props.data.length;
|
|
@@ -32704,22 +33623,26 @@ function renderSemioticChartWidgetHTML() {
|
|
|
32704
33623
|
return { output, meta };
|
|
32705
33624
|
}
|
|
32706
33625
|
|
|
32707
|
-
function
|
|
32708
|
-
const
|
|
32709
|
-
|
|
32710
|
-
if (Array.isArray(props.nodes)) return props.nodes.slice(0, 50);
|
|
32711
|
-
if (Array.isArray(props.edges)) return props.edges.slice(0, 50);
|
|
32712
|
-
if (Array.isArray(props.links)) return props.links.slice(0, 50);
|
|
32713
|
-
return [];
|
|
33626
|
+
function dataPreview(meta) {
|
|
33627
|
+
const preview = meta?.dataPreview;
|
|
33628
|
+
return preview && Array.isArray(preview.rows) ? preview : null;
|
|
32714
33629
|
}
|
|
32715
33630
|
|
|
32716
|
-
function renderTable(
|
|
33631
|
+
function renderTable(preview) {
|
|
33632
|
+
const rows = preview?.rows || [];
|
|
32717
33633
|
if (!rows.length) return '<pre>No row data was provided in the widget metadata.</pre>';
|
|
32718
33634
|
const columns = Array.from(rows.reduce((set, row) => {
|
|
32719
33635
|
Object.keys(row || {}).forEach((key) => set.add(key));
|
|
32720
33636
|
return set;
|
|
32721
33637
|
}, new Set()));
|
|
32722
|
-
|
|
33638
|
+
const totalRows = Number.isFinite(preview?.totalRows) ? preview.totalRows : rows.length;
|
|
33639
|
+
const collection = preview?.collection || 'data';
|
|
33640
|
+
const notes = [
|
|
33641
|
+
'Showing ' + rows.length + ' of ' + totalRows + ' ' + html(collection) + ' rows.',
|
|
33642
|
+
preview?.truncated ? 'Preview values or rows were truncated.' : '',
|
|
33643
|
+
preview?.redactedFields ? 'Sensitive fields were redacted.' : ''
|
|
33644
|
+
].filter(Boolean).join(' ');
|
|
33645
|
+
return '<div class="summary">' + notes + '</div><table><thead><tr>' + columns.map((col) => '<th>' + html(col) + '</th>').join('') +
|
|
32723
33646
|
'</tr></thead><tbody>' + rows.map((row) => '<tr>' + columns.map((col) => '<td>' + html(row?.[col]) + '</td>').join('') + '</tr>').join('') + '</tbody></table>';
|
|
32724
33647
|
}
|
|
32725
33648
|
|
|
@@ -32734,8 +33657,8 @@ function renderSemioticChartWidgetHTML() {
|
|
|
32734
33657
|
} else {
|
|
32735
33658
|
chartEl.innerHTML = '<div class="empty">No SVG payload received. The model-visible chart summary is still available above.</div>';
|
|
32736
33659
|
}
|
|
32737
|
-
const
|
|
32738
|
-
dataDrawer.innerHTML = renderTable(
|
|
33660
|
+
const preview = dataPreview(hidden);
|
|
33661
|
+
dataDrawer.innerHTML = renderTable(preview);
|
|
32739
33662
|
evidenceText.textContent = JSON.stringify(payload.evidence || hidden.evidence || {}, null, 2);
|
|
32740
33663
|
}
|
|
32741
33664
|
|
|
@@ -32799,6 +33722,53 @@ function renderSemioticChartWidgetHTML() {
|
|
|
32799
33722
|
</body>
|
|
32800
33723
|
</html>`.trim();
|
|
32801
33724
|
}
|
|
33725
|
+
function capRenderedToolResult(result, args) {
|
|
33726
|
+
const limit = inspectMcpOutputLimit(result, args.maximum);
|
|
33727
|
+
if (limit.ok) return result;
|
|
33728
|
+
return {
|
|
33729
|
+
content: [{
|
|
33730
|
+
type: "text",
|
|
33731
|
+
text: formatMcpOutputLimitError({
|
|
33732
|
+
label: args.label,
|
|
33733
|
+
limit,
|
|
33734
|
+
setting: args.setting
|
|
33735
|
+
})
|
|
33736
|
+
}],
|
|
33737
|
+
isError: true,
|
|
33738
|
+
structuredContent: {
|
|
33739
|
+
code: "OUTPUT_LIMIT_EXCEEDED",
|
|
33740
|
+
maximumBytes: limit.maximum,
|
|
33741
|
+
observedBytes: limit.observed
|
|
33742
|
+
}
|
|
33743
|
+
};
|
|
33744
|
+
}
|
|
33745
|
+
function capRenderChartResult(result) {
|
|
33746
|
+
const limits = resolveMcpRenderOutputLimits();
|
|
33747
|
+
return capRenderedToolResult(result, {
|
|
33748
|
+
label: "Rendered chart",
|
|
33749
|
+
maximum: limits.maxRenderOutputBytes,
|
|
33750
|
+
setting: "MCP_MAX_RENDER_OUTPUT_BYTES"
|
|
33751
|
+
});
|
|
33752
|
+
}
|
|
33753
|
+
function capInteractiveWidgetResult(result) {
|
|
33754
|
+
const limits = resolveMcpRenderOutputLimits();
|
|
33755
|
+
return capRenderedToolResult(result, {
|
|
33756
|
+
label: "Interactive widget",
|
|
33757
|
+
maximum: limits.maxWidgetOutputBytes,
|
|
33758
|
+
setting: "MCP_MAX_WIDGET_OUTPUT_BYTES"
|
|
33759
|
+
});
|
|
33760
|
+
}
|
|
33761
|
+
var SURFACE_VERSION = `${PACKAGE_VERSION}-ai`;
|
|
33762
|
+
function buildInfoForProfile(profile) {
|
|
33763
|
+
return resolveSemioticBuildInfo({
|
|
33764
|
+
packageVersion: PACKAGE_VERSION,
|
|
33765
|
+
surfaceVersion: SURFACE_VERSION,
|
|
33766
|
+
toolProfile: profile
|
|
33767
|
+
});
|
|
33768
|
+
}
|
|
33769
|
+
function profileResult(result) {
|
|
33770
|
+
return { ...result, surfaceVersion: SURFACE_VERSION };
|
|
33771
|
+
}
|
|
32802
33772
|
async function getSchemaHandler(args) {
|
|
32803
33773
|
const component = args.component;
|
|
32804
33774
|
if (!component) {
|
|
@@ -32809,7 +33779,7 @@ ${list.join(", ")}
|
|
|
32809
33779
|
|
|
32810
33780
|
Components marked [renderable] can be rendered to SVG via renderChart (pass theme parameter for styled output). Others (Realtime*) require a browser environment.
|
|
32811
33781
|
|
|
32812
|
-
For full agent context, read MCP resources: semiotic://schema, semiotic://components, semiotic://behavior-contracts, semiotic://system-prompt, semiotic://examples.
|
|
33782
|
+
For full agent context, read MCP resources: semiotic://schema, semiotic://components, semiotic://surface-manifest, semiotic://behavior-contracts, semiotic://system-prompt, semiotic://examples.
|
|
32813
33783
|
|
|
32814
33784
|
All charts support CSS custom properties for theming (--semiotic-bg, --semiotic-text, --semiotic-grid, etc.) and <ThemeProvider>. Use COLOR_BLIND_SAFE_CATEGORICAL (import from semiotic/themes) for accessible color palettes.
|
|
32815
33785
|
|
|
@@ -32859,98 +33829,148 @@ async function suggestChartHandler(args) {
|
|
|
32859
33829
|
}
|
|
32860
33830
|
return { content, structuredContent: result };
|
|
32861
33831
|
}
|
|
32862
|
-
async function renderChartHandler(args) {
|
|
33832
|
+
async function renderChartHandler(args, context = {}) {
|
|
33833
|
+
const limits = context.limits ?? resolveMcpRenderExecutionLimits();
|
|
33834
|
+
const signal = context.signal;
|
|
32863
33835
|
const component = args.component;
|
|
32864
33836
|
const props = args.props ?? {};
|
|
32865
33837
|
const theme = args.theme;
|
|
32866
33838
|
const format = args.format || "svg";
|
|
32867
33839
|
if (!component) {
|
|
32868
|
-
return {
|
|
33840
|
+
return capRenderChartResult({
|
|
32869
33841
|
content: [{ type: "text", text: `Missing 'component' field. Provide { component: '<name>', props: { ... } }. Available: ${componentNames.join(", ")}` }],
|
|
32870
33842
|
isError: true
|
|
32871
|
-
};
|
|
33843
|
+
});
|
|
32872
33844
|
}
|
|
32873
33845
|
if (!COMPONENT_REGISTRY[component]) {
|
|
32874
33846
|
if (schemaByComponent[component]) {
|
|
32875
|
-
return {
|
|
33847
|
+
return capRenderChartResult({
|
|
32876
33848
|
content: [{ type: "text", text: `Component "${component}" is known but cannot be rendered via renderChart. It requires a browser/live environment. Renderable components: ${componentNames.join(", ")}` }],
|
|
32877
33849
|
isError: true
|
|
32878
|
-
};
|
|
33850
|
+
});
|
|
32879
33851
|
}
|
|
32880
|
-
return {
|
|
33852
|
+
return capRenderChartResult({
|
|
32881
33853
|
content: [{ type: "text", text: `Unknown component "${component}". Available: ${componentNames.join(", ")}` }],
|
|
32882
33854
|
isError: true
|
|
32883
|
-
};
|
|
33855
|
+
});
|
|
33856
|
+
}
|
|
33857
|
+
let result;
|
|
33858
|
+
try {
|
|
33859
|
+
result = await runRenderStep(
|
|
33860
|
+
"render work",
|
|
33861
|
+
limits.maxRenderWorkMs,
|
|
33862
|
+
signal,
|
|
33863
|
+
() => renderHOCToSVG(component, props)
|
|
33864
|
+
);
|
|
33865
|
+
} catch (err) {
|
|
33866
|
+
if (isRenderExecutionError(err)) {
|
|
33867
|
+
return capRenderChartResult(renderExecutionErrorResult(err.message, err.code));
|
|
33868
|
+
}
|
|
33869
|
+
throw err;
|
|
32884
33870
|
}
|
|
32885
|
-
const result = renderHOCToSVG(component, props);
|
|
32886
33871
|
if (result.error) {
|
|
32887
|
-
return {
|
|
33872
|
+
return capRenderChartResult({
|
|
32888
33873
|
content: [{ type: "text", text: result.error }],
|
|
32889
33874
|
isError: true
|
|
32890
|
-
};
|
|
33875
|
+
});
|
|
32891
33876
|
}
|
|
32892
33877
|
let svg = result.svg;
|
|
32893
33878
|
let evidenceBlock = null;
|
|
32894
33879
|
try {
|
|
32895
|
-
const { svg: evidenceSvg, evidence } =
|
|
33880
|
+
const { svg: evidenceSvg, evidence } = await runRenderStep(
|
|
33881
|
+
"layout/render evidence",
|
|
33882
|
+
limits.maxRenderWorkMs,
|
|
33883
|
+
signal,
|
|
33884
|
+
() => (0, import_server2.renderChartWithEvidence)(component, props)
|
|
33885
|
+
);
|
|
32896
33886
|
svg = evidenceSvg;
|
|
32897
33887
|
evidenceBlock = {
|
|
32898
33888
|
type: "text",
|
|
32899
33889
|
text: `Render evidence:
|
|
32900
33890
|
${JSON.stringify(evidence, null, 2)}`
|
|
32901
33891
|
};
|
|
32902
|
-
} catch {
|
|
33892
|
+
} catch (err) {
|
|
33893
|
+
if (isRenderExecutionError(err)) {
|
|
33894
|
+
return capRenderChartResult(renderExecutionErrorResult(err.message, err.code));
|
|
33895
|
+
}
|
|
32903
33896
|
evidenceBlock = {
|
|
32904
33897
|
type: "text",
|
|
32905
33898
|
text: `Render evidence: unavailable for ${component} (no server render config). The SVG above is the validated React render; mark-count / domain evidence is only produced for components with a server render path.`
|
|
32906
33899
|
};
|
|
32907
33900
|
}
|
|
32908
33901
|
if (theme && Object.keys(theme).length > 0) {
|
|
32909
|
-
|
|
32910
|
-
|
|
32911
|
-
|
|
33902
|
+
try {
|
|
33903
|
+
svg = await runRenderStep(
|
|
33904
|
+
"theme application",
|
|
33905
|
+
limits.maxRenderWorkMs,
|
|
33906
|
+
signal,
|
|
33907
|
+
() => {
|
|
33908
|
+
const isUnsafeCssValue = (v) => /<|>|{|}|@|expression\(|javascript:|url\(|\*\//i.test(v);
|
|
33909
|
+
const validVars = Object.entries(theme).filter(([k, v]) => k.startsWith("--semiotic-") && typeof v === "string" && !isUnsafeCssValue(v)).map(([k, v]) => `${k}: ${v}`).join("; ");
|
|
33910
|
+
if (!validVars) return svg;
|
|
33911
|
+
return svg.replace(/<svg([^>]*)>/, `<svg$1><style>:root { ${validVars} }</style>`);
|
|
33912
|
+
}
|
|
33913
|
+
);
|
|
33914
|
+
} catch (err) {
|
|
33915
|
+
if (isRenderExecutionError(err)) {
|
|
33916
|
+
return capRenderChartResult(renderExecutionErrorResult(err.message, err.code));
|
|
33917
|
+
}
|
|
33918
|
+
throw err;
|
|
32912
33919
|
}
|
|
32913
33920
|
}
|
|
32914
33921
|
if (format === "png") {
|
|
32915
33922
|
try {
|
|
32916
|
-
const
|
|
32917
|
-
|
|
32918
|
-
|
|
33923
|
+
const pngBuffer = await runRenderStep(
|
|
33924
|
+
"PNG conversion",
|
|
33925
|
+
limits.maxPngConversionMs,
|
|
33926
|
+
signal,
|
|
33927
|
+
async () => {
|
|
33928
|
+
const sharpMod = await Function('return import("sharp")')();
|
|
33929
|
+
const sharpFn = sharpMod.default || sharpMod;
|
|
33930
|
+
return sharpFn(Buffer.from(svg)).png().toBuffer();
|
|
33931
|
+
}
|
|
33932
|
+
);
|
|
32919
33933
|
const base643 = pngBuffer.toString("base64");
|
|
32920
|
-
return {
|
|
33934
|
+
return capRenderChartResult({
|
|
32921
33935
|
content: [
|
|
32922
|
-
{ type: "
|
|
33936
|
+
{ type: "image", data: base643, mimeType: "image/png" },
|
|
32923
33937
|
...evidenceBlock ? [evidenceBlock] : []
|
|
32924
33938
|
]
|
|
32925
|
-
};
|
|
33939
|
+
});
|
|
32926
33940
|
} catch (err) {
|
|
32927
|
-
if (err
|
|
32928
|
-
return
|
|
33941
|
+
if (isRenderExecutionError(err)) {
|
|
33942
|
+
return capRenderChartResult(renderExecutionErrorResult(err.message, err.code));
|
|
33943
|
+
}
|
|
33944
|
+
const typedErr = err;
|
|
33945
|
+
if (typedErr.code === "MODULE_NOT_FOUND" || typedErr.code === "ERR_MODULE_NOT_FOUND") {
|
|
33946
|
+
return capRenderChartResult({
|
|
32929
33947
|
content: [{ type: "text", text: `PNG output requires the 'sharp' package. Install it with: npm install sharp
|
|
32930
33948
|
|
|
32931
33949
|
Falling back to SVG output:
|
|
32932
33950
|
|
|
32933
33951
|
${svg}` }]
|
|
32934
|
-
};
|
|
33952
|
+
});
|
|
32935
33953
|
}
|
|
32936
|
-
return {
|
|
32937
|
-
content: [{ type: "text", text: `PNG conversion failed: ${
|
|
33954
|
+
return capRenderChartResult({
|
|
33955
|
+
content: [{ type: "text", text: `PNG conversion failed: ${typedErr.message || "unknown error"}
|
|
32938
33956
|
|
|
32939
33957
|
SVG output:
|
|
32940
33958
|
|
|
32941
33959
|
${svg}` }],
|
|
32942
33960
|
isError: true
|
|
32943
|
-
};
|
|
33961
|
+
});
|
|
32944
33962
|
}
|
|
32945
33963
|
}
|
|
32946
|
-
return {
|
|
33964
|
+
return capRenderChartResult({
|
|
32947
33965
|
content: [
|
|
32948
33966
|
{ type: "text", text: svg },
|
|
32949
33967
|
...evidenceBlock ? [evidenceBlock] : []
|
|
32950
33968
|
]
|
|
32951
|
-
};
|
|
33969
|
+
});
|
|
32952
33970
|
}
|
|
32953
|
-
async function renderInteractiveChartHandler(args) {
|
|
33971
|
+
async function renderInteractiveChartHandler(args, context = {}) {
|
|
33972
|
+
const limits = context.limits ?? resolveMcpRenderExecutionLimits();
|
|
33973
|
+
const signal = context.signal;
|
|
32954
33974
|
const component = args.component;
|
|
32955
33975
|
const props = args.props ?? {};
|
|
32956
33976
|
const rendered = await renderChartHandler({
|
|
@@ -32958,10 +33978,31 @@ async function renderInteractiveChartHandler(args) {
|
|
|
32958
33978
|
props,
|
|
32959
33979
|
theme: args.theme,
|
|
32960
33980
|
format: "svg"
|
|
32961
|
-
});
|
|
33981
|
+
}, context);
|
|
32962
33982
|
if (rendered.isError) return rendered;
|
|
32963
|
-
const
|
|
32964
|
-
|
|
33983
|
+
const svgBlock = rendered.content.find(
|
|
33984
|
+
(block) => block.type === "text" && block.text.trimStart().startsWith("<")
|
|
33985
|
+
);
|
|
33986
|
+
let svg;
|
|
33987
|
+
try {
|
|
33988
|
+
svg = await runRenderStep(
|
|
33989
|
+
"interactive SVG sanitization",
|
|
33990
|
+
limits.maxInteractiveSanitizeMs,
|
|
33991
|
+
signal,
|
|
33992
|
+
() => sanitizeSvgForWidget(svgBlock?.text ?? "")
|
|
33993
|
+
);
|
|
33994
|
+
} catch (err) {
|
|
33995
|
+
if (isRenderExecutionError(err)) {
|
|
33996
|
+
return capInteractiveWidgetResult(renderExecutionErrorResult(err.message, err.code));
|
|
33997
|
+
}
|
|
33998
|
+
return capInteractiveWidgetResult({
|
|
33999
|
+
content: [{ type: "text", text: "Interactive SVG sanitization failed." }],
|
|
34000
|
+
isError: true
|
|
34001
|
+
});
|
|
34002
|
+
}
|
|
34003
|
+
const outputLimits = resolveMcpRenderOutputLimits();
|
|
34004
|
+
const evidence = createWidgetEvidencePreview(parseRenderEvidence(rendered), outputLimits);
|
|
34005
|
+
const dataPreview = createWidgetDataPreview(props, outputLimits);
|
|
32965
34006
|
const title = chartTitleFromProps(component || "Semiotic chart", props);
|
|
32966
34007
|
const datumCount = chartDatumCount(props);
|
|
32967
34008
|
const summary = [
|
|
@@ -32969,7 +34010,7 @@ async function renderInteractiveChartHandler(args) {
|
|
|
32969
34010
|
datumCount == null ? "No row count was inferred from props." : `${datumCount} input row${datumCount === 1 ? "" : "s"} available in the widget data drawer.`,
|
|
32970
34011
|
"Use the widget controls to zoom, fit width, inspect data, and inspect render evidence."
|
|
32971
34012
|
].join(" ");
|
|
32972
|
-
return {
|
|
34013
|
+
return capInteractiveWidgetResult({
|
|
32973
34014
|
content: [{
|
|
32974
34015
|
type: "text",
|
|
32975
34016
|
text: `Rendered ${title} (${component}) as an interactive ChatGPT Apps widget.`
|
|
@@ -32982,15 +34023,14 @@ async function renderInteractiveChartHandler(args) {
|
|
|
32982
34023
|
evidence
|
|
32983
34024
|
},
|
|
32984
34025
|
_meta: {
|
|
32985
|
-
component,
|
|
34026
|
+
component: component ?? "SemioticChart",
|
|
32986
34027
|
title,
|
|
32987
|
-
|
|
32988
|
-
theme: args.theme ?? null,
|
|
34028
|
+
dataPreview,
|
|
32989
34029
|
svg,
|
|
32990
34030
|
evidence,
|
|
32991
34031
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
32992
34032
|
}
|
|
32993
|
-
};
|
|
34033
|
+
});
|
|
32994
34034
|
}
|
|
32995
34035
|
function filterUsageModeDiagnoses(component, usageMode, diagnoses) {
|
|
32996
34036
|
if (dataRequiredForUsageMode(component, usageMode)) return diagnoses;
|
|
@@ -33053,6 +34093,26 @@ async function auditAccessibilityHandler(args) {
|
|
|
33053
34093
|
isError: !result.ok
|
|
33054
34094
|
};
|
|
33055
34095
|
}
|
|
34096
|
+
async function auditMobileVisualizationHandler(args) {
|
|
34097
|
+
const component = args.component;
|
|
34098
|
+
const props = args.props ?? {};
|
|
34099
|
+
if (!component) {
|
|
34100
|
+
return {
|
|
34101
|
+
content: [{ type: "text", text: "Missing 'component' field. Provide { component: 'LineChart', props: { ... } }." }],
|
|
34102
|
+
isError: true
|
|
34103
|
+
};
|
|
34104
|
+
}
|
|
34105
|
+
const result = (0, import_ai3.auditMobileVisualization)(component, props, {
|
|
34106
|
+
viewportWidth: typeof args.viewportWidth === "number" ? args.viewportWidth : void 0,
|
|
34107
|
+
targetSize: typeof args.targetSize === "number" ? args.targetSize : void 0,
|
|
34108
|
+
inChartContainer: args.inChartContainer === true
|
|
34109
|
+
});
|
|
34110
|
+
return {
|
|
34111
|
+
content: [{ type: "text", text: (0, import_ai3.formatMobileVisualizationAudit)(result) }],
|
|
34112
|
+
// Block only on high-risk mobile issues; medium/low warnings remain advisory.
|
|
34113
|
+
isError: !result.ok
|
|
34114
|
+
};
|
|
34115
|
+
}
|
|
33056
34116
|
async function reportIssueHandler(args) {
|
|
33057
34117
|
const title = args.title;
|
|
33058
34118
|
const body = args.body;
|
|
@@ -33275,6 +34335,74 @@ async function suggestChartsHandler(args) {
|
|
|
33275
34335
|
structuredContent: { suggestions }
|
|
33276
34336
|
};
|
|
33277
34337
|
}
|
|
34338
|
+
var ALLOWED_TOKEN_TASK_INTENTS = [
|
|
34339
|
+
"precise-comparison",
|
|
34340
|
+
"frequency-reasoning",
|
|
34341
|
+
"probability-estimation",
|
|
34342
|
+
"risk-communication",
|
|
34343
|
+
"memory",
|
|
34344
|
+
"editorial-engagement",
|
|
34345
|
+
"public-explanation",
|
|
34346
|
+
"support-decision",
|
|
34347
|
+
"measure",
|
|
34348
|
+
"estimate probability",
|
|
34349
|
+
"understand risk",
|
|
34350
|
+
"remember",
|
|
34351
|
+
"decide"
|
|
34352
|
+
];
|
|
34353
|
+
function isTokenTaskIntent(value) {
|
|
34354
|
+
return ALLOWED_TOKEN_TASK_INTENTS.includes(value);
|
|
34355
|
+
}
|
|
34356
|
+
async function suggestTokenEncodingHandler(args) {
|
|
34357
|
+
if (!args.taskIntent) {
|
|
34358
|
+
return {
|
|
34359
|
+
content: [{
|
|
34360
|
+
type: "text",
|
|
34361
|
+
text: "Missing 'taskIntent'. Provide a token task such as 'estimate probability', 'understand risk', 'remember', 'measure', or 'decide'."
|
|
34362
|
+
}],
|
|
34363
|
+
isError: true
|
|
34364
|
+
};
|
|
34365
|
+
}
|
|
34366
|
+
if (!isTokenTaskIntent(args.taskIntent)) {
|
|
34367
|
+
return {
|
|
34368
|
+
content: [{
|
|
34369
|
+
type: "text",
|
|
34370
|
+
text: `Invalid 'taskIntent': "${args.taskIntent}". Expected one of: ${ALLOWED_TOKEN_TASK_INTENTS.join(", ")}.`
|
|
34371
|
+
}],
|
|
34372
|
+
isError: true
|
|
34373
|
+
};
|
|
34374
|
+
}
|
|
34375
|
+
const taskIntent = args.taskIntent;
|
|
34376
|
+
const suggestion = (0, import_ai3.suggestTokenEncoding)({
|
|
34377
|
+
taskIntent,
|
|
34378
|
+
dataType: args.dataType,
|
|
34379
|
+
audience: args.audience,
|
|
34380
|
+
precisionNeed: args.precisionNeed,
|
|
34381
|
+
availableSpace: args.availableSpace,
|
|
34382
|
+
concreteEntity: args.concreteEntity
|
|
34383
|
+
});
|
|
34384
|
+
const capabilityIntents = (0, import_ai3.tokenTaskIntentToCapabilityIntents)(taskIntent);
|
|
34385
|
+
const warnings = suggestion.warnings.length ? `
|
|
34386
|
+
Warnings:
|
|
34387
|
+
${suggestion.warnings.map((warning) => `- [${warning.code}] ${warning.message}`).join("\n")}` : "";
|
|
34388
|
+
const encoding = suggestion.tokenEncoding ? `
|
|
34389
|
+
Encoding:
|
|
34390
|
+
${JSON.stringify(suggestion.tokenEncoding, null, 2)}` : "";
|
|
34391
|
+
return {
|
|
34392
|
+
content: [{
|
|
34393
|
+
type: "text",
|
|
34394
|
+
text: [
|
|
34395
|
+
`Recommended token encoding: ${suggestion.recommendedEncoding}`,
|
|
34396
|
+
`Rationale: ${suggestion.rationale}`,
|
|
34397
|
+
`Capability intents: ${capabilityIntents.join(", ")}`,
|
|
34398
|
+
encoding.trim(),
|
|
34399
|
+
warnings.trim(),
|
|
34400
|
+
`Alternatives: ${suggestion.alternatives.join(", ")}`
|
|
34401
|
+
].filter(Boolean).join("\n\n")
|
|
34402
|
+
}],
|
|
34403
|
+
structuredContent: { suggestion, capabilityIntents }
|
|
34404
|
+
};
|
|
34405
|
+
}
|
|
33278
34406
|
async function suggestStreamChartsHandler(args) {
|
|
33279
34407
|
const { schema: schema2, intent, maxResults } = args;
|
|
33280
34408
|
const intentArg = Array.isArray(intent) ? intent : intent ? [intent] : void 0;
|
|
@@ -33437,17 +34565,135 @@ async function groundChartHandler(args) {
|
|
|
33437
34565
|
structuredContent: grounding
|
|
33438
34566
|
};
|
|
33439
34567
|
}
|
|
34568
|
+
function compactPublicChartProps(props) {
|
|
34569
|
+
const compact = { ...props };
|
|
34570
|
+
delete compact.data;
|
|
34571
|
+
delete compact.nodes;
|
|
34572
|
+
delete compact.edges;
|
|
34573
|
+
return compact;
|
|
34574
|
+
}
|
|
34575
|
+
function compactPublicSuggestion(suggestion) {
|
|
34576
|
+
return { ...suggestion, props: compactPublicChartProps(suggestion.props) };
|
|
34577
|
+
}
|
|
34578
|
+
async function createChartHandler(args, context = {}) {
|
|
34579
|
+
const intent = Array.isArray(args.intent) ? args.intent : args.intent ? [args.intent] : void 0;
|
|
34580
|
+
const suggestions = (0, import_ai3.suggestCharts)(args.data, { intent, audience: args.audience, maxResults: 40 }).filter((suggestion) => metadataForComponent(suggestion.component).renderable).slice(0, 8);
|
|
34581
|
+
const selected = args.component ? suggestions.find((suggestion) => suggestion.component === args.component) : suggestions[0];
|
|
34582
|
+
if (!selected) {
|
|
34583
|
+
return {
|
|
34584
|
+
content: [{ type: "text", text: "No renderable Semiotic chart was suggested for this data. Use getChartSchema for code-level guidance." }],
|
|
34585
|
+
isError: true,
|
|
34586
|
+
structuredContent: profileResult({
|
|
34587
|
+
status: "no-suggestion",
|
|
34588
|
+
suggestions: suggestions.map(compactPublicSuggestion),
|
|
34589
|
+
dataRowCount: args.data.length
|
|
34590
|
+
})
|
|
34591
|
+
};
|
|
34592
|
+
}
|
|
34593
|
+
const props = { data: args.data, ...selected.props, ...args.props };
|
|
34594
|
+
const publicProps = compactPublicChartProps(props);
|
|
34595
|
+
const publicSuggestion = compactPublicSuggestion(selected);
|
|
34596
|
+
const diagnosis = (0, import_ai3.diagnoseConfig)(selected.component, props);
|
|
34597
|
+
const blocking = diagnosis.diagnoses.filter((item) => item.severity === "error");
|
|
34598
|
+
if (blocking.length) {
|
|
34599
|
+
return {
|
|
34600
|
+
content: [{ type: "text", text: `Selected ${selected.component}, but blocking diagnostics require repair before rendering.` }],
|
|
34601
|
+
isError: true,
|
|
34602
|
+
structuredContent: profileResult({
|
|
34603
|
+
status: "blocked",
|
|
34604
|
+
component: selected.component,
|
|
34605
|
+
props: publicProps,
|
|
34606
|
+
dataRowCount: args.data.length,
|
|
34607
|
+
suggestion: publicSuggestion,
|
|
34608
|
+
diagnostics: diagnosis.diagnoses
|
|
34609
|
+
})
|
|
34610
|
+
};
|
|
34611
|
+
}
|
|
34612
|
+
const rendered = await renderInteractiveChartHandler({ component: selected.component, props, theme: args.theme }, context);
|
|
34613
|
+
if (rendered.isError) {
|
|
34614
|
+
return {
|
|
34615
|
+
...rendered,
|
|
34616
|
+
structuredContent: profileResult({
|
|
34617
|
+
status: "blocked",
|
|
34618
|
+
component: selected.component,
|
|
34619
|
+
props: publicProps,
|
|
34620
|
+
dataRowCount: args.data.length,
|
|
34621
|
+
suggestion: publicSuggestion,
|
|
34622
|
+
diagnostics: diagnosis.diagnoses,
|
|
34623
|
+
render: rendered.structuredContent ?? null
|
|
34624
|
+
})
|
|
34625
|
+
};
|
|
34626
|
+
}
|
|
34627
|
+
const output = rendered.structuredContent ?? {};
|
|
34628
|
+
return {
|
|
34629
|
+
...rendered,
|
|
34630
|
+
structuredContent: profileResult({
|
|
34631
|
+
status: "render-proven",
|
|
34632
|
+
component: selected.component,
|
|
34633
|
+
props: publicProps,
|
|
34634
|
+
dataRowCount: args.data.length,
|
|
34635
|
+
suggestion: publicSuggestion,
|
|
34636
|
+
diagnostics: diagnosis.diagnoses,
|
|
34637
|
+
render: output
|
|
34638
|
+
})
|
|
34639
|
+
};
|
|
34640
|
+
}
|
|
34641
|
+
async function improveChartHandler(args) {
|
|
34642
|
+
const data = args.data ?? (Array.isArray(args.props.data) ? args.props.data : []);
|
|
34643
|
+
const intent = Array.isArray(args.intent) ? args.intent : args.intent ? [args.intent] : void 0;
|
|
34644
|
+
const diagnosis = (0, import_ai3.diagnoseConfig)(args.component, args.props);
|
|
34645
|
+
const repair = (0, import_ai3.repairChartConfig)(args.component, data, { intent });
|
|
34646
|
+
const capability = (0, import_ai3.getCapability)(args.component);
|
|
34647
|
+
const variants = capability ? (0, import_ai3.proposeVariant)(args.component, capability, { profile: (0, import_ai3.profileData)(data), intent }) : [];
|
|
34648
|
+
return {
|
|
34649
|
+
content: [{ type: "text", text: `Improvement analysis for ${args.component}: ${diagnosis.diagnoses.length} diagnosis item(s), repair status ${repair.status}, ${variants.length} variant proposal(s).` }],
|
|
34650
|
+
structuredContent: profileResult({ status: repair.status === "ok" ? "reviewed" : "repair-needed", component: args.component, diagnostics: diagnosis.diagnoses, repair, variants })
|
|
34651
|
+
};
|
|
34652
|
+
}
|
|
34653
|
+
async function explainChartHandler(args) {
|
|
34654
|
+
const grounded = await groundChartHandler(args);
|
|
34655
|
+
return {
|
|
34656
|
+
...grounded,
|
|
34657
|
+
structuredContent: grounded.structuredContent ? profileResult({ status: "grounded", grounding: grounded.structuredContent }) : void 0
|
|
34658
|
+
};
|
|
34659
|
+
}
|
|
34660
|
+
async function auditChartHandler(args) {
|
|
34661
|
+
const diagnosis = (0, import_ai3.diagnoseConfig)(args.component, args.props);
|
|
34662
|
+
const accessibility = (0, import_ai3.auditAccessibility)(args.component, args.props, { inChartContainer: true, describe: true, navigable: true });
|
|
34663
|
+
const mobile = (0, import_ai3.auditMobileVisualization)(args.component, args.props, { viewportWidth: args.viewportWidth, inChartContainer: true });
|
|
34664
|
+
const blocking = diagnosis.diagnoses.some((item) => item.severity === "error") || !accessibility.ok || !mobile.ok;
|
|
34665
|
+
return {
|
|
34666
|
+
content: [{ type: "text", text: `Audit for ${args.component}: ${blocking ? "blocking findings need attention" : "no blocking findings"}.` }],
|
|
34667
|
+
isError: blocking,
|
|
34668
|
+
structuredContent: profileResult({ status: blocking ? "findings" : "passed", component: args.component, diagnostics: diagnosis.diagnoses, accessibility, mobile })
|
|
34669
|
+
};
|
|
34670
|
+
}
|
|
33440
34671
|
var READ_ONLY_TOOL_ANNOTATIONS = {
|
|
33441
34672
|
readOnlyHint: true,
|
|
33442
34673
|
destructiveHint: false,
|
|
33443
34674
|
idempotentHint: true,
|
|
33444
34675
|
openWorldHint: false
|
|
33445
34676
|
};
|
|
33446
|
-
function createServer2() {
|
|
34677
|
+
function createServer2(profile = "developer", options = {}) {
|
|
34678
|
+
const buildInfo = buildInfoForProfile(profile);
|
|
34679
|
+
const serverRenderContext = {
|
|
34680
|
+
signal: options.signal,
|
|
34681
|
+
limits: options.limits ?? resolveMcpRenderExecutionLimits()
|
|
34682
|
+
};
|
|
33447
34683
|
const srv = new McpServer({
|
|
33448
|
-
|
|
33449
|
-
|
|
34684
|
+
...mcpServerInfoForBuild(buildInfo),
|
|
34685
|
+
description: "Deterministic Semiotic chart selection, validation, rendering, and non-visual chart grounding. Use suggestCharts, getSchema, diagnoseConfig, and renderChart in that order for static chart generation."
|
|
33450
34686
|
});
|
|
34687
|
+
srv.registerResource(
|
|
34688
|
+
"semiotic-build-info",
|
|
34689
|
+
"semiotic://build-info",
|
|
34690
|
+
{
|
|
34691
|
+
title: "Semiotic Build Information",
|
|
34692
|
+
description: "Read-only deployment identity for this Semiotic MCP server.",
|
|
34693
|
+
mimeType: "application/json"
|
|
34694
|
+
},
|
|
34695
|
+
(uri) => textResource(uri, "application/json", JSON.stringify(buildInfo, null, 2))
|
|
34696
|
+
);
|
|
33451
34697
|
srv.registerResource(
|
|
33452
34698
|
"semiotic-schema",
|
|
33453
34699
|
"semiotic://schema",
|
|
@@ -33468,6 +34714,16 @@ function createServer2() {
|
|
|
33468
34714
|
},
|
|
33469
34715
|
(uri) => textResource(uri, "application/json", componentIndexJSON())
|
|
33470
34716
|
);
|
|
34717
|
+
srv.registerResource(
|
|
34718
|
+
"semiotic-surface-manifest",
|
|
34719
|
+
"semiotic://surface-manifest",
|
|
34720
|
+
{
|
|
34721
|
+
title: "Semiotic AI Surface Manifest",
|
|
34722
|
+
description: "Generated inventory of schema components, AI exports, MCP renderability, tools, resources, and prompts.",
|
|
34723
|
+
mimeType: "application/json"
|
|
34724
|
+
},
|
|
34725
|
+
(uri) => textResource(uri, "application/json", readAIFile("surface-manifest.json"))
|
|
34726
|
+
);
|
|
33471
34727
|
srv.registerResource(
|
|
33472
34728
|
"semiotic-behavior-contracts",
|
|
33473
34729
|
"semiotic://behavior-contracts",
|
|
@@ -33583,6 +34839,51 @@ function createServer2() {
|
|
|
33583
34839
|
"Return the smallest safe fix first, then mention any follow-up cleanup or issue-reporting step."
|
|
33584
34840
|
].join("\n"))
|
|
33585
34841
|
);
|
|
34842
|
+
if (profile === "public") {
|
|
34843
|
+
srv.registerTool("createChart", {
|
|
34844
|
+
title: "Create and prove a chart",
|
|
34845
|
+
description: "Select, validate, diagnose, render, and prove a static-data Semiotic chart. This is the default public workflow.",
|
|
34846
|
+
inputSchema: {
|
|
34847
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).min(1),
|
|
34848
|
+
intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional(),
|
|
34849
|
+
audience: external_exports3.object({ name: external_exports3.string().optional(), receptionModality: external_exports3.enum(["visual", "screen-reader", "sonified", "agent"]).optional() }).passthrough().optional(),
|
|
34850
|
+
component: external_exports3.string().optional().describe("Optional chart preference; the fit-ranked result remains authoritative."),
|
|
34851
|
+
props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).optional().describe("Optional props to merge over the selected chart recipe."),
|
|
34852
|
+
theme: external_exports3.record(external_exports3.string(), external_exports3.string()).optional()
|
|
34853
|
+
},
|
|
34854
|
+
outputSchema: { status: external_exports3.enum(["render-proven", "blocked", "no-suggestion"]), component: external_exports3.string().optional(), surfaceVersion: external_exports3.string() },
|
|
34855
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
34856
|
+
_meta: { ui: { resourceUri: SEMIOTIC_CHART_WIDGET_URI }, "openai/outputTemplate": SEMIOTIC_CHART_WIDGET_URI }
|
|
34857
|
+
}, (args) => createChartHandler(args, serverRenderContext));
|
|
34858
|
+
srv.registerTool("improveChart", {
|
|
34859
|
+
title: "Improve an existing chart",
|
|
34860
|
+
description: "Diagnose a chart configuration, assess data fit, and propose repairs or variants.",
|
|
34861
|
+
inputSchema: { component: external_exports3.string(), props: external_exports3.record(external_exports3.string(), external_exports3.unknown()), data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).optional(), intent: external_exports3.union([external_exports3.string(), external_exports3.array(external_exports3.string())]).optional() },
|
|
34862
|
+
outputSchema: { status: external_exports3.enum(["reviewed", "repair-needed"]), component: external_exports3.string(), surfaceVersion: external_exports3.string() },
|
|
34863
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS
|
|
34864
|
+
}, improveChartHandler);
|
|
34865
|
+
srv.registerTool("explainChart", {
|
|
34866
|
+
title: "Explain a chart without pixels",
|
|
34867
|
+
description: "Return reader grounding: chart description, communicative intent, and navigable data structure.",
|
|
34868
|
+
inputSchema: { component: external_exports3.string(), props: external_exports3.record(external_exports3.string(), external_exports3.unknown()) },
|
|
34869
|
+
outputSchema: { status: external_exports3.literal("grounded"), grounding: external_exports3.record(external_exports3.string(), external_exports3.unknown()), surfaceVersion: external_exports3.string() },
|
|
34870
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS
|
|
34871
|
+
}, explainChartHandler);
|
|
34872
|
+
srv.registerTool("auditChart", {
|
|
34873
|
+
title: "Audit chart quality and accessibility",
|
|
34874
|
+
description: "Run design diagnostics plus accessibility and mobile audits, returning prioritized structured findings.",
|
|
34875
|
+
inputSchema: { component: external_exports3.string(), props: external_exports3.record(external_exports3.string(), external_exports3.unknown()), viewportWidth: external_exports3.number().int().min(240).max(1600).optional() },
|
|
34876
|
+
outputSchema: { status: external_exports3.enum(["passed", "findings"]), component: external_exports3.string(), surfaceVersion: external_exports3.string() },
|
|
34877
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS
|
|
34878
|
+
}, auditChartHandler);
|
|
34879
|
+
srv.registerTool("getChartSchema", {
|
|
34880
|
+
title: "Get a chart schema",
|
|
34881
|
+
description: "Return canonical Semiotic prop-schema guidance for code editing and advanced configuration.",
|
|
34882
|
+
inputSchema: { component: external_exports3.string().optional() },
|
|
34883
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS
|
|
34884
|
+
}, getSchemaHandler);
|
|
34885
|
+
return srv;
|
|
34886
|
+
}
|
|
33586
34887
|
srv.tool(
|
|
33587
34888
|
"getSchema",
|
|
33588
34889
|
`Return the prop schema for a Semiotic chart component. Pass { component: '<name>' } to get its props, or omit component to list all available components. Components marked [renderable] can be passed to renderChart for static SVG output.`,
|
|
@@ -33613,15 +34914,15 @@ function createServer2() {
|
|
|
33613
34914
|
);
|
|
33614
34915
|
srv.tool(
|
|
33615
34916
|
"renderChart",
|
|
33616
|
-
`Render a Semiotic chart to static SVG or PNG. This is a static snapshot path: props must include data immediately, and ref/push-mode charts cannot be rendered through this tool. Returns SVG
|
|
34917
|
+
`Render a Semiotic chart to static SVG or PNG. This is a static snapshot path: props must include data immediately, and ref/push-mode charts cannot be rendered through this tool. Returns SVG text by default or an image/png artifact when format='png', plus a "Render evidence" JSON block (mark counts by type, resolved axis domains, empty flag, annotation count, accessible name) \u2014 read the evidence instead of parsing the SVG to verify the chart actually rendered data marks. Optionally pass theme CSS custom properties (--semiotic-bg, --semiotic-text, etc.) to style the output. PNG requires the 'sharp' package to be installed. Available components: ${componentNames.join(", ")}.`,
|
|
33617
34918
|
{
|
|
33618
34919
|
component: external_exports3.string().describe("Chart component name, e.g. 'LineChart', 'BarChart'"),
|
|
33619
34920
|
props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).optional().describe("Chart props object, e.g. { data: [...], xAccessor: 'x' }."),
|
|
33620
34921
|
theme: external_exports3.record(external_exports3.string(), external_exports3.string()).optional().describe("CSS custom properties for theming, e.g. { '--semiotic-bg': '#1a1a2e', '--semiotic-text': '#ededed' }. Only --semiotic-* variables are applied."),
|
|
33621
|
-
format: external_exports3.enum(["svg", "png"]).optional().describe("Output format: 'svg' (default) returns SVG markup, 'png' returns
|
|
34922
|
+
format: external_exports3.enum(["svg", "png"]).optional().describe("Output format: 'svg' (default) returns SVG markup, 'png' returns image/png artifact data. PNG requires the 'sharp' package.")
|
|
33622
34923
|
},
|
|
33623
34924
|
READ_ONLY_TOOL_ANNOTATIONS,
|
|
33624
|
-
renderChartHandler
|
|
34925
|
+
(args) => renderChartHandler(args, serverRenderContext)
|
|
33625
34926
|
);
|
|
33626
34927
|
srv.registerTool(
|
|
33627
34928
|
"renderInteractiveChart",
|
|
@@ -33653,7 +34954,7 @@ function createServer2() {
|
|
|
33653
34954
|
"openai/toolInvocation/invoked": "Rendered Semiotic chart."
|
|
33654
34955
|
}
|
|
33655
34956
|
},
|
|
33656
|
-
renderInteractiveChartHandler
|
|
34957
|
+
(args) => renderInteractiveChartHandler(args, serverRenderContext)
|
|
33657
34958
|
);
|
|
33658
34959
|
srv.tool(
|
|
33659
34960
|
"diagnoseConfig",
|
|
@@ -33679,6 +34980,19 @@ function createServer2() {
|
|
|
33679
34980
|
READ_ONLY_TOOL_ANNOTATIONS,
|
|
33680
34981
|
auditAccessibilityHandler
|
|
33681
34982
|
);
|
|
34983
|
+
srv.tool(
|
|
34984
|
+
"auditMobileVisualization",
|
|
34985
|
+
"Audit a Semiotic chart configuration for mobile visualization risks. Use before generating phone-sized charts or when adapting a desktop chart to mobile. Flags fixed desktop widths, rough mark-density overload, hover-only detail, small touch targets, complex gestures without controls, legend dependence, annotation overload, and missing mobile transformation hints. Static analysis only: still verify rendered charts at phone widths.",
|
|
34986
|
+
{
|
|
34987
|
+
component: external_exports3.string().describe("Chart component name, e.g. 'LineChart', 'Scatterplot', or 'BarChart'."),
|
|
34988
|
+
props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).optional().describe("Chart props/config to audit."),
|
|
34989
|
+
viewportWidth: external_exports3.number().int().min(240).max(1600).optional().describe("Mobile viewport width in CSS pixels. Defaults to 390."),
|
|
34990
|
+
targetSize: external_exports3.number().int().min(24).max(80).optional().describe("Desired comfortable touch target size in CSS pixels. Defaults to 44."),
|
|
34991
|
+
inChartContainer: external_exports3.boolean().optional().describe("Whether the chart is wrapped in ChartContainer or an equivalent summary/control surface.")
|
|
34992
|
+
},
|
|
34993
|
+
READ_ONLY_TOOL_ANNOTATIONS,
|
|
34994
|
+
auditMobileVisualizationHandler
|
|
34995
|
+
);
|
|
33682
34996
|
srv.tool(
|
|
33683
34997
|
"reportIssue",
|
|
33684
34998
|
"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.",
|
|
@@ -33710,14 +35024,25 @@ function createServer2() {
|
|
|
33710
35024
|
READ_ONLY_TOOL_ANNOTATIONS,
|
|
33711
35025
|
interrogateChartHandler
|
|
33712
35026
|
);
|
|
33713
|
-
srv.
|
|
35027
|
+
srv.registerTool(
|
|
33714
35028
|
"groundChart",
|
|
33715
|
-
"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).",
|
|
33716
35029
|
{
|
|
33717
|
-
|
|
33718
|
-
|
|
35030
|
+
title: "Ground a Semiotic chart for a non-visual reader",
|
|
35031
|
+
description: "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), and a structured navigation tree (chart \u2192 axes/series \u2192 datum). Use this to interpret a chart faithfully without pixels.",
|
|
35032
|
+
inputSchema: {
|
|
35033
|
+
component: external_exports3.string().describe("Chart component name, e.g. 'LineChart'"),
|
|
35034
|
+
props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).describe("The full chart props including data")
|
|
35035
|
+
},
|
|
35036
|
+
outputSchema: {
|
|
35037
|
+
component: external_exports3.string(),
|
|
35038
|
+
description: external_exports3.record(external_exports3.string(), external_exports3.unknown()),
|
|
35039
|
+
intent: external_exports3.record(external_exports3.string(), external_exports3.unknown()).optional(),
|
|
35040
|
+
structure: external_exports3.record(external_exports3.string(), external_exports3.unknown()).optional(),
|
|
35041
|
+
physics: external_exports3.record(external_exports3.string(), external_exports3.unknown()).optional(),
|
|
35042
|
+
text: external_exports3.string()
|
|
35043
|
+
},
|
|
35044
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS
|
|
33719
35045
|
},
|
|
33720
|
-
READ_ONLY_TOOL_ANNOTATIONS,
|
|
33721
35046
|
groundChartHandler
|
|
33722
35047
|
);
|
|
33723
35048
|
srv.tool(
|
|
@@ -33753,6 +35078,20 @@ function createServer2() {
|
|
|
33753
35078
|
READ_ONLY_TOOL_ANNOTATIONS,
|
|
33754
35079
|
suggestDashboardHandler
|
|
33755
35080
|
);
|
|
35081
|
+
srv.tool(
|
|
35082
|
+
"suggestTokenEncoding",
|
|
35083
|
+
"Recommend a semantic token / ISOTYPE encoding for a reader task. Use before drawing repeated dots, icons, glyphs, natural-frequency grids, quantile dotplots, or hybrid bar-token views. Returns the recommended tokenEncoding, warnings, alternatives, and matching suggestCharts capability intents. Accepts canonical token intents (precise-comparison, probability-estimation, risk-communication, memory, support-decision, etc.) and friendly aliases (measure, estimate probability, understand risk, remember, decide).",
|
|
35084
|
+
{
|
|
35085
|
+
taskIntent: external_exports3.string().describe("Reader task intent, e.g. 'estimate probability', 'understand risk', 'remember', 'measure', 'decide', or canonical token intents like 'probability-estimation'."),
|
|
35086
|
+
dataType: external_exports3.enum(["count", "measure", "distribution", "probability", "risk", "category"]).optional().describe("Data shape or meaning behind the tokenized view."),
|
|
35087
|
+
audience: external_exports3.enum(["expert", "general-public", "internal"]).optional().describe("Audience for the recommendation."),
|
|
35088
|
+
precisionNeed: external_exports3.enum(["low", "medium", "high"]).optional().describe("How much exact magnitude reading matters."),
|
|
35089
|
+
availableSpace: external_exports3.enum(["small", "medium", "large"]).optional().describe("Space budget for visible tokens."),
|
|
35090
|
+
concreteEntity: external_exports3.string().optional().describe("Concrete icon/glyph concept, e.g. person, bus, server. Becomes tokenEncoding.icon when useful.")
|
|
35091
|
+
},
|
|
35092
|
+
READ_ONLY_TOOL_ANNOTATIONS,
|
|
35093
|
+
suggestTokenEncodingHandler
|
|
35094
|
+
);
|
|
33756
35095
|
srv.tool(
|
|
33757
35096
|
"suggestStretchCharts",
|
|
33758
35097
|
"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.",
|
|
@@ -33778,16 +35117,27 @@ function createServer2() {
|
|
|
33778
35117
|
READ_ONLY_TOOL_ANNOTATIONS,
|
|
33779
35118
|
suggestStretchChartsHandler
|
|
33780
35119
|
);
|
|
33781
|
-
srv.
|
|
35120
|
+
srv.registerTool(
|
|
33782
35121
|
"repairChartConfig",
|
|
33783
|
-
"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).",
|
|
33784
35122
|
{
|
|
33785
|
-
|
|
33786
|
-
|
|
33787
|
-
|
|
33788
|
-
|
|
35123
|
+
title: "Repair an unsuitable chart choice",
|
|
35124
|
+
description: "Validate that a chart component is a sensible choice for a dataset, and if not, propose ranked alternatives that fit. Returns a structured status of ok, alternative, or unknown.",
|
|
35125
|
+
inputSchema: {
|
|
35126
|
+
component: external_exports3.string().describe("Chart component name to validate, e.g. 'PieChart'"),
|
|
35127
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
|
|
35128
|
+
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."),
|
|
35129
|
+
maxAlternatives: external_exports3.number().int().min(1).max(10).optional().describe("Cap on alternatives returned (default 3).")
|
|
35130
|
+
},
|
|
35131
|
+
outputSchema: {
|
|
35132
|
+
status: external_exports3.enum(["ok", "alternative", "unknown"]),
|
|
35133
|
+
component: external_exports3.string(),
|
|
35134
|
+
reason: external_exports3.string().optional(),
|
|
35135
|
+
alternatives: external_exports3.array(external_exports3.unknown()).optional(),
|
|
35136
|
+
profile: external_exports3.record(external_exports3.string(), external_exports3.unknown()),
|
|
35137
|
+
repairs: external_exports3.array(external_exports3.string()).optional()
|
|
35138
|
+
},
|
|
35139
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS
|
|
33789
35140
|
},
|
|
33790
|
-
READ_ONLY_TOOL_ANNOTATIONS,
|
|
33791
35141
|
repairChartConfigHandler
|
|
33792
35142
|
);
|
|
33793
35143
|
srv.tool(
|
|
@@ -33817,53 +35167,171 @@ function createServer2() {
|
|
|
33817
35167
|
READ_ONLY_TOOL_ANNOTATIONS,
|
|
33818
35168
|
proposeChartVariantsHandler
|
|
33819
35169
|
);
|
|
33820
|
-
srv.
|
|
35170
|
+
srv.registerTool(
|
|
33821
35171
|
"suggestCharts",
|
|
33822
|
-
"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.",
|
|
33823
35172
|
{
|
|
33824
|
-
|
|
33825
|
-
|
|
33826
|
-
|
|
33827
|
-
|
|
33828
|
-
|
|
33829
|
-
|
|
33830
|
-
|
|
33831
|
-
|
|
33832
|
-
|
|
33833
|
-
external_exports3.string(),
|
|
33834
|
-
external_exports3.
|
|
33835
|
-
|
|
33836
|
-
|
|
33837
|
-
|
|
33838
|
-
|
|
33839
|
-
|
|
33840
|
-
|
|
33841
|
-
|
|
33842
|
-
|
|
35173
|
+
title: "Recommend Semiotic charts",
|
|
35174
|
+
description: "Recommend Semiotic charts for a dataset using heuristic capability descriptors. Returns ranked, structured suggestions with scores, reasons, caveats, and ready-to-use props; no LLM call is made.",
|
|
35175
|
+
inputSchema: {
|
|
35176
|
+
data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
|
|
35177
|
+
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."),
|
|
35178
|
+
maxResults: external_exports3.number().int().min(1).max(40).optional().describe("Cap on suggestions returned (default 8)."),
|
|
35179
|
+
allow: external_exports3.array(external_exports3.string()).optional().describe("Restrict to these component names."),
|
|
35180
|
+
deny: external_exports3.array(external_exports3.string()).optional().describe("Exclude these component names."),
|
|
35181
|
+
audience: external_exports3.object({
|
|
35182
|
+
name: external_exports3.string().optional(),
|
|
35183
|
+
familiarity: external_exports3.record(external_exports3.string(), external_exports3.number()).optional(),
|
|
35184
|
+
targets: external_exports3.record(
|
|
35185
|
+
external_exports3.string(),
|
|
35186
|
+
external_exports3.object({
|
|
35187
|
+
direction: external_exports3.enum(["increase", "decrease"]),
|
|
35188
|
+
weight: external_exports3.number().int().min(1).max(3).optional(),
|
|
35189
|
+
reason: external_exports3.string().optional()
|
|
35190
|
+
})
|
|
35191
|
+
).optional(),
|
|
35192
|
+
exposureLevel: external_exports3.union([external_exports3.literal(0), external_exports3.literal(1), external_exports3.literal(2)]).optional(),
|
|
35193
|
+
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 and adds receivability caveats.")
|
|
35194
|
+
}).optional().describe("Audience profile \u2014 familiarity, adoption targets, exposure level, and reception modality.")
|
|
35195
|
+
},
|
|
35196
|
+
outputSchema: { suggestions: external_exports3.array(external_exports3.unknown()) },
|
|
35197
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS
|
|
33843
35198
|
},
|
|
33844
|
-
READ_ONLY_TOOL_ANNOTATIONS,
|
|
33845
35199
|
suggestChartsHandler
|
|
33846
35200
|
);
|
|
33847
35201
|
return srv;
|
|
33848
35202
|
}
|
|
33849
35203
|
var cliArgs = process.argv.slice(2);
|
|
33850
35204
|
var httpMode = cliArgs.includes("--http");
|
|
35205
|
+
var profileFlagIndex = cliArgs.indexOf("--profile");
|
|
35206
|
+
var requestedProfile = profileFlagIndex !== -1 ? cliArgs[profileFlagIndex + 1] : process.env.MCP_TOOL_PROFILE;
|
|
35207
|
+
var toolProfile = requestedProfile === "public" ? "public" : "developer";
|
|
33851
35208
|
var portFlagIndex = cliArgs.indexOf("--port");
|
|
33852
35209
|
var parsedPort = portFlagIndex !== -1 && cliArgs[portFlagIndex + 1] != null ? parseInt(cliArgs[portFlagIndex + 1], 10) : NaN;
|
|
33853
35210
|
var port = Number.isFinite(parsedPort) ? parsedPort : 3001;
|
|
35211
|
+
var host = resolveHTTPListenHost(cliArgs);
|
|
35212
|
+
function operationLimitForMcpRequest(body, limits) {
|
|
35213
|
+
const requests = Array.isArray(body) ? body : [body];
|
|
35214
|
+
for (const candidate of requests) {
|
|
35215
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) continue;
|
|
35216
|
+
const request = candidate;
|
|
35217
|
+
if (request.method !== "tools/call") continue;
|
|
35218
|
+
if (!request.params || typeof request.params !== "object" || Array.isArray(request.params)) continue;
|
|
35219
|
+
const params = request.params;
|
|
35220
|
+
if (!("arguments" in params)) continue;
|
|
35221
|
+
const result = inspectMcpOperationInput(params.arguments, limits);
|
|
35222
|
+
if (!result.ok) return result;
|
|
35223
|
+
}
|
|
35224
|
+
return null;
|
|
35225
|
+
}
|
|
33854
35226
|
async function main() {
|
|
33855
35227
|
if (httpMode) {
|
|
33856
35228
|
const allowedHosts = (process.env.MCP_ALLOWED_HOSTS || "").split(",").map((h) => h.trim().toLowerCase()).filter(Boolean);
|
|
35229
|
+
const allowedOrigins = (process.env.MCP_ALLOWED_ORIGINS || "").split(",").map((o) => o.trim().toLowerCase()).filter(Boolean);
|
|
35230
|
+
const parsedMaxBody = parseInt(process.env.MCP_MAX_BODY_BYTES || "", 10);
|
|
35231
|
+
const maxBodyBytes = Number.isFinite(parsedMaxBody) && parsedMaxBody > 0 ? parsedMaxBody : 4194304;
|
|
35232
|
+
const operationLimits = resolveMcpOperationLimits();
|
|
33857
35233
|
const openaiAppsChallengeToken = (process.env.OPENAI_APPS_CHALLENGE_TOKEN || "").trim();
|
|
35234
|
+
const renderExecutionLimits = resolveMcpRenderExecutionLimits();
|
|
35235
|
+
const requestLimits = resolveMcpRequestLimits();
|
|
35236
|
+
const requestLimiter = createMcpRequestLimiter(requestLimits);
|
|
35237
|
+
const protocolVersions = (process.env.MCP_SUPPORTED_PROTOCOL_VERSIONS || "").split(",").map((version2) => version2.trim()).filter(Boolean);
|
|
35238
|
+
const protocolVersion = protocolVersions[0] || DEFAULT_MCP_SUPPORTED_PROTOCOL_VERSION;
|
|
35239
|
+
const authToken = (process.env.MCP_AUTH_TOKEN || "").trim();
|
|
35240
|
+
const authScheme = (process.env.MCP_AUTH_SCHEME || "Bearer").trim() || "Bearer";
|
|
35241
|
+
const readJsonBodyWithLimit = (req) => new Promise((resolve2) => {
|
|
35242
|
+
let size = 0;
|
|
35243
|
+
let done = false;
|
|
35244
|
+
const chunks = [];
|
|
35245
|
+
const finish = (result) => {
|
|
35246
|
+
if (done) return;
|
|
35247
|
+
done = true;
|
|
35248
|
+
resolve2(result);
|
|
35249
|
+
};
|
|
35250
|
+
req.on("data", (chunk) => {
|
|
35251
|
+
if (done) return;
|
|
35252
|
+
size += chunk.length;
|
|
35253
|
+
if (size > maxBodyBytes) {
|
|
35254
|
+
finish({
|
|
35255
|
+
ok: false,
|
|
35256
|
+
status: 413,
|
|
35257
|
+
code: -32600,
|
|
35258
|
+
message: "Request body too large",
|
|
35259
|
+
reason: "request_body_too_large"
|
|
35260
|
+
});
|
|
35261
|
+
return;
|
|
35262
|
+
}
|
|
35263
|
+
chunks.push(chunk);
|
|
35264
|
+
});
|
|
35265
|
+
req.on("end", () => {
|
|
35266
|
+
if (done) return;
|
|
35267
|
+
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
35268
|
+
if (!raw) return finish({ ok: true, body: void 0, bodyBytes: size });
|
|
35269
|
+
try {
|
|
35270
|
+
const body = JSON.parse(raw);
|
|
35271
|
+
const operationLimit = operationLimitForMcpRequest(body, operationLimits);
|
|
35272
|
+
if (operationLimit && !operationLimit.ok) {
|
|
35273
|
+
finish({
|
|
35274
|
+
ok: false,
|
|
35275
|
+
status: 413,
|
|
35276
|
+
code: -32602,
|
|
35277
|
+
message: formatMcpOperationLimitError(operationLimit),
|
|
35278
|
+
reason: "operation_limit"
|
|
35279
|
+
});
|
|
35280
|
+
return;
|
|
35281
|
+
}
|
|
35282
|
+
finish({ ok: true, body, bodyBytes: size });
|
|
35283
|
+
} catch {
|
|
35284
|
+
finish({
|
|
35285
|
+
ok: false,
|
|
35286
|
+
status: 400,
|
|
35287
|
+
code: -32600,
|
|
35288
|
+
message: "Invalid JSON body",
|
|
35289
|
+
reason: "invalid_json"
|
|
35290
|
+
});
|
|
35291
|
+
}
|
|
35292
|
+
});
|
|
35293
|
+
req.on("error", () => finish({
|
|
35294
|
+
ok: false,
|
|
35295
|
+
status: 400,
|
|
35296
|
+
code: -32600,
|
|
35297
|
+
message: "Request stream error",
|
|
35298
|
+
reason: "request_stream_error"
|
|
35299
|
+
}));
|
|
35300
|
+
});
|
|
35301
|
+
const buildInfo = buildInfoForProfile(toolProfile);
|
|
33858
35302
|
const healthBody = () => JSON.stringify({
|
|
33859
35303
|
status: "ok",
|
|
33860
35304
|
name: "semiotic-mcp",
|
|
33861
|
-
version:
|
|
35305
|
+
version: buildInfo.packageVersion,
|
|
33862
35306
|
transport: "streamable-http",
|
|
33863
|
-
mode: "stateless"
|
|
35307
|
+
mode: "stateless",
|
|
35308
|
+
channel: buildInfo.channel,
|
|
35309
|
+
packageVersion: buildInfo.packageVersion,
|
|
35310
|
+
surfaceVersion: buildInfo.surfaceVersion,
|
|
35311
|
+
...buildInfo.commitSha ? { commitSha: buildInfo.commitSha } : {},
|
|
35312
|
+
...buildInfo.buildId ? { buildId: buildInfo.buildId } : {},
|
|
35313
|
+
...buildInfo.builtAt ? { builtAt: buildInfo.builtAt } : {}
|
|
33864
35314
|
});
|
|
35315
|
+
const writeHealthResponse = (res) => {
|
|
35316
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
35317
|
+
res.end(healthBody());
|
|
35318
|
+
};
|
|
33865
35319
|
const httpServer = http.createServer(async (req, res) => {
|
|
33866
|
-
|
|
35320
|
+
const requestStartedAt = Date.now();
|
|
35321
|
+
const pathname = (() => {
|
|
35322
|
+
try {
|
|
35323
|
+
return new URL(req.url || "/", "http://localhost").pathname;
|
|
35324
|
+
} catch {
|
|
35325
|
+
return "/";
|
|
35326
|
+
}
|
|
35327
|
+
})();
|
|
35328
|
+
const origin = String(req.headers.origin || "").trim().toLowerCase();
|
|
35329
|
+
if (allowedOrigins.length > 0) {
|
|
35330
|
+
res.setHeader("Access-Control-Allow-Origin", allowedOrigins.includes(origin) ? origin : allowedOrigins[0]);
|
|
35331
|
+
res.setHeader("Vary", "Origin");
|
|
35332
|
+
} else {
|
|
35333
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
35334
|
+
}
|
|
33867
35335
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
33868
35336
|
res.setHeader(
|
|
33869
35337
|
"Access-Control-Allow-Headers",
|
|
@@ -33875,25 +35343,35 @@ async function main() {
|
|
|
33875
35343
|
res.end();
|
|
33876
35344
|
return;
|
|
33877
35345
|
}
|
|
33878
|
-
|
|
33879
|
-
|
|
33880
|
-
|
|
33881
|
-
|
|
33882
|
-
|
|
33883
|
-
|
|
33884
|
-
|
|
35346
|
+
if (allowedOrigins.length > 0 && origin && !allowedOrigins.includes(origin)) {
|
|
35347
|
+
mcpLogger.warn("request_rejected", {
|
|
35348
|
+
reason: "forbidden_origin",
|
|
35349
|
+
method: req.method,
|
|
35350
|
+
route: pathname,
|
|
35351
|
+
status: 403
|
|
35352
|
+
});
|
|
35353
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
35354
|
+
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32e3, message: "Forbidden origin" }, id: null }));
|
|
35355
|
+
return;
|
|
35356
|
+
}
|
|
35357
|
+
res.setHeader("MCP-Protocol-Version", protocolVersion);
|
|
33885
35358
|
if (allowedHosts.length > 0) {
|
|
33886
35359
|
const rawHost = String(req.headers.host || "").trim().toLowerCase();
|
|
33887
35360
|
const normalizedHost = rawHost.startsWith("[") ? rawHost.replace(/^\[([^\]]+)\](?::\d+)?$/, "$1") : rawHost.split(":")[0];
|
|
33888
35361
|
if (!allowedHosts.includes(rawHost) && !allowedHosts.includes(normalizedHost)) {
|
|
35362
|
+
mcpLogger.warn("request_rejected", {
|
|
35363
|
+
reason: "forbidden_host",
|
|
35364
|
+
method: req.method,
|
|
35365
|
+
route: pathname,
|
|
35366
|
+
status: 403
|
|
35367
|
+
});
|
|
33889
35368
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
33890
35369
|
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32e3, message: "Forbidden host" }, id: null }));
|
|
33891
35370
|
return;
|
|
33892
35371
|
}
|
|
33893
35372
|
}
|
|
33894
|
-
if (req.method === "GET" &&
|
|
33895
|
-
res
|
|
33896
|
-
res.end(healthBody());
|
|
35373
|
+
if (req.method === "GET" && pathname === "/health") {
|
|
35374
|
+
writeHealthResponse(res);
|
|
33897
35375
|
return;
|
|
33898
35376
|
}
|
|
33899
35377
|
if (req.method === "GET" && pathname === "/.well-known/openai-apps-challenge" && openaiAppsChallengeToken) {
|
|
@@ -33910,55 +35388,155 @@ async function main() {
|
|
|
33910
35388
|
return;
|
|
33911
35389
|
}
|
|
33912
35390
|
if (req.method === "GET") {
|
|
33913
|
-
|
|
33914
|
-
|
|
35391
|
+
if (pathname === "/mcp") {
|
|
35392
|
+
res.writeHead(405, { "Content-Type": "application/json", Allow: "POST, OPTIONS" });
|
|
35393
|
+
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32e3, message: "Method not allowed (stateless server offers no SSE stream)" }, id: null }));
|
|
35394
|
+
return;
|
|
35395
|
+
}
|
|
35396
|
+
writeHealthResponse(res);
|
|
33915
35397
|
return;
|
|
33916
35398
|
}
|
|
33917
35399
|
if (req.method !== "POST") {
|
|
33918
|
-
res.writeHead(405, { "Content-Type": "application/json" });
|
|
35400
|
+
res.writeHead(405, { "Content-Type": "application/json", Allow: "POST, OPTIONS" });
|
|
33919
35401
|
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32e3, message: "Method not allowed" }, id: null }));
|
|
33920
35402
|
return;
|
|
33921
35403
|
}
|
|
33922
|
-
const
|
|
33923
|
-
|
|
33924
|
-
|
|
33925
|
-
|
|
33926
|
-
|
|
33927
|
-
|
|
33928
|
-
|
|
33929
|
-
if (torndown) return;
|
|
33930
|
-
torndown = true;
|
|
33931
|
-
Promise.resolve(transport.close()).catch(() => {
|
|
35404
|
+
const requestAbortSignal = createMcpRequestCancellationSignal(req, res);
|
|
35405
|
+
if (!hasSupportedAccept(String(req.headers.accept || ""))) {
|
|
35406
|
+
mcpLogger.warn("request_rejected", {
|
|
35407
|
+
reason: "unsupported_accept",
|
|
35408
|
+
method: req.method,
|
|
35409
|
+
route: pathname,
|
|
35410
|
+
status: 406
|
|
33932
35411
|
});
|
|
33933
|
-
|
|
35412
|
+
writeJsonRpcError(
|
|
35413
|
+
res,
|
|
35414
|
+
406,
|
|
35415
|
+
-32e3,
|
|
35416
|
+
"Not Acceptable: this endpoint supports JSON transport only"
|
|
35417
|
+
);
|
|
35418
|
+
return;
|
|
35419
|
+
}
|
|
35420
|
+
if (!isSupportedProtocolVersion(
|
|
35421
|
+
String(req.headers["mcp-protocol-version"] || ""),
|
|
35422
|
+
protocolVersions
|
|
35423
|
+
)) {
|
|
35424
|
+
mcpLogger.warn("request_rejected", {
|
|
35425
|
+
reason: "unsupported_protocol_version",
|
|
35426
|
+
method: req.method,
|
|
35427
|
+
route: pathname,
|
|
35428
|
+
status: 400,
|
|
35429
|
+
// The header's value can be attacker-controlled; presence is enough
|
|
35430
|
+
// operationally and keeps it out of the log boundary.
|
|
35431
|
+
protocolVersionPresent: Boolean(req.headers["mcp-protocol-version"])
|
|
33934
35432
|
});
|
|
33935
|
-
|
|
33936
|
-
|
|
35433
|
+
writeJsonRpcError(
|
|
35434
|
+
res,
|
|
35435
|
+
400,
|
|
35436
|
+
-32e3,
|
|
35437
|
+
"Unsupported MCP protocol version"
|
|
35438
|
+
);
|
|
35439
|
+
return;
|
|
35440
|
+
}
|
|
35441
|
+
if (authToken && !isAuthorizedRequest(req, authToken, authScheme)) {
|
|
35442
|
+
mcpLogger.warn("request_rejected", {
|
|
35443
|
+
reason: "unauthorized",
|
|
35444
|
+
method: req.method,
|
|
35445
|
+
route: pathname,
|
|
35446
|
+
status: 401
|
|
35447
|
+
});
|
|
35448
|
+
res.setHeader("WWW-Authenticate", `${authScheme} realm="semiotic-mcp"`);
|
|
35449
|
+
writeJsonRpcError(res, 401, -32e3, "Unauthorized");
|
|
35450
|
+
return;
|
|
35451
|
+
}
|
|
35452
|
+
const requestSlot = requestLimiter.tryAcquire();
|
|
35453
|
+
if (!requestSlot.ok) {
|
|
35454
|
+
res.setHeader("Retry-After", String(Math.max(1, Math.ceil(requestSlot.retryAfterMs / 1e3))));
|
|
35455
|
+
mcpLogger.warn("request_rejected", {
|
|
35456
|
+
reason: requestSlot.code === "MCP_REQUEST_CONCURRENCY" ? "request_concurrency" : "request_rate",
|
|
35457
|
+
method: req.method,
|
|
35458
|
+
route: pathname,
|
|
35459
|
+
status: 429
|
|
35460
|
+
});
|
|
35461
|
+
writeJsonRpcError(res, 429, -32e3, requestSlot.message);
|
|
35462
|
+
return;
|
|
35463
|
+
}
|
|
33937
35464
|
try {
|
|
33938
|
-
await
|
|
33939
|
-
|
|
33940
|
-
|
|
33941
|
-
|
|
33942
|
-
|
|
33943
|
-
|
|
33944
|
-
|
|
35465
|
+
const bodyResult = await readJsonBodyWithLimit(req);
|
|
35466
|
+
if (!bodyResult.ok) {
|
|
35467
|
+
mcpLogger.warn("request_rejected", {
|
|
35468
|
+
reason: bodyResult.reason,
|
|
35469
|
+
method: req.method,
|
|
35470
|
+
route: pathname,
|
|
35471
|
+
status: bodyResult.status
|
|
35472
|
+
});
|
|
35473
|
+
if (!res.headersSent) {
|
|
35474
|
+
res.writeHead(bodyResult.status, { "Content-Type": "application/json" });
|
|
35475
|
+
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: bodyResult.code, message: bodyResult.message }, id: null }));
|
|
35476
|
+
}
|
|
35477
|
+
return;
|
|
35478
|
+
}
|
|
35479
|
+
const srv = createServer2(toolProfile, {
|
|
35480
|
+
signal: requestAbortSignal,
|
|
35481
|
+
limits: renderExecutionLimits
|
|
35482
|
+
});
|
|
35483
|
+
const transport = new StreamableHTTPServerTransport({
|
|
35484
|
+
sessionIdGenerator: void 0,
|
|
35485
|
+
enableJsonResponse: true
|
|
35486
|
+
});
|
|
35487
|
+
let torndown = false;
|
|
35488
|
+
const teardown = () => {
|
|
35489
|
+
if (torndown) return;
|
|
35490
|
+
torndown = true;
|
|
35491
|
+
Promise.resolve(transport.close()).catch(() => {
|
|
35492
|
+
});
|
|
35493
|
+
Promise.resolve(srv.close()).catch(() => {
|
|
35494
|
+
});
|
|
35495
|
+
};
|
|
35496
|
+
res.on("close", teardown);
|
|
35497
|
+
try {
|
|
35498
|
+
await srv.connect(transport);
|
|
35499
|
+
await transport.handleRequest(req, res, bodyResult.body);
|
|
35500
|
+
mcpLogger.info("request_completed", {
|
|
35501
|
+
method: req.method,
|
|
35502
|
+
route: pathname,
|
|
35503
|
+
status: res.statusCode,
|
|
35504
|
+
durationMs: Date.now() - requestStartedAt,
|
|
35505
|
+
bodyBytes: bodyResult.bodyBytes
|
|
35506
|
+
});
|
|
35507
|
+
} catch {
|
|
35508
|
+
mcpLogger.error("request_failed", {
|
|
35509
|
+
reason: "request_handler_error",
|
|
35510
|
+
method: req.method,
|
|
35511
|
+
route: pathname,
|
|
35512
|
+
status: 500,
|
|
35513
|
+
durationMs: Date.now() - requestStartedAt,
|
|
35514
|
+
bodyBytes: bodyResult.bodyBytes
|
|
35515
|
+
});
|
|
35516
|
+
if (!res.headersSent) {
|
|
35517
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
35518
|
+
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32603, message: "Internal server error" }, id: null }));
|
|
35519
|
+
}
|
|
35520
|
+
} finally {
|
|
35521
|
+
teardown();
|
|
33945
35522
|
}
|
|
33946
35523
|
} finally {
|
|
33947
|
-
|
|
35524
|
+
requestSlot.release();
|
|
33948
35525
|
}
|
|
33949
35526
|
});
|
|
33950
|
-
httpServer.listen(port, () => {
|
|
33951
|
-
|
|
33952
|
-
|
|
33953
|
-
|
|
35527
|
+
httpServer.listen(port, host, () => {
|
|
35528
|
+
mcpLogger.info("service_started", {
|
|
35529
|
+
profile: toolProfile,
|
|
35530
|
+
retentionDays: mcpLoggingPolicy.retentionDays
|
|
35531
|
+
});
|
|
33954
35532
|
});
|
|
33955
35533
|
} else {
|
|
33956
|
-
const srv = createServer2();
|
|
35534
|
+
const srv = createServer2(toolProfile);
|
|
33957
35535
|
const transport = new StdioServerTransport();
|
|
33958
35536
|
await srv.connect(transport);
|
|
33959
35537
|
}
|
|
33960
35538
|
}
|
|
33961
|
-
main().catch((
|
|
33962
|
-
|
|
35539
|
+
main().catch(() => {
|
|
35540
|
+
mcpLogger.error("service_fatal", { reason: "service_startup_failure" });
|
|
33963
35541
|
process.exit(1);
|
|
33964
35542
|
});
|