import{createRequire as ne}from"node:module";import{existsSync as G,mkdirSync as oe,writeFileSync as z}from"node:fs";import{dirname as Z,join as F,resolve as q}from"node:path";import{fileURLToPath as J}from"node:url";var re=ne(import.meta.url),C=null;function ie(){return C||(C=re("@resvg/resvg-js")),C}var K=1200,ae=627,se=4096,ce=320,le="#3b82f6",k="Noto Sans",de=3;function he(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let e=Z(J(import.meta.url)),t=q(e,"..","bin","mcp-skill.mjs");return G(t)?t:null}function fe(){let e=Z(J(import.meta.url)),t=q(e,"..","assets","fonts");return["NotoSans-Regular.ttf","NotoSans-Bold.ttf"].map(n=>F(t,n)).filter(n=>G(n))}function ue(){let e=process.env.ZIBBY_NODE_SESSION_PATH,t=process.env.ZIBBY_SESSION_PATH,n=e||(t?F(t,"social-card"):F(process.cwd(),".zibby","output","social-cards"));return oe(n,{recursive:!0}),n}function U(e,t){let n=Number(e);return Number.isFinite(n)?Math.max(ce,Math.min(se,Math.round(n))):t}function _(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function pe(e){return typeof e!="string"?null:e.trim().replace(/\.(png|svg)$/i,"").replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^[.-]+|[.-]+$/g,"")||null}function ge(e,t){if(typeof e!="string")return t;let n=e.trim();return/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(n)?n:t}function X(e,t,n){return String(e).length*t*n}function E(e,t,n,h){let a=String(e).trim().split(/\s+/).filter(Boolean),o=[],r="";for(let i of a){let f=r?`${r} ${i}`:i;r&&X(f,n,h)>t?(o.push(r),r=i):r=f}return r&&o.push(r),o.length?o:[""]}function me(e){return e==="light"?{bg:"#ffffff",fg:"#0b0f14",muted:"#5b6673",pillText:"#0b0f14",checkFg:"#ffffff",divider:"#e2e6ea"}:{bg:"#0b0f14",fg:"#e9edf1",muted:"#8b98a5",pillText:"#e9edf1",checkFg:"#0b0f14",divider:"#22303c"}}function j(e,t,n,h,a){let o=(Array.isArray(e)?e:[]).map(l=>String(l??"").trim()).filter(Boolean).slice(0,de);if(o.length<2)return null;let r=24,i=54,f=26,m=90,y=17,b=o.map(l=>Math.max(96,X(l,r,.58)+f*2)),$=b.reduce((l,p)=>l+p,0)+m*(o.length-1),s=t-$/2,c=n+i/2,x=[];for(let l=0;l<o.length;l++){let p=b[l];if(x.push(`<rect x="${s.toFixed(1)}" y="${n}" width="${p.toFixed(1)}" height="${i}" rx="${i/2}" fill="${a}" fill-opacity="0.12" stroke="${a}" stroke-opacity="0.55" stroke-width="1.5"/>`,`<text x="${(s+p/2).toFixed(1)}" y="${(c+r*.35).toFixed(1)}" text-anchor="middle" font-family="${k}" font-size="${r}" font-weight="700" fill="${h.pillText}">${_(o[l])}</text>`),s+=p,l<o.length-1){let A=s,S=s+m,N=(A+S)/2;x.push(`<line x1="${A.toFixed(1)}" y1="${c}" x2="${S.toFixed(1)}" y2="${c}" stroke="${a}" stroke-opacity="0.55" stroke-width="2"/>`,`<circle cx="${N.toFixed(1)}" cy="${c}" r="${y}" fill="${a}"/>`,`<path d="M ${(N-8).toFixed(1)} ${c.toFixed(1)} l 5 5 l 9 -11" fill="none" stroke="${h.checkFg}" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>`),s=S}}return{svg:x.join(`
`),height:i}}function ye(e){let{width:t,height:n,theme:h,accent:a}=e,o=me(h),r=t/2,i=Math.round(t*.07),f=t-i*2,m=String(e.headline).trim(),y=e.eyebrow?String(e.eyebrow).trim().toUpperCase():"",b=e.subhead?String(e.subhead).trim():"",$=e.stat?String(e.stat).trim():"",s=e.footer?String(e.footer).trim():"",c=t/K,x=Math.round(22*c),l=Math.round(29*c),p=b?E(b,f,l,.52):[],A=Math.round(l*1.28),S=4,N=Math.round(26*c),T=Math.round(20*c),B=Math.round(24*c),D=Math.round(30*c),P=!!($||s),R=i,Q=P?Math.round(110*c):i,H=n-R-Q,M=j(e.diagram,r,0,o,a),W=(d,w)=>{let O=S+N;return y&&(O+=x+T),O+=w.length*Math.round(d*1.16),p.length&&(O+=B+p.length*A),M&&(O+=D+M.height),O},I=[76,66,58,50,44,38].map(d=>Math.round(d*c)),V=4,v=I[I.length-1],L=E(m,f,v,.6);for(let d of I){let w=E(m,f,d,.6);if(w.length<=V&&W(d,w)<=H){v=d,L=w;break}}let ee=Math.round(v*1.16),te=W(v,L),u=R+Math.max(0,(H-te)/2),g=[];g.push(`<rect x="0" y="0" width="${t}" height="${n}" fill="${o.bg}"/>`);let Y=Math.round(60*c);g.push(`<rect x="${(r-Y/2).toFixed(1)}" y="${u}" width="${Y}" height="${S}" rx="2" fill="${a}"/>`),u+=S+N,y&&(g.push(`<text x="${r}" y="${(u+x*.82).toFixed(1)}" text-anchor="middle" font-family="${k}" font-size="${x}" font-weight="700" letter-spacing="3" fill="${a}">${_(y)}</text>`),u+=x+T);for(let d of L)g.push(`<text x="${r}" y="${(u+v*.82).toFixed(1)}" text-anchor="middle" font-family="${k}" font-size="${v}" font-weight="700" fill="${o.fg}">${_(d)}</text>`),u+=ee;if(p.length){u+=B;for(let d of p)g.push(`<text x="${r}" y="${(u+l*.82).toFixed(1)}" text-anchor="middle" font-family="${k}" font-size="${l}" font-weight="400" fill="${o.muted}">${_(d)}</text>`),u+=A}if(M){u+=D;let d=j(e.diagram,r,u,o,a);d&&g.push(d.svg)}if(P){let d=Math.round(24*c),w=n-Math.round(46*c);s&&g.push(`<text x="${i}" y="${w}" text-anchor="start" font-family="${k}" font-size="${d}" font-weight="400" fill="${o.muted}">${_(s)}</text>`),$&&g.push(`<text x="${t-i}" y="${w}" text-anchor="end" font-family="${k}" font-size="${d}" font-weight="700" fill="${a}">${_($)}</text>`)}return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${n}" viewBox="0 0 ${t} ${n}">
${g.join(`
`)}
</svg>`}function be(e){let{Resvg:t}=ie();return new t(e,{font:{fontFiles:fe(),loadSystemFonts:!0,defaultFontFamily:k}}).render().asPng()}var ke={id:"social-card",serverName:"social_card",allowedTools:["mcp__social_card__*"],description:'Social card \u2014 render a branded LinkedIn "concept card" PNG locally (bold headline + eyebrow + optional stat/footer/diagram); nothing leaves the box',promptFragment:`## Social Card (branded concept card, local)
You can render a BRANDED concept card PNG with the social_card_render tool \u2014 the
clean, high-signal LinkedIn "concept card" style (bold headline + small uppercase
eyebrow + optional stat/footer + optional A\u2014\u2713\u2014B diagram). Give it STRUCTURED
fields that capture the ONE key idea of your post:
- headline (required): the big, bold line \u2014 the single takeaway.
- eyebrow: a short uppercase kicker (e.g. "MY WORKFLOW", "OPEN SOURCE").
- subhead: one supporting line under the headline.
- stat / footer: e.g. stat "11.8k stars", footer "Apache 2.0".
- diagram: 2-3 short labels rendered as a chain, e.g. ["Claude Code","Codex"].
- theme ('dark' default | 'light'), accent (hex).
It renders server-side to a PNG in the run's output folder and returns
{ ok:true, files:[{ path, format:'png', bytes }] }. Pass the returned \`path\` as
\`imagePath\` when you draft/publish a LinkedIn post to ATTACH the card as the
post image. No browser, no external service \u2014 the data never leaves the machine.`,resolve({sessionPath:e,nodeName:t}={}){let n=he();if(!n)return{command:null,args:[],env:{},description:this.description};let h={},a=e&&t?F(e,t):null;a&&(h.ZIBBY_NODE_SESSION_PATH=a),e&&(h.ZIBBY_SESSION_PATH=e);for(let o of["ZIBBY_NODE_SESSION_PATH","ZIBBY_SESSION_PATH"])!h[o]&&process.env[o]&&(h[o]=process.env[o]);return{type:"stdio",command:"node",args:[n,"../dist/socialCard.js","socialCardSkill"],env:h,description:this.description,alwaysLoad:!0}},async handleToolCall(e,t){if(e!=="social_card_render")return JSON.stringify({error:`Unknown tool: ${e}`});try{let n=t?.headline;if(typeof n!="string"||!n.trim())return JSON.stringify({error:"headline (the big bold line) is required and must be a non-empty string."});let h=U(t?.width,K),a=U(t?.height,ae),o=t?.theme==="light"?"light":"dark",r=ge(t?.accent,le),i;try{i=ye({width:h,height:a,theme:o,accent:r,headline:n,eyebrow:t?.eyebrow,subhead:t?.subhead,stat:t?.stat,footer:t?.footer,diagram:t?.diagram})}catch(s){return JSON.stringify({error:`Card layout failed: ${s.message}`})}let f;try{f=be(i)}catch(s){return JSON.stringify({error:`PNG rasterization failed: ${s.message}`})}let m=ue(),y=pe(t?.filename)||`social-card-${Date.now()}`,b=F(m,`${y}.png`);z(b,f);let $=[{path:b,format:"png",bytes:f.length}];if(t?.output==="both"||t?.output==="svg"){let s=F(m,`${y}.svg`);z(s,i,"utf-8"),$.push({path:s,format:"svg",bytes:Buffer.byteLength(i,"utf-8")})}return JSON.stringify({ok:!0,width:h,height:a,theme:o,files:$})}catch(n){return JSON.stringify({error:`social_card_render failed: ${n.message}`})}},tools:[{name:"social_card_render",description:'Render a BRANDED "concept card" PNG LOCALLY (no external service) from structured fields \u2014 the clean LinkedIn concept-card style: bold headline + small uppercase eyebrow + optional supporting subhead, stat, footer, and an A\u2014\u2713\u2014B diagram. Returns { ok:true, files:[{ path, format:"png", bytes }] }. Pass the returned `path` as `imagePath` to a LinkedIn post tool to attach it as the post image. Example: { "headline":"No more copy-paste between AI tools", "eyebrow":"MY WORKFLOW", "stat":"11.8k stars", "footer":"Apache 2.0", "diagram":["Claude Code","Codex"] }.',input_schema:{type:"object",properties:{headline:{type:"string",description:"REQUIRED. The big, bold line \u2014 the single key idea/takeaway. Word-wrapped + auto-sized."},eyebrow:{type:"string",description:'Small uppercase kicker above the headline (e.g. "MY WORKFLOW", "OPEN SOURCE"). Rendered uppercased in the accent color.'},subhead:{type:"string",description:"One supporting line under the headline (muted)."},stat:{type:"string",description:'Optional stat, shown bottom-right in the accent color (e.g. "11.8k stars", "3x faster").'},footer:{type:"string",description:'Optional footer, shown bottom-left (muted) (e.g. "Apache 2.0", a repo name).'},diagram:{type:"array",items:{type:"string"},description:'Optional 2-3 short labels rendered as a chain of pills joined by a checkmark (A \u2014\u2713\u2014 B), e.g. ["Claude Code","Codex"].'},theme:{type:"string",enum:["dark","light"],description:"Card theme (default 'dark' \u2014 near-black bg, off-white text)."},accent:{type:"string",description:'Accent hex color (e.g. "#f97316"). Defaults to a tasteful blue (#3b82f6).'},width:{type:"number",description:"Image width in px (default 1200 \u2014 LinkedIn 1.91:1 link image)."},height:{type:"number",description:"Image height in px (default 627)."},filename:{type:"string",description:"Optional file basename (no extension); defaults to social-card-<timestamp>."},output:{type:"string",enum:["png","both"],description:"Which file(s) to write (default 'png'; 'both' also writes the .svg)."}},required:["headline"]}}]};export{ke as socialCardSkill};
