@bicharts/chart-mcp 0.6.71 → 0.6.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,9 +42,10 @@ The main tools:
42
42
  call to the engine and therefore **metered** — see Signing in).
43
43
  By default it **auto-detects the project's language** (JS/TS vs Python from the
44
44
  working dir) and returns the charts for THAT language — **scoped to its renderers
45
- and ranked by the picker's chart-type×renderer weights** (best first), each tagged
45
+ and ordered by how well each type fits this data** (best first), each tagged
46
46
  with its **source language** (JavaScript for D3/Vega, Python for Plotly/matplotlib),
47
- its renderer, and a 0–100 score. Pass `language: "javascript"|"python"` to force it,
47
+ its renderer, and a 0–100 score. `order: "variety"` orders the same list for variety
48
+ instead (newer and less-common types first), for when you want to explore. Pass `language: "javascript"|"python"` to force it,
48
49
  `renderer: "D3"/"PLOTLY"/…` to rank one specific renderer, or `renderer: ""` for the
49
50
  full **renderer-agnostic** eligibility across all renderers (unranked — the wide "what
50
51
  *can* render" net). `top: N` trims to the best N. If the language can't be auto-detected
package/dist/index.mjs CHANGED
@@ -73,7 +73,7 @@ License: MIT
73
73
  `&&a[m]!=="\r";)m++;n+=" ",r=m,l=!1;continue}if(c==="/"&&d==="*"){let m=a.indexOf("*/",r+2),g=(m<0?a.slice(r+2):a.slice(r+2,m)).match(/\r\n|\r|\n/g);n+=g?g.join(""):" ",r=m<0?t:m+2,l=!1;continue}if(c==="'"||c==='"'){let m=r+1;for(;m<t&&a[m]!==c&&a[m]!==`
74
74
  `;)m+=a[m]==="\\"?2:1;n+=a.slice(r,Math.min(m+1,t)),r=m+1,i=c,s="",l=!1;continue}if(c==="`"){o.push(-1),n+=c,r++,l=!1;continue}if(c==="/"&&u()){let m=r+1,h=!1;for(;m<t&&a[m]!==`
75
75
  `;){let g=a[m];if(g==="\\"){m+=2;continue}if(g==="[")h=!0;else if(g==="]")h=!1;else if(g==="/"&&!h)break;m++}if(m<t&&a[m]==="/"){for(m++;m<t&&/[A-Za-z]/.test(a[m]);)m++;n+=a.slice(r,m),r=m,i="/",s="",l=!1;continue}}if(p!==null&&p>=0){if(c==="{")o[o.length-1]=p+1;else if(c==="}"){if(p===0){o[o.length-1]=-1,n+=c,r++;continue}o[o.length-1]=p-1}}n+=c,r++,/\s/.test(c)?l=!1:(/[A-Za-z0-9_$]/.test(c)?(s=l?s+c:c,l=!0):(s="",l=!1),i=c)}return n}var kN=Object.freeze({sankey:"d3-sankey",sankeyLinkHorizontal:"d3-sankey",sankeyJustify:"d3-sankey",sankeyCenter:"d3-sankey",sankeyLeft:"d3-sankey",sankeyRight:"d3-sankey",hexbin:"d3-hexbin",voronoiTreemap:"d3-voronoi-treemap",voronoiMap:"d3-voronoi-map",weightedVoronoi:"d3-weighted-voronoi",mermaid:"mermaid",llmMermaid:"mermaid"});function X2(e){let a=new Set,t=WN(String(e||"")),n=r=>{let o=kN[r];o&&a.add(o)};for(let r of t.matchAll(/\bd3\s*\.\s*(\w+)/g))n(r[1]);for(let r of t.matchAll(/\bd3\s*\[\s*['"](\w+)['"]\s*\]/g))n(r[1]);for(let r of t.matchAll(/\{([^{}]*)\}\s*=\s*d3\b/g))for(let o of r[1].split(","))n(o.split(":")[0].trim());return[...a].sort()}var OJ=Object.freeze({sourceId:null,rows:Object.freeze([])});/*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */var bF=10,SF=1e5,WF=1e4,Z1=e=>Object.freeze({...e,...e.values?{values:Object.freeze([...e.values])}:{}}),Vs=Object.freeze({aggregation:Z1({timing:"live-and-next-generate",default:"",values:["","sum","average","median","min","max","count","distinct"],wire:"request"}),colorScaleLow:Z1({timing:"live-and-next-generate",default:"",wire:"request"}),colorScaleHigh:Z1({timing:"live-and-next-generate",default:"",wire:"request"}),palette:Z1({timing:"live-and-next-generate",default:"",wire:"request"}),maxMapPoints:Z1({timing:"live-and-next-generate",default:Mn,min:bF,max:SF,wire:"clientHints"}),pageSize:Z1({timing:"live",default:0,min:0}),valueAxisBaseline:Z1({timing:"live",default:Gy,values:["fit","zero","auto"]}),seasonalMarkers:Z1({timing:"live",default:Xy,values:["auto","always","never"]}),animAutoPlay:Z1({timing:"live",default:!1}),animPlaySpeedMs:Z1({timing:"live",default:Kt,min:Wn,max:kn}),animLoopDelaySec:Z1({timing:"live",default:vn,min:Oy}),animStopAtEnd:Z1({timing:"live",default:!1}),animMaxIdealFrames:Z1({timing:"live",default:Vt,min:Cn,max:wn}),animTimelineStyle:Z1({timing:"live",default:"",values:["","line","boxes"]}),filtersDuringPlay:Z1({timing:"live",default:!1}),flipMode:Z1({timing:"live",default:By,values:["both","all","single"]}),flipIntervalMs:Z1({timing:"live",default:"",min:0,max:$y}),flipDirection:Z1({timing:"live",default:Hy,values:["horizontal","vertical"]}),cardBackgroundColor:Z1({timing:"live",default:""}),hoverDropLines:Z1({timing:"live",default:"",values:["","on","off"]}),levelOfDetail:Z1({timing:"next-generate",default:"",values:["","High","Medium","Low"],wire:"clientHints"}),favorLimitTo:Z1({timing:"next-generate",default:"",values:["","latest","top / greatest","bottom / smallest","most common","outliers"],wire:"clientHints"}),favorLimitCount:Z1({timing:"next-generate",default:0,min:0,max:WF,wire:"clientHints"}),favorTitle:Z1({timing:"next-generate",default:"",values:["","1","0"],wire:"clientHints"}),favorDPValues:Z1({timing:"next-generate",default:"",values:["","1","0"],wire:"clientHints"}),legendPlacement:Z1({timing:"next-generate",default:"",values:["","outside","inside","none"],wire:"clientHints"}),industryContext:Z1({timing:"next-generate",default:"",wire:"clientHints"}),suggestFontFamily:Z1({timing:"next-generate",default:"",wire:"clientHints"}),visionReview:Z1({timing:"after-render",default:!1}),saveThumbnails:Z1({timing:"after-render",default:!1})}),k11=Object.freeze(Object.keys(Vs).filter(e=>Vs[e].timing==="live"||Vs[e].timing==="live-and-next-generate"));var kF=/\.(?:getFullYear|getMonth|getDate|getDay|getHours|getMinutes|setFullYear|setMonth|setDate|setHours|setMinutes|setSeconds|setMilliseconds)\s*\(/,vF=/\bd3\s*\.\s*(?:scaleTime|time[A-Z]\w*)\b/,CF=/\bnew\s+Date\s*\(\s*[^(),]+,/,wF=/\bIntl\s*\.\s*DateTimeFormat\b|\.toLocaleDateString\s*\(|\.toLocaleTimeString\s*\(/;function AN(e){return e?kF.test(e)||vF.test(e)||CF.test(e)?!0:wF.test(e)&&!/timeZone/.test(e):!1}var _N="loose";function PN(e){return typeof e=="string"&&e.trim().toLowerCase()==="exact"?"exact":_N}function Zs(e){return typeof e!="string"||e===""?"":e.normalize("NFD").replace(/[\u0300-\u036f]/g,"").toLowerCase().replace(/\s+/g," ").trim()}var vN=2;function MF(e,a){for(let t=e.indexOf(a);t>=0;t=e.indexOf(a,t+1)){if(t===0)return!0;let n=e.charCodeAt(t-1);if(!(n>=97&&n<=122||n>=48&&n<=57))return!0}return!1}function CN(e){let a="",t=new Set,n=!1;for(let r of e){let o=m4(r),i=r.charCodeAt(0),s=i>=97&&i<=122||i>=48&&i<=57;o&&(n||t.add(a.length),a+=o),n=s}return{form:a,starts:t}}function wN(e,a){for(let t=e.form.indexOf(a);t>=0;t=e.form.indexOf(a,t+1))if(e.starts.has(t))return!0;return!1}function V2(e,a,t,n=_N){let r=Array.isArray(e)?e.slice():[],o=Zs(a);if(o.length<vN)return{rows:r,tier:"all",term:""};let i=n==="loose"?m4(o):"",s=i.length>=vN?i:"",l=[],u=[],c=[];for(let d of r){let p=t(d),m=Zs(p.name);if(m==="")continue;if(m.indexOf(o)>=0){(MF(m,o)?l:u).push(d);continue}if(s&&wN(CN(m),s)){l.push(d);continue}let h=Zs(p.description);(h.indexOf(o)>=0||s&&wN(CN(h),s))&&c.push(d)}return l.length>0?{rows:l,tier:"name",term:o}:u.length>0?{rows:u,tier:"namePart",term:o}:c.length>0?{rows:c,tier:"desc",term:o}:{rows:[],tier:"none",term:o}}function In(e){return{name:e.name,description:e.description}}function UN(e){return{name:e.name,description:e.reason}}function u3(e,a,t,n){var r,o=arguments.length,i=o<3?a:n===null?n=Object.getOwnPropertyDescriptor(a,t):n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(e,a,t,n);else for(var s=e.length-1;s>=0;s--)(r=e[s])&&(i=(o<3?r(i):o>3?r(a,t,i):r(a,t))||i);return o>3&&i&&Object.defineProperty(a,t,i),i}function L3(e,a,t){if(t||arguments.length===2)for(var n,r=0,o=a.length;r<o;r++)!n&&r in a||(n||(n=Array.prototype.slice.call(a,0,r)),n[r]=a[r]);return e.concat(n||Array.prototype.slice.call(a))}var TN=function(e,a,t){return[e,a,t].map((function(n){return(n/=255)>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92}))},RN=function(e,a,t){return[e,a,t].map((function(n){return 255*(n<=.00304?12.92*n:1.055*Math.pow(n,1/2.4)-.055)}))},fe=function(e,a,t){return Math.min(Math.max(e,a),t)},zN=function(e,a){return Math.round((e+Number.EPSILON)*Math.pow(10,a))/Math.pow(10,a)},Un=function(e,a){return Math.floor(Math.random()*(a-e+1)-e)},IN=function(e,a,t,n){for(var r,o=[e,a,t],i="#",s=0;s<o.length;s++)i+=(r=o[s],Math.round(fe(r,0,255)).toString(16).padStart(2,"0"));return n!=null&&(i+=Math.round(fe(n,0,100)/100*255).toString(16).padStart(2,"0")),i},EN=function(e){var a=e.length,t=(e=(function(o){var i=(o=/^#/.test(o)?o.slice(1):o).length;if(![3,4,6,8].includes(i))return"000000";if(i===6||i===8)return o;if(i===3||i===4){for(var s="",l=0;l<i;l++){var u=o[l];s+=""+u+u}return s}return"000000"})(e).padEnd(8,"ff")).match(/.{2}/g);if(!t)return[0,0,0,1];var n=[0,0,0],r=!1;return t.forEach((function(o,i){i<3?n[i]=parseInt(o,16):r=100*parseInt(o,16)/255})),r===!1||a<8?n:L3(L3([],n,!0),[r],!1)},xN=function(e,a,t){var n;n=[e,a,t].map((function(i){return i/255})),e=n[0],a=n[1],t=n[2];var r=1-Math.max(e,a,t),o=r<1?1/(1-r):0;return[(1-e-r)*o*100,(1-a-r)*o*100,(1-t-r)*o*100,100*r]},jN=function(e,a,t,n){return n===100?[0,0,0]:(n/=100,[e,a,t].map((function(r){return(r/=100)>=1?0:255*(1-r)*(1-n)})))};function al(e,a,t,n){var r;n===void 0&&(n="l"),r=[e,a,t].map((function(m){return m/255})),e=r[0],a=r[1],t=r[2];var o=Math.max(e,a,t),i=Math.min(e,a,t),s=(function(m,h,g,f){var y;f===void 0&&(f=!1),y=[m,h,g].map((function(C){return C/255})),m=y[0],h=y[1],g=y[2];var W=Math.max(m,h,g),k=Math.min(m,h,g),A=0;if(W!==k)if(f)A=(m-h+(m-g))/2,A/=Math.sqrt((m-h)*(m-h)+(m-g)*(h-g)),A=Math.acos(A),g>h&&(A=2*Math.PI-A),A/=2*Math.PI;else{var P=W-k;A=W===m?(h-g)/P+(h<g?6:0):W===h?(g-m)/P+2:(m-h)/P+4,A/=6}else A=NaN;return 360*A})(e,a,t,n==="i"),l=0,u=(o+i)/2,c=o-i,d=o,p=(e+a+t)/3;return n==="v"&&(l=o===0?0:c/o),o!==i&&n==="l"&&(l=u>.5?c/(2-o-i):c/(o+i)),n==="i"&&(l=p>0?1-i/p:0),l*=100,u*=100,p*=100,n==="l"?[s,l,u]:n==="v"?[s,l,d*=100]:[s,l,p]}var tl=function(e,a,t){return al(e,a,t,"l")},Z4=function(e,a,t){var n,r,o=function(i){return 6*(i=i<0?i+1:i>1?i-1:i)<1?n+(r-n)*i*6:2*i<1?r:3*i<2?n+(r-n)*(.6666666666666666-i)*6:n};return e=e%360/360,a=fe(a/100,0,1),t=fe(t/100,0,1),n=2*t-(r=t<=.5?t*(a+1):t+a-t*a),[255*o(e+1/3),255*o(e),255*o(e-1/3)]},LN=function(e,a,t){return al(e,a,t,"v")},nl=function(e,a,t){var n,r,o=[t/=100,t*(1-(a/=100)),t*(1-(r=(e=e%360/360*360)/60-(n=Math.floor(e/60%6)))*a),t*(1-(1-r)*a)],i=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return[255*o[i[n][0]],255*o[i[n][1]],255*o[i[n][2]]]},FN=function(e,a,t){return al(e,a,t,"i")},rl=function(e,a,t){var n,r,o,i;a/=100,t/=100,isNaN(e)&&(e=0),isNaN(a)&&(a=0);var s=function(l){return(1+a*Math.cos(2*Math.PI*l)/Math.cos(Math.PI/3-2*Math.PI*l))/3};return(e=(360+e)%360/360)<1/3?o=1-((i=(1-a)/3)+(r=s(e))):e<2/3?i=1-((r=(1-a)/3)+(o=s(e-=1/3))):r=1-((o=(1-a)/3)+(i=s(e-=2/3))),n=[r,o,i].map((function(l){return 255*fe(t*l*3,0,1)})),[r=n[0],o=n[1],i=n[2]]},DN=function(e,a,t){return[tl(e,a,t)[0],100*(Math.min(e,a,t)/255),100*(1-Math.max(e,a,t)/255)]};function ol(e,a,t){return a/=100,t/=100,Z4(e,100,50).map((function(n){return 255*(n/255*(1-a-t)+a)}))}var qs={x:[.4124564,.3575761,.1804375],y:[.2126729,.7151522,.072175],z:[.0193339,.119192,.9503041]},Js={r:[3.2404542,-1.5371385,-.4985314],g:[-.969266,1.8760108,.041556],b:[.0556434,-.2040259,1.0572252]},ON=.95047,BN=1,$N=1.08883,AF=.206896552,_F=.008856452,HN=24389/27,Ys=function(e,a,t){var n=TN(e,a,t);return[100*qs.x.reduce((function(r,o,i){return r+o*n[i]}),0),100*qs.y.reduce((function(r,o,i){return r+o*n[i]}),0),100*qs.z.reduce((function(r,o,i){return r+o*n[i]}),0)]},Z2=function(e,a,t){var n=[e,a,t],r=Js.r.reduce((function(s,l,u){return s+l*n[u]}),0)/100,o=Js.g.reduce((function(s,l,u){return s+l*n[u]}),0)/100,i=Js.b.reduce((function(s,l,u){return s+l*n[u]}),0)/100;return RN(r,o,i)},Tn=function(e,a,t){var n;return n=[e=e/ON/100,a=a/BN/100,t=t/$N/100].map((function(r){return r>_F?Math.pow(r,1/3):(HN*r+16)/116})),e=n[0],a=n[1],t=n[2],[Math.max(0,116*a-16),500*(e-a),200*(a-t)]},il=function(e,a,t){var n,r=(e+16)/116,o=isNaN(a)?r:r+a/500,i=isNaN(t)?r:r-t/200;return n=[o,r,i].map((function(s){return s>AF?Math.pow(s,3):(116*s-16)/HN})),o=n[0],r=n[1],i=n[2],[o*ON*100,r*BN*100,i*$N*100]},sl=function(e,a,t){return Z2.apply(void 0,il(e,a,t))},Qs=function(e,a,t){a=fe(a,-100,100),t=fe(t,-100,100);var n=Math.sqrt(a*a+t*t),r=(180*Math.atan2(t,a)/Math.PI+360)%360;return Math.round(1e4*n)===0&&(r=Number.NaN),[e,n,r]},GN=function(e,a,t){return isNaN(t)&&(t=0),t*=Math.PI/180,[e,Math.cos(t)*a,Math.sin(t)*a]},ll=function(e,a,t){return il.apply(void 0,GN(e,a,t))},XN=function(e,a,t){var n=e+a+t,r=0,o=0;return n>0&&(r=e/n,o=a/n),[r,o,a]},PF=Object.freeze({__proto__:null,linear2rgb:RN,rgb2linear:TN,rgb2hex:IN,hex2rgb:EN,rgb2cmyk:xN,cmyk2rgb:jN,rgb2hsl:tl,hsl2rgb:Z4,rgb2hsv:LN,hsv2rgb:nl,rgb2hsi:FN,hsi2rgb:rl,rgb2hwb:DN,hwb2rgb:ol,rgb2xyz:Ys,xyz2rgb:Z2,xyz2lab:Tn,lab2xyz:il,rgb2lab:function(e,a,t){return Tn.apply(void 0,Ys(e,a,t))},lab2rgb:sl,lch2lab:GN,lab2lch:Qs,xyz2lch:function(e,a,t){return Qs.apply(void 0,Tn(e,a,t))},lch2xyz:ll,xyY2xyz:function(e,a,t){return a===0?[0,0,0]:[e*(t/a),t,t/a*(1-e-a)]},xyz2xyY:XN});function j3(e,a){return a===void 0&&(a=!1),function(t,n,r){var o=r.value;r.value=function(){for(var i=[],s=0;s<arguments.length;s++)i[s]=arguments[s];if(i.length>0&&a){var l=JSON.stringify(i);e+=l}if(this.cache.has(e))return this.cache.get(e);var u=o.call.apply(o,L3([this],i,!1));return this.cache.set(e,u),u}}}function S3(e,a,t,n){return e===void 0&&(e=[0,2,2]),a===void 0&&(a=0),t===void 0&&(t=!0),n===void 0&&(n=0),function(r,o,i){var s=i.value;i.value=function(){for(var l=[],u=0;u<arguments.length;u++)l[u]=arguments[u];var c=l[n]===void 0?t:l[n],d=s.call.apply(s,L3([this],l,!1));if(c===!1)return d;var p=typeof c=="number"?Math.round(c):0,m=typeof e=="number"?new Array(d.length).fill(e):e,h=m.map((function(g){return a===1?typeof c=="number"?p:g:g+p}));return d.map((function(g,f){return zN(g,h[f])}))}}}var KN=function(e,a,t){var n=e instanceof be?e:new be(e),r=a instanceof be?a:new be(a),o=fe(t,0,100)/100,i=2*o-1,s=n.alpha()-r.alpha(),l=((i*s==-1?i:(i+s)/(1+i*s))+1)/2,u=1-l,c=[Math.round(fe(n.red()*l+r.red()*u,0,255)),Math.round(fe(n.green()*l+r.green()*u,0,255)),Math.round(fe(n.blue()*l+r.blue()*u,0,255))],d=n.alpha()*o+r.alpha()*(1-o);return new be(c,d)},t3=Math.sqrt,x1=Math.pow,Qt=Math.cos,K2=Math.abs,MN=Math.sin,UF=Math.exp,TF=Math.atan2,VN=Math.PI,V4=function(e){return VN*e/180},el=function(e,a,t){t===void 0&&(t=!0);var n=TF(a,e);return t&&(n=(n=(n=180*n/VN)>0?n:n+360)>360?n-360:n),n},e8=function(e,a){a===void 0&&(a=!0);var t=e.lab(!1),n=t[0],r=t[1],o=t[2];return[n,t3(x1(r,2)+x1(o,2)),el(r,o,a),r,o]},RF=["CMC","CIE","CIE2000","CIE1994","CIE1976"],zF="CMC",IF="CIE2000",EF="CIE1994",xF="CIE1976",ZN=function(e,a,t,n){t===void 0&&(t="CIE");var r=(function(c){var d=c.toUpperCase();return RF.includes(d)&&d!=="CIE"?d:IF})(t);if(n=n||{},r===zF){var o=Object.assign({},{l:1,c:1},n);return(function(c,d,p,m){p===void 0&&(p=1),m===void 0&&(m=1);var h=e8(c,!0),g=h[0],f=h[1],y=h[2],W=h[3],k=h[4],A=e8(d),P=A[0],C=A[1],I=A[3],$=f-C,v=g-P,N=k-A[4],M=t3(x1(W-I,2)+x1(N,2)-x1($,2)),_=g<16?.511:.040975*g/(1+.01765*g),S=.0638*f/(1+.0131*f)+.638,b=164<=y&&y<=345?.56+K2(.2*Qt(V4(y+168))):.36+K2(.4*Qt(V4(y+35))),w=t3(x1(f,4)/(x1(f,4)+1900)),z=S*(w*b+1-w);return t3(x1(v/(p*_),2)+x1($/(m*S),2)+x1(M/z,2))})(e,a,o.l,o.c)}if(r===EF){var i={kL:1,kC:1,kH:1,cate:"graphic"},s=Object.assign({},i,n);return(function(c,d,p,m,h,g){p===void 0&&(p=1),m===void 0&&(m=1),h===void 0&&(h=1),g===void 0&&(g="graphic");var f=g==="textiles"?.048:.045,y=g==="textiles"?.014:.015;p=g==="textiles"?2:p;var W=e8(c),k=W[0],A=W[1],P=W[3],C=W[4],I=e8(d),$=I[0],v=I[1],N=I[3],M=k-$,_=A-v,S=C-I[4],b=1+f*A,w=1+y*A,z=t3(x1(P-N,2)+x1(S,2)-x1(_,2));return t3(x1(M/(1*p),2)+x1(_/(m*b),2)+x1(z/(h*w),2))})(e,a,s.kL,s.kC,s.kH,s.cate)}if(r===xF)return(function(c,d){var p=c.lab(!1),m=p[0],h=p[1],g=p[2],f=d.lab(!1),y=f[0],W=f[1],k=f[2];return t3(x1(m-y,2)+x1(h-W,2)+x1(g-k,2))})(e,a);var l={kL:1,kC:1,kH:1},u=Object.assign({},l,n);return(function(c,d,p,m,h){p===void 0&&(p=1),m===void 0&&(m=1),h===void 0&&(h=1);var g=e8(c),f=g[0],y=g[1],W=g[3],k=g[4],A=e8(d),P=A[0],C=A[1],I=A[3],$=A[4],v=(f+P)/2,N=(y+C)/2,M=(1-t3(x1(N,7)/(x1(N,7)+x1(25,7))))/2,_=W*(1+M),S=I*(1+M),b=t3(x1(_,2)+x1(k,2)),w=t3(x1(S,2)+x1($,2)),z=el(_,k,!0),E=el(S,$,!0),R=(b+w)/2,B=K2(z-E)>180?(z+E+360)/2:(z+E)/2,x=1-.17*Qt(V4(B-30))+.24*Qt(V4(2*B))+.32*Qt(V4(3*B+6))-.2*Qt(V4(4*B-63)),X=K2(E-z)<=180?E-z:K2(E-z)>180&&E<=z?E-z+360:E-z-360,O=P-f,L=C-y,U=2*t3(b*w)*MN(V4(X)/2),K=1+.015*x1(v-50,2)/t3(20+x1(v-50,2)),D=1+.045*R,q=1+.015*R*x,w1=30*UF(-x1((B-275)/25,2)),Y=-2*t3(x1(R,7)/(x1(R,7)+x1(25,7)))*MN(2*V4(w1));return t3(x1(O/(p*K),2)+x1(L/(m*D),2)+x1(U/(h*q),2)+Y*(L/(m*D))*(U/(h*q)))})(e,a,u.kL,u.kC,u.kH)},jF=function(e,a,t){var n=Math.abs,r=Math.max,o=Math.min,i=e instanceof be?e:new be(e),s=a instanceof be?a:new be(a),l=Object.assign({},{b:125,c:500},t);return!(n(255*i.brightness()/100-255*s.brightness()/100)<=l.b)&&!(r(i.red(),s.red())-o(i.red(),s.red())+(r(i.green(),s.green())-o(i.green(),s.green()))+(r(i.blue(),s.blue())-o(i.blue(),s.blue()))<=l.c)},a8=function(e,a,t){var n,r=function(u){return fe(u,0,100)},o=function(u){return fe(u,0,255)},i={h:[0,function(u){return u%360}],s:[1,r],l:[2,r],r:[0,o],g:[1,o],b:[2,o]},s=i[a][0];if(["h","s","l"].includes(a)){var l=e.hsl();if(t===void 0)return l[s];t=i[a][1](t),l[s]=t,n=Z4.apply(void 0,l)}else{if(n=e.rgb(),t===void 0)return n[s];t=i[a][1](t),n[s]=t}return new be(n,e.alpha())},zn={},LF=new Set(["rgb","rgba","cmyk","lab","hsl","hsla","hsv","hsva","hsi","hsia","xyz","lch","hwb","hwba"]),FF=/^([a-zA-Z]+)\(([\s\S]+)\)$/,Rn=function(e){return typeof e=="string"?e.indexOf("%")===-1?Rn(Number(e.trim())):(e=e.split("%")[0],(e=Number(e.trim()))||0):Math.abs(e)<1?100*e:e},qN=function(e,a){a===void 0&&(a=new Set);var t=typeof e=="string"?e:e.join(",");if(a.has(t))throw new Error("Invalid Color");a.add(t);var n="rgb",r=[0,0,0],o=100;if(Array.isArray(e)){if(e.length<3)throw new Error("Invalid Color");for(var i=0;i<e.length;i++)if(i<3)r[i]=e[i];else{if(i!==3||e[3]===void 0)break;o=e[3]}}else{var s=!1,l=e.trim().match(FF);if(l||(s=!0),l){var u=l[1].toLocaleLowerCase();if(n=u,LF.has(u)||(s=!0),l[2]&&!s){var c=l[2],d=c.indexOf(",")!==-1?",":" ",p=c.split(d);for(i=0;i<3;i++)p[i]!==void 0&&(["lch","lab"].includes(n)&&i===0||["hsl","hsla","hsv","hsva","hwb","hwba","hsi","hsia"].includes(n)&&i>0?r[i]=Rn(p[i]):r[i]=Number(p[i].trim()));["rgba","hsla","hsva","hwba","hsia"].includes(n)?(n=n.slice(0,-1),p[3]!==void 0&&(o=Rn(p[3]))):n==="cmyk"&&r.push(p[3]!==void 0?Rn(p[3]):0)}}if(s){if(!/^#(([a-fA-F\d]{3}){1,2}|[a-fA-F\d]{8})$/.test(e))try{return e=(function(m,h){if(h===void 0&&(h=!1),m=m.toLowerCase(),zn[m]===void 0){if(h)throw new Error("Unknown color name: ".concat(m,")"));return m}return zn[m]})(e,!0),qN(e,a)}catch{throw new Error("Invalid Color")}r=EN(e)}}return[n,r,o]},JN={thowParseError:!1},be=(function(){function e(a,t,n){this.cache=new Map,this._rgb=[0,0,0],this._alpha=100;var r={thowParseError:JN.thowParseError},o=Object.assign({},r,n??{});try{var i=(function(u){var c,d={lab2rgb:sl,hsl2rgb:Z4,hsv2rgb:nl,xyz2rgb:Z2,hwb2rgb:ol,hsi2rgb:rl},p=qN(u),m=p[0],h=p[1],g=p[2];if(m==="rgb")return[h,g];m==="lch"&&(m=(c=["xyz",ll(h[0],h[1],h[2])])[0],h=c[1]);var f=h[0],y=h[1],W=h[2],k=h[3];if(m==="cmyk")return[jN(f,y,W,k).map((function(P){return fe(P,0,255)})),g];var A="".concat(m,"2rgb");if(typeof d[A]=="function")return[d[A](f,y,W).map((function(P){return fe(P,0,255)})),g];throw new Error("Invalid color")})(a),s=i[0],l=i[1];this._alpha=l,this._rgb=s}catch(u){if(o.thowParseError)throw u}t!==void 0&&(this._alpha=fe(t,0,100))}return e.prototype.red=function(a){return a8(this,"r",a)},e.prototype.green=function(a){return a8(this,"g",a)},e.prototype.blue=function(a){return a8(this,"b",a)},e.prototype.alpha=function(a){return a===void 0?this._alpha:(a=fe(a,0,100),new e(this.rgb(),a))},e.prototype.fadeIn=function(a,t){return a===void 0&&(a=10),a=t&&t==="relative"?this._alpha*a/100:a,new e(this.rgb(),fe(this._alpha+a,0,100))},e.prototype.fadeOut=function(a,t){return a===void 0&&(a=10),a=t&&t==="relative"?this._alpha*a/100:a,new e(this.rgb(),fe(this._alpha-a,0,100))},e.prototype.opacify=function(a,t){return a===void 0&&(a=10),this.fadeIn(a,t)},e.prototype.transparentize=function(a,t){return a===void 0&&(a=10),this.fadeOut(a,t)},e.prototype.hue=function(a){return a8(this,"h",a)},e.prototype.saturation=function(a){return a8(this,"s",a)},e.prototype.lightness=function(a){return a8(this,"l",a)},e.prototype.rgb=function(a){return L3([],this._rgb,!0)},e.prototype.rgba=function(a){return L3(L3([],this.rgb(!1),!0),[this._alpha],!1)},e.prototype.cmyk=function(a){return xN.apply(void 0,this._rgb)},e.prototype.hsl=function(a){return tl.apply(void 0,this._rgb)},e.prototype.hsla=function(a){return L3(L3([],this.hsl(!1),!0),[this._alpha],!1)},e.prototype.hsv=function(a){return LN.apply(void 0,this._rgb)},e.prototype.hsi=function(a){return FN.apply(void 0,this._rgb)},e.prototype.hwb=function(a){return DN.apply(void 0,this._rgb)},e.prototype.xyz=function(a){return Ys.apply(void 0,this._rgb)},e.prototype.lab=function(a){return Tn.apply(void 0,this.xyz(!1))},e.prototype.lch=function(a){return Qs.apply(void 0,this.lab(!1))},e.prototype.xyY=function(a){return XN.apply(void 0,this.xyz(!1))},e.prototype.hex=function(a){a===void 0&&(a=2);var t=a===0?void 0:a===1?this._alpha:this._alpha===100?void 0:this._alpha,n="color:hex:param_".concat(a);if(this.cache.has(n))return this.cache.get(n);var r=IN.apply(void 0,L3(L3([],this._rgb,!1),[t],!1));return this.cache.set(n,r),r},e.prototype.lighten=function(a,t){a===void 0&&(a=5);var n=this.hsl(!1),r=n[0],o=n[1],i=n[2];return i=fe(i+=t!==void 0&&t==="relative"?i*(a/100):a,0,100),new e(Z4(r,o,i),this._alpha)},e.prototype.darken=function(a,t){return a===void 0&&(a=5),this.lighten(-a,t)},e.prototype.saturate=function(a,t){a===void 0&&(a=5);var n=this.hsl(!1),r=n[0],o=n[1],i=n[2];return o=fe(o+=t!==void 0&&t==="relative"?o*(a/100):a,0,100),new e(Z4(r,o,i),this._alpha)},e.prototype.desaturate=function(a,t){return a===void 0&&(a=5),this.saturate(-a,t)},e.prototype.spin=function(a){var t=this.hsl(!1),n=t[0],r=t[1],o=t[2];return new e(Z4(n=(n+a%360+360)%360,r,o),this._alpha)},e.prototype.adjustHue=function(a){return this.spin(a)},e.prototype.complement=function(){return this.spin(180)},e.prototype.invert=function(){var a=this._rgb.map((function(t){return 255-t}));return new e([a[0],a[1],a[2]],this._alpha)},e.prototype.mix=function(a,t){return t===void 0&&(t=50),KN(this,a,100-fe(t,0,100))},e.prototype.luma=function(){var a=this._rgb.map((function(t){return(t/=255)<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4)}));return .2126*a[0]+.7152*a[1]+.0722*a[2]},e.prototype.brightness=function(){var a=this._rgb;return(function(t,n,r){return(299*t+587*n+114*r)/1e3/255*100})(a[0],a[1],a[2])},e.prototype.deltaE=function(a,t,n){return t===void 0&&(t="CMC"),ZN(this,a,t,n)},e.prototype.visibility=function(a,t){return jF(this,a,t)},u3([S3(0,1,!0,0),j3("color:rgb")],e.prototype,"rgb",null),u3([S3(0,1,!0,0)],e.prototype,"rgba",null),u3([S3(0,1,!0,0),j3("color:cmyk")],e.prototype,"cmyk",null),u3([S3(0,1,!0,0),j3("color:hsl")],e.prototype,"hsl",null),u3([S3(0,1,!0,0)],e.prototype,"hsla",null),u3([S3(0,1,!0,0),j3("color:hsv")],e.prototype,"hsv",null),u3([S3(0,1,!0,0),j3("color:hsi")],e.prototype,"hsi",null),u3([S3(0,1,!0,0),j3("color: hwb")],e.prototype,"hwb",null),u3([S3(2,1,!0,0),j3("color:xyz")],e.prototype,"xyz",null),u3([S3(2,1,!0,0),j3("color:lab")],e.prototype,"lab",null),u3([S3(2,1,!0,0),j3("color:lch")],e.prototype,"lch",null),u3([S3(2,1,!0,0),j3("color:xyY")],e.prototype,"xyY",null),u3([j3("color:luma")],e.prototype,"luma",null),e})(),DF=function(e,a,t,n){return new be([e,a,t],n)},OF=function(e,a,t,n){return new be(Z4(e,a,t),n)},BF=function(e,a,t,n){return new be(nl(e,a,t),n)},$F=function(e,a,t,n){return new be(rl(e,a,t),n)},HF=function(e,a,t,n){return new be(ol(e,a,t),n)},GF=function(e,a,t,n){return new be(Z2(e,a,t),n)},XF=function(e,a,t,n){return new be(sl(e,a,t),n)},KF=function(e,a,t,n){return new be(Z2.apply(void 0,ll(e,a,t)),n)};function Re(e,a,t){return new be(e,a,t)}Re.config=function(e){Object.assign(JN,e)},Re.random=function(){var e=Un(0,255),a=Un(0,255),t=Un(0,255);return new be([e,a,t])},Re.convertor=PF,Re.Color=be,Re.rgb=DF,Re.hsl=OF,Re.hsv=BF,Re.hsi=$F,Re.hwb=HF,Re.xyz=GF,Re.lab=XF,Re.lch=KF,Re.mix=KN,Re.deltaE=ZN,Re.utils={roundDecimal:zN,randomRange:Un},Re.useNames=function(e,a){return(function(t,n){if(n!==void 0&&typeof n=="function"){var r={};for(var o in t){var i=n(o,t[o]),s=i[0],l=i[1];r[s]=l}Object.assign(zn,r)}else Object.assign(zn,t)})(e,a),Re};var YN=9e5,VF=15e3,QN=2e3,ZF=12e4,qF=3e4,JF=3e5,YF=6e4;function eb(e){return e<ZF?VF:e<JF?qF:YF}function QF(e){return e?typeof e.c!="string"||e.c.trim()==="":!1}function ab(e,a){return!e||typeof e.c!="string"||e.c.trim()===""||typeof a!="string"||a.trim()===""?!1:a.trim().toLowerCase()===e.c.trim().toLowerCase()}function tb(e,a,t){return e?(t??0)>=e.v?"delivered":a-e.t>YN?"expired":QF(e)?"blind":"poll":"none"}function nb(e,a){return Math.max(0,e.t+YN-a)}var eD="The connection dropped before the chart finished - nothing was charged. Generate again.";function rb(e){let a=String(e??"").trim();return a!==""?a:eD}function ul(e,a){return a}function ob(e){if(!e)return null;let a=String(e.pollOutcome??"").trim().toLowerCase();if(e.isGenerationCancelled===!0||e.isPollFinal===!0&&a==="cancelled")return"cancelled";if(e.isPollFinal===!0)return a==="not-received"?"not-received":"failed";if(e.isPollFinal==null&&e.isVersionNotFound===!0){let t=String(e.errorCode??"").trim().toUpperCase();if(t==="GENERATION_NOT_RECEIVED")return"not-received";if(t==="GENERATION_FAILED")return"failed";if(t==="GENERATION_CANCELLED")return"cancelled"}return null}function ib(e){return e==="window-closed"||e==="hard-error"||e==="unreachable"}var aD=3;function sb(e,a){return!a&&e>=aD}var tD="The connection dropped before the chart finished - nothing was charged. Generate again.",nD="The charting service has no record of that request, so nothing was generated and nothing was charged. Generate again.",rD="That chart didn't finish on the server, so there's nothing to show. Generate again.",lb="We couldn't reach the charting service to check on your chart - it may be offline, or blocked on this network. Try again in a moment.";function ub(e,a){let t=String(a??"").trim();return t!==""?t:e==="cancelled"?tD:e==="not-received"?nD:rD}import{createServer as oD}from"node:http";import{createHash as iD,randomBytes as db}from"node:crypto";import{spawn as sD}from"node:child_process";import{homedir as lD,hostname as uD}from"node:os";import{dirname as cD,join as dD}from"node:path";import{chmodSync as hD,mkdirSync as pD,readFileSync as mD,renameSync as gD,rmSync as fD,writeFileSync as yD}from"node:fs";var q2="OAUTH_TOKEN_EXPIRED",Q3="OAUTH_SIGNED_OUT";function cb(e,a){let t=(a??"").trim();return!t||e.licenseKey!==""||e.licensee!==""||e.secretKey!==""?{}:{accessToken:t}}var hl="chart-mcp",ND=18e4,bD=6e4,SD=6e5,hb=384,t8="SIGN_IN_REQUIRED",pl="SIGN_IN_UNREACHABLE";function WD(e){let[a,t]=process.platform==="win32"?["rundll32",["url.dll,FileProtocolHandler",e]]:process.platform==="darwin"?["open",[e]]:["xdg-open",[e]],n=sD(a,t,{detached:!0,stdio:"ignore",windowsHide:!0});n.on("error",()=>{}),n.unref()}var kD={fetch:(e,a)=>fetch(e,a),openBrowser:WD,log:e=>{process.stderr.write(e+`
76
- `)},now:()=>Date.now(),hostname:()=>uD()},n8={...kD},fb=null;function yb(e){fb=e}function ml(e){if(e==null)return;let a=e.trim();return a===""||/^\$\{[^}]*\}$/.test(a)?void 0:a}function gl(e=process.env){return/^(off|0|false|no)$/i.test(ml(e.BIC_SIGNIN)??"")}function Nb(e){let a=Number(ml(e.BIC_SIGNIN_WAIT_MS));return Number.isFinite(a)&&a>=0?a:ND}function fl(e=process.env){return ml(e.BIC_OAUTH_FILE)??dD(lD(),".bic","oauth.json")}function yl(e){try{let a=JSON.parse(mD(fl(e),"utf-8"));return a&&typeof a=="object"&&!Array.isArray(a)?a:{}}catch{return{}}}function bb(e,a=process.env){let t=yl(a)[e];return!t||typeof t!="object"||t.base!==e||typeof t.accessToken!="string"||typeof t.refreshToken!="string"||!t.refreshToken?null:t}function Sb(e,a=process.env){let t=yl(a);t[e.base]=e,Wb(t,a)}function pb(e,a=process.env){let t=yl(a);if(e in t){if(delete t[e],Object.keys(t).length>0){Wb(t,a);return}try{fD(fl(a),{force:!0})}catch{}}}function Wb(e,a){let t=fl(a);pD(cD(t),{recursive:!0,mode:448});let n=`${t}.${process.pid}.tmp`;yD(n,JSON.stringify(e,null,2),{encoding:"utf-8",mode:hb});try{hD(n,hb)}catch{}gD(n,t)}function kb(e){return`Sign in to continue. It's free to try, and nothing needs configuring: ${e} - or, on a machine with no browser, set a license key instead (BIC_LICENSEE and BIC_LICENSE_KEY).`}function vb(e){return`You've been signed out. Sign in again to continue: ${e}`}function vD(e){return`Run the request again to open a new sign-in: the last one was canceled in the browser, so nothing was sent. ${e}`}function mb(e,a){return`Run the request again to open a new sign-in: the last one didn't finish (${e}). ${a}`}function CD(e,a){return`Try the request again in a moment: your sign-in couldn't be renewed because the service didn't answer (${e}). ${a}`}async function Cb(e,a,t){let n;try{n=await n8.fetch(`${e}/api/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(a).toString(),signal:AbortSignal.timeout(3e4)})}catch(u){return{kind:"unreachable",detail:String(u?.message??u)}}let r=null;try{r=JSON.parse(await n.text())}catch{}if(n.status>=500||n.status!==200&&!r)return{kind:"unreachable",detail:`HTTP ${n.status}`};if(n.status!==200)return{kind:"rejected",error:String(r?.error??"invalid_request"),description:String(r?.error_description??"")};let o=typeof r?.access_token=="string"?r.access_token:"",i=typeof r?.refresh_token=="string"&&r.refresh_token?r.refresh_token:t;if(!o||!i)return{kind:"unreachable",detail:"the answer carried no sign-in"};let s=n8.now(),l=Number(r.expires_in);return{kind:"ok",entry:{base:e,accessToken:o,accessExpiresUtc:new Date(s+(Number.isFinite(l)&&l>0?l:3600)*1e3).toISOString(),refreshToken:i,obtainedUtc:new Date(s).toISOString()}}}var cl=new Map;function wD(e,a,t){let n=cl.get(e);if(n)return n;let r=(async()=>{let o=await Cb(e,{grant_type:"refresh_token",refresh_token:a.refreshToken,client_id:hl},a.refreshToken);return o.kind==="ok"&&Sb(o.entry,t),o})().finally(()=>cl.delete(e));return cl.set(e,r),r}var xn=new Map,En=new Map;function dl(e){return e.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function J2(e,a,t,n){let r=`<!doctype html><html><head><meta charset="utf-8"><title>${t}</title></head><body style="font-family:system-ui,sans-serif;max-width:32em;margin:4em auto;line-height:1.5"><h1 style="font-size:1.4em">${t}</h1><p>${n}</p></body></html>`;e.writeHead(a,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store",Connection:"close"}),e.end(r)}async function MD(e,a){let t=dl(db(32)),n=dl(iD("sha256").update(t).digest()),r=dl(db(16)),o=null,i=null,s,l=new Promise(f=>{s=f}),u=!1,c=f=>{u||(u=!0,s(f),xn.get(e)===g&&xn.delete(e),i&&clearTimeout(i),setTimeout(()=>o?.close(),50).unref?.())},d="";o=oD((f,y)=>{(async()=>{let W=new URL(f.url??"/","http://127.0.0.1");if(W.pathname!=="/callback"){y.writeHead(404,{Connection:"close"}),y.end();return}if(W.searchParams.get("state")!==r){J2(y,400,"This sign-in link is out of date","It doesn't match the sign-in your editor is waiting for. Close this tab and use the newest link.");return}let k=W.searchParams.get("error");if(k){J2(y,200,"Sign-in canceled","Nothing was shared. You can close this tab."),c({ok:!1,canceled:k==="access_denied",detail:k});return}let A=W.searchParams.get("code")??"",P=await Cb(e,{grant_type:"authorization_code",code:A,code_verifier:t,redirect_uri:d,client_id:hl},null);if(P.kind!=="ok"){let C=P.kind==="rejected"?P.description||P.error:P.detail;J2(y,200,"Sign-in didn't finish",`${C}. You can close this tab and try again from your editor.`),c({ok:!1,canceled:!1,detail:C});return}Sb(P.entry,a),J2(y,200,"You're signed in","You can close this tab and go back to your editor - it's carrying on."),c({ok:!0,entry:P.entry})})().catch(W=>{try{J2(y,500,"Sign-in didn't finish","Something went wrong here. You can close this tab.")}catch{}c({ok:!1,canceled:!1,detail:String(W?.message??W)})})}),await new Promise((f,y)=>{o.once("error",y),o.listen(0,"127.0.0.1",()=>f())}),d=`http://127.0.0.1:${o.address().port}/callback`;let m=new URLSearchParams({response_type:"code",client_id:hl,redirect_uri:d,code_challenge:n,code_challenge_method:"S256",state:r,scope:"charts",device_name:(n8.hostname()||"").slice(0,64)}),g={url:`${e}/oauth/authorize?${m.toString()}`,done:l,waitedOut:!1,close:()=>c({ok:!1,canceled:!1,detail:"the sign-in was closed"})};return i=setTimeout(()=>c({ok:!1,canceled:!1,detail:"the sign-in link expired"}),Math.max(SD,Nb(a))),i.unref?.(),o.unref(),g}function AD(e){let a=`Sign in to continue - your browser is opening this page (open it yourself if it doesn't): ${e}`;n8.log(`[bic-chart] ${a}`);try{fb?.(a)}catch{}}async function _D(e,a,t){let n=xn.get(e);if(!n){let u=En.get(e),c=!u;u||(u=MD(e,a).then(d=>(xn.set(e,d),AD(d.url),d)),En.set(e,u),u.then(()=>En.delete(e),()=>En.delete(e)));try{n=await u}catch(d){return{ok:!1,code:t8,message:mb(`no local port: ${d?.message??d}`,e)}}if(c)try{await n8.openBrowser(n.url)}catch{}}let r=()=>({ok:!1,code:t?Q3:t8,message:t?vb(n.url):kb(n.url)}),o=u=>{if(u.ok===!0)return{ok:!0,accessToken:u.entry.accessToken};let c=u;return{ok:!1,code:t8,message:c.canceled?vD(e):mb(c.detail,e)}};if(n.waitedOut)return r();let i=null,s=new Promise(u=>{i=setTimeout(()=>u("timeout"),Nb(a))}),l=await Promise.race([n.done,s]);return i&&clearTimeout(i),l==="timeout"?(n.waitedOut=!0,r()):o(l)}async function wb(e,a,t){let n=bb(e,a),r=!!n&&!!t.refused&&n.accessToken===t.refused.token,o=!n&&!!t.refused?.signedOut;if(n&&r&&t.refused.signedOut&&(pb(e,a),n=null,o=!0),n){let i=Date.parse(n.accessExpiresUtc)-n8.now();if(!r&&i>bD)return{ok:!0,accessToken:n.accessToken};let s=await wD(e,n,a);if(s.kind==="ok")return{ok:!0,accessToken:s.entry.accessToken};if(s.kind==="unreachable")return!r&&i>0?{ok:!0,accessToken:n.accessToken}:{ok:!1,code:pl,message:CD(s.detail,e)};pb(e,a),o=!0}return t.interactive?_D(e,a,o):{ok:!1,code:o?Q3:t8,message:o?vb(e):kb(e)}}var gb=!1;function Mb(e,a,t){return gb||t||gl(a)||bb(e,a)?null:(gb=!0,"Sign in to see which charts fit this data: call list_eligible_charts, and its first call opens a browser sign-in. It's free to try, and nothing needs configuring.")}import{AsyncLocalStorage as PD}from"node:async_hooks";var Nl="X-BIC-Client-IP",jn=new PD,Ab=!1;function _b(e,a){return jn.run(e,a)}function Pb(){return jn.getStore()}function Ub(){Ab=!0}function g4(){return Ab||jn.getStore()!==void 0}var bl="Reconnect this chart server to continue: your sign-in for it has expired or was signed out. Reconnect it in your app's connector or MCP settings and sign in again, then repeat the request.";function Tb(e){let a=Array.isArray(e)?e[0]:e,t=/^\s*Bearer\s+(\S+)\s*$/i.exec(a??"");return t?t[1]:null}function Rb(e){let a=(Array.isArray(e)?e[0]:e??"").trim();return/^[0-9A-Za-z.:%_-]{1,64}$/.test(a)?a:void 0}function Ln(e){return{post(a,t,n,r){let o=jn.getStore()?.clientIp;return e.post(a,t,o?{...n,[Nl]:o}:n,r)}}}var ED="2Qy@Y\\{>",Sl=ps(ED);function Fn(e){return jy({signer:Sl,transport:Ln(Sn((a,t)=>fetch(a,t))),clock:{now:()=>Date.now()}},{baseUrl:()=>Y2(e),apiPath:"/api",nocache:a=>UD(a==="qualify"?8:16).toString("hex")})}function Bb(e){return AbortSignal.timeout(e),e>0?e:Number.MIN_VALUE}var xD="2.1.0.0",jD=new Set(["D3","PLOTLY"]);function $b(e=process.env){let a=e.BIC_CREDENTIALS_FILE||ID(zD(),".bic","credentials.json");try{return JSON.parse(RD(a,"utf-8"))}catch{return{}}}function f4(e){return e!=null&&/^\$\{[^}]*\}$/.test(e.trim())?void 0:e}function Wl(e=process.env){let a=$b(e),t={licenseKey:f4(e.BIC_LICENSE_KEY)??a.licenseKey??"",licensee:f4(e.BIC_LICENSEE)??a.licensee??"",secretKey:f4(e.BIC_SECRET_KEY)??a.secretKey??""};if(!t.licenseKey||!t.licensee)throw new Error(`Missing BIC trial/paid credentials. Set BIC_LICENSE_KEY + BIC_LICENSEE (BIC_SECRET_KEY optional) in the MCP server's env, or put {"licenseKey":"\u2026","licensee":"\u2026"} in ~/.bic/credentials.json. MCP access requires a trial or paid account (no freemium).`);return t}var zb={licenseKey:"",licensee:"",secretKey:""};function Hb(e){try{return Wl(e)}catch{return null}}async function Dn(e,a){if(g4())return LD();let t=Hb(e);if(t)return{kind:"key",auth:t};if(gl(e))return{kind:"none"};let n=a.refusedWith?.credential,r=n?.kind==="token"?{token:n.accessToken,signedOut:a.refusedWith.code===Q3}:void 0,o=await wb(Y2(e),e,{interactive:a.interactive,refused:r});if(o.ok===!0)return{kind:"token",accessToken:o.accessToken};let i=o;return{kind:"failed",code:i.code,message:i.message}}async function Gb(e,a,t){return a.kind!=="token"||t!==q2&&t!==Q3?null:g4()?{kind:"failed",code:t,message:bl}:Dn(e,{interactive:!0,refusedWith:{credential:a,code:t}})}function LD(){let e=Pb()?.accessToken?.trim();return e?{kind:"token",accessToken:e}:{kind:"failed",code:Q3,message:bl}}function Xb(e){let a;try{a=JSON.parse(e)}catch{return null}let t=String(a?.errorCode??a?.ErrorCode??"");return t!==q2&&t!==Q3?null:{code:t,message:String(a?.errorMessage??a?.ErrorMessage??t)}}function kl(e){return e.kind==="key"?{auth:e.auth}:e.kind==="token"?{auth:zb,accessToken:e.accessToken}:{auth:zb}}function Kb(e=process.env){return Mb(Y2(e),e,Hb(e)!==null)}function Y2(e=process.env){let a=$b(e);return(f4(e.BIC_URL)??a.url??"https://bizintelligencechampions.com").replace(/\/+$/,"")}function On(e=process.env){return f4(e.BIC_MCP_CLIENT_VERSION)??xD}function Q2(e,a,t=process.env,n){let r=TD(),o=Py(e.shape),i=(e.fontFamily??"").replace(/[^A-Za-z0-9 ,.\-]/g," ").replace(/\s+/g," ").trim().slice(0,100),s=_y({measure:()=>({width:Math.round(e.width??800),height:Math.round(e.height??600)})}),l=Ay({triple:()=>({licensee:a.licensee.trim(),licenseKey:a.licenseKey.trim(),secretKey:a.secretKey.trim()})});return{payload:{...l.request,...cb(l.request,n),clientVersion:On(t),host:"SDK",...g4()?{mcpHosted:!0}:{},supportsStreaming:!0,...s.request,totalRows:e.totalRows,cultureCode:e.cultureCode??"en-US",...bs({genNew:!0,settingVersion:0}),identifier:"",temp:R0,modifiers:[],backgroundColor:"#ffffff",palette:"",shape:e.shape,model:e.model??f4(t.BIC_MCP_MODEL)??"",renderer:e.renderer??"D3",language:e.language??"",sampleCsv:e.sampleCsv??null,...Ty({budget:3}),rendererSpecificPayload:null,reasoningMode:e.reasoningMode||t.BIC_MCP_REASONING||"",...Uy({renderers:jD}),correlationId:r,compactness:"",clientHints:{supportsDatasetGlobal:!0,supportsMermaid:!0,supportsHtmlScene:!0,...s.hints,rowCount:e.totalRows,...Ry(e.leafCardinality),maxNonMeasureCardinality:o,favorStyle:e.chartHint??"",userCommentary:e.prompt??"",...e.rowsPolicy?{rowsPolicy:e.rowsPolicy}:{},...e.requiredColumns?.length?{requiredColumns:e.requiredColumns}:{},...e.forbidDerivedColumns?{forbidDerivedColumns:!0}:{},...e.levelOfDetail?{levelOfDetail:e.levelOfDetail}:{},...i?{suggestFontFamily:i}:{},...e.geoExtent?{geoExtent:e.geoExtent}:{}}},correlationId:r}}function FD(e){if(e.ok||!e.isServiceError||T0(e)||e.isRateLimited===!0||!e.raw)return!1;let a=My(Ns(e.raw));if(a!==null)return a;let t=(e.errorMessage||"").toLowerCase();return/billed|still be running|completed server-side|may have completed/.test(t)||/no credits were used|nothing was generated/.test(t)?!1:/could ?n[o']?t reach|unable to reach|provider|upstream|rate.?limit|temporarily|try again|timed? out contacting|service unavailable/.test(t)}var Ib=[2e3,6e3];async function Vb(e,a=process.env){let t=Math.max(0,Math.min(2,Number(f4(a.BIC_MCP_GENERATE_RETRIES)??1))),n=[],r=null;for(let o=0;o<=t;o++){if(o>0){let i=Ib[Math.min(o-1,Ib.length-1)];e.onProgress?.(`Provider unavailable \u2014 retrying in ${Math.round(i/1e3)}s (attempt ${o+1} of ${t+1})`),await new Promise(s=>setTimeout(s,i))}if(r=await OD(e,a),r.correlationId&&n.push(r.correlationId),!FD(r))break}return r&&!r.ok&&n.length>1?{...r,errorMessage:`${r.errorMessage} (retried ${n.length} times; correlationIds: ${n.join(", ")})`}:r}function Bn(e,a){return{ok:!1,code:"",language:"",version:0,errorMessage:a,isServiceError:!0,isRefusal:!1,isRateLimited:!1,retryAfterSeconds:null,outputHash:"",codeSummary:"",finalChartName:"",warningMessage:"",creditCost:null,geoColumn:"",geoKind:"",pointCityColumn:"",pointStateColumn:"",pointZipColumn:"",pointCountryColumn:"",pointLatColumn:"",pointLonColumn:"",destPointCityColumn:"",destPointStateColumn:"",destPointZipColumn:"",destPointCountryColumn:"",destPointLatColumn:"",destPointLonColumn:"",correlationId:e,raw:null}}function Zb(e,a){let t=Ns(e),n=t.geoPointCols??{},r=n.dest??{};return{ok:!!t.code&&!t.errorMessage,code:t.code,language:t.language,version:t.version,errorMessage:t.errorMessage,isServiceError:t.isServiceError,isRefusal:t.isRefusal,isRateLimited:t.isRateLimited,retryAfterSeconds:t.retryAfterSeconds,outputHash:t.outputHash,codeSummary:t.codeSummary,finalChartName:t.finalChartName,warningMessage:t.warningMessage,creditCost:t.creditCost,geoColumn:t.geoColumn,geoKind:t.geoKind,pointCityColumn:n.city??"",pointCountryColumn:n.country??"",pointStateColumn:n.state??"",pointZipColumn:n.zip??"",pointLatColumn:n.lat??"",pointLonColumn:n.lon??"",destPointCityColumn:r.city??"",destPointCountryColumn:r.country??"",destPointStateColumn:r.state??"",destPointZipColumn:r.zip??"",destPointLatColumn:r.lat??"",destPointLonColumn:r.lon??"",correlationId:a,servedCorrelationId:t.servedCorrelationId,isVersionNotFound:t.isVersionNotFound,isGenerationCancelled:t.isGenerationCancelled,...DD(t),raw:e}}function DD(e){let a={};return typeof e.isPollFinal=="boolean"&&(a.isPollFinal=e.isPollFinal),typeof e.pollOutcome=="string"&&e.pollOutcome!==""&&(a.pollOutcome=e.pollOutcome),typeof e.errorCode=="string"&&e.errorCode!==""&&(a.errorCode=e.errorCode),a}function Eb(e){return{...Bn("",e.message),isServiceError:!1,errorCode:e.code}}async function OD(e,a){let t=await Dn(a,{interactive:!0});if(t.kind==="failed")return Eb(t);let n=await xb(e,a,t),r=await Gb(a,t,n.errorCode);return r?r.kind==="failed"?Eb(r):xb(e,a,r):n}async function xb(e,a,t){let{auth:n,accessToken:r}=t.kind==="none"?{auth:Wl(a),accessToken:void 0}:kl(t),{payload:o,correlationId:i}=Q2(e,n,a,r),s=Number(f4(a.BIC_MCP_TIMEOUT_MS)??9e5),l=Date.now(),u=f=>Bn(i,f),c=f=>({...u(`Cancelled after ${f}s. The server was told to stop and bills only the passes that had already completed; nothing further is running. correlationId ${i}.`),isServiceError:!1}),d=f=>u(`Gave up waiting after ${f}s \u2014 this MCP client's own timeout (BIC_MCP_TIMEOUT_MS=${s}). The generation may still be running server-side and may be billed. Raise BIC_MCP_TIMEOUT_MS, or lower the cost of the request (simpler chart type, fewer rows, reasoning_mode "1P"). correlationId ${i}.`),p=(f,y)=>e.signal?.aborted?c(f):y?.name==="TimeoutError"||y?.name==="AbortError"?d(f):u(`Could not reach the BIC backend after ${f}s: ${String(y?.message??y)}. correlationId ${i}.`),m;try{m=Bb(s)}catch(f){return p(Math.round((Date.now()-l)/1e3),f)}let h=await Fn(a).generate(o,{timeoutMs:m,signal:e.signal??null,onStage:e.onProgress??null}),g=Math.round((Date.now()-l)/1e3);if(h.kind==="transport"&&!h.headersReceived){let f=h.error,y=f?.name==="TimeoutError"||f?.name==="AbortError";return e.signal?.aborted||y||BD(f)||!ul(!1,o.genNew)?p(g,h.error):Db({correlationId:i,startedAt:l,cutAtMs:Date.now(),deadlineAt:l+s,pick:e.chartHint??"",cause:String(f?.message??f),signal:e.signal,onProgress:e.onProgress,preHeader:!0},{fetchByCorrelation:W=>jb(e,i,a,W),refund:()=>Fb(i,a),now:()=>Date.now(),sleep:Lb})}if(h.kind==="http"){let y=(h.status===499||h.status===502||h.status===504)&&h.bodyStart.trim().length===0?`The connection was cut by an intermediary after ${g}s (HTTP ${h.status}, empty body) while the request was still in flight. The generation very likely COMPLETED server-side and MAY HAVE BEEN BILLED \u2014 it just could not be delivered. Raising this client's timeout will NOT help: the ceiling is a gateway between us, not your wait. Get under it by making the request cheaper \u2014 a simpler chart type, fewer rows, or reasoning_mode "1P" \u2014 and quote correlationId ${i} to BIC support to recover or refund this generation.`:`HTTP ${h.status}: ${h.bodyStart} (correlationId ${i})`,W=Xb(h.bodyStart);return W?{...u(W.message),isServiceError:!1,errorCode:W.code}:u(y)}if(h.kind==="transport"){let f=h.error;if(e.signal?.aborted)return c(g);if(f?.name==="TimeoutError"||f?.name==="AbortError")return d(g);let y=String(f?.message??f);return ul(!0,o.genNew)?Db({correlationId:i,startedAt:l,cutAtMs:Date.now(),deadlineAt:l+s,pick:e.chartHint??"",cause:y,signal:e.signal,onProgress:e.onProgress},{fetchByCorrelation:W=>jb(e,i,a,W),refund:()=>Fb(i,a),now:()=>Date.now(),sleep:Lb}):u(`The response stream ended after ${g}s without a result. The generation may have COMPLETED and BEEN BILLED \u2014 quote correlationId ${i} to BIC support to recover or refund it. (${y})`)}return Zb(h.value,i)}function BD(e){let a=String(e?.message??"");return e?.cause?.code==="ERR_INVALID_URL"||/^Failed to parse URL\b/.test(a)||/cannot keep a deadline/.test(a)}var $D=6e4;async function jb(e,a,t,n){let r=await Dn(t,{interactive:!1}),{auth:o,accessToken:i}=r.kind==="none"?{auth:Wl(t),accessToken:void 0}:kl(r),{payload:s}=Q2(e,o,t,i),l=await Fn(t).generate({...s,...bs({genNew:!1,fetchCorrelationId:a}),supportsStreaming:!1},{timeoutMs:$D,signal:n??null});if(l.kind==="transport")throw l.error;return l.kind==="http"?Bn(a,`HTTP ${l.status}: ${l.bodyStart}`):Zb(l.value,a)}function Lb(e,a){return new Promise((t,n)=>{if(a?.aborted){n(a.reason??new Error("aborted"));return}let r=()=>{clearTimeout(o),n(a?.reason??new Error("aborted"))},o=setTimeout(()=>{a?.removeEventListener("abort",r),t()},e);a?.addEventListener("abort",r,{once:!0})})}var HD=5e3;async function Fb(e,a=process.env){let t=Fn(a);if(typeof t.refund!="function")return{sent:!1,ok:!1,message:"this build has no refund call, so no refund was requested"};try{let n=await t.refund(e,{timeoutMs:HD});return n.kind==="answer"?{sent:!0,ok:n.value?.ok===!0,message:String(n.value?.message??"")}:n.kind==="http"?{sent:!0,ok:!1,message:`HTTP ${n.status}`}:{sent:!1,ok:!1,message:"the refund could not reach the service"}}catch(n){return{sent:!1,ok:!1,message:String(n?.message??n)}}}async function Db(e,a){let t={v:1,t:e.startedAt,c:e.correlationId,p:e.pick,h:0},n=Math.round((e.cutAtMs-e.startedAt)/1e3),r=()=>Math.min(nb(t,a.now()),e.deadlineAt-a.now()),o=m=>Bn(e.correlationId,m),i=`It may still complete and be billed \u2014 quote correlationId ${e.correlationId} to BIC support to recover or refund it.`,s=e.preHeader?`Could not reach the BIC backend after ${n}s: ${e.cause} - no answer arrived, though the server may still have received the request`:`The response stream was cut after ${n}s, after the server had accepted the request`,l=async m=>{if(!ib(m)||!a.refund)return i;let h;try{h=await a.refund()}catch(g){h={sent:!1,ok:!1,message:String(g?.message??g)}}return h.sent?`A refund for it was requested (the server applies it once the generation is recorded, unless the chart was delivered: ${h.message||(h.ok?"refunded":"no answer")}). Quote correlationId ${e.correlationId} to BIC support if anything looks wrong.`:`${i} (The automatic refund request could not be sent: ${h.message}.)`};if(tb(t,a.now(),0)!=="poll"||r()<=0)return o(`${s}, and there is no time left in this call to check for the chart. ${i} (${e.cause})`);let u=QN,c=0,d=0,p=!1;for(;;){try{await a.sleep(Math.max(0,Math.min(u,r())),e.signal)}catch{}if(e.signal?.aborted)return{...o(`Cancelled while checking for a chart whose response stream was cut after ${n}s. The server had already accepted that generation, so cancelling the check did not stop it. ${i}`),isServiceError:!1};c++,e.onProgress?.(`The connection dropped after ${n}s, before the chart arrived. Checking for it on the server (check ${c})`);let m=null;try{m=await a.fetchByCorrelation(e.signal)}catch{}if(!m||!m.raw&&m.isServiceError?d++:(p=!0,d=0),m?.ok&&m.code&&ab(t,m.servedCorrelationId))return{...m,correlationId:e.correlationId,creditCost:null,recoveredAfterMs:a.now()-e.startedAt};let h=ob(m);if(h==="cancelled")return o(`${rb(m.errorMessage)} correlationId ${e.correlationId}.`);if(h==="failed"||h==="not-received")return{...o(`${ub(h,m.errorMessage)} correlationId ${e.correlationId}.`),isServiceError:!1,isPollFinal:!0,pollOutcome:h,...m.errorCode?{errorCode:m.errorCode}:{}};if(sb(d,p))return o(`${s}. ${lb} This client checked ${c} time(s) and no check reached the service. ${await l("unreachable")} (${e.cause})`);if(!(!m||m.ok&&!!m.code||m.isVersionNotFound||m.isServiceError&&!m.isRefusal))return o(`${s}. Checking for the chart by its correlation, the server answered that there is nothing to deliver: ${m.errorMessage||"no code returned"}. correlationId ${e.correlationId}. ${await l("hard-error")}`);if(r()<=0){let f=Math.round((a.now()-e.cutAtMs)/1e3);return o(`${s}. This client checked for the finished chart ${c} time(s) over ${f}s and it had not arrived when the wait ended (the shared recovery window, or BIC_MCP_TIMEOUT_MS, whichever is sooner). ${await l("window-closed")} (${e.cause})`)}u=eb(a.now()-t.t)}}var $n="metered: free within an hourly allowance, usage credits beyond it";async function vl(e,a=process.env){let t=await Dn(a,{interactive:!0});if(t.kind==="failed")return{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:t.message,errorCode:t.code};let n=await Ob(e,a,t),r=await Gb(a,t,n.errorCode);return r?r.kind==="failed"?{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:r.message,errorCode:r.code}:Ob(e,a,r):n}async function Ob(e,a,t){let{auth:n,accessToken:r}=kl(t),{payload:o}=Q2({shape:e.shape,totalRows:e.totalRows,leafCardinality:e.leafCardinality,geoExtent:e.geoExtent,width:e.width,height:e.height,renderer:e.renderer??"",language:e.language??"",levelOfDetail:e.levelOfDetail},n,a,r),i=Fn(a),s=async p=>i.qualify(o,{timeoutMs:Bb(Number(f4(a.BIC_MCP_QUALIFY_TIMEOUT_MS)??6e4)),route:p}),l=await s("/RegiaBI/whatfits");if(l.kind==="http"&&l.status===404&&(l=await s("/LLMChart/qualify")),l.kind==="transport")throw l.error;if(l.kind==="http"){let p=Xb(l.bodyStart);return p?{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:p.message,errorCode:p.code}:{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:`HTTP ${l.status}: ${l.bodyStart.slice(0,200)}`}}let u=wy(l.value);if(u.errorMessage)return{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:u.errorMessage,...u.errorCode?{errorCode:u.errorCode}:{}};let c=(u.charts??[]).map(p=>({name:p.name,description:p.description,rank:p.rank,score:p.score,renderer:p.renderer,language:p.language,recommended:p.recommended,isPreview:p.isPreview})),d=u.refused.map(p=>({name:p.name,reason:p.reason,isVeto:p.isVeto}));return{ok:!0,charts:c,refused:d,noFitSummary:u.noFitSummary,errorMessage:""}}/*! @bicharts/shape-core — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; US Census/TIGER (public domain). Full text: NOTICE in this package. */function GD(e){return!e||!e.trim()?0:Math.max(0,e.trim().split(/\r?\n/).length-1)}function qb(e,a,t="",n=process.env){let{payload:r}=Q2(e,{licenseKey:"",licensee:"",secretKey:""},n),o=GD(e.sampleCsv),i=V0(r,{sampleNote:`${o} obfuscated sample row(s) travel at privacy_level ${a}; their values are not shown here. Lower privacy_level to send none.`,emptyShapeNote:"No columns were measured - pass csv_path, csv_text or data."});return{head:`NOTHING WAS SENT. This is the request generate_chart would send for these arguments${t}, with the licence, install id and correlation id removed (they are credentials, not your data). privacy_level ${a}: ${o>0?`${o} obfuscated sample row(s) travel`:"no rows travel - only the measured shape"}.`,preview:i,sampleRows:o}}function Hn(e){let t=(e||"").replace(/[^A-Za-z0-9]+/g," ").trim().split(/\s+/).filter(Boolean).map(n=>n[0].toUpperCase()+n.slice(1)).join("");return(!t||/^[0-9]/.test(t))&&(t="Bic"+t),t.endsWith("Chart")?t:t+"Chart"}var XD=/^__.*__$/;function Jb(e){let a=Hn(e.chartName),t=e.columns.filter(s=>!XD.test(s.name)).map(s=>({name:s.name,dataType:s.dataType,isMeasure:!!s.isMeasure})),n=e.plugins.flatMap((s,l)=>["// eslint-disable-next-line @typescript-eslint/ban-ts-comment",`// @ts-ignore - ${s} often ships no type declarations; the chart only reaches it through d3. npm install ${s}`,`import * as d3Plugin${l} from "${s}";`]),r=e.plugins.map((s,l)=>`d3Plugin${l}`),o=s=>JSON.stringify(s,null,2),i=!!e.defaultOptions&&Object.keys(e.defaultOptions).length>0;return[`// BIC generated React host for "${e.chartName}" - renders ./chart.js through @bicharts/chart-host.`,"// Regenerate with the MCP generate_chart tool rather than editing: it is rewritten with the chart.",'import { useMemo } from "react";','import * as d3base from "d3";',...n,'import { assembleD3, type GeoPointBinding, type MarkAnnotation, type Filter, type Controls } from "@bicharts/chart-host";','import { BicChart, BicChartGroup } from "@bicharts/chart-host/react";','import code from "./chart.js?raw";',"","/** The columns this chart was generated for. Each row must be keyed by these names. */",`export const columns = ${o(t)};`,"","/** How the payload is built from rows: the choropleth join, and where points and a route's far end come from. */","export const binding: {"," geo: { column: string; kind: string } | null;"," point: GeoPointBinding | null;"," destination: GeoPointBinding | null;",`} = ${o(e.binding)};`,"",'/** The geometry the chart draws on ("" when it draws none). */',`export const geoKind = ${JSON.stringify(e.geoKind||"")};`,"",...i?["/** Options the user chose for this chart when it was generated; the options prop still overrides them. */",`const chartDefaults = ${JSON.stringify(e.defaultOptions)};`,""]:[],"// One d3 for the chart, with the plugins its code calls attached (an ES-module d3 namespace cannot be assigned onto).",`const d3 = assembleD3(d3base${r.length?", "+r.join(", "):""});`,"",'const key = (s: string) => s.replace(/^[^[]*\\[(.+)\\]$/, "$1").toLowerCase().replace(/[^a-z0-9]/g, "");',"","/**"," * Rows keyed by this chart's column names, from a query result of { columns: [{ name }], rows: [[...]] }.",` * A DAX result's "Table[Column]" and "[Measure]" headers match by the bracketed name, ignoring case, spaces and`,' * punctuation, so "[Average Daily Rate]" fills AverageDailyRate with no alias. Pass `rename` for anything else.'," */","export function rowsFromTable("," table: { columns: { name: string }[]; rows: unknown[][] },"," rename: Record<string, string> = {},","): Record<string, unknown>[] {"," const wanted = new Map(columns.map((c) => [key(c.name), c.name]));"," const target = table.columns.map((c) => rename[c.name] ?? wanted.get(key(c.name)));"," return table.rows.map((r) => {"," const o: Record<string, unknown> = {};"," target.forEach((t, k) => { if (t) o[t] = r[k]; });"," return o;"," });","}","",`export interface ${a}Props {`," /** The live query result as it arrives ({ columns, rows }); mapped with rowsFromTable. Or pass rows. */"," table?: { columns: { name: string }[]; rows: unknown[][] };"," /** Header -> column name, for any header rowsFromTable can't match by name. */"," rename?: Record<string, string>;"," /** Rows already keyed by the chart's column names, instead of table. */"," rows?: Record<string, unknown>[];"," width: number;"," height: number;"," /**",' * The page filter a click on this chart sets - from useBicFilter("<key column>") in @bicharts/chart-host/react.'," * A click sets it, the same click or empty canvas clears it, filter.clear() clears the marks too, and new data"," * keeps a pick it still draws. Read filter.value / filter.row on the page; no select handler to write."," */"," selects?: Filter;"," /**",' * Show only the rows a page filter keeps - { filter: region, columns: ["OriginCode", "DestinationCode"] }'," * keeps a route that starts or ends in the selected region (columns default to the filter's key). Applied here,"," * after the rows are mapped, so the chart redraws only when the filter or the data changes."," */"," filterBy?: { filter: Filter; columns?: string[] };"," /** What a screen reader announces for the chart. Defaults to the chart type's name. */"," ariaLabel?: string;",' /** What the chart says when it has no rows to draw ("Nothing for this filter"). */'," emptyText?: string;"," /** The data lacks a column the chart is built on: called with the chart's reason instead of the chart throwing. */"," onInvalidSentinel?: (info: { reason: string; message: string }) => void;"," /**"," * The chart's own controls (a What-if chart's sliders) as page state - from useBicControls(). values holds"," * every knob from the first draw, summary the chart's own label and readout; set(saved) applies a scenario."," */"," controls?: Controls;"," /**"," * The clicked marks' source rows - read a stable key from them (an id or code), never a row position. An empty"," * list means the selection was CLEARED (the same mark clicked again, empty canvas, or new data without it): set"," * your state from exactly this, never toggle it yourself. Prefer `selects`."," */"," onSelectRows?: (rows: Record<string, unknown>[]) => void;"," /** Extra chart options (palette, colour scale, theme colours); a restyle, never a regeneration. */"," options?: Record<string, unknown>;"," /**"," * Notes on marks: a badge on each key's mark, kept there through filters, re-queries and zooms -",' * [{ column: "<a key column above>", value: "<its value>", label: "2", title: "the note" }], or a key over'," * several columns: { where: { <column>: <value>, ... } } (a route by both ends). Key by stable values from"," * the model, never a row position."," */"," annotations?: MarkAnnotation[];"," /** A badge was clicked (the mark beneath is not selected). */"," onAnnotationClick?: (annotation: MarkAnnotation) => void;","}","","/** Renders the chart from live data: the group builds the payload (row index, geometry columns) from the binding. */",`export function ${a}({ table, rename, rows: given, width, height, onSelectRows, options,`,` annotations, onAnnotationClick, selects, controls, filterBy, ariaLabel, emptyText, onInvalidSentinel }: ${a}Props) {`," // Mapped once per result: a new rows array rebuilds the chart's payload."," const mapped = useMemo(() => given ?? (table ? rowsFromTable(table, rename) : []), [given, table, rename]);"," // keep() hands back the same array until the filter or the rows change, so filtering never churns the payload."," const rows = filterBy ? filterBy.filter.keep(mapped, filterBy.columns) : mapped;"," return ("," <BicChartGroup columns={columns} rows={rows}"," geo={binding.geo} point={binding.point} destination={binding.destination}>"," <BicChart code={code} d3={d3} geoKind={geoKind || undefined}",` options={{ width, height, ...(emptyText ? { noDataText: emptyText } : {}), ${i?"...chartDefaults, ":""}...options }}`," onInvalidSentinel={onInvalidSentinel}"," annotations={annotations} onAnnotationClick={onAnnotationClick}",` selects={selects} controls={controls} ariaLabel={ariaLabel ?? ${JSON.stringify(e.chartName)}}`," onSelect={(idxs) => onSelectRows?.(idxs.map((k) => rows[k]))} />"," </BicChartGroup>"," );","}",""].join(`
76
+ `)},now:()=>Date.now(),hostname:()=>uD()},n8={...kD},fb=null;function yb(e){fb=e}function ml(e){if(e==null)return;let a=e.trim();return a===""||/^\$\{[^}]*\}$/.test(a)?void 0:a}function gl(e=process.env){return/^(off|0|false|no)$/i.test(ml(e.BIC_SIGNIN)??"")}function Nb(e){let a=Number(ml(e.BIC_SIGNIN_WAIT_MS));return Number.isFinite(a)&&a>=0?a:ND}function fl(e=process.env){return ml(e.BIC_OAUTH_FILE)??dD(lD(),".bic","oauth.json")}function yl(e){try{let a=JSON.parse(mD(fl(e),"utf-8"));return a&&typeof a=="object"&&!Array.isArray(a)?a:{}}catch{return{}}}function bb(e,a=process.env){let t=yl(a)[e];return!t||typeof t!="object"||t.base!==e||typeof t.accessToken!="string"||typeof t.refreshToken!="string"||!t.refreshToken?null:t}function Sb(e,a=process.env){let t=yl(a);t[e.base]=e,Wb(t,a)}function pb(e,a=process.env){let t=yl(a);if(e in t){if(delete t[e],Object.keys(t).length>0){Wb(t,a);return}try{fD(fl(a),{force:!0})}catch{}}}function Wb(e,a){let t=fl(a);pD(cD(t),{recursive:!0,mode:448});let n=`${t}.${process.pid}.tmp`;yD(n,JSON.stringify(e,null,2),{encoding:"utf-8",mode:hb});try{hD(n,hb)}catch{}gD(n,t)}function kb(e){return`Sign in to continue. It's free to try, and nothing needs configuring: ${e} - or, on a machine with no browser, set a license key instead (BIC_LICENSEE and BIC_LICENSE_KEY).`}function vb(e){return`You've been signed out. Sign in again to continue: ${e}`}function vD(e){return`Run the request again to open a new sign-in: the last one was canceled in the browser, so nothing was sent. ${e}`}function mb(e,a){return`Run the request again to open a new sign-in: the last one didn't finish (${e}). ${a}`}function CD(e,a){return`Try the request again in a moment: your sign-in couldn't be renewed because the service didn't answer (${e}). ${a}`}async function Cb(e,a,t){let n;try{n=await n8.fetch(`${e}/api/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams(a).toString(),signal:AbortSignal.timeout(3e4)})}catch(u){return{kind:"unreachable",detail:String(u?.message??u)}}let r=null;try{r=JSON.parse(await n.text())}catch{}if(n.status>=500||n.status!==200&&!r)return{kind:"unreachable",detail:`HTTP ${n.status}`};if(n.status!==200)return{kind:"rejected",error:String(r?.error??"invalid_request"),description:String(r?.error_description??"")};let o=typeof r?.access_token=="string"?r.access_token:"",i=typeof r?.refresh_token=="string"&&r.refresh_token?r.refresh_token:t;if(!o||!i)return{kind:"unreachable",detail:"the answer carried no sign-in"};let s=n8.now(),l=Number(r.expires_in);return{kind:"ok",entry:{base:e,accessToken:o,accessExpiresUtc:new Date(s+(Number.isFinite(l)&&l>0?l:3600)*1e3).toISOString(),refreshToken:i,obtainedUtc:new Date(s).toISOString()}}}var cl=new Map;function wD(e,a,t){let n=cl.get(e);if(n)return n;let r=(async()=>{let o=await Cb(e,{grant_type:"refresh_token",refresh_token:a.refreshToken,client_id:hl},a.refreshToken);return o.kind==="ok"&&Sb(o.entry,t),o})().finally(()=>cl.delete(e));return cl.set(e,r),r}var xn=new Map,En=new Map;function dl(e){return e.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function J2(e,a,t,n){let r=`<!doctype html><html><head><meta charset="utf-8"><title>${t}</title></head><body style="font-family:system-ui,sans-serif;max-width:32em;margin:4em auto;line-height:1.5"><h1 style="font-size:1.4em">${t}</h1><p>${n}</p></body></html>`;e.writeHead(a,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store",Connection:"close"}),e.end(r)}async function MD(e,a){let t=dl(db(32)),n=dl(iD("sha256").update(t).digest()),r=dl(db(16)),o=null,i=null,s,l=new Promise(f=>{s=f}),u=!1,c=f=>{u||(u=!0,s(f),xn.get(e)===g&&xn.delete(e),i&&clearTimeout(i),setTimeout(()=>o?.close(),50).unref?.())},d="";o=oD((f,y)=>{(async()=>{let W=new URL(f.url??"/","http://127.0.0.1");if(W.pathname!=="/callback"){y.writeHead(404,{Connection:"close"}),y.end();return}if(W.searchParams.get("state")!==r){J2(y,400,"This sign-in link is out of date","It doesn't match the sign-in your editor is waiting for. Close this tab and use the newest link.");return}let k=W.searchParams.get("error");if(k){J2(y,200,"Sign-in canceled","Nothing was shared. You can close this tab."),c({ok:!1,canceled:k==="access_denied",detail:k});return}let A=W.searchParams.get("code")??"",P=await Cb(e,{grant_type:"authorization_code",code:A,code_verifier:t,redirect_uri:d,client_id:hl},null);if(P.kind!=="ok"){let C=P.kind==="rejected"?P.description||P.error:P.detail;J2(y,200,"Sign-in didn't finish",`${C}. You can close this tab and try again from your editor.`),c({ok:!1,canceled:!1,detail:C});return}Sb(P.entry,a),J2(y,200,"You're signed in","You can close this tab and go back to your editor - it's carrying on."),c({ok:!0,entry:P.entry})})().catch(W=>{try{J2(y,500,"Sign-in didn't finish","Something went wrong here. You can close this tab.")}catch{}c({ok:!1,canceled:!1,detail:String(W?.message??W)})})}),await new Promise((f,y)=>{o.once("error",y),o.listen(0,"127.0.0.1",()=>f())}),d=`http://127.0.0.1:${o.address().port}/callback`;let m=new URLSearchParams({response_type:"code",client_id:hl,redirect_uri:d,code_challenge:n,code_challenge_method:"S256",state:r,scope:"charts",device_name:(n8.hostname()||"").slice(0,64)}),g={url:`${e}/oauth/authorize?${m.toString()}`,done:l,waitedOut:!1,close:()=>c({ok:!1,canceled:!1,detail:"the sign-in was closed"})};return i=setTimeout(()=>c({ok:!1,canceled:!1,detail:"the sign-in link expired"}),Math.max(SD,Nb(a))),i.unref?.(),o.unref(),g}function AD(e){let a=`Sign in to continue - your browser is opening this page (open it yourself if it doesn't): ${e}`;n8.log(`[bic-chart] ${a}`);try{fb?.(a)}catch{}}async function _D(e,a,t){let n=xn.get(e);if(!n){let u=En.get(e),c=!u;u||(u=MD(e,a).then(d=>(xn.set(e,d),AD(d.url),d)),En.set(e,u),u.then(()=>En.delete(e),()=>En.delete(e)));try{n=await u}catch(d){return{ok:!1,code:t8,message:mb(`no local port: ${d?.message??d}`,e)}}if(c)try{await n8.openBrowser(n.url)}catch{}}let r=()=>({ok:!1,code:t?Q3:t8,message:t?vb(n.url):kb(n.url)}),o=u=>{if(u.ok===!0)return{ok:!0,accessToken:u.entry.accessToken};let c=u;return{ok:!1,code:t8,message:c.canceled?vD(e):mb(c.detail,e)}};if(n.waitedOut)return r();let i=null,s=new Promise(u=>{i=setTimeout(()=>u("timeout"),Nb(a))}),l=await Promise.race([n.done,s]);return i&&clearTimeout(i),l==="timeout"?(n.waitedOut=!0,r()):o(l)}async function wb(e,a,t){let n=bb(e,a),r=!!n&&!!t.refused&&n.accessToken===t.refused.token,o=!n&&!!t.refused?.signedOut;if(n&&r&&t.refused.signedOut&&(pb(e,a),n=null,o=!0),n){let i=Date.parse(n.accessExpiresUtc)-n8.now();if(!r&&i>bD)return{ok:!0,accessToken:n.accessToken};let s=await wD(e,n,a);if(s.kind==="ok")return{ok:!0,accessToken:s.entry.accessToken};if(s.kind==="unreachable")return!r&&i>0?{ok:!0,accessToken:n.accessToken}:{ok:!1,code:pl,message:CD(s.detail,e)};pb(e,a),o=!0}return t.interactive?_D(e,a,o):{ok:!1,code:o?Q3:t8,message:o?vb(e):kb(e)}}var gb=!1;function Mb(e,a,t){return gb||t||gl(a)||bb(e,a)?null:(gb=!0,"Sign in to see which charts fit this data: call list_eligible_charts, and its first call opens a browser sign-in. It's free to try, and nothing needs configuring.")}import{AsyncLocalStorage as PD}from"node:async_hooks";var Nl="X-BIC-Client-IP",jn=new PD,Ab=!1;function _b(e,a){return jn.run(e,a)}function Pb(){return jn.getStore()}function Ub(){Ab=!0}function g4(){return Ab||jn.getStore()!==void 0}var bl="Reconnect this chart server to continue: your sign-in for it has expired or was signed out. Reconnect it in your app's connector or MCP settings and sign in again, then repeat the request.";function Tb(e){let a=Array.isArray(e)?e[0]:e,t=/^\s*Bearer\s+(\S+)\s*$/i.exec(a??"");return t?t[1]:null}function Rb(e){let a=(Array.isArray(e)?e[0]:e??"").trim();return/^[0-9A-Za-z.:%_-]{1,64}$/.test(a)?a:void 0}function Ln(e){return{post(a,t,n,r){let o=jn.getStore()?.clientIp;return e.post(a,t,o?{...n,[Nl]:o}:n,r)}}}var ED="2Qy@Y\\{>",Sl=ps(ED);function Fn(e){return jy({signer:Sl,transport:Ln(Sn((a,t)=>fetch(a,t))),clock:{now:()=>Date.now()}},{baseUrl:()=>Y2(e),apiPath:"/api",nocache:a=>UD(a==="qualify"?8:16).toString("hex")})}function Bb(e){return AbortSignal.timeout(e),e>0?e:Number.MIN_VALUE}var xD="2.1.0.0",jD=new Set(["D3","PLOTLY"]);function $b(e=process.env){let a=e.BIC_CREDENTIALS_FILE||ID(zD(),".bic","credentials.json");try{return JSON.parse(RD(a,"utf-8"))}catch{return{}}}function f4(e){return e!=null&&/^\$\{[^}]*\}$/.test(e.trim())?void 0:e}function Wl(e=process.env){let a=$b(e),t={licenseKey:f4(e.BIC_LICENSE_KEY)??a.licenseKey??"",licensee:f4(e.BIC_LICENSEE)??a.licensee??"",secretKey:f4(e.BIC_SECRET_KEY)??a.secretKey??""};if(!t.licenseKey||!t.licensee)throw new Error(`Missing BIC trial/paid credentials. Set BIC_LICENSE_KEY + BIC_LICENSEE (BIC_SECRET_KEY optional) in the MCP server's env, or put {"licenseKey":"\u2026","licensee":"\u2026"} in ~/.bic/credentials.json. MCP access requires a trial or paid account (no freemium).`);return t}var zb={licenseKey:"",licensee:"",secretKey:""};function Hb(e){try{return Wl(e)}catch{return null}}async function Dn(e,a){if(g4())return LD();let t=Hb(e);if(t)return{kind:"key",auth:t};if(gl(e))return{kind:"none"};let n=a.refusedWith?.credential,r=n?.kind==="token"?{token:n.accessToken,signedOut:a.refusedWith.code===Q3}:void 0,o=await wb(Y2(e),e,{interactive:a.interactive,refused:r});if(o.ok===!0)return{kind:"token",accessToken:o.accessToken};let i=o;return{kind:"failed",code:i.code,message:i.message}}async function Gb(e,a,t){return a.kind!=="token"||t!==q2&&t!==Q3?null:g4()?{kind:"failed",code:t,message:bl}:Dn(e,{interactive:!0,refusedWith:{credential:a,code:t}})}function LD(){let e=Pb()?.accessToken?.trim();return e?{kind:"token",accessToken:e}:{kind:"failed",code:Q3,message:bl}}function Xb(e){let a;try{a=JSON.parse(e)}catch{return null}let t=String(a?.errorCode??a?.ErrorCode??"");return t!==q2&&t!==Q3?null:{code:t,message:String(a?.errorMessage??a?.ErrorMessage??t)}}function kl(e){return e.kind==="key"?{auth:e.auth}:e.kind==="token"?{auth:zb,accessToken:e.accessToken}:{auth:zb}}function Kb(e=process.env){return Mb(Y2(e),e,Hb(e)!==null)}function Y2(e=process.env){let a=$b(e);return(f4(e.BIC_URL)??a.url??"https://bizintelligencechampions.com").replace(/\/+$/,"")}function On(e=process.env){return f4(e.BIC_MCP_CLIENT_VERSION)??xD}function Q2(e,a,t=process.env,n){let r=TD(),o=Py(e.shape),i=(e.fontFamily??"").replace(/[^A-Za-z0-9 ,.\-]/g," ").replace(/\s+/g," ").trim().slice(0,100),s=_y({measure:()=>({width:Math.round(e.width??800),height:Math.round(e.height??600)})}),l=Ay({triple:()=>({licensee:a.licensee.trim(),licenseKey:a.licenseKey.trim(),secretKey:a.secretKey.trim()})});return{payload:{...l.request,...cb(l.request,n),clientVersion:On(t),host:"SDK",...g4()?{mcpHosted:!0}:{},supportsStreaming:!0,...s.request,totalRows:e.totalRows,cultureCode:e.cultureCode??"en-US",...bs({genNew:!0,settingVersion:0}),identifier:"",temp:R0,modifiers:[],backgroundColor:"#ffffff",palette:"",shape:e.shape,model:e.model??f4(t.BIC_MCP_MODEL)??"",renderer:e.renderer??"D3",language:e.language??"",sampleCsv:e.sampleCsv??null,...Ty({budget:3}),rendererSpecificPayload:null,reasoningMode:e.reasoningMode||t.BIC_MCP_REASONING||"",...Uy({renderers:jD}),correlationId:r,compactness:"",clientHints:{supportsDatasetGlobal:!0,supportsMermaid:!0,supportsHtmlScene:!0,...s.hints,rowCount:e.totalRows,...Ry(e.leafCardinality),maxNonMeasureCardinality:o,favorStyle:e.chartHint??"",userCommentary:e.prompt??"",...e.rowsPolicy?{rowsPolicy:e.rowsPolicy}:{},...e.requiredColumns?.length?{requiredColumns:e.requiredColumns}:{},...e.forbidDerivedColumns?{forbidDerivedColumns:!0}:{},...e.levelOfDetail?{levelOfDetail:e.levelOfDetail}:{},...e.qualifyOrder?{qualifyOrder:e.qualifyOrder}:{},...i?{suggestFontFamily:i}:{},...e.geoExtent?{geoExtent:e.geoExtent}:{}}},correlationId:r}}function FD(e){if(e.ok||!e.isServiceError||T0(e)||e.isRateLimited===!0||!e.raw)return!1;let a=My(Ns(e.raw));if(a!==null)return a;let t=(e.errorMessage||"").toLowerCase();return/billed|still be running|completed server-side|may have completed/.test(t)||/no credits were used|nothing was generated/.test(t)?!1:/could ?n[o']?t reach|unable to reach|provider|upstream|rate.?limit|temporarily|try again|timed? out contacting|service unavailable/.test(t)}var Ib=[2e3,6e3];async function Vb(e,a=process.env){let t=Math.max(0,Math.min(2,Number(f4(a.BIC_MCP_GENERATE_RETRIES)??1))),n=[],r=null;for(let o=0;o<=t;o++){if(o>0){let i=Ib[Math.min(o-1,Ib.length-1)];e.onProgress?.(`Provider unavailable \u2014 retrying in ${Math.round(i/1e3)}s (attempt ${o+1} of ${t+1})`),await new Promise(s=>setTimeout(s,i))}if(r=await OD(e,a),r.correlationId&&n.push(r.correlationId),!FD(r))break}return r&&!r.ok&&n.length>1?{...r,errorMessage:`${r.errorMessage} (retried ${n.length} times; correlationIds: ${n.join(", ")})`}:r}function Bn(e,a){return{ok:!1,code:"",language:"",version:0,errorMessage:a,isServiceError:!0,isRefusal:!1,isRateLimited:!1,retryAfterSeconds:null,outputHash:"",codeSummary:"",finalChartName:"",warningMessage:"",creditCost:null,geoColumn:"",geoKind:"",pointCityColumn:"",pointStateColumn:"",pointZipColumn:"",pointCountryColumn:"",pointLatColumn:"",pointLonColumn:"",destPointCityColumn:"",destPointStateColumn:"",destPointZipColumn:"",destPointCountryColumn:"",destPointLatColumn:"",destPointLonColumn:"",correlationId:e,raw:null}}function Zb(e,a){let t=Ns(e),n=t.geoPointCols??{},r=n.dest??{};return{ok:!!t.code&&!t.errorMessage,code:t.code,language:t.language,version:t.version,errorMessage:t.errorMessage,isServiceError:t.isServiceError,isRefusal:t.isRefusal,isRateLimited:t.isRateLimited,retryAfterSeconds:t.retryAfterSeconds,outputHash:t.outputHash,codeSummary:t.codeSummary,finalChartName:t.finalChartName,warningMessage:t.warningMessage,creditCost:t.creditCost,geoColumn:t.geoColumn,geoKind:t.geoKind,pointCityColumn:n.city??"",pointCountryColumn:n.country??"",pointStateColumn:n.state??"",pointZipColumn:n.zip??"",pointLatColumn:n.lat??"",pointLonColumn:n.lon??"",destPointCityColumn:r.city??"",destPointCountryColumn:r.country??"",destPointStateColumn:r.state??"",destPointZipColumn:r.zip??"",destPointLatColumn:r.lat??"",destPointLonColumn:r.lon??"",correlationId:a,servedCorrelationId:t.servedCorrelationId,isVersionNotFound:t.isVersionNotFound,isGenerationCancelled:t.isGenerationCancelled,...DD(t),raw:e}}function DD(e){let a={};return typeof e.isPollFinal=="boolean"&&(a.isPollFinal=e.isPollFinal),typeof e.pollOutcome=="string"&&e.pollOutcome!==""&&(a.pollOutcome=e.pollOutcome),typeof e.errorCode=="string"&&e.errorCode!==""&&(a.errorCode=e.errorCode),a}function Eb(e){return{...Bn("",e.message),isServiceError:!1,errorCode:e.code}}async function OD(e,a){let t=await Dn(a,{interactive:!0});if(t.kind==="failed")return Eb(t);let n=await xb(e,a,t),r=await Gb(a,t,n.errorCode);return r?r.kind==="failed"?Eb(r):xb(e,a,r):n}async function xb(e,a,t){let{auth:n,accessToken:r}=t.kind==="none"?{auth:Wl(a),accessToken:void 0}:kl(t),{payload:o,correlationId:i}=Q2(e,n,a,r),s=Number(f4(a.BIC_MCP_TIMEOUT_MS)??9e5),l=Date.now(),u=f=>Bn(i,f),c=f=>({...u(`Cancelled after ${f}s. The server was told to stop and bills only the passes that had already completed; nothing further is running. correlationId ${i}.`),isServiceError:!1}),d=f=>u(`Gave up waiting after ${f}s \u2014 this MCP client's own timeout (BIC_MCP_TIMEOUT_MS=${s}). The generation may still be running server-side and may be billed. Raise BIC_MCP_TIMEOUT_MS, or lower the cost of the request (simpler chart type, fewer rows, reasoning_mode "1P"). correlationId ${i}.`),p=(f,y)=>e.signal?.aborted?c(f):y?.name==="TimeoutError"||y?.name==="AbortError"?d(f):u(`Could not reach the BIC backend after ${f}s: ${String(y?.message??y)}. correlationId ${i}.`),m;try{m=Bb(s)}catch(f){return p(Math.round((Date.now()-l)/1e3),f)}let h=await Fn(a).generate(o,{timeoutMs:m,signal:e.signal??null,onStage:e.onProgress??null}),g=Math.round((Date.now()-l)/1e3);if(h.kind==="transport"&&!h.headersReceived){let f=h.error,y=f?.name==="TimeoutError"||f?.name==="AbortError";return e.signal?.aborted||y||BD(f)||!ul(!1,o.genNew)?p(g,h.error):Db({correlationId:i,startedAt:l,cutAtMs:Date.now(),deadlineAt:l+s,pick:e.chartHint??"",cause:String(f?.message??f),signal:e.signal,onProgress:e.onProgress,preHeader:!0},{fetchByCorrelation:W=>jb(e,i,a,W),refund:()=>Fb(i,a),now:()=>Date.now(),sleep:Lb})}if(h.kind==="http"){let y=(h.status===499||h.status===502||h.status===504)&&h.bodyStart.trim().length===0?`The connection was cut by an intermediary after ${g}s (HTTP ${h.status}, empty body) while the request was still in flight. The generation very likely COMPLETED server-side and MAY HAVE BEEN BILLED \u2014 it just could not be delivered. Raising this client's timeout will NOT help: the ceiling is a gateway between us, not your wait. Get under it by making the request cheaper \u2014 a simpler chart type, fewer rows, or reasoning_mode "1P" \u2014 and quote correlationId ${i} to BIC support to recover or refund this generation.`:`HTTP ${h.status}: ${h.bodyStart} (correlationId ${i})`,W=Xb(h.bodyStart);return W?{...u(W.message),isServiceError:!1,errorCode:W.code}:u(y)}if(h.kind==="transport"){let f=h.error;if(e.signal?.aborted)return c(g);if(f?.name==="TimeoutError"||f?.name==="AbortError")return d(g);let y=String(f?.message??f);return ul(!0,o.genNew)?Db({correlationId:i,startedAt:l,cutAtMs:Date.now(),deadlineAt:l+s,pick:e.chartHint??"",cause:y,signal:e.signal,onProgress:e.onProgress},{fetchByCorrelation:W=>jb(e,i,a,W),refund:()=>Fb(i,a),now:()=>Date.now(),sleep:Lb}):u(`The response stream ended after ${g}s without a result. The generation may have COMPLETED and BEEN BILLED \u2014 quote correlationId ${i} to BIC support to recover or refund it. (${y})`)}return Zb(h.value,i)}function BD(e){let a=String(e?.message??"");return e?.cause?.code==="ERR_INVALID_URL"||/^Failed to parse URL\b/.test(a)||/cannot keep a deadline/.test(a)}var $D=6e4;async function jb(e,a,t,n){let r=await Dn(t,{interactive:!1}),{auth:o,accessToken:i}=r.kind==="none"?{auth:Wl(t),accessToken:void 0}:kl(r),{payload:s}=Q2(e,o,t,i),l=await Fn(t).generate({...s,...bs({genNew:!1,fetchCorrelationId:a}),supportsStreaming:!1},{timeoutMs:$D,signal:n??null});if(l.kind==="transport")throw l.error;return l.kind==="http"?Bn(a,`HTTP ${l.status}: ${l.bodyStart}`):Zb(l.value,a)}function Lb(e,a){return new Promise((t,n)=>{if(a?.aborted){n(a.reason??new Error("aborted"));return}let r=()=>{clearTimeout(o),n(a?.reason??new Error("aborted"))},o=setTimeout(()=>{a?.removeEventListener("abort",r),t()},e);a?.addEventListener("abort",r,{once:!0})})}var HD=5e3;async function Fb(e,a=process.env){let t=Fn(a);if(typeof t.refund!="function")return{sent:!1,ok:!1,message:"this build has no refund call, so no refund was requested"};try{let n=await t.refund(e,{timeoutMs:HD});return n.kind==="answer"?{sent:!0,ok:n.value?.ok===!0,message:String(n.value?.message??"")}:n.kind==="http"?{sent:!0,ok:!1,message:`HTTP ${n.status}`}:{sent:!1,ok:!1,message:"the refund could not reach the service"}}catch(n){return{sent:!1,ok:!1,message:String(n?.message??n)}}}async function Db(e,a){let t={v:1,t:e.startedAt,c:e.correlationId,p:e.pick,h:0},n=Math.round((e.cutAtMs-e.startedAt)/1e3),r=()=>Math.min(nb(t,a.now()),e.deadlineAt-a.now()),o=m=>Bn(e.correlationId,m),i=`It may still complete and be billed \u2014 quote correlationId ${e.correlationId} to BIC support to recover or refund it.`,s=e.preHeader?`Could not reach the BIC backend after ${n}s: ${e.cause} - no answer arrived, though the server may still have received the request`:`The response stream was cut after ${n}s, after the server had accepted the request`,l=async m=>{if(!ib(m)||!a.refund)return i;let h;try{h=await a.refund()}catch(g){h={sent:!1,ok:!1,message:String(g?.message??g)}}return h.sent?`A refund for it was requested (the server applies it once the generation is recorded, unless the chart was delivered: ${h.message||(h.ok?"refunded":"no answer")}). Quote correlationId ${e.correlationId} to BIC support if anything looks wrong.`:`${i} (The automatic refund request could not be sent: ${h.message}.)`};if(tb(t,a.now(),0)!=="poll"||r()<=0)return o(`${s}, and there is no time left in this call to check for the chart. ${i} (${e.cause})`);let u=QN,c=0,d=0,p=!1;for(;;){try{await a.sleep(Math.max(0,Math.min(u,r())),e.signal)}catch{}if(e.signal?.aborted)return{...o(`Cancelled while checking for a chart whose response stream was cut after ${n}s. The server had already accepted that generation, so cancelling the check did not stop it. ${i}`),isServiceError:!1};c++,e.onProgress?.(`The connection dropped after ${n}s, before the chart arrived. Checking for it on the server (check ${c})`);let m=null;try{m=await a.fetchByCorrelation(e.signal)}catch{}if(!m||!m.raw&&m.isServiceError?d++:(p=!0,d=0),m?.ok&&m.code&&ab(t,m.servedCorrelationId))return{...m,correlationId:e.correlationId,creditCost:null,recoveredAfterMs:a.now()-e.startedAt};let h=ob(m);if(h==="cancelled")return o(`${rb(m.errorMessage)} correlationId ${e.correlationId}.`);if(h==="failed"||h==="not-received")return{...o(`${ub(h,m.errorMessage)} correlationId ${e.correlationId}.`),isServiceError:!1,isPollFinal:!0,pollOutcome:h,...m.errorCode?{errorCode:m.errorCode}:{}};if(sb(d,p))return o(`${s}. ${lb} This client checked ${c} time(s) and no check reached the service. ${await l("unreachable")} (${e.cause})`);if(!(!m||m.ok&&!!m.code||m.isVersionNotFound||m.isServiceError&&!m.isRefusal))return o(`${s}. Checking for the chart by its correlation, the server answered that there is nothing to deliver: ${m.errorMessage||"no code returned"}. correlationId ${e.correlationId}. ${await l("hard-error")}`);if(r()<=0){let f=Math.round((a.now()-e.cutAtMs)/1e3);return o(`${s}. This client checked for the finished chart ${c} time(s) over ${f}s and it had not arrived when the wait ended (the shared recovery window, or BIC_MCP_TIMEOUT_MS, whichever is sooner). ${await l("window-closed")} (${e.cause})`)}u=eb(a.now()-t.t)}}var $n="metered: free within an hourly allowance, usage credits beyond it";async function vl(e,a=process.env){let t=await Dn(a,{interactive:!0});if(t.kind==="failed")return{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:t.message,errorCode:t.code};let n=await Ob(e,a,t),r=await Gb(a,t,n.errorCode);return r?r.kind==="failed"?{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:r.message,errorCode:r.code}:Ob(e,a,r):n}async function Ob(e,a,t){let{auth:n,accessToken:r}=kl(t),{payload:o}=Q2({shape:e.shape,totalRows:e.totalRows,leafCardinality:e.leafCardinality,geoExtent:e.geoExtent,width:e.width,height:e.height,renderer:e.renderer??"",language:e.language??"",levelOfDetail:e.levelOfDetail,qualifyOrder:e.order},n,a,r),i=Fn(a),s=async p=>i.qualify(o,{timeoutMs:Bb(Number(f4(a.BIC_MCP_QUALIFY_TIMEOUT_MS)??6e4)),route:p}),l=await s("/RegiaBI/whatfits");if(l.kind==="http"&&l.status===404&&(l=await s("/LLMChart/qualify")),l.kind==="transport")throw l.error;if(l.kind==="http"){let p=Xb(l.bodyStart);return p?{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:p.message,errorCode:p.code}:{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:`HTTP ${l.status}: ${l.bodyStart.slice(0,200)}`}}let u=wy(l.value);if(u.errorMessage)return{ok:!1,charts:[],refused:[],noFitSummary:"",errorMessage:u.errorMessage,...u.errorCode?{errorCode:u.errorCode}:{}};let c=(u.charts??[]).map(p=>({name:p.name,description:p.description,rank:p.rank,score:p.score,renderer:p.renderer,language:p.language,recommended:p.recommended,isPreview:p.isPreview})),d=u.refused.map(p=>({name:p.name,reason:p.reason,isVeto:p.isVeto}));return{ok:!0,charts:c,refused:d,noFitSummary:u.noFitSummary,errorMessage:""}}/*! @bicharts/shape-core — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; US Census/TIGER (public domain). Full text: NOTICE in this package. */function GD(e){return!e||!e.trim()?0:Math.max(0,e.trim().split(/\r?\n/).length-1)}function qb(e,a,t="",n=process.env){let{payload:r}=Q2(e,{licenseKey:"",licensee:"",secretKey:""},n),o=GD(e.sampleCsv),i=V0(r,{sampleNote:`${o} obfuscated sample row(s) travel at privacy_level ${a}; their values are not shown here. Lower privacy_level to send none.`,emptyShapeNote:"No columns were measured - pass csv_path, csv_text or data."});return{head:`NOTHING WAS SENT. This is the request generate_chart would send for these arguments${t}, with the licence, install id and correlation id removed (they are credentials, not your data). privacy_level ${a}: ${o>0?`${o} obfuscated sample row(s) travel`:"no rows travel - only the measured shape"}.`,preview:i,sampleRows:o}}function Hn(e){let t=(e||"").replace(/[^A-Za-z0-9]+/g," ").trim().split(/\s+/).filter(Boolean).map(n=>n[0].toUpperCase()+n.slice(1)).join("");return(!t||/^[0-9]/.test(t))&&(t="Bic"+t),t.endsWith("Chart")?t:t+"Chart"}var XD=/^__.*__$/;function Jb(e){let a=Hn(e.chartName),t=e.columns.filter(s=>!XD.test(s.name)).map(s=>({name:s.name,dataType:s.dataType,isMeasure:!!s.isMeasure})),n=e.plugins.flatMap((s,l)=>["// eslint-disable-next-line @typescript-eslint/ban-ts-comment",`// @ts-ignore - ${s} often ships no type declarations; the chart only reaches it through d3. npm install ${s}`,`import * as d3Plugin${l} from "${s}";`]),r=e.plugins.map((s,l)=>`d3Plugin${l}`),o=s=>JSON.stringify(s,null,2),i=!!e.defaultOptions&&Object.keys(e.defaultOptions).length>0;return[`// BIC generated React host for "${e.chartName}" - renders ./chart.js through @bicharts/chart-host.`,"// Regenerate with the MCP generate_chart tool rather than editing: it is rewritten with the chart.",'import { useMemo } from "react";','import * as d3base from "d3";',...n,'import { assembleD3, type GeoPointBinding, type MarkAnnotation, type Filter, type Controls } from "@bicharts/chart-host";','import { BicChart, BicChartGroup } from "@bicharts/chart-host/react";','import code from "./chart.js?raw";',"","/** The columns this chart was generated for. Each row must be keyed by these names. */",`export const columns = ${o(t)};`,"","/** How the payload is built from rows: the choropleth join, and where points and a route's far end come from. */","export const binding: {"," geo: { column: string; kind: string } | null;"," point: GeoPointBinding | null;"," destination: GeoPointBinding | null;",`} = ${o(e.binding)};`,"",'/** The geometry the chart draws on ("" when it draws none). */',`export const geoKind = ${JSON.stringify(e.geoKind||"")};`,"",...i?["/** Options the user chose for this chart when it was generated; the options prop still overrides them. */",`const chartDefaults = ${JSON.stringify(e.defaultOptions)};`,""]:[],"// One d3 for the chart, with the plugins its code calls attached (an ES-module d3 namespace cannot be assigned onto).",`const d3 = assembleD3(d3base${r.length?", "+r.join(", "):""});`,"",'const key = (s: string) => s.replace(/^[^[]*\\[(.+)\\]$/, "$1").toLowerCase().replace(/[^a-z0-9]/g, "");',"","/**"," * Rows keyed by this chart's column names, from a query result of { columns: [{ name }], rows: [[...]] }.",` * A DAX result's "Table[Column]" and "[Measure]" headers match by the bracketed name, ignoring case, spaces and`,' * punctuation, so "[Average Daily Rate]" fills AverageDailyRate with no alias. Pass `rename` for anything else.'," */","export function rowsFromTable("," table: { columns: { name: string }[]; rows: unknown[][] },"," rename: Record<string, string> = {},","): Record<string, unknown>[] {"," const wanted = new Map(columns.map((c) => [key(c.name), c.name]));"," const target = table.columns.map((c) => rename[c.name] ?? wanted.get(key(c.name)));"," return table.rows.map((r) => {"," const o: Record<string, unknown> = {};"," target.forEach((t, k) => { if (t) o[t] = r[k]; });"," return o;"," });","}","",`export interface ${a}Props {`," /** The live query result as it arrives ({ columns, rows }); mapped with rowsFromTable. Or pass rows. */"," table?: { columns: { name: string }[]; rows: unknown[][] };"," /** Header -> column name, for any header rowsFromTable can't match by name. */"," rename?: Record<string, string>;"," /** Rows already keyed by the chart's column names, instead of table. */"," rows?: Record<string, unknown>[];"," width: number;"," height: number;"," /**",' * The page filter a click on this chart sets - from useBicFilter("<key column>") in @bicharts/chart-host/react.'," * A click sets it, the same click or empty canvas clears it, filter.clear() clears the marks too, and new data"," * keeps a pick it still draws. Read filter.value / filter.row on the page; no select handler to write."," */"," selects?: Filter;"," /**",' * Show only the rows a page filter keeps - { filter: region, columns: ["OriginCode", "DestinationCode"] }'," * keeps a route that starts or ends in the selected region (columns default to the filter's key). Applied here,"," * after the rows are mapped, so the chart redraws only when the filter or the data changes."," */"," filterBy?: { filter: Filter; columns?: string[] };"," /** What a screen reader announces for the chart. Defaults to the chart type's name. */"," ariaLabel?: string;",' /** What the chart says when it has no rows to draw ("Nothing for this filter"). */'," emptyText?: string;"," /** The data lacks a column the chart is built on: called with the chart's reason instead of the chart throwing. */"," onInvalidSentinel?: (info: { reason: string; message: string }) => void;"," /**"," * The chart's own controls (a What-if chart's sliders) as page state - from useBicControls(). values holds"," * every knob from the first draw, summary the chart's own label and readout; set(saved) applies a scenario."," */"," controls?: Controls;"," /**"," * The clicked marks' source rows - read a stable key from them (an id or code), never a row position. An empty"," * list means the selection was CLEARED (the same mark clicked again, empty canvas, or new data without it): set"," * your state from exactly this, never toggle it yourself. Prefer `selects`."," */"," onSelectRows?: (rows: Record<string, unknown>[]) => void;"," /** Extra chart options (palette, colour scale, theme colours); a restyle, never a regeneration. */"," options?: Record<string, unknown>;"," /**"," * Notes on marks: a badge on each key's mark, kept there through filters, re-queries and zooms -",' * [{ column: "<a key column above>", value: "<its value>", label: "2", title: "the note" }], or a key over'," * several columns: { where: { <column>: <value>, ... } } (a route by both ends). Key by stable values from"," * the model, never a row position."," */"," annotations?: MarkAnnotation[];"," /** A badge was clicked (the mark beneath is not selected). */"," onAnnotationClick?: (annotation: MarkAnnotation) => void;","}","","/** Renders the chart from live data: the group builds the payload (row index, geometry columns) from the binding. */",`export function ${a}({ table, rename, rows: given, width, height, onSelectRows, options,`,` annotations, onAnnotationClick, selects, controls, filterBy, ariaLabel, emptyText, onInvalidSentinel }: ${a}Props) {`," // Mapped once per result: a new rows array rebuilds the chart's payload."," const mapped = useMemo(() => given ?? (table ? rowsFromTable(table, rename) : []), [given, table, rename]);"," // keep() hands back the same array until the filter or the rows change, so filtering never churns the payload."," const rows = filterBy ? filterBy.filter.keep(mapped, filterBy.columns) : mapped;"," return ("," <BicChartGroup columns={columns} rows={rows}"," geo={binding.geo} point={binding.point} destination={binding.destination}>"," <BicChart code={code} d3={d3} geoKind={geoKind || undefined}",` options={{ width, height, ...(emptyText ? { noDataText: emptyText } : {}), ${i?"...chartDefaults, ":""}...options }}`," onInvalidSentinel={onInvalidSentinel}"," annotations={annotations} onAnnotationClick={onAnnotationClick}",` selects={selects} controls={controls} ariaLabel={ariaLabel ?? ${JSON.stringify(e.chartName)}}`," onSelect={(idxs) => onSelectRows?.(idxs.map((k) => rows[k]))} />"," </BicChartGroup>"," );","}",""].join(`
77
77
  `)}import{spawn as tS}from"node:child_process";import{existsSync as e7,readFileSync as Ka,readdirSync as Yb,writeFileSync as nS}from"node:fs";import{join as W3}from"node:path";function Pl(e,a,t=3e5){return new Promise((n,r)=>{let o=tS("npm",a,{cwd:e,shell:process.platform==="win32",windowsHide:!0,stdio:["ignore","ignore","pipe"]}),i="";o.stderr.on("data",l=>{i=(i+l).slice(-2e3)});let s=setTimeout(()=>{o.kill(),r(new Error(`timed out after ${t/1e3} s`))},t);o.on("error",l=>{clearTimeout(s),r(l)}),o.on("close",l=>{clearTimeout(s),l===0?n():r(new Error(i.trim()||`exit ${l}`))})})}function Ul(e){let a=W3(e,"package.json"),t={has:new Set,hasCssTheme:!1};if(!e7(a))return{ok:!1,why:`no package.json in ${e}`,...t};let n;try{n=JSON.parse(Ka(a,"utf-8"))}catch(d){return{ok:!1,why:`package.json does not parse (${d?.message??d})`,...t}}let r={...n.devDependencies??{},...n.dependencies??{}},o=new Set(Object.keys(r));if(!o.has("@microsoft/fabric-app-data")||!e7(W3(e,"fabric.yaml")))return{ok:!1,has:o,hasCssTheme:!1,why:"this is not a Rayfin data app project (it needs @microsoft/fabric-app-data and fabric.yaml)"};let i=W3(e,"node_modules","@microsoft","fabric-visuals","dist","index.d.ts"),s=e7(i)&&/\buseCssTheme\b/.test(Ka(i,"utf-8")),l=W3(e,"node_modules","@microsoft","fabric-visuals-core","dist","index.d.ts"),u=e7(l)?Ka(l,"utf-8"):"",c=/\breadCssTheme\b/.test(u)&&/\bcssThemeChanged\b/.test(u);return{ok:!0,has:o,hasCssTheme:s,hasCoreTheme:c,ranges:r}}function Qb(e){let a=/^\s*[\^~>=v]*\s*(\d+)\.(\d+)\.(\d+)/.exec(e??"");return a?[+a[1],+a[2],+a[3]]:null}var KD=(e,a)=>e[0]!==a[0]?e[0]<a[0]:e[1]!==a[1]?e[1]<a[1]:e[2]<a[2];function rS(e,a,t,n={}){let r=[],o=Qb(n["@bicharts/chart-host"]),i=a?Qb(a):null;return t?r.push(`@bicharts/chart-host@${t}`):e.has("@bicharts/chart-host")?o&&i&&KD(o,i)&&r.push(`@bicharts/chart-host@^${a}`):r.push(a?`@bicharts/chart-host@^${a}`:"@bicharts/chart-host"),e.has("d3")||r.push("d3"),{deps:r,devDeps:e.has("@types/d3")?[]:["@types/d3"]}}function oS(e){return/@bicharts\/chart-host@(\d+\.\d+\.\d+[^\s,]*)/.exec(e)?.[1]??null}var Tl="// Added by the RegiaBI chart server (setup_fabric_app). Yours to edit; it is never rewritten.";function iS(e){return[Tl,'import { useMemo } from "react";',e,"","/**"," * Chart options from the app's resolved Fabric theme, so every chart follows light, dark and the host's palette."," * Spread with the measured size: options={{ ...useBicChartOptions(), width, height }}. A change here restyles"," * the chart live; it never regenerates it."," */","export function useBicChartOptions() {"," const theme = useCssTheme();"," return useMemo(() => ({"," palette: theme.categoricalPalette ? [...theme.categoricalPalette] : [],"," themeFg: theme.foreground,"," themeAccent: theme.brandForeground,"," backgroundColor: theme.background,"," }), [theme]);","}",""].join(`
78
78
  `)}var VD=iS('import { useCssTheme } from "@microsoft/fabric-visuals";'),ZD=[Tl,"// The resolved Fabric theme from the page's CSS, kept current - the same logic as @microsoft/fabric-visuals' useCssTheme","// (MIT), on @microsoft/fabric-visuals-core alone, so reading the theme doesn't bundle Vega.",'import { useSyncExternalStore } from "react";','import { readCssTheme, cssThemeChanged, type VisualTheme } from "@microsoft/fabric-visuals-core";',"","const listeners = new Set<() => void>();","let cached: VisualTheme | undefined;","let stop: (() => void) | undefined;","","function current(): VisualTheme {"," if (cached === undefined) cached = readCssTheme();"," return cached;","}","","function recompute() {"," const next = readCssTheme();"," if (cached === undefined || cssThemeChanged(cached, next)) {"," cached = next;"," listeners.forEach((l) => l());"," }","}","","function watch(): () => void {",' if (typeof document === "undefined") return () => {};'," const observer = new MutationObserver(recompute);",' observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class", "style", "data-appearance"] });'," observer.observe(document.head, { subtree: true, childList: true, characterData: true });",' const queries = ["(prefers-color-scheme: dark)", "(forced-colors: active)", "(prefers-contrast: more)"]'," .map((q) => window.matchMedia?.(q)).filter((m): m is MediaQueryList => !!m);",' queries.forEach((m) => m.addEventListener("change", recompute));',' return () => { observer.disconnect(); queries.forEach((m) => m.removeEventListener("change", recompute)); };',"}","","function subscribe(listener: () => void) {"," if (listeners.size === 0) stop = watch();"," listeners.add(listener);"," recompute();"," return () => {"," listeners.delete(listener);"," if (listeners.size === 0) { stop?.(); stop = undefined; }"," };","}","","export function useCssTheme(): VisualTheme {"," return useSyncExternalStore(subscribe, current, current);","}",""].join(`
79
79
  `),qD=iS('import { useCssTheme } from "@/lib/bic-css-theme";'),eS=/^import \{ useCssTheme \} from ["']@microsoft\/fabric-visuals["'];?[ \t]*$/m,Cl="src/main.tsx";function sS(e){let a=W3(e,Cl);if(!e7(W3(e,"src","lib","bic-css-theme.ts")))return[];let t;try{t=Ka(a,"utf-8")}catch{return[]}if(!eS.test(t))return[];if((t.match(/from ["']@microsoft\/fabric-visuals["']/g)??[]).length!==1)return[];let n=t.replace(eS,'import { useCssTheme } from "@/lib/bic-css-theme";'),r="its one import of useCssTheme from @microsoft/fabric-visuals bundles Vega and Vega-Lite (about half of a production build that charts nothing with Vega); src/lib/bic-css-theme.ts is the same hook on fabric-visuals-core";try{nS(a,n,"utf-8")}catch(o){return[`not patched: ${Cl} (${o?.message??o}) - ${r}`]}return[`patched: ${Cl} - ${r}. Nothing else in the file changed; a VegaVisual anywhere in the app brings Vega back, as it should.`]}var JD=[Tl,'import { useRef, useState, type ReactNode } from "react";','import { useMeasuredSize } from "@bicharts/chart-host/react";',"","export type QueryTable = { columns: { name: string }[]; rows: unknown[][] };","","/** What useSemanticModelQuery returns (the template's hook); only these fields are read. */","export interface PanelQueryResult {",' data?: { status: "success"; table: QueryTable } | { status: "error"; error: { message: string } } | undefined;'," isLoading: boolean;"," error?: Error;","}","","interface BicChartPanelProps {"," result: PanelQueryResult;"," /** The panel's height when its cell has none (a section with no height of its own). A cell with a height - even a"," * smaller one - keeps it: the panel fills that cell and scrolls, so it never runs over what's below it. */"," minHeight?: number;"," /** The smallest size this chart is drawn at; below it the panel scrolls rather than squash or clip the chart."," * A world map wants about 2:1 (e.g. 560 x 300); a time series wants height. */"," minChartWidth?: number;"," minChartHeight?: number;",' /** A page filter narrowed the query to nothing: shown as a "Clear" beside "Nothing matches" - e.g. region.clear. */'," onClearFilters?: () => void;"," /** Renders the chart once the query has rows and the panel has a size. */"," children: (table: QueryTable, size: { width: number; height: number }) => ReactNode;","}","","/**"," * A chart's box: sized by the layout (put it in a cell that has a height - a grid row, h-full, a flex item with"," * min-h-0), never by the chart. The measured box is absolutely positioned inside its cell, so a drawn chart can't"," * make it taller than the card shows; when the cell is smaller than the chart's minimum, the panel scrolls. Shows"," * the query's loading, error and empty states in place of the chart. While a NEW result loads (a filter changed the"," * query), the last one stays on screen, dimmed: the chart isn't unmounted, so it keeps its zoom and its selection."," * <BicChartPanel result={useSemanticModelQuery({ connection, query })} minChartWidth={560} minChartHeight={300}>"," * {(table, size) => <MyChart table={table} {...size} options={options} />}"," * </BicChartPanel>"," */","export function BicChartPanel({ result, minHeight = 360, minChartWidth = 320, minChartHeight = 240, onClearFilters, children }: BicChartPanelProps) {"," const ref = useRef<HTMLDivElement>(null);"," const { width: boxWidth, height: boxHeight } = useMeasuredSize(ref);"," const width = Math.max(boxWidth, minChartWidth);"," const height = Math.max(boxHeight, minChartHeight);"," const { data, isLoading, error } = result;",' const failed = error?.message ?? (data?.status === "error" ? data.error.message : undefined);',' const fresh = data?.status === "success" ? data.table : undefined;'," // The last result, kept while the next one loads (state set during render: React's pattern for a previous value)."," const [last, setLast] = useState<QueryTable | undefined>(undefined);"," if (fresh && fresh !== last) setLast(fresh);"," const table = fresh ?? (isLoading ? last : undefined);"," const stale = !fresh && !!table;"," // The template's tokens: muted text for loading and empty, destructive for a failure.",' const note = (text: string, role?: "alert") => (',' <div role={role} className={role ? "text-300 text-destructive" : "text-300 text-muted-foreground"}',' style={{ display: "grid", placeItems: "center", height: "100%" }}>{text}</div>'," );"," return (",' <div style={{ position: "relative", width: "100%", height: "100%", minWidth: 0 }}>'," {/* The fallback height, capped at 100% of the panel: in a cell with a height the cap holds it to the cell; in a"," cell with none, 100% resolves to nothing and this gives the panel its height. A min-height can't tell the two. */}",' <div aria-hidden="true" style={{ height: minHeight, maxHeight: "100%" }} />',' <div ref={ref} style={{ position: "absolute", inset: 0, overflow: "auto" }}>',' {failed ? note(`The query failed: ${failed}`, "alert")',' : !table ? note("Loading...")'," : table.rows.length === 0"," ? onClearFilters",' ? <div className="text-300 text-muted-foreground" style={{ display: "grid", placeItems: "center", height: "100%" }}>',' <span>Nothing matches the current filter. <button type="button" className="underline" onClick={onClearFilters}>Clear</button></span>'," </div>",' : note("No data for this selection.")'," : boxWidth > 0 && boxHeight > 0 && width > 0 && height > 0",' ? <div aria-busy={stale || undefined} style={{ opacity: stale ? 0.55 : 1, transition: "opacity 120ms" }}>'," {children(table, { width, height })}"," </div>"," : null}",' {stale ? <div role="status" className="text-200 text-muted-foreground" style={{ position: "absolute", top: 8, right: 8 }}>Updating...</div> : null}'," </div>"," </div>"," );","}",""].join(`
@@ -245,8 +245,8 @@ data:
245
245
 
246
246
  `,a.enqueue(t.encode(o)),!0}catch(o){return this.onerror?.(o),!1}}handleUnsupportedRequest(){return this.onerror?.(new Error("Method not allowed.")),new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Method not allowed."},id:null}),{status:405,headers:{Allow:"GET, POST, DELETE","Content-Type":"application/json"}})}async handlePostRequest(a,t){try{let n=a.headers.get("accept");if(!n?.includes("application/json")||!n.includes("text/event-stream"))return this.onerror?.(new Error("Not Acceptable: Client must accept both application/json and text/event-stream")),this.createJsonErrorResponse(406,-32e3,"Not Acceptable: Client must accept both application/json and text/event-stream");let r=a.headers.get("content-type");if(!r||!r.includes("application/json"))return this.onerror?.(new Error("Unsupported Media Type: Content-Type must be application/json")),this.createJsonErrorResponse(415,-32e3,"Unsupported Media Type: Content-Type must be application/json");let o={headers:Object.fromEntries(a.headers.entries()),url:new URL(a.url)},i;if(t?.parsedBody!==void 0)i=t.parsedBody;else try{i=await a.json()}catch{return this.onerror?.(new Error("Parse error: Invalid JSON")),this.createJsonErrorResponse(400,-32700,"Parse error: Invalid JSON")}let s;try{Array.isArray(i)?s=i.map(y=>x8.parse(y)):s=[x8.parse(i)]}catch{return this.onerror?.(new Error("Parse error: Invalid JSON-RPC message")),this.createJsonErrorResponse(400,-32700,"Parse error: Invalid JSON-RPC message")}let l=s.some($o);if(l){if(this._initialized&&this.sessionId!==void 0)return this.onerror?.(new Error("Invalid Request: Server already initialized")),this.createJsonErrorResponse(400,-32600,"Invalid Request: Server already initialized");if(s.length>1)return this.onerror?.(new Error("Invalid Request: Only one initialization request is allowed")),this.createJsonErrorResponse(400,-32600,"Invalid Request: Only one initialization request is allowed");this.sessionId=this.sessionIdGenerator?.(),this._initialized=!0,this.sessionId&&this._onsessioninitialized&&await Promise.resolve(this._onsessioninitialized(this.sessionId))}if(!l){let y=this.validateSession(a);if(y)return y;let W=this.validateProtocolVersion(a);if(W)return W}if(!s.some(_4)){for(let y of s)this.onmessage?.(y,{authInfo:t?.authInfo,requestInfo:o});return new Response(null,{status:202})}let c=crypto.randomUUID(),d=s.find(y=>$o(y)),p=d?d.params.protocolVersion:a.headers.get("mcp-protocol-version")??fd;if(this._enableJsonResponse)return new Promise(y=>{this._streamMapping.set(c,{resolveJson:y,cleanup:()=>{this._streamMapping.delete(c)}});for(let W of s)_4(W)&&this._requestToStreamMapping.set(W.id,c);for(let W of s)this.onmessage?.(W,{authInfo:t?.authInfo,requestInfo:o})});let m=new TextEncoder,h,g=new ReadableStream({start:y=>{h=y},cancel:()=>{this._streamMapping.delete(c)}}),f={"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"};this.sessionId!==void 0&&(f["mcp-session-id"]=this.sessionId);for(let y of s)_4(y)&&(this._streamMapping.set(c,{controller:h,encoder:m,cleanup:()=>{this._streamMapping.delete(c);try{h.close()}catch{}}}),this._requestToStreamMapping.set(y.id,c));await this.writePrimingEvent(h,m,c,p);for(let y of s){let W,k;_4(y)&&this._eventStore&&p>="2025-11-25"&&(W=()=>{this.closeSSEStream(y.id)},k=()=>{this.closeStandaloneSSEStream()}),this.onmessage?.(y,{authInfo:t?.authInfo,requestInfo:o,closeSSEStream:W,closeStandaloneSSEStream:k})}return new Response(g,{status:200,headers:f})}catch(n){return this.onerror?.(n),this.createJsonErrorResponse(400,-32700,"Parse error",{data:String(n)})}}async handleDeleteRequest(a){let t=this.validateSession(a);if(t)return t;let n=this.validateProtocolVersion(a);return n||(await Promise.resolve(this._onsessionclosed?.(this.sessionId)),await this.close(),new Response(null,{status:200}))}validateSession(a){if(this.sessionIdGenerator===void 0)return;if(!this._initialized)return this.onerror?.(new Error("Bad Request: Server not initialized")),this.createJsonErrorResponse(400,-32e3,"Bad Request: Server not initialized");let t=a.headers.get("mcp-session-id");if(!t)return this.onerror?.(new Error("Bad Request: Mcp-Session-Id header is required")),this.createJsonErrorResponse(400,-32e3,"Bad Request: Mcp-Session-Id header is required");if(t!==this.sessionId)return this.onerror?.(new Error("Session not found")),this.createJsonErrorResponse(404,-32001,"Session not found")}validateProtocolVersion(a){let t=a.headers.get("mcp-protocol-version");if(t!==null&&!ht.includes(t))return this.onerror?.(new Error(`Bad Request: Unsupported protocol version: ${t} (supported versions: ${ht.join(", ")})`)),this.createJsonErrorResponse(400,-32e3,`Bad Request: Unsupported protocol version: ${t} (supported versions: ${ht.join(", ")})`)}async close(){this._streamMapping.forEach(({cleanup:a})=>{a()}),this._streamMapping.clear(),this._requestResponseMap.clear(),this.onclose?.()}closeSSEStream(a){let t=this._requestToStreamMapping.get(a);if(!t)return;let n=this._streamMapping.get(t);n&&n.cleanup()}closeStandaloneSSEStream(){let a=this._streamMapping.get(this._standaloneSseStreamId);a&&a.cleanup()}async send(a,t){let n=t?.relatedRequestId;if((o4(a)||pt(a))&&(n=a.id),n===void 0){if(o4(a)||pt(a))throw new Error("Cannot send a response on a standalone SSE stream unless resuming a previous client request");let i;this._eventStore&&(i=await this._eventStore.storeEvent(this._standaloneSseStreamId,a));let s=this._streamMapping.get(this._standaloneSseStreamId);if(s===void 0)return;s.controller&&s.encoder&&this.writeSSEEvent(s.controller,s.encoder,a,i);return}let r=this._requestToStreamMapping.get(n);if(!r)throw new Error(`No connection established for request ID: ${String(n)}`);let o=this._streamMapping.get(r);if(!this._enableJsonResponse&&o?.controller&&o?.encoder){let i;this._eventStore&&(i=await this._eventStore.storeEvent(r,a)),this.writeSSEEvent(o.controller,o.encoder,a,i)}if(o4(a)||pt(a)){this._requestResponseMap.set(n,a);let i=Array.from(this._requestToStreamMapping.entries()).filter(([l,u])=>u===r).map(([l])=>l);if(i.every(l=>this._requestResponseMap.has(l))){if(!o)throw new Error(`No connection established for request ID: ${String(n)}`);if(this._enableJsonResponse&&o.resolveJson){let l={"Content-Type":"application/json"};this.sessionId!==void 0&&(l["mcp-session-id"]=this.sessionId);let u=i.map(c=>this._requestResponseMap.get(c));u.length===1?o.resolveJson(new Response(JSON.stringify(u[0]),{status:200,headers:l})):o.resolveJson(new Response(JSON.stringify(u),{status:200,headers:l}))}else o.cleanup();for(let l of i)this._requestResponseMap.delete(l),this._requestToStreamMapping.delete(l)}}}};var yr=class{constructor(a={}){this._requestContext=new WeakMap,this._webStandardTransport=new fr(a),this._requestListener=hu(async t=>{let n=this._requestContext.get(t);return this._webStandardTransport.handleRequest(t,{authInfo:n?.authInfo,parsedBody:n?.parsedBody})},{overrideGlobalObjects:!1})}get sessionId(){return this._webStandardTransport.sessionId}set onclose(a){this._webStandardTransport.onclose=a}get onclose(){return this._webStandardTransport.onclose}set onerror(a){this._webStandardTransport.onerror=a}get onerror(){return this._webStandardTransport.onerror}set onmessage(a){this._webStandardTransport.onmessage=a}get onmessage(){return this._webStandardTransport.onmessage}async start(){return this._webStandardTransport.start()}async close(){return this._webStandardTransport.close()}async send(a,t){return this._webStandardTransport.send(a,t)}async handleRequest(a,t,n){let r=a.auth;await hu(async i=>this._webStandardTransport.handleRequest(i,{authInfo:r,parsedBody:n}),{overrideGlobalObjects:!1})(a,t)}closeSSEStream(a){this._webStandardTransport.closeSSEStream(a)}closeStandaloneSSEStream(){this._webStandardTransport.closeStandaloneSSEStream()}};var t$=16*1024*1024;function VW(e,a){let t=i=>{let s=e.indexOf(i);return s>=0&&s+1<e.length?e[s+1]:void 0},n=e.includes("--http")||/^(1|true|yes|on)$/i.test((a.BIC_MCP_HOSTED??"").trim()),r=t("--port")??a.BIC_MCP_HTTP_PORT??"8799",o=Number(r);if(!Number.isInteger(o)||o<0||o>65535)throw new Error(`--port must be a whole number from 0 to 65535 (got "${r}").`);return{http:n,host:t("--host")??"127.0.0.1",port:o}}function Nr(e,a,t,n={}){if(e.headersSent){e.end();return}e.writeHead(a,{"Content-Type":"application/json","Cache-Control":"no-store",...n}),e.end(JSON.stringify(t))}function s7(e,a,t,n,r={}){Nr(e,a,{jsonrpc:"2.0",error:{code:t,message:n},id:null},r)}function n$(e,a,t){return new Promise((n,r)=>{let o=[],i=0,s=!1;e.on("data",l=>{if(!s){if(i+=l.length,i>t){s=!0,o.length=0,s7(a,413,-32600,`The request is larger than this server accepts (${Math.floor(t/1048576)} MB). Send the table at the chart's grain - aggregated - or with fewer columns.`,{Connection:"close"}),n(null);return}o.push(l)}}),e.on("end",()=>{s||n(Buffer.concat(o).toString("utf-8"))}),e.on("error",r)})}async function r$(e,a,t){let n=Tb(e.headers.authorization);if(!n){s7(a,401,-32001,"Sign in to use this chart server: connect to it from your app, which sends your account's access token with each request.",{"WWW-Authenticate":"Bearer"});return}let r=await n$(e,a,t.maxBodyBytes??t$);if(r===null)return;let o;try{o=JSON.parse(r)}catch{s7(a,400,-32700,"Parse error: the request body isn't JSON.");return}let i=t.newServer(),s=new yr({sessionIdGenerator:void 0});a.on("close",()=>{s.close().catch(()=>{}),i.close().catch(()=>{})}),await i.connect(s);let l=Rb(e.headers[Nl.toLowerCase()]);await _b({accessToken:n,...l?{clientIp:l}:{}},()=>s.handleRequest(e,a,o))}function ZW(e){let a=e.log??(n=>{process.stderr.write(n+`
247
247
  `)}),t=a$((n,r)=>{let o=new URL(n.url??"/","http://localhost").pathname;if(o==="/healthz"){if(n.method!=="GET"&&n.method!=="HEAD"){Nr(r,405,{error:"Use GET."},{Allow:"GET"});return}Nr(r,200,{ok:!0,server:"bic-chart",version:e.version});return}if(o!=="/mcp"){Nr(r,404,{error:"Not found. The MCP endpoint is /mcp."});return}if(n.method!=="POST"){s7(r,405,-32e3,"Method not allowed: this server is stateless, so it takes POST only.",{Allow:"POST"});return}r$(n,r,e).catch(i=>{a(`[bic-chart http] request failed (${i?.name??"Error"})`),s7(r,500,-32603,"Internal error: the chart server couldn't handle this request. Try again.")})});return new Promise((n,r)=>{t.once("error",r),t.listen(e.port,e.host,()=>{t.off("error",r),n(t)})})}var QW=["assess_data_shape","list_eligible_charts","generate_chart","get_guide","preview_request"],l7="This hosted server receives your table, profiles it in memory and sends only the profile to generation; rows aren't stored or logged.",ek={csv_path:"this hosted server can't read files on your machine, so pass the table as data or csv_text",project_dir:"this hosted server can't see your project folder, so pass language or renderer instead",out_dir:"this hosted server returns the chart inline; it can't write to your machine",preview_html:"this hosted server returns the chart inline; it can't write to your machine"},Sr=e=>`Not accepted by this hosted server: ${ek[e]}.`,br={csv_path:T.string().optional().describe(Sr("csv_path")),project_dir:T.string().optional().describe(Sr("project_dir"))},qW={out_dir:T.string().optional().describe(Sr("out_dir")),preview_html:T.boolean().optional().describe(Sr("preview_html"))},JW=T.enum(["javascript","typescript","python",""]).optional(),YW=["csv_path","project_dir","out_dir","preview_html"],ak={assess_data_shape:{description:`Profile a dataset: per-column types, cardinality, ranges, measure/dimension roles, temporal/ordinal detection, and cross-column signals (nesting, shared values, association) - the same measurement engine the BIC Power BI visual uses before generating a chart. Pass the table as data ({columns, rows}) or csv_text. ${l7} This tool sends nothing on.`,inputs:{csv_path:br.csv_path},refuse:["csv_path"]},list_eligible_charts:{description:"The AUTHORITATIVE list of chart types that can render this dataset - the server's own eligibility engine, NOT a guess. Pass the table as data ({columns, rows}) or csv_text. "+l7+" Ranked for JavaScript (D3) unless you pass language ('python' ranks Plotly and matplotlib) or renderer ('D3'/'PLOTLY'/... for one renderer, '' for every renderer). No model runs, but the call is METERED: free within a generous hourly allowance, then usage credits per call, so avoid calling it in a tight loop.",inputs:{...br,language:JW.describe("Project source language: javascript/typescript ranks D3 and Vega, python ranks Plotly and matplotlib. Omit for JavaScript; `renderer`, when given, overrides it.")},refuse:["csv_path","project_dir"]},generate_chart:{description:`Generate ready-to-render chart code for a dataset: the backend picks a suitable chart type (or honors chart_type) and returns code that has passed its eligibility gates and quality checks. Pass the table as data ({columns, rows}) or csv_text. ${l7} The code and the render-ready data come back inline in the reply; this server writes no files. JavaScript (D3) unless you pass language or renderer. The D3 code is a portable render(container, data, options) function meant to be MERGED into your own app; an integration contract describes exactly how to call it. A generation uses your account's credits.`,inputs:{...br,...qW,language:JW.describe("Project source language: javascript/typescript generates D3 (the renderer @bicharts/chart-host draws), python lets the backend pick within Plotly/matplotlib. Omit for JavaScript (D3); `renderer`, when given, overrides it.")},refuse:YW},preview_request:{description:`Shows exactly what generate_chart would send to generation for these arguments - the measured shape of your data (column names, types, counts, ranges), the settings, and whether any sample rows travel - with the credentials removed. It sends nothing on and costs nothing. ${l7} Takes the same arguments as generate_chart.`,inputs:{...br,...qW},refuse:YW},get_guide:{description:"How to build an app with these charts, from the guide this server ships. Free, and it sends nothing on. topic 'fabric-app' (the default) is what a Microsoft Fabric App on the Rayfin data app template needs; 'all' is the whole guide, including Blazor; 'chart-shapes' lists every chart type with the columns, limits and renderers it needs. The guide also names tools that only the local server (npx -y @bicharts/chart-mcp) has, because they write into your project. Read it before the first generate_chart call."}};function tk(e,a){let t=(a??[]).filter(n=>{let r=e?.[n];return r!=null&&r!==!1&&r!==""});return t.length===0?null:t.map(n=>`${n} isn't accepted here: ${ek[n]}.`).join(" ")}var nk=["This is RegiaBI's hosted chart server. When a request asks for RegiaBI charts, it means these tools.",l7+" It can't read or write files on your machine: pass each table as data ({columns, rows}) or csv_text, and the chart comes back inline.","Asked which charts suit the data? Answer from list_eligible_charts, not from general knowledge.","Five rules for charts that fit on the first try:","1. Pass the chart's WHOLE result at its grain, not a sample: what fits depends on its counts.","2. Give columns the plain names your app renders with (rename Table[Column] first), unchanged at render time.","3. Call list_eligible_charts on that data before choosing, and choose what answers the question as asked. Where a chart has controls drawn inside the chart, build no input beside it.","4. Host the code with @bicharts/chart-host. generate_chart returns the code, the render-ready rows and the binding: pass them as they are, and never hand-build __rowIdx__ or __geo* columns.","5. Use `prompt` for what the chart shows; selection, cross-filtering, sizing and theming are the host's: filter with useBicFilter + selects, read a chart's sliders with useBicControls + controls (@bicharts/chart-host/react). Never write a select handler, toggle or clear.","Building an app? get_guide has the setup steps. The local server (npx -y @bicharts/chart-mcp) adds project tools that write the chart files into your app for you."].join(`
248
- `);function f8(e,a){return ir(e,a).dir??qa(e??process.cwd())}var mu="0.6.71",ok=[],kr=null,k3={registerTool(e,a,t){ok.push({name:e,config:a,cb:t})},get server(){if(!kr)throw new Error("The local server isn't running in this process.");return kr.server}};function rk(e){let a=e?new v2({name:"bic-chart",version:mu},{instructions:nk}):new v2({name:"bic-chart",version:mu},{instructions:zW});e||(a.server.registerCapabilities({logging:{}}),yb(t=>{a.server.sendLoggingMessage({level:"notice",logger:"sign-in",data:t}).catch(()=>{})}));for(let t of ok){if(e&&!QW.includes(t.name))continue;let n=e?ak[t.name]:void 0,r={...t.config,...n?{description:n.description,inputSchema:{...t.config.inputSchema,...n.inputs??{}}}:{},annotations:{title:t.config.title,...t.config.annotations}},o=n?.refuse?(i,s)=>{let l=tk(i,n.refuse);return l?{isError:!0,content:[{type:"text",text:l}]}:t.cb(i,s)}:t.cb;a.registerTool(t.name,r,o)}return a}var u7="2026-10-06T20:38:18Z src:e208619893b7 (33 files)",gu="@bicharts/chart-host@0.6.70, @bicharts/shape-core@0.6.70",o$=T.object({columns:T.array(T.object({name:T.string(),dataType:T.enum(["String","Integer","Decimal","DateTime"]).optional().describe("Known type (DAX/semantic-model callers have it); omit to infer from values."),isMeasure:T.boolean().optional().describe("Known measure/dimension role; omit to apply the numeric-non-identifier heuristic. A semantic-model caller should set this."),format:T.string().optional().describe('Format string from the model (e.g. "$#,##0") \u2192 modelFormat.'),description:T.string().optional().describe("Column description from the model \u2192 modelDesc.")})).min(1),rows:T.array(T.union([T.array(T.any()),T.record(T.string(),T.any())])).min(1).describe("Rows as positional arrays aligned to columns, OR objects keyed by column name.")}).describe("A pre-typed {columns, rows} table (DAX query results, dataframe, arrow). Use INSTEAD of csv_path/csv_text."),fu={csv_path:T.string().optional().describe("Path to a CSV file (header row required)."),csv_text:T.string().optional().describe("Inline CSV text (alternative to csv_path)."),data:o$.optional().describe("A pre-typed {columns, rows} table \u2014 the shape a Fabric DAX query / dataframe already has. Alternative to csv_path/csv_text; when columns carry isMeasure/format/description the shape matches PBI fidelity with no guessing."),measures:T.array(T.string()).optional().describe("Columns to treat as MEASURES (the PBI 'Values' well \u2014 fields the chart aggregates). Numeric non-identifier columns are measures by default."),dimensions:T.array(T.string()).optional().describe("Columns to treat as DIMENSIONS (a PBI category/axis well \u2014 fields to group/break by). Use for numeric codes/years that should NOT be aggregated."),formats:T.record(T.string(),T.string()).optional().describe(`Per-column number/date FORMAT STRING (e.g. {"Revenue":"$#,##0","Margin":"0.0%"}). PBI supplies these from its model; a CSV can't, so provide them to steer number formatting.`),descriptions:T.record(T.string(),T.string()).optional().describe("Per-column human DESCRIPTION \u2014 gives the model semantic context the bare column name lacks."),group_by:T.array(T.string()).optional().describe("Columns that are the PRIMARY series/breakdown (the PBI 'Group by' well); the backend leads the visualization with these."),non_additive:T.array(T.string()).optional().describe("MEASURE columns that must NOT be summed (a ratio/average/rate \u2014 use mean, never stack). Usually auto-detected; this is an authoritative override."),privacy_level:T.enum(["0","10","20","30"]).optional().describe("How much detail to compute/share: 0 names only, 10 +counts, 20 +detailed stats (default), 30 +obfuscated sample rows.")};function g8(e){return{measures:e.measures,dimensions:e.dimensions,formats:e.formats,descriptions:e.descriptions,groupBy:e.group_by,nonAdditive:e.non_additive,privacyLevel:e.privacy_level??"20"}}function Cr(e){if(e.data)return jf(e.data.columns,e.data.rows,g8(e));if(e.csv_text)return B4(e.csv_text,g8(e));if(e.csv_path)return B4(c7(qa(e.csv_path),"utf-8"),g8(e));throw new Error("Provide one of: data ({columns, rows}), csv_text, or csv_path.")}k3.registerTool("assess_data_shape",{title:"Assess data shape",description:"Profile a dataset locally (no data leaves the machine): per-column types, cardinality, ranges, measure/dimension roles, temporal/ordinal detection, and cross-column signals (nesting, shared values, association). This is the same measurement engine the BIC Power BI visual uses before generating a chart.",inputSchema:fu,annotations:{readOnlyHint:!0,openWorldHint:!1}},async e=>{let a=Cr(e),t={totalRows:a.totalRows,leafCardinality:a.index.getLeafCardinality(),columns:a.shape},n=g4()?null:Kb(process.env);return{content:[{type:"text",text:JSON.stringify(t,null,2)},...n?[{type:"text",text:n}]:[]]}});k3.registerTool("get_guide",{title:"Read the build guide",description:"How to build an app with these charts, from the guide this package ships. Local and free: no network, no credentials. topic 'fabric-app' (the default) is what a Microsoft Fabric App on the Rayfin data app template needs: what to pull, generating, wiring in React, the Fabric App section and the time-savers. 'all' is the whole guide, including Blazor. 'chart-shapes' lists every chart type with the columns, limits and renderers it needs. Read it before the first generate_chart call.",inputSchema:{topic:T.enum(xW).optional().describe("'fabric-app' (default), 'all', or 'chart-shapes'.")},annotations:{readOnlyHint:!0,openWorldHint:!1}},async e=>{try{return{content:[{type:"text",text:jW(e.topic??"fabric-app")}]}}catch(a){return{isError:!0,content:[{type:"text",text:`The guide could not be read from this package (${a?.message??a}). It is also published as skills/bic-charts/SKILL.md inside @bicharts/chart-mcp on npm.`}]}}});k3.registerTool("list_eligible_charts",{title:"List eligible chart types",description:"The AUTHORITATIVE list of chart types that can render this dataset \u2014 the server's own eligibility engine, NOT a local guess. Profiles the data locally, then sends that profile to the backend. NO LLM in the loop, but this is a NETWORK call and it is METERED \u2014 see the licensing note below. By default the tool DETECTS the project's language (JS/TS vs Python from the working dir) and returns the charts for THAT language, SCOPED + RANKED by the picker's chart-type\xD7renderer weights (best first), each tagged with its source language and renderer. Pass `language` ('javascript'|'python') to force it, or `renderer` ('D3'/'PLOTLY'/\u2026) to rank one specific renderer, or renderer '' for the full renderer-agnostic eligibility across ALL renderers (also ranked, by chart type alone, with no renderer/language tag). If the language can't be auto-detected and none is given, the tool asks you to specify one. Needs an account: eligibility IS the engine, so programmatic access to it is licensed. With nothing configured, the first call opens a browser sign-in, waits for it and then answers (a license key in the environment is the alternative for a machine with no browser). Free within a generous hourly allowance; beyond it a call may draw usage credits, so avoid calling it in a tight loop.",inputSchema:{...fu,language:T.enum(["javascript","typescript","python",""]).optional().describe("Project source language \u2192 the server ranks across that language's renderers (javascript/typescript = D3/Vega, python = Plotly/matplotlib). Omit to AUTO-DETECT from the working dir; `renderer` (if given) overrides this."),project_dir:T.string().optional().describe("Directory to auto-detect the project language from (default: the folder setup_fabric_app used, else the working directory or the one project folder directly inside it)."),renderer:T.enum(["D3","PLOTLY","PYMATPLOT","VEGA",""]).optional().describe("Force a specific renderer (overrides `language`): a concrete renderer ranks that renderer's charts; '' = the full renderer-agnostic eligibility (all renderers, ranked by chart type alone). Omit to use `language`/auto-detection."),level_of_detail:T.enum(["High","Medium","Low",""]).optional().describe("How much of the data the user wants to SEE \u2014 ASK THEM, do not infer. 'High' = every observation as its own mark, 'Medium' = every row shown as a distribution, 'Low' = one mark per category. Ranks this list the same way a generation would, so what you see here is what you will get. Omit if they have expressed no preference."),name_filter:T.string().optional().describe("Show only chart types matching this text (the same matcher the Power BI and Excel chart-type lists use). Three tiers, first non-empty one wins outright: the term starting a WORD in the name ('gan' -> Gantt chart, and NOT Organization chart), then mid-word in the name ('eth' -> Choropleth), then the description. A name match therefore SUPPRESSES description matches. Case- and accent-insensitive and, by default, space- and punctuation-insensitive too ('barchart' and 'bar-chart' find Bar chart; see name_filter_match). Minimum two characters, and it never reorders - the picker's ranking is preserved and the ranks stay as issued. Applied after ranking and before `top`."),name_filter_match:T.enum(["loose","exact"]).optional().describe("How name_filter matches a name. 'loose' (the default) ignores accents, case, spaces and punctuation, so 'barchart' finds Bar chart. 'exact' folds accents and case and collapses repeated spaces, and nothing else: a name typed without its space or hyphen matches nothing. The same setting the Power BI and Excel chart-type lists offer."),top:T.number().optional().describe("Show only the top-N ranked results. Omit for all."),width:T.number().optional().describe("Viewport width px (default 800) \u2014 affects small-viewport / facet-budget gates."),height:T.number().optional().describe("Viewport height px (default 600).")},annotations:{readOnlyHint:!0,openWorldHint:!0}},async e=>{let a=Cr(e),t="",n="",r="",o="";if(e.renderer!==void 0)t=e.renderer;else if(e.language)n=e.language;else if(g4())n="javascript",r=" (language: javascript, this server's default - pass language or renderer for another)";else{let f=rr(f8(e.project_dir,s8));f.language?(n=f.language,r=` (auto-detected language: ${f.language} \u2014 ${f.reason})`):o=`Couldn't tell the project's language (${f.reason}), so this is the list across all renderers; pass language: "javascript" or "python", or project_dir, to narrow it.
249
- `}Dl("list_eligible_charts",process.env);let i=await vl({shape:a.shape,totalRows:a.totalRows,leafCardinality:a.index.getLeafCardinality(),geoExtent:a.index.getGeoExtent(),width:e.width,height:e.height,renderer:t,language:n,levelOfDetail:e.level_of_detail||void 0});if(!i.ok)return{isError:!0,content:[{type:"text",text:Hl(i)?i.errorMessage:`Could not list eligible charts: ${i.errorMessage}`}]};let s=i.charts.length>0&&i.charts[0].rank!==void 0,l=n?`${n}`:t||"all renderers",u=i.charts,c=u.length,d=PN(e.name_filter_match),p=V2(u,e.name_filter,In,d);u=p.rows;let m;if(s?(e.top&&e.top>0&&(u=u.slice(0,e.top)),m=`Top ${u.length} chart type(s) for this data in ${l}, ranked by the picker's weights (authoritative \u2014 the server's eligibility engine; ${$n})${r}:`):m=`${u.length} chart type(s) can render this data \u2014 renderer-agnostic eligibility (authoritative \u2014 the server's eligibility engine; ${$n}):`,m=o+m,p.tier!=="all"){let f=p.tier==="desc"?" (no NAME matched; these matched on description)":p.tier==="namePart"?" (matched mid-word in the name)":"";m=`Filtered to "${e.name_filter}"${f}: ${u.length} of ${c} eligible chart type(s). The other ${c-u.length} are eligible and simply do not match the filter.
248
+ `);function f8(e,a){return ir(e,a).dir??qa(e??process.cwd())}var mu="0.6.72",ok=[],kr=null,k3={registerTool(e,a,t){ok.push({name:e,config:a,cb:t})},get server(){if(!kr)throw new Error("The local server isn't running in this process.");return kr.server}};function rk(e){let a=e?new v2({name:"bic-chart",version:mu},{instructions:nk}):new v2({name:"bic-chart",version:mu},{instructions:zW});e||(a.server.registerCapabilities({logging:{}}),yb(t=>{a.server.sendLoggingMessage({level:"notice",logger:"sign-in",data:t}).catch(()=>{})}));for(let t of ok){if(e&&!QW.includes(t.name))continue;let n=e?ak[t.name]:void 0,r={...t.config,...n?{description:n.description,inputSchema:{...t.config.inputSchema,...n.inputs??{}}}:{},annotations:{title:t.config.title,...t.config.annotations}},o=n?.refuse?(i,s)=>{let l=tk(i,n.refuse);return l?{isError:!0,content:[{type:"text",text:l}]}:t.cb(i,s)}:t.cb;a.registerTool(t.name,r,o)}return a}var u7="2026-10-06T21:48:45Z src:81e731fb800d (33 files)",gu="@bicharts/chart-host@0.6.70, @bicharts/shape-core@0.6.70",o$=T.object({columns:T.array(T.object({name:T.string(),dataType:T.enum(["String","Integer","Decimal","DateTime"]).optional().describe("Known type (DAX/semantic-model callers have it); omit to infer from values."),isMeasure:T.boolean().optional().describe("Known measure/dimension role; omit to apply the numeric-non-identifier heuristic. A semantic-model caller should set this."),format:T.string().optional().describe('Format string from the model (e.g. "$#,##0") \u2192 modelFormat.'),description:T.string().optional().describe("Column description from the model \u2192 modelDesc.")})).min(1),rows:T.array(T.union([T.array(T.any()),T.record(T.string(),T.any())])).min(1).describe("Rows as positional arrays aligned to columns, OR objects keyed by column name.")}).describe("A pre-typed {columns, rows} table (DAX query results, dataframe, arrow). Use INSTEAD of csv_path/csv_text."),fu={csv_path:T.string().optional().describe("Path to a CSV file (header row required)."),csv_text:T.string().optional().describe("Inline CSV text (alternative to csv_path)."),data:o$.optional().describe("A pre-typed {columns, rows} table \u2014 the shape a Fabric DAX query / dataframe already has. Alternative to csv_path/csv_text; when columns carry isMeasure/format/description the shape matches PBI fidelity with no guessing."),measures:T.array(T.string()).optional().describe("Columns to treat as MEASURES (the PBI 'Values' well \u2014 fields the chart aggregates). Numeric non-identifier columns are measures by default."),dimensions:T.array(T.string()).optional().describe("Columns to treat as DIMENSIONS (a PBI category/axis well \u2014 fields to group/break by). Use for numeric codes/years that should NOT be aggregated."),formats:T.record(T.string(),T.string()).optional().describe(`Per-column number/date FORMAT STRING (e.g. {"Revenue":"$#,##0","Margin":"0.0%"}). PBI supplies these from its model; a CSV can't, so provide them to steer number formatting.`),descriptions:T.record(T.string(),T.string()).optional().describe("Per-column human DESCRIPTION \u2014 gives the model semantic context the bare column name lacks."),group_by:T.array(T.string()).optional().describe("Columns that are the PRIMARY series/breakdown (the PBI 'Group by' well); the backend leads the visualization with these."),non_additive:T.array(T.string()).optional().describe("MEASURE columns that must NOT be summed (a ratio/average/rate \u2014 use mean, never stack). Usually auto-detected; this is an authoritative override."),privacy_level:T.enum(["0","10","20","30"]).optional().describe("How much detail to compute/share: 0 names only, 10 +counts, 20 +detailed stats (default), 30 +obfuscated sample rows.")};function g8(e){return{measures:e.measures,dimensions:e.dimensions,formats:e.formats,descriptions:e.descriptions,groupBy:e.group_by,nonAdditive:e.non_additive,privacyLevel:e.privacy_level??"20"}}function Cr(e){if(e.data)return jf(e.data.columns,e.data.rows,g8(e));if(e.csv_text)return B4(e.csv_text,g8(e));if(e.csv_path)return B4(c7(qa(e.csv_path),"utf-8"),g8(e));throw new Error("Provide one of: data ({columns, rows}), csv_text, or csv_path.")}k3.registerTool("assess_data_shape",{title:"Assess data shape",description:"Profile a dataset locally (no data leaves the machine): per-column types, cardinality, ranges, measure/dimension roles, temporal/ordinal detection, and cross-column signals (nesting, shared values, association). This is the same measurement engine the BIC Power BI visual uses before generating a chart.",inputSchema:fu,annotations:{readOnlyHint:!0,openWorldHint:!1}},async e=>{let a=Cr(e),t={totalRows:a.totalRows,leafCardinality:a.index.getLeafCardinality(),columns:a.shape},n=g4()?null:Kb(process.env);return{content:[{type:"text",text:JSON.stringify(t,null,2)},...n?[{type:"text",text:n}]:[]]}});k3.registerTool("get_guide",{title:"Read the build guide",description:"How to build an app with these charts, from the guide this package ships. Local and free: no network, no credentials. topic 'fabric-app' (the default) is what a Microsoft Fabric App on the Rayfin data app template needs: what to pull, generating, wiring in React, the Fabric App section and the time-savers. 'all' is the whole guide, including Blazor. 'chart-shapes' lists every chart type with the columns, limits and renderers it needs. Read it before the first generate_chart call.",inputSchema:{topic:T.enum(xW).optional().describe("'fabric-app' (default), 'all', or 'chart-shapes'.")},annotations:{readOnlyHint:!0,openWorldHint:!1}},async e=>{try{return{content:[{type:"text",text:jW(e.topic??"fabric-app")}]}}catch(a){return{isError:!0,content:[{type:"text",text:`The guide could not be read from this package (${a?.message??a}). It is also published as skills/bic-charts/SKILL.md inside @bicharts/chart-mcp on npm.`}]}}});k3.registerTool("list_eligible_charts",{title:"List eligible chart types",description:"The AUTHORITATIVE list of chart types that can render this dataset \u2014 the server's own eligibility engine, NOT a local guess. Profiles the data locally, then sends that profile to the backend. NO LLM in the loop, but this is a NETWORK call and it is METERED \u2014 see the licensing note below. By default the tool DETECTS the project's language (JS/TS vs Python from the working dir) and returns the charts for THAT language, SCOPED and ordered by how well each type fits this data (best first; `order: 'variety'` favors newer and less-common types instead), each tagged with its source language and renderer. Pass `language` ('javascript'|'python') to force it, or `renderer` ('D3'/'PLOTLY'/\u2026) to rank one specific renderer, or renderer '' for the full renderer-agnostic eligibility across ALL renderers (also ranked, by chart type alone, with no renderer/language tag). If the language can't be auto-detected and none is given, the tool asks you to specify one. Needs an account: eligibility IS the engine, so programmatic access to it is licensed. With nothing configured, the first call opens a browser sign-in, waits for it and then answers (a license key in the environment is the alternative for a machine with no browser). Free within a generous hourly allowance; beyond it a call may draw usage credits, so avoid calling it in a tight loop.",inputSchema:{...fu,language:T.enum(["javascript","typescript","python",""]).optional().describe("Project source language \u2192 the server ranks across that language's renderers (javascript/typescript = D3/Vega, python = Plotly/matplotlib). Omit to AUTO-DETECT from the working dir; `renderer` (if given) overrides this."),project_dir:T.string().optional().describe("Directory to auto-detect the project language from (default: the folder setup_fabric_app used, else the working directory or the one project folder directly inside it)."),renderer:T.enum(["D3","PLOTLY","PYMATPLOT","VEGA",""]).optional().describe("Force a specific renderer (overrides `language`): a concrete renderer ranks that renderer's charts; '' = the full renderer-agnostic eligibility (all renderers, ranked by chart type alone). Omit to use `language`/auto-detection."),level_of_detail:T.enum(["High","Medium","Low",""]).optional().describe("How much of the data the user wants to SEE \u2014 ASK THEM, do not infer. 'High' = every observation as its own mark, 'Medium' = every row shown as a distribution, 'Low' = one mark per category. Ranks this list the same way a generation would, so what you see here is what you will get. Omit if they have expressed no preference."),name_filter:T.string().optional().describe("Show only chart types matching this text (the same matcher the Power BI and Excel chart-type lists use). Three tiers, first non-empty one wins outright: the term starting a WORD in the name ('gan' -> Gantt chart, and NOT Organization chart), then mid-word in the name ('eth' -> Choropleth), then the description. A name match therefore SUPPRESSES description matches. Case- and accent-insensitive and, by default, space- and punctuation-insensitive too ('barchart' and 'bar-chart' find Bar chart; see name_filter_match). Minimum two characters, and it never reorders - the picker's ranking is preserved and the ranks stay as issued. Applied after ranking and before `top`."),name_filter_match:T.enum(["loose","exact"]).optional().describe("How name_filter matches a name. 'loose' (the default) ignores accents, case, spaces and punctuation, so 'barchart' finds Bar chart. 'exact' folds accents and case and collapses repeated spaces, and nothing else: a name typed without its space or hyphen matches nothing. The same setting the Power BI and Excel chart-type lists offer."),order:T.enum(["fit","variety"]).optional().describe("How the list is ordered. 'fit' (the default) = by how well each chart type fits THIS data, nothing else - use it to choose a chart for a question. 'variety' = the picker's selection order, which favors newer and less-common types on purpose - use it when the user wants to explore or be surprised. Both lists hold the same chart types; only the order differs."),top:T.number().optional().describe("Show only the top-N ranked results. Omit for all."),width:T.number().optional().describe("Viewport width px (default 800) \u2014 affects small-viewport / facet-budget gates."),height:T.number().optional().describe("Viewport height px (default 600).")},annotations:{readOnlyHint:!0,openWorldHint:!0}},async e=>{let a=Cr(e),t="",n="",r="",o="";if(e.renderer!==void 0)t=e.renderer;else if(e.language)n=e.language;else if(g4())n="javascript",r=" (language: javascript, this server's default - pass language or renderer for another)";else{let f=rr(f8(e.project_dir,s8));f.language?(n=f.language,r=` (auto-detected language: ${f.language} \u2014 ${f.reason})`):o=`Couldn't tell the project's language (${f.reason}), so this is the list across all renderers; pass language: "javascript" or "python", or project_dir, to narrow it.
249
+ `}Dl("list_eligible_charts",process.env);let i=await vl({shape:a.shape,totalRows:a.totalRows,leafCardinality:a.index.getLeafCardinality(),geoExtent:a.index.getGeoExtent(),width:e.width,height:e.height,renderer:t,language:n,levelOfDetail:e.level_of_detail||void 0,order:e.order??"fit"});if(!i.ok)return{isError:!0,content:[{type:"text",text:Hl(i)?i.errorMessage:`Could not list eligible charts: ${i.errorMessage}`}]};let s=i.charts.length>0&&i.charts[0].rank!==void 0,l=n?`${n}`:t||"all renderers",u=i.charts,c=u.length,d=PN(e.name_filter_match),p=V2(u,e.name_filter,In,d);u=p.rows;let m;if(s){e.top&&e.top>0&&(u=u.slice(0,e.top));let f=(e.order??"fit")==="variety"?'ordered for variety (newer and less-common types first; order: "fit" ranks by fit to this data)':'ordered by fit to this data (order: "variety" favors newer and less-common types)';m=`Top ${u.length} chart type(s) for this data in ${l}, ${f} (authoritative \u2014 the server's eligibility engine; ${$n})${r}:`}else m=`${u.length} chart type(s) can render this data \u2014 renderer-agnostic eligibility (authoritative \u2014 the server's eligibility engine; ${$n}):`;if(m=o+m,p.tier!=="all"){let f=p.tier==="desc"?" (no NAME matched; these matched on description)":p.tier==="namePart"?" (matched mid-word in the name)":"";m=`Filtered to "${e.name_filter}"${f}: ${u.length} of ${c} eligible chart type(s). The other ${c-u.length} are eligible and simply do not match the filter.
250
250
  `+m}let h=RW(u);if(u.length===0&&p.tier!=="all"&&c>0){let f=V2(i.refused,e.name_filter,UN,d),y=f.tier==="name"||f.tier==="namePart"?f.rows.filter(k=>k.reason).slice(0,3):[],W=y.length>0?`
251
251
 
252
252
  It IS in the catalogue and was checked, and here is why it was refused for this data:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bicharts/chart-mcp",
3
- "version": "0.6.71",
3
+ "version": "0.6.72",
4
4
  "description": "MCP (Model Context Protocol) stdio server for BIC AI charts: profile a dataset locally, then generate chart code that has passed the BIC backend's render gates. Works with any MCP-capable client (Claude Code, Claude Desktop, Cursor, Copilot Studio). An account pays to author charts; the code it writes is yours and runs with no licence.",
5
5
  "keywords": [
6
6
  "mcp",