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.
Files changed (575) hide show
  1. package/CLAUDE.md +63 -18
  2. package/README.md +121 -27
  3. package/agent-skill/semiotic-charts/SKILL.md +146 -0
  4. package/ai/cli.js +133 -45
  5. package/ai/componentMetadata.cjs +6 -1
  6. package/ai/dist/mcp-server.js +1741 -163
  7. package/ai/examples.md +174 -0
  8. package/ai/schema.json +2733 -536
  9. package/ai/surface-manifest.json +201 -0
  10. package/ai/system-prompt.md +20 -4
  11. package/dist/__tests__/scenarios/mcpProtocolTypes.d.ts +20 -0
  12. package/dist/components/AccessibleNavTree.d.ts +7 -1
  13. package/dist/components/CategoryColors.d.ts +1 -1
  14. package/dist/components/ChartContainer.d.ts +91 -0
  15. package/dist/components/ChartGrid.d.ts +11 -1
  16. package/dist/components/CircularBrush.d.ts +61 -0
  17. package/dist/components/ContextLayout.d.ts +5 -1
  18. package/dist/components/DirectManipulationControl.d.ts +63 -0
  19. package/dist/components/LinkedCharts.d.ts +3 -1
  20. package/dist/components/MobileAnnotationCalloutList.d.ts +13 -0
  21. package/dist/components/MobileChartContainer.d.ts +51 -0
  22. package/dist/components/MobileStandardControls.d.ts +68 -0
  23. package/dist/components/SmallMultipleChart.d.ts +84 -0
  24. package/dist/components/Tooltip/FlippingTooltip.d.ts +21 -0
  25. package/dist/components/ai/ChartRecipe.d.ts +16 -0
  26. package/dist/components/ai/IntentMark.d.ts +15 -0
  27. package/dist/components/ai/chartCapabilities.d.ts +8 -1
  28. package/dist/components/ai/chartCapabilityTypes.d.ts +26 -1
  29. package/dist/components/ai/chartClinic.d.ts +91 -0
  30. package/dist/components/ai/chartClinicMetadata.generated.d.ts +15 -0
  31. package/dist/components/ai/chartRecipeRegistry.d.ts +14 -0
  32. package/dist/components/ai/chartRecipes.d.ts +278 -0
  33. package/dist/components/ai/dataPitfallsBridge.d.ts +102 -0
  34. package/dist/components/ai/describeChart.d.ts +7 -0
  35. package/dist/components/ai/describeRecipeChart.d.ts +16 -0
  36. package/dist/components/ai/generativeChart.d.ts +28 -3
  37. package/dist/components/ai/intentManifest.d.ts +62 -0
  38. package/dist/components/ai/navigationTree.d.ts +3 -0
  39. package/dist/components/ai/observedSceneAudit.d.ts +72 -0
  40. package/dist/components/ai/readerGrounding.d.ts +83 -0
  41. package/dist/components/ai/recipeCapability.d.ts +8 -0
  42. package/dist/components/ai/recipeNavigation.d.ts +13 -0
  43. package/dist/components/ai/recipeSemantics.d.ts +11 -0
  44. package/dist/components/ai/repairChartConfig.d.ts +9 -0
  45. package/dist/components/ai/suggestCharts.d.ts +11 -1
  46. package/dist/components/ai/useNavigationSync.d.ts +17 -2
  47. package/dist/components/chartContainerMobile.d.ts +9 -0
  48. package/dist/components/charts/custom/GeoCustomChart.d.ts +48 -0
  49. package/dist/components/charts/custom/NetworkCustomChart.d.ts +8 -2
  50. package/dist/components/charts/custom/OrdinalCustomChart.d.ts +8 -2
  51. package/dist/components/charts/custom/XYCustomChart.d.ts +11 -2
  52. package/dist/components/charts/geo/ChoroplethMap.d.ts +19 -2
  53. package/dist/components/charts/geo/DistanceCartogram.d.ts +15 -3
  54. package/dist/components/charts/geo/FlowMap.d.ts +11 -7
  55. package/dist/components/charts/geo/ProportionalSymbolMap.d.ts +15 -3
  56. package/dist/components/charts/geo/index.d.ts +2 -0
  57. package/dist/components/charts/index.d.ts +35 -1
  58. package/dist/components/charts/network/ChordDiagram.d.ts +10 -2
  59. package/dist/components/charts/network/CirclePack.d.ts +1 -1
  60. package/dist/components/charts/network/ForceDirectedGraph.d.ts +26 -5
  61. package/dist/components/charts/network/OrbitDiagram.d.ts +1 -1
  62. package/dist/components/charts/network/ProcessSankey.d.ts +1 -1
  63. package/dist/components/charts/network/SankeyDiagram.d.ts +10 -2
  64. package/dist/components/charts/network/TreeDiagram.d.ts +1 -1
  65. package/dist/components/charts/network/Treemap.d.ts +1 -1
  66. package/dist/components/charts/network/useForceLayout.d.ts +17 -0
  67. package/dist/components/charts/ordinal/BarChart.d.ts +22 -1
  68. package/dist/components/charts/ordinal/BoxPlot.d.ts +1 -1
  69. package/dist/components/charts/ordinal/DonutChart.d.ts +1 -1
  70. package/dist/components/charts/ordinal/DotPlot.d.ts +1 -1
  71. package/dist/components/charts/ordinal/FunnelChart.d.ts +1 -1
  72. package/dist/components/charts/ordinal/GroupedBarChart.d.ts +12 -1
  73. package/dist/components/charts/ordinal/Histogram.d.ts +1 -1
  74. package/dist/components/charts/ordinal/PieChart.d.ts +1 -1
  75. package/dist/components/charts/ordinal/RidgelinePlot.d.ts +1 -1
  76. package/dist/components/charts/ordinal/StackedBarChart.d.ts +12 -1
  77. package/dist/components/charts/ordinal/SwarmPlot.d.ts +1 -1
  78. package/dist/components/charts/ordinal/SwimlaneChart.d.ts +1 -1
  79. package/dist/components/charts/ordinal/ViolinPlot.d.ts +1 -1
  80. package/dist/components/charts/physics/ChainReactionChart.d.ts +9 -0
  81. package/dist/components/charts/physics/CollisionSwarmChart.capability.d.ts +2 -0
  82. package/dist/components/charts/physics/CollisionSwarmChart.d.ts +54 -0
  83. package/dist/components/charts/physics/EventDropChart.capability.d.ts +2 -0
  84. package/dist/components/charts/physics/EventDropChart.d.ts +60 -0
  85. package/dist/components/charts/physics/GaltonBoardChart.capability.d.ts +2 -0
  86. package/dist/components/charts/physics/GaltonBoardChart.d.ts +74 -0
  87. package/dist/components/charts/physics/GauntletChart.capability.d.ts +2 -0
  88. package/dist/components/charts/physics/GauntletChart.d.ts +73 -0
  89. package/dist/components/charts/physics/PhysicalFlowChart.capability.d.ts +2 -0
  90. package/dist/components/charts/physics/PhysicalFlowChart.d.ts +63 -0
  91. package/dist/components/charts/physics/PhysicsCustomChart.d.ts +99 -0
  92. package/dist/components/charts/physics/PhysicsPileChart.capability.d.ts +2 -0
  93. package/dist/components/charts/physics/PhysicsPileChart.d.ts +60 -0
  94. package/dist/components/charts/physics/ProcessFlowChart.capability.d.ts +2 -0
  95. package/dist/components/charts/physics/ProcessFlowChart.d.ts +96 -0
  96. package/dist/components/charts/physics/chainReactionOverlay.d.ts +22 -0
  97. package/dist/components/charts/physics/chainReactionRuntime.d.ts +37 -0
  98. package/dist/components/charts/physics/chainReactionTypes.d.ts +97 -0
  99. package/dist/components/charts/physics/collisionSwarmPhysics.d.ts +27 -0
  100. package/dist/components/charts/physics/dependencyMachine.d.ts +188 -0
  101. package/dist/components/charts/physics/eventDropPhysics.d.ts +64 -0
  102. package/dist/components/charts/physics/galtonBoardPhysics.d.ts +28 -0
  103. package/dist/components/charts/physics/gauntletChartProps.d.ts +67 -0
  104. package/dist/components/charts/physics/gauntletChrome.d.ts +33 -0
  105. package/dist/components/charts/physics/gauntletController.d.ts +73 -0
  106. package/dist/components/charts/physics/gauntletEffects.d.ts +36 -0
  107. package/dist/components/charts/physics/gauntletPhysics.d.ts +71 -0
  108. package/dist/components/charts/physics/gauntletRuntime.d.ts +42 -0
  109. package/dist/components/charts/physics/gauntletTypes.d.ts +213 -0
  110. package/dist/components/charts/physics/physicalFlowPhysics.d.ts +57 -0
  111. package/dist/components/charts/physics/physicsChartShared.d.ts +57 -0
  112. package/dist/components/charts/physics/physicsChartUtils.d.ts +18 -0
  113. package/dist/components/charts/physics/physicsCustomLayout.d.ts +32 -0
  114. package/dist/components/charts/physics/physicsEncoding.d.ts +142 -0
  115. package/dist/components/charts/physics/physicsHocHandle.d.ts +53 -0
  116. package/dist/components/charts/physics/physicsHocUtils.d.ts +128 -0
  117. package/dist/components/charts/physics/physicsPilePhysics.d.ts +41 -0
  118. package/dist/components/charts/physics/physicsProcessPrimitives.d.ts +38 -0
  119. package/dist/components/charts/physics/processFlowPhysics.d.ts +97 -0
  120. package/dist/components/charts/realtime/RealtimeHeatmap.d.ts +9 -1
  121. package/dist/components/charts/realtime/RealtimeHistogram.d.ts +9 -1
  122. package/dist/components/charts/realtime/RealtimeLineChart.d.ts +9 -1
  123. package/dist/components/charts/realtime/RealtimeSwarmChart.d.ts +16 -2
  124. package/dist/components/charts/realtime/RealtimeWaterfallChart.d.ts +9 -1
  125. package/dist/components/charts/shared/AnnotationLabel.d.ts +88 -0
  126. package/dist/components/charts/shared/annotationActivation.d.ts +35 -0
  127. package/dist/components/charts/shared/annotationLabelLayout.d.ts +5 -0
  128. package/dist/components/charts/shared/annotationRules.d.ts +2 -1
  129. package/dist/components/charts/shared/auditMobileVisualization.d.ts +91 -0
  130. package/dist/components/charts/shared/chartDefinitionPilot.d.ts +145 -0
  131. package/dist/components/charts/shared/chartFamilySets.d.ts +20 -0
  132. package/dist/components/charts/shared/chartSelectionUtils.d.ts +4 -0
  133. package/dist/components/charts/shared/chartSpecCore.d.ts +165 -0
  134. package/dist/components/charts/shared/chartSpecs.d.ts +8 -127
  135. package/dist/components/charts/shared/chartSpecsGeo.d.ts +2 -0
  136. package/dist/components/charts/shared/chartSpecsNetwork.d.ts +2 -0
  137. package/dist/components/charts/shared/chartSpecsOrdinal.d.ts +2 -0
  138. package/dist/components/charts/shared/chartSpecsPhysics.d.ts +2 -0
  139. package/dist/components/charts/shared/chartSpecsRealtime.d.ts +2 -0
  140. package/dist/components/charts/shared/chartSpecsValue.d.ts +2 -0
  141. package/dist/components/charts/shared/chartSpecsXY.d.ts +2 -0
  142. package/dist/components/charts/shared/colorContrast.d.ts +3 -0
  143. package/dist/components/charts/shared/colorUtils.d.ts +16 -1
  144. package/dist/components/charts/shared/datumTypes.d.ts +2 -0
  145. package/dist/components/charts/shared/diagnoseAnnotationChecks.d.ts +6 -0
  146. package/dist/components/charts/shared/diagnoseConfig.d.ts +9 -14
  147. package/dist/components/charts/shared/diagnoseMisleadingChecks.d.ts +9 -0
  148. package/dist/components/charts/shared/diagnosePhysicsChecks.d.ts +3 -0
  149. package/dist/components/charts/shared/diagnoseTypes.d.ts +10 -0
  150. package/dist/components/charts/shared/formatUtils.d.ts +3 -3
  151. package/dist/components/charts/shared/hatchFill.d.ts +87 -0
  152. package/dist/components/charts/shared/hooks.d.ts +34 -10
  153. package/dist/components/charts/shared/knownChartComponents.d.ts +9 -0
  154. package/dist/components/charts/shared/leastSquaresRegression.d.ts +16 -0
  155. package/dist/components/charts/shared/mergeShapeStyle.d.ts +3 -2
  156. package/dist/components/charts/shared/motionEncoding.d.ts +145 -0
  157. package/dist/components/charts/shared/responsiveRules.d.ts +56 -0
  158. package/dist/components/charts/shared/semanticInteractions.d.ts +42 -0
  159. package/dist/components/charts/shared/sparseArray.d.ts +1 -1
  160. package/dist/components/charts/shared/streamPropsHelpers.d.ts +17 -5
  161. package/dist/components/charts/shared/styleRules.d.ts +205 -0
  162. package/dist/components/charts/shared/temporalStrings.d.ts +7 -0
  163. package/dist/components/charts/shared/tooltipUtils.d.ts +22 -9
  164. package/dist/components/charts/shared/types.d.ts +58 -7
  165. package/dist/components/charts/shared/useAreaSeriesSetup.d.ts +16 -2
  166. package/dist/components/charts/shared/useChartSetup.d.ts +11 -4
  167. package/dist/components/charts/shared/useCustomChartSetup.d.ts +17 -5
  168. package/dist/components/charts/shared/useFrameImperativeHandle.d.ts +1 -2
  169. package/dist/components/charts/shared/useLikertAggregation.d.ts +4 -4
  170. package/dist/components/charts/shared/useNetworkChartSetup.d.ts +6 -2
  171. package/dist/components/charts/shared/useOrdinalBrush.d.ts +2 -1
  172. package/dist/components/charts/shared/useOrdinalPieceStyle.d.ts +25 -2
  173. package/dist/components/charts/shared/useStreamingLegend.d.ts +2 -2
  174. package/dist/components/charts/shared/useSyncedPushData.d.ts +49 -0
  175. package/dist/components/charts/shared/useXYLineStyle.d.ts +10 -0
  176. package/dist/components/charts/shared/useXYPointStyle.d.ts +19 -1
  177. package/dist/components/charts/shared/validateChartData.d.ts +7 -5
  178. package/dist/components/charts/shared/validationMap.d.ts +7 -9
  179. package/dist/components/charts/shared/validationMap.generated.d.ts +6 -0
  180. package/dist/components/charts/shared/withChartWrapper.d.ts +4 -3
  181. package/dist/components/charts/value/targetPresentation.d.ts +22 -0
  182. package/dist/components/charts/value/types.d.ts +5 -6
  183. package/dist/components/charts/xy/AreaChart.d.ts +9 -1
  184. package/dist/components/charts/xy/BubbleChart.d.ts +10 -1
  185. package/dist/components/charts/xy/ConnectedScatterplot.d.ts +7 -0
  186. package/dist/components/charts/xy/DifferenceChart.d.ts +1 -52
  187. package/dist/components/charts/xy/Heatmap.d.ts +2 -2
  188. package/dist/components/charts/xy/LineChart.d.ts +12 -1
  189. package/dist/components/charts/xy/MinimapChart.d.ts +1 -1
  190. package/dist/components/charts/xy/MultiAxisLineChart.d.ts +2 -2
  191. package/dist/components/charts/xy/QuadrantChart.d.ts +8 -1
  192. package/dist/components/charts/xy/Scatterplot.d.ts +11 -1
  193. package/dist/components/charts/xy/ScatterplotMatrix.d.ts +11 -1
  194. package/dist/components/charts/xy/StackedAreaChart.d.ts +16 -4
  195. package/dist/components/charts/xy/differenceSegments.d.ts +49 -0
  196. package/dist/components/charts/xy/scatterplotMatrixInteractionTypes.d.ts +12 -0
  197. package/dist/components/controls/SentenceFilter.d.ts +97 -0
  198. package/dist/components/controls/controlAudit.d.ts +24 -0
  199. package/dist/components/controls/controlContract.d.ts +57 -0
  200. package/dist/components/data/fromFlintChart.d.ts +74 -0
  201. package/dist/components/data/fromVegaLite.d.ts +46 -9
  202. package/dist/components/data/portability/index.d.ts +6 -3
  203. package/dist/components/data/portability/result.d.ts +52 -0
  204. package/dist/components/data/portability/spec.d.ts +31 -0
  205. package/dist/components/data/portability/vegaLite.d.ts +24 -6
  206. package/dist/components/export/chartConfig.d.ts +11 -0
  207. package/dist/components/realtime/types.d.ts +11 -0
  208. package/dist/components/recipes/annotationLayout.d.ts +29 -0
  209. package/dist/components/recipes/axisFixedForce.d.ts +119 -0
  210. package/dist/components/recipes/{gofishBoba.d.ts → boba.d.ts} +2 -2
  211. package/dist/components/recipes/cyclical.d.ts +39 -0
  212. package/dist/components/recipes/edgeRouter.d.ts +103 -0
  213. package/dist/components/recipes/forceLayout.d.ts +48 -0
  214. package/dist/components/recipes/forceLayoutAsync.d.ts +17 -0
  215. package/dist/components/recipes/gofishBobaHandwritten.d.ts +3 -0
  216. package/dist/components/recipes/gofishDisplayListFixtures.generated.d.ts +37 -0
  217. package/dist/components/recipes/gofishIR.d.ts +178 -132
  218. package/dist/components/recipes/gofishIRExamples.d.ts +30 -81
  219. package/dist/components/recipes/intervalLanes.d.ts +87 -0
  220. package/dist/components/recipes/intervals.d.ts +80 -0
  221. package/dist/components/recipes/isometricLandmarks.d.ts +88 -0
  222. package/dist/components/recipes/isotypeGlyphs.d.ts +17 -0
  223. package/dist/components/recipes/mobileAnnotationStrategy.d.ts +48 -0
  224. package/dist/components/recipes/mobileChartFamilyRecipes.d.ts +59 -0
  225. package/dist/components/recipes/networkAnalysis.d.ts +102 -0
  226. package/dist/components/recipes/networkLayouts.d.ts +83 -0
  227. package/dist/components/recipes/physics.d.ts +122 -0
  228. package/dist/components/recipes/physicsReference.d.ts +102 -0
  229. package/dist/components/recipes/processAggregates.d.ts +32 -0
  230. package/dist/components/recipes/processChrome.d.ts +67 -0
  231. package/dist/components/recipes/processJourney.d.ts +54 -0
  232. package/dist/components/recipes/processPhysics.d.ts +300 -0
  233. package/dist/components/recipes/processVolumeGeometry.d.ts +28 -0
  234. package/dist/components/recipes/radialCoords.d.ts +69 -0
  235. package/dist/components/recipes/random.d.ts +2 -0
  236. package/dist/components/recipes/recipeChrome.d.ts +91 -0
  237. package/dist/components/recipes/recipeGlyph.d.ts +42 -0
  238. package/dist/components/recipes/recipeLegend.d.ts +53 -1
  239. package/dist/components/recipes/recipeUtils.d.ts +52 -0
  240. package/dist/components/recipes/runs.d.ts +59 -0
  241. package/dist/components/recipes/tokenEncoding.d.ts +157 -0
  242. package/dist/components/recipes/tokenLayer.d.ts +79 -0
  243. package/dist/components/recipes/unitize.d.ts +108 -0
  244. package/dist/components/recipes/vector.d.ts +28 -0
  245. package/dist/components/recipes/waffle.d.ts +43 -0
  246. package/dist/components/rough/createRoughRenderMode.d.ts +46 -0
  247. package/dist/components/semiotic-ai-core.d.ts +47 -0
  248. package/dist/components/semiotic-ai.d.ts +53 -9
  249. package/dist/components/semiotic-controls.d.ts +20 -0
  250. package/dist/components/semiotic-experimental.d.ts +38 -9
  251. package/dist/components/semiotic-geo.d.ts +15 -0
  252. package/dist/components/semiotic-network.d.ts +15 -0
  253. package/dist/components/semiotic-ordinal.d.ts +14 -0
  254. package/dist/components/semiotic-physics-matter.d.ts +10 -0
  255. package/dist/components/semiotic-physics-rapier.d.ts +9 -0
  256. package/dist/components/semiotic-physics.d.ts +60 -0
  257. package/dist/components/semiotic-realtime-core.d.ts +34 -0
  258. package/dist/components/semiotic-realtime-react.d.ts +10 -0
  259. package/dist/components/semiotic-realtime.d.ts +4 -30
  260. package/dist/components/semiotic-recipes-core.d.ts +92 -0
  261. package/dist/components/semiotic-recipes-react.d.ts +7 -0
  262. package/dist/components/semiotic-recipes.d.ts +4 -43
  263. package/dist/components/semiotic-rough.d.ts +4 -0
  264. package/dist/components/semiotic-server-edge.d.ts +8 -0
  265. package/dist/components/semiotic-server-node.d.ts +5 -0
  266. package/dist/components/semiotic-server.d.ts +2 -2
  267. package/dist/components/semiotic-themes-core.d.ts +53 -0
  268. package/dist/components/semiotic-themes-react.d.ts +4 -0
  269. package/dist/components/semiotic-themes.d.ts +6 -76
  270. package/dist/components/semiotic-utils-core.d.ts +50 -0
  271. package/dist/components/semiotic-utils-react.d.ts +5 -0
  272. package/dist/components/semiotic-utils.d.ts +3 -39
  273. package/dist/components/semiotic-xy.d.ts +12 -0
  274. package/dist/components/semiotic.d.ts +44 -8
  275. package/dist/components/server/animatedGif.d.ts +36 -0
  276. package/dist/components/server/optionalImageTypes.d.ts +37 -0
  277. package/dist/components/server/renderEvidence.d.ts +1 -1
  278. package/dist/components/server/renderToStaticSVG.d.ts +3 -35
  279. package/dist/components/server/serverChartConfigShared.d.ts +21 -0
  280. package/dist/components/server/serverChartConfigs.d.ts +22 -12
  281. package/dist/components/server/serverChartConfigsCustom.d.ts +5 -0
  282. package/dist/components/server/serverChartConfigsGeo.d.ts +9 -0
  283. package/dist/components/server/serverChartConfigsNetwork.d.ts +8 -0
  284. package/dist/components/server/serverChartConfigsOrdinal.d.ts +16 -0
  285. package/dist/components/server/serverChartConfigsPhysics.d.ts +9 -0
  286. package/dist/components/server/serverChartConfigsXY.d.ts +11 -0
  287. package/dist/components/server/staticAnnotations.d.ts +6 -3
  288. package/dist/components/server/staticGeo.d.ts +4 -0
  289. package/dist/components/server/staticLegend.d.ts +2 -2
  290. package/dist/components/server/staticNetwork.d.ts +8 -0
  291. package/dist/components/server/staticOrdinal.d.ts +11 -0
  292. package/dist/components/server/staticPhysics.d.ts +3 -0
  293. package/dist/components/server/staticSVGChrome.d.ts +110 -0
  294. package/dist/components/server/staticXY.d.ts +4 -0
  295. package/dist/components/store/ObservationStore.d.ts +23 -2
  296. package/dist/components/store/themeSerialization.d.ts +32 -0
  297. package/dist/components/store/useChartInterrogation.d.ts +9 -0
  298. package/dist/components/stream/AccessibleDataTable.d.ts +7 -23
  299. package/dist/components/stream/AriaLiveTooltip.d.ts +9 -0
  300. package/dist/components/stream/CanvasHitTester.d.ts +4 -4
  301. package/dist/components/stream/DataSourceAdapter.d.ts +1 -1
  302. package/dist/components/stream/FocusRing.d.ts +4 -2
  303. package/dist/components/stream/FrameRuntime.d.ts +57 -0
  304. package/dist/components/stream/GeoCanvasHitTester.d.ts +1 -1
  305. package/dist/components/stream/GeoParticlePool.d.ts +1 -1
  306. package/dist/components/stream/GeoPipelineStore.d.ts +62 -3
  307. package/dist/components/stream/GeoSVGOverlay.d.ts +64 -0
  308. package/dist/components/stream/NetworkCanvasHitTester.d.ts +2 -1
  309. package/dist/components/stream/NetworkPipelineStore.d.ts +44 -36
  310. package/dist/components/stream/NetworkSSRFrame.d.ts +17 -0
  311. package/dist/components/stream/NetworkSVGOverlay.d.ts +10 -1
  312. package/dist/components/stream/OrdinalCanvasHitTester.d.ts +2 -2
  313. package/dist/components/stream/OrdinalPipelineStore.d.ts +55 -11
  314. package/dist/components/stream/OrdinalSVGOverlay.d.ts +9 -1
  315. package/dist/components/stream/OrdinalStyleResolver.d.ts +12 -0
  316. package/dist/components/stream/ParticlePool.d.ts +1 -1
  317. package/dist/components/stream/PipelineStore.d.ts +81 -174
  318. package/dist/components/stream/SVGOverlay.d.ts +6 -0
  319. package/dist/components/stream/SceneGraph.d.ts +12 -4
  320. package/dist/components/stream/StreamGeoFrame.d.ts +1 -1
  321. package/dist/components/stream/StreamNetworkFrame.d.ts +1 -1
  322. package/dist/components/stream/StreamOrdinalFrame.d.ts +1 -1
  323. package/dist/components/stream/StreamXYFrame.d.ts +2 -18
  324. package/dist/components/stream/accessibleDataRows.d.ts +33 -0
  325. package/dist/components/stream/accessorUtils.d.ts +25 -12
  326. package/dist/components/stream/annotationAccessorResolver.d.ts +2 -2
  327. package/dist/components/stream/brushAccessibility.d.ts +25 -0
  328. package/dist/components/stream/canvasBackground.d.ts +24 -0
  329. package/dist/components/stream/canvasSetup.d.ts +4 -1
  330. package/dist/components/stream/customLayoutFailure.d.ts +33 -0
  331. package/dist/components/stream/customLayoutPalette.d.ts +19 -9
  332. package/dist/components/stream/frameGraphics.d.ts +4 -0
  333. package/dist/components/stream/frameKeyboardNavigation.d.ts +45 -0
  334. package/dist/components/stream/frameThemeColors.d.ts +24 -0
  335. package/dist/components/stream/geoAnnotationAnchors.d.ts +14 -0
  336. package/dist/components/stream/geoCartogram.d.ts +17 -0
  337. package/dist/components/stream/geoCustomLayout.d.ts +59 -0
  338. package/dist/components/stream/geoDefaultTooltip.d.ts +11 -0
  339. package/dist/components/stream/geoFrameHelpers.d.ts +34 -0
  340. package/dist/components/stream/geoPipelineHelpers.d.ts +46 -0
  341. package/dist/components/stream/geoPipelineUpdateResults.d.ts +34 -0
  342. package/dist/components/stream/geoSceneBuilder.d.ts +16 -0
  343. package/dist/components/stream/geoTypes.d.ts +97 -15
  344. package/dist/components/stream/glyphDef.d.ts +98 -0
  345. package/dist/components/stream/hitTarget.d.ts +170 -0
  346. package/dist/components/stream/hitTestUtils.d.ts +2 -2
  347. package/dist/components/stream/hoverUtils.d.ts +7 -2
  348. package/dist/components/stream/keyboardNav.d.ts +4 -1
  349. package/dist/components/stream/layouts/forceLayoutPlugin.d.ts +9 -1
  350. package/dist/components/stream/layouts/forceLayoutWorkerClient.d.ts +58 -0
  351. package/dist/components/stream/layouts/hierarchyUtils.d.ts +2 -2
  352. package/dist/components/stream/networkBezier.d.ts +10 -0
  353. package/dist/components/stream/networkColorAccessors.d.ts +49 -0
  354. package/dist/components/stream/networkCustomLayoutRunner.d.ts +23 -0
  355. package/dist/components/stream/networkCustomRestyle.d.ts +15 -0
  356. package/dist/components/stream/networkDefaultTooltip.d.ts +10 -0
  357. package/dist/components/stream/networkFrameAnimation.d.ts +7 -0
  358. package/dist/components/stream/networkFrameHandleTypes.d.ts +39 -0
  359. package/dist/components/stream/networkFrameInteraction.d.ts +37 -0
  360. package/dist/components/stream/networkFrameObservations.d.ts +15 -0
  361. package/dist/components/stream/networkFramePaint.d.ts +52 -0
  362. package/dist/components/stream/networkInteractionTypes.d.ts +26 -0
  363. package/dist/components/stream/networkPipelineConfig.d.ts +22 -0
  364. package/dist/components/stream/networkPipelineHelpers.d.ts +12 -0
  365. package/dist/components/stream/networkPipelineUpdateResults.d.ts +38 -0
  366. package/dist/components/stream/networkRealtimeEncoding.d.ts +41 -0
  367. package/dist/components/stream/networkTypes.d.ts +103 -51
  368. package/dist/components/stream/ordinalCanvasRenderers.d.ts +7 -0
  369. package/dist/components/stream/ordinalDataIndex.d.ts +5 -0
  370. package/dist/components/stream/ordinalDefaultTooltip.d.ts +10 -0
  371. package/dist/components/stream/ordinalDomain.d.ts +38 -0
  372. package/dist/components/stream/ordinalPipelineUpdateResults.d.ts +31 -0
  373. package/dist/components/stream/ordinalPulse.d.ts +10 -0
  374. package/dist/components/stream/ordinalPulseResources.d.ts +3 -0
  375. package/dist/components/stream/ordinalSceneBuilders/sceneBuilderMap.d.ts +5 -0
  376. package/dist/components/stream/ordinalSceneBuilders/types.d.ts +2 -2
  377. package/dist/components/stream/ordinalSpatialIndex.d.ts +9 -0
  378. package/dist/components/stream/ordinalTypes.d.ts +68 -9
  379. package/dist/components/stream/paintNeeds.d.ts +31 -0
  380. package/dist/components/stream/physics/CapacityQueueController.d.ts +5 -0
  381. package/dist/components/stream/physics/CapacityQueueTypes.d.ts +134 -0
  382. package/dist/components/stream/physics/MatterPhysicsEngineAdapter.d.ts +42 -0
  383. package/dist/components/stream/physics/PhysicsAccessibility.d.ts +48 -0
  384. package/dist/components/stream/physics/PhysicsAnnotations.d.ts +58 -0
  385. package/dist/components/stream/physics/PhysicsBodyBudget.d.ts +26 -0
  386. package/dist/components/stream/physics/PhysicsBodySpatialIndex.d.ts +10 -0
  387. package/dist/components/stream/physics/PhysicsCanvasTheme.d.ts +26 -0
  388. package/dist/components/stream/physics/PhysicsControllers.d.ts +75 -0
  389. package/dist/components/stream/physics/PhysicsEngineAdapter.d.ts +59 -0
  390. package/dist/components/stream/physics/PhysicsEngineConformance.d.ts +23 -0
  391. package/dist/components/stream/physics/PhysicsEvidence.d.ts +25 -0
  392. package/dist/components/stream/physics/PhysicsKernel.d.ts +207 -0
  393. package/dist/components/stream/physics/PhysicsOptionalEngineAdapters.d.ts +12 -0
  394. package/dist/components/stream/physics/PhysicsPipelineStore.d.ts +86 -0
  395. package/dist/components/stream/physics/PhysicsPipelineTypes.d.ts +181 -0
  396. package/dist/components/stream/physics/PhysicsSVGOverlay.d.ts +78 -0
  397. package/dist/components/stream/physics/PhysicsSediment.d.ts +69 -0
  398. package/dist/components/stream/physics/PhysicsSettledSVG.d.ts +18 -0
  399. package/dist/components/stream/physics/PhysicsSettledScene.d.ts +21 -0
  400. package/dist/components/stream/physics/PhysicsWorkerClient.d.ts +24 -0
  401. package/dist/components/stream/physics/PhysicsWorkerProtocol.d.ts +101 -0
  402. package/dist/components/stream/physics/PhysicsWorkerRuntime.d.ts +5 -0
  403. package/dist/components/stream/physics/RapierPhysicsEngineAdapter.d.ts +18 -0
  404. package/dist/components/stream/physics/ServiceOperationsControllers.d.ts +27 -0
  405. package/dist/components/stream/physics/ServiceOperationsTypes.d.ts +89 -0
  406. package/dist/components/stream/physics/StreamPhysicsFrame.d.ts +6 -0
  407. package/dist/components/stream/physics/StreamPhysicsTypes.d.ts +317 -0
  408. package/dist/components/stream/physics/physicsBodyCanvas.d.ts +27 -0
  409. package/dist/components/stream/physics/physicsFrameObservations.d.ts +19 -0
  410. package/dist/components/stream/physics/physicsFrameSetup.d.ts +4 -0
  411. package/dist/components/stream/physics/physicsPipelineControls.d.ts +4 -0
  412. package/dist/components/stream/physics/physicsPipelineHelpers.d.ts +41 -0
  413. package/dist/components/stream/physics/physicsPipelineObservations.d.ts +14 -0
  414. package/dist/components/stream/physics/physicsPipelineUpdateResults.d.ts +27 -0
  415. package/dist/components/stream/physics/physicsRegionRuntime.d.ts +54 -0
  416. package/dist/components/stream/physics/physicsSemanticUI.d.ts +20 -0
  417. package/dist/components/stream/physics/usePhysicsFrameLifecyclePolicy.d.ts +18 -0
  418. package/dist/components/stream/pipelineBufferUtils.d.ts +26 -0
  419. package/dist/components/stream/pipelineConfig.d.ts +179 -0
  420. package/dist/components/stream/pipelineDecay.d.ts +21 -3
  421. package/dist/components/stream/pipelineDomainResolution.d.ts +62 -0
  422. package/dist/components/stream/pipelineIdentityOps.d.ts +26 -0
  423. package/dist/components/stream/pipelinePulse.d.ts +17 -3
  424. package/dist/components/stream/pipelineRibbons.d.ts +41 -0
  425. package/dist/components/stream/pipelineSpatialIndex.d.ts +12 -0
  426. package/dist/components/stream/pipelineStoreUpdateResults.d.ts +33 -0
  427. package/dist/components/stream/pipelineStyleResolvers.d.ts +46 -0
  428. package/dist/components/stream/pipelineTransitions.d.ts +3 -1
  429. package/dist/components/stream/pipelineUpdateContract.d.ts +69 -0
  430. package/dist/components/stream/pipelineUpdateStore.d.ts +21 -0
  431. package/dist/components/stream/pulseFrameRefresh.d.ts +22 -0
  432. package/dist/components/stream/renderBackend.d.ts +27 -0
  433. package/dist/components/stream/renderers/canvasRenderHelpers.d.ts +15 -1
  434. package/dist/components/stream/renderers/geoCanvasRenderer.d.ts +3 -2
  435. package/dist/components/stream/renderers/glyphCanvasRenderer.d.ts +6 -0
  436. package/dist/components/stream/renderers/networkParticleRenderer.d.ts +1 -1
  437. package/dist/components/stream/renderers/resolveCSSColor.d.ts +6 -0
  438. package/dist/components/stream/sceneRenderBackendTypes.d.ts +28 -0
  439. package/dist/components/stream/sceneRevisionDiagnostics.d.ts +45 -0
  440. package/dist/components/stream/streamSemanticTypes.d.ts +16 -0
  441. package/dist/components/stream/streamStoreSync.d.ts +37 -0
  442. package/dist/components/stream/streamThemeTypes.d.ts +14 -0
  443. package/dist/components/stream/svgOverlayUtils.d.ts +10 -0
  444. package/dist/components/stream/test-utils/frameScheduler.d.ts +12 -0
  445. package/dist/components/stream/test-utils/revisionConsumption.d.ts +13 -0
  446. package/dist/components/stream/titleLayout.d.ts +31 -0
  447. package/dist/components/stream/types.d.ts +165 -72
  448. package/dist/components/stream/useCanvasFrameHost.d.ts +71 -0
  449. package/dist/components/stream/useFrame.d.ts +44 -2
  450. package/dist/components/stream/useHydration.d.ts +6 -0
  451. package/dist/components/stream/useLegendCategoryEmission.d.ts +5 -0
  452. package/dist/components/stream/useSemanticFrameInteractions.d.ts +22 -0
  453. package/dist/components/stream/useUpdateResultSnapshot.d.ts +7 -0
  454. package/dist/components/stream/workerModuleUrl.d.ts +10 -0
  455. package/dist/components/stream/xyAnnotationAnchors.d.ts +13 -0
  456. package/dist/components/stream/xyCanvasRenderers.d.ts +7 -0
  457. package/dist/components/stream/xyCrosshair.d.ts +11 -0
  458. package/dist/components/stream/xyDateTicks.d.ts +9 -0
  459. package/dist/components/stream/xyDefaultTooltip.d.ts +10 -0
  460. package/dist/components/stream/xyFrameAxisTypes.d.ts +50 -0
  461. package/dist/components/stream/xySceneBuilders/types.d.ts +10 -9
  462. package/dist/controls.min.js +2 -0
  463. package/dist/controls.module.min.js +2 -0
  464. package/dist/forceLayoutWorker.js +1 -0
  465. package/dist/geo.min.js +1 -1
  466. package/dist/geo.module.min.js +1 -1
  467. package/dist/network.min.js +1 -1
  468. package/dist/network.module.min.js +1 -1
  469. package/dist/ordinal.min.js +1 -1
  470. package/dist/ordinal.module.min.js +1 -1
  471. package/dist/physics-matter.min.js +1 -0
  472. package/dist/physics-matter.module.min.js +1 -0
  473. package/dist/physics-rapier.min.js +1 -0
  474. package/dist/physics-rapier.module.min.js +1 -0
  475. package/dist/physics.min.js +2 -0
  476. package/dist/physics.module.min.js +2 -0
  477. package/dist/physicsWorker.js +1 -0
  478. package/dist/realtime.min.js +1 -1
  479. package/dist/realtime.module.min.js +1 -1
  480. package/dist/rough.min.js +1 -0
  481. package/dist/rough.module.min.js +1 -0
  482. package/dist/semiotic-ai-chunk-OG7BQUUW.module.min.js +2 -0
  483. package/dist/semiotic-ai-core.d.ts +47 -0
  484. package/dist/semiotic-ai-core.min.js +1 -0
  485. package/dist/semiotic-ai-core.module.min.js +1 -0
  486. package/dist/semiotic-ai-statisticalOverlays-CY4WKR4A.module.min.js +2 -0
  487. package/dist/semiotic-ai.d.ts +53 -9
  488. package/dist/semiotic-ai.min.js +1 -1
  489. package/dist/semiotic-ai.module.min.js +1 -1
  490. package/dist/semiotic-chunk-3FSVZ46U.module.min.js +2 -0
  491. package/dist/semiotic-controls.d.ts +20 -0
  492. package/dist/semiotic-data.min.js +1 -1
  493. package/dist/semiotic-data.module.min.js +1 -1
  494. package/dist/semiotic-experimental.d.ts +38 -9
  495. package/dist/semiotic-experimental.min.js +1 -1
  496. package/dist/semiotic-experimental.module.min.js +1 -1
  497. package/dist/semiotic-geo.d.ts +15 -0
  498. package/dist/semiotic-network.d.ts +15 -0
  499. package/dist/semiotic-ordinal.d.ts +14 -0
  500. package/dist/semiotic-physics-matter.d.ts +10 -0
  501. package/dist/semiotic-physics-rapier.d.ts +9 -0
  502. package/dist/semiotic-physics.d.ts +60 -0
  503. package/dist/semiotic-realtime-core.d.ts +34 -0
  504. package/dist/semiotic-realtime-core.min.js +1 -0
  505. package/dist/semiotic-realtime-core.module.min.js +1 -0
  506. package/dist/semiotic-realtime-react.d.ts +10 -0
  507. package/dist/semiotic-realtime-react.min.js +2 -0
  508. package/dist/semiotic-realtime-react.module.min.js +2 -0
  509. package/dist/semiotic-realtime.d.ts +4 -30
  510. package/dist/semiotic-recipes-core.d.ts +92 -0
  511. package/dist/semiotic-recipes-core.min.js +1 -0
  512. package/dist/semiotic-recipes-core.module.min.js +1 -0
  513. package/dist/semiotic-recipes-react.d.ts +7 -0
  514. package/dist/semiotic-recipes-react.min.js +2 -0
  515. package/dist/semiotic-recipes-react.module.min.js +2 -0
  516. package/dist/semiotic-recipes.d.ts +4 -43
  517. package/dist/semiotic-recipes.min.js +1 -1
  518. package/dist/semiotic-recipes.module.min.js +1 -1
  519. package/dist/semiotic-rough.d.ts +4 -0
  520. package/dist/semiotic-server-edge.d.ts +8 -0
  521. package/dist/semiotic-server-edge.min.js +1 -0
  522. package/dist/semiotic-server-edge.module.min.js +1 -0
  523. package/dist/semiotic-server-node.d.ts +5 -0
  524. package/dist/semiotic-server-node.min.js +1 -0
  525. package/dist/semiotic-server-node.module.min.js +1 -0
  526. package/dist/semiotic-server.d.ts +2 -2
  527. package/dist/semiotic-statisticalOverlays-UOMSFKVJ.module.min.js +2 -0
  528. package/dist/semiotic-themes-core.d.ts +53 -0
  529. package/dist/semiotic-themes-core.min.js +1 -0
  530. package/dist/semiotic-themes-core.module.min.js +1 -0
  531. package/dist/semiotic-themes-react.d.ts +4 -0
  532. package/dist/semiotic-themes-react.min.js +2 -0
  533. package/dist/semiotic-themes-react.module.min.js +2 -0
  534. package/dist/semiotic-themes.d.ts +6 -76
  535. package/dist/semiotic-themes.min.js +1 -2
  536. package/dist/semiotic-themes.module.min.js +1 -2
  537. package/dist/semiotic-utils-core.d.ts +50 -0
  538. package/dist/semiotic-utils-core.min.js +1 -0
  539. package/dist/semiotic-utils-core.module.min.js +1 -0
  540. package/dist/semiotic-utils-react.d.ts +5 -0
  541. package/dist/semiotic-utils-react.min.js +2 -0
  542. package/dist/semiotic-utils-react.module.min.js +2 -0
  543. package/dist/semiotic-utils.d.ts +3 -39
  544. package/dist/semiotic-utils.min.js +1 -2
  545. package/dist/semiotic-utils.module.min.js +1 -2
  546. package/dist/semiotic-value.min.js +1 -1
  547. package/dist/semiotic-value.module.min.js +1 -1
  548. package/dist/semiotic-xy.d.ts +12 -0
  549. package/dist/semiotic.d.ts +44 -8
  550. package/dist/semiotic.min.js +1 -1
  551. package/dist/semiotic.module.min.js +1 -1
  552. package/dist/server.min.js +1 -1
  553. package/dist/server.module.min.js +1 -1
  554. package/dist/test-utils/capturedFrameProps.d.ts +67 -0
  555. package/dist/test-utils/frameMock.d.ts +12 -9
  556. package/dist/xy-chunk-IWD6IB6V.module.min.js +2 -0
  557. package/dist/xy-statisticalOverlays-7RWG6LJT.module.min.js +2 -0
  558. package/dist/xy.min.js +1 -1
  559. package/dist/xy.module.min.js +1 -1
  560. package/package.json +259 -88
  561. package/spec/README.md +152 -0
  562. package/spec/bindings/README.md +35 -0
  563. package/spec/bindings/vega-lite.mjs +112 -0
  564. package/spec/v0.1/annotation-provenance.schema.json +127 -0
  565. package/spec/v0.1/audience-profile.schema.json +67 -0
  566. package/spec/v0.1/chart-capability.schema.json +186 -0
  567. package/dist/components/recipes/gofish.d.ts +0 -207
  568. package/dist/components/recipes/gofishInterpreter.d.ts +0 -52
  569. package/dist/components/recipes/gofishLambdas.d.ts +0 -145
  570. package/dist/semiotic-ai-semiotic-ai-u954ylUn.js +0 -2
  571. package/dist/semiotic-ai-statisticalOverlays-CU7jW05Q.js +0 -1
  572. package/dist/semiotic-semiotic-BmrYbi99.js +0 -2
  573. package/dist/semiotic-statisticalOverlays-IjZw8Lsu.js +0 -1
  574. package/dist/xy-semiotic-xy-Dufu3D0-.js +0 -2
  575. package/dist/xy-statisticalOverlays-3Ni9bRph.js +0 -1
@@ -3206,11 +3206,11 @@ var require_utils = __commonJS({
3206
3206
  output.address = address.join("");
3207
3207
  return output;
3208
3208
  }
3209
- function normalizeIPv6(host) {
3210
- if (findToken(host, ":") < 2) {
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(host);
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(host, isIP) {
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 host.replace(re, (ch) => HOST_DELIMS[ch]);
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 host = unescape(component.host);
3388
- if (!isIPv4(host)) {
3389
- const ipV6res = normalizeIPv6(host);
3387
+ let host2 = unescape(component.host);
3388
+ if (!isIPv4(host2)) {
3389
+ const ipV6res = normalizeIPv6(host2);
3390
3390
  if (ipV6res.isIPV6 === true) {
3391
- host = `[${ipV6res.escapedHost}]`;
3391
+ host2 = `[${ipV6res.escapedHost}]`;
3392
3392
  } else {
3393
- host = reescapeHostDelimiters(host, false);
3393
+ host2 = reescapeHostDelimiters(host2, false);
3394
3394
  }
3395
3395
  }
3396
- uriTokens.push(host);
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 isObject2 = isObject;
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 (!isObject2(input)) {
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 isObject2 = isObject;
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 (!isObject2(input)) {
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 host = (incoming instanceof import_http22.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
31208
- if (!host) {
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}://${host}${incomingUrl}`);
31221
- if (url2.hostname.length !== host.length && url2.hostname !== host.replace(/:\d+$/, "")) {
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
- function stripUnsafeSvg(svg) {
32530
- return svg.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/\son[a-z]+\s*=\s*"[^"]*"/gi, "").replace(/\son[a-z]+\s*=\s*'[^']*'/gi, "").replace(/\s(href|xlink:href)\s*=\s*(["'])\s*javascript:[^"']*\2/gi, "");
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((block) => block.text.startsWith("Render evidence:\n"))?.text;
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
- return typeof props.title === "string" && props.title.trim() ? props.title.trim() : component;
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 sampleRows(meta) {
32708
- const props = meta?.props || {};
32709
- if (Array.isArray(props.data)) return props.data.slice(0, 50);
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(rows) {
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
- return '<table><thead><tr>' + columns.map((col) => '<th>' + html(col) + '</th>').join('') +
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 rows = sampleRows(hidden);
32738
- dataDrawer.innerHTML = renderTable(rows);
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 } = (0, import_server2.renderChartWithEvidence)(component, props);
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
- const validVars = Object.entries(theme).filter(([k]) => k.startsWith("--semiotic-")).map(([k, v]) => `${k}: ${v}`).join("; ");
32910
- if (validVars) {
32911
- svg = svg.replace(/<svg([^>]*)>/, `<svg$1><style>:root { ${validVars} }</style>`);
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 sharpMod = await Function('return import("sharp")')();
32917
- const sharpFn = sharpMod.default || sharpMod;
32918
- const pngBuffer = await sharpFn(Buffer.from(svg)).png().toBuffer();
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: "text", text: `data:image/png;base64,${base643}` },
33936
+ { type: "image", data: base643, mimeType: "image/png" },
32923
33937
  ...evidenceBlock ? [evidenceBlock] : []
32924
33938
  ]
32925
- };
33939
+ });
32926
33940
  } catch (err) {
32927
- if (err.code === "MODULE_NOT_FOUND" || err.code === "ERR_MODULE_NOT_FOUND") {
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: ${err.message}
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 svg = stripUnsafeSvg(rendered.content[0]?.text ?? "");
32964
- const evidence = parseRenderEvidence(rendered);
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
- props,
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
- name: "semiotic",
33449
- version: schema.version || "3.0.0"
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 string (default) or Base64-encoded PNG image, 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(", ")}.`,
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 a Base64-encoded PNG image. PNG requires the 'sharp' package.")
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.tool(
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
- component: external_exports3.string().describe("Chart component name, e.g. 'LineChart'"),
33718
- props: external_exports3.record(external_exports3.string(), external_exports3.unknown()).describe("The full chart props including data")
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.tool(
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
- component: external_exports3.string().describe("Chart component name to validate, e.g. 'PieChart'"),
33786
- data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
33787
- 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."),
33788
- maxAlternatives: external_exports3.number().int().min(1).max(10).optional().describe("Cap on alternatives returned (default 3).")
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.tool(
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
- data: external_exports3.array(external_exports3.record(external_exports3.string(), external_exports3.unknown())).describe("Row data \u2014 array of objects."),
33825
- 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."),
33826
- maxResults: external_exports3.number().int().min(1).max(40).optional().describe("Cap on suggestions returned (default 8)."),
33827
- allow: external_exports3.array(external_exports3.string()).optional().describe("Restrict to these component names."),
33828
- deny: external_exports3.array(external_exports3.string()).optional().describe("Exclude these component names."),
33829
- audience: external_exports3.object({
33830
- name: external_exports3.string().optional(),
33831
- familiarity: external_exports3.record(external_exports3.string(), external_exports3.number()).optional(),
33832
- targets: external_exports3.record(
33833
- external_exports3.string(),
33834
- external_exports3.object({
33835
- direction: external_exports3.enum(["increase", "decrease"]),
33836
- weight: external_exports3.number().int().min(1).max(3).optional(),
33837
- reason: external_exports3.string().optional()
33838
- })
33839
- ).optional(),
33840
- exposureLevel: external_exports3.union([external_exports3.literal(0), external_exports3.literal(1), external_exports3.literal(2)]).optional(),
33841
- receptionModality: external_exports3.enum(["visual", "screen-reader", "sonified", "agent"]).optional().describe("Reception channel. A non-visual value down-ranks charts the audience can't receive in that channel (e.g. a many-slice pie for a screen reader) and adds receivability caveats.")
33842
- }).optional().describe("Audience profile \u2014 familiarity, adoption targets, exposure level, and reception modality.")
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: schema.version || "3.0.0",
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
- res.setHeader("Access-Control-Allow-Origin", "*");
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
- const pathname = (() => {
33879
- try {
33880
- return new URL(req.url || "/", "http://localhost").pathname;
33881
- } catch {
33882
- return "/";
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" && (pathname === "/healthz" || pathname === "/health")) {
33895
- res.writeHead(200, { "Content-Type": "application/json" });
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
- res.writeHead(200, { "Content-Type": "application/json" });
33914
- res.end(healthBody());
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 srv = createServer2();
33923
- const transport = new StreamableHTTPServerTransport({
33924
- sessionIdGenerator: void 0,
33925
- enableJsonResponse: true
33926
- });
33927
- let torndown = false;
33928
- const teardown = () => {
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
- Promise.resolve(srv.close()).catch(() => {
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
- res.on("close", teardown);
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 srv.connect(transport);
33939
- await transport.handleRequest(req, res);
33940
- } catch (err) {
33941
- console.error("Request handling error:", err);
33942
- if (!res.headersSent) {
33943
- res.writeHead(500, { "Content-Type": "application/json" });
33944
- res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32603, message: "Internal server error" }, id: null }));
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
- teardown();
35524
+ requestSlot.release();
33948
35525
  }
33949
35526
  });
33950
- httpServer.listen(port, () => {
33951
- console.error(`Semiotic MCP server (HTTP) listening on http://localhost:${port}`);
33952
- console.error("Tools: getSchema, suggestChart, suggestCharts, proposeChartVariants, suggestStreamCharts, suggestDashboard, suggestStretchCharts, repairChartConfig, renderChart, renderInteractiveChart, interrogateChart, groundChart, diagnoseConfig, auditAccessibility, reportIssue, applyTheme");
33953
- console.error("Resources: semiotic://schema, semiotic://components, semiotic://behavior-contracts, semiotic://system-prompt, semiotic://examples, ui://semiotic/chart-widget.html");
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((err) => {
33962
- console.error("MCP server error:", err);
35539
+ main().catch(() => {
35540
+ mcpLogger.error("service_fatal", { reason: "service_startup_failure" });
33963
35541
  process.exit(1);
33964
35542
  });