@hraness/slopcamera 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/NOTICE.md +14 -0
  2. package/README.md +294 -298
  3. package/apps/desktop/application/html-overlay-integrity.ts +27 -4
  4. package/apps/desktop/application/operation.ts +1 -1
  5. package/apps/desktop/application/operations/spatial-render.ts +1 -1
  6. package/apps/desktop/cli/capability-manifest.ts +15 -2
  7. package/apps/desktop/cli/commands.ts +1 -1
  8. package/apps/desktop/cli/help.ts +23 -4
  9. package/apps/desktop/cli/portable-surface.ts +1 -0
  10. package/apps/desktop/cli/verbs.ts +4 -0
  11. package/apps/desktop/dist/cli/main.js +306 -284
  12. package/dist/cli.js +24 -4
  13. package/dist/{index-842t02pp.js → index-m6g0ca9b.js} +1 -1
  14. package/dist/{index-y8spxs77.js → index-mgychzh3.js} +6 -3
  15. package/dist/{index-k9bjw80z.js → index-rxx27q8b.js} +4 -4
  16. package/dist/index.js +1 -1
  17. package/dist/operations.js +1 -1
  18. package/dist/workflow.js +1 -1
  19. package/docs/README.md +4 -1
  20. package/package.json +5 -3
  21. package/skills/slopcamera/SKILL.md +2 -0
  22. package/skills/slopcamera/references/customization.md +8 -1
  23. package/skills/slopcamera/references/icon-place.md +76 -0
  24. package/skills/slopcamera/references/install.md +2 -2
  25. package/skills/slopcamera/references/music-video.md +10 -2
  26. package/skills/slopcamera/references/soundtracks.md +58 -0
  27. package/src/bounded-file.ts +135 -0
  28. package/src/cli.ts +191 -0
  29. package/src/icon-scene.ts +695 -0
  30. package/src/index.ts +2 -0
  31. package/src/mcp/tools.ts +311 -0
  32. package/src/mcp/types.ts +4 -0
  33. package/src/operations.ts +306 -0
  34. package/src/soundtrack.ts +489 -0
  35. package/src/version.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{VectorizeDeadline,encodeTracePng,loadRaster,normalizedHexColor,parseHexColor,resolveVectorizeLimits,vectorizeHardLimits,vectorizeImage}from"./index-mnp0bftq.js";import{SlopcameraCloudError,createFixedGatewayFetch,generateSlopcameraImage,generateSlopcameraImageFile,resolveSlopcameraGatewayCredential,slopcameraGatewayApiBaseUrl,slopcameraImageModels,slopcameraMaximumPromptBytes}from"./index-p74xy76d.js";import{createDefaultHostResourceCoordinator}from"./index-b3geqczn.js";import{__require}from"./index-80a36bc0.js";import{randomUUID as randomUUID3}from"crypto";import{mkdir as mkdir3,readFile as readFile2,rename as rename2,rm as rm3,writeFile as writeFile3}from"fs/promises";import{dirname as dirname3,join as join2,resolve as resolve3}from"path";var shared='fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"';var builtInIcons=Object.freeze({brain:{viewBox:"0 0 24 24",body:`<path ${shared} d="M9.5 4.5A3.5 3.5 0 0 0 6 8v.35A3.5 3.5 0 0 0 5.5 15 3.5 3.5 0 0 0 9 19.5M14.5 4.5A3.5 3.5 0 0 1 18 8v.35a3.5 3.5 0 0 1 .5 6.65 3.5 3.5 0 0 1-3.5 4.5M9.5 4.5v15M14.5 4.5v15M6 9.5h3.5M14.5 14.5H18"/>`},check:{viewBox:"0 0 24 24",body:`<path ${shared} d="m5 12 4.25 4.25L19 6.5"/>`},code:{viewBox:"0 0 24 24",body:`<path ${shared} d="m8.5 7-5 5 5 5M15.5 7l5 5-5 5M13.5 4l-3 16"/>`},database:{viewBox:"0 0 24 24",body:`<ellipse ${shared} cx="12" cy="5" rx="7.5" ry="3"/><path ${shared} d="M4.5 5v7c0 1.66 3.36 3 7.5 3s7.5-1.34 7.5-3V5M4.5 12v7c0 1.66 3.36 3 7.5 3s7.5-1.34 7.5-3v-7"/>`},document:{viewBox:"0 0 24 24",body:`<path ${shared} d="M6 2.75h8l4 4V21.25H6zM14 2.75v4h4M9 11h6M9 15h6"/>`},globe:{viewBox:"0 0 24 24",body:`<circle ${shared} cx="12" cy="12" r="9"/><path ${shared} d="M3 12h18M12 3c2.4 2.45 3.5 5.45 3.5 9S14.4 18.55 12 21M12 3C9.6 5.45 8.5 8.45 8.5 12s1.1 6.55 3.5 9"/>`},search:{viewBox:"0 0 24 24",body:`<circle ${shared} cx="10.5" cy="10.5" r="6.5"/><path ${shared} d="m15.25 15.25 5 5"/>`},server:{viewBox:"0 0 24 24",body:`<rect ${shared} x="3" y="3.5" width="18" height="7" rx="2"/><rect ${shared} x="3" y="13.5" width="18" height="7" rx="2"/><path ${shared} d="M7 7h.01M7 17h.01M11 7h6M11 17h6"/>`},shield:{viewBox:"0 0 24 24",body:`<path ${shared} d="M12 2.75 20 6v5.5c0 5.25-3.35 8.2-8 10-4.65-1.8-8-4.75-8-10V6z"/>`},user:{viewBox:"0 0 24 24",body:`<circle ${shared} cx="12" cy="8" r="4"/><path ${shared} d="M4.5 21c.5-4.2 3-6.5 7.5-6.5s7 2.3 7.5 6.5"/>`}});function sanitizeIcon(icon){const dangerous=/<\s*(script|style|foreignObject|iframe|object|embed|image|use|a)\b|on[a-z]+\s*=|(?:xlink:)?href\s*=|style\s*=|javascript:|url\s*\(/i;if(dangerous.test(icon.body)){throw new Error("Icon body contains executable or externally embedded SVG content")}if(!/^[-+.\d\s]+$/.test(icon.viewBox.trim())){throw new Error(`Invalid icon viewBox: ${icon.viewBox}`)}return icon}var defaultLabelFontSize=22;var defaultLabelWeight=600;var defaultLineHeightRatio=1.35;var defaultRowGap=8;var iconLabelGap=12;function characterWidthRatio(fontFamily){return fontFamily==="mono"?0.62:0.56}function estimateDiagramTextWidth(text,fontSize,fontFamily="default"){return text.length*fontSize*characterWidthRatio(fontFamily)}function wrapDiagramText(text,maxWidth,fontSize,fontFamily="default"){const explicitLines=text.split(`
2
+ import{VectorizeDeadline,encodeTracePng,loadRaster,normalizedHexColor,parseHexColor,resolveVectorizeLimits,vectorizeHardLimits,vectorizeImage}from"./index-mnp0bftq.js";import{SlopcameraCloudError,createFixedGatewayFetch,generateSlopcameraImage,generateSlopcameraImageFile,resolveSlopcameraGatewayCredential,slopcameraGatewayApiBaseUrl,slopcameraImageModels,slopcameraMaximumPromptBytes}from"./index-p74xy76d.js";import{createDefaultHostResourceCoordinator}from"./index-b3geqczn.js";import{__require}from"./index-80a36bc0.js";import{randomUUID as randomUUID4}from"crypto";import{mkdir as mkdir4,readFile as readFile2,rename as rename3,rm as rm4,writeFile as writeFile3}from"fs/promises";import{dirname as dirname4,join as join3,resolve as resolve4}from"path";var shared='fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"';var builtInIcons=Object.freeze({brain:{viewBox:"0 0 24 24",body:`<path ${shared} d="M9.5 4.5A3.5 3.5 0 0 0 6 8v.35A3.5 3.5 0 0 0 5.5 15 3.5 3.5 0 0 0 9 19.5M14.5 4.5A3.5 3.5 0 0 1 18 8v.35a3.5 3.5 0 0 1 .5 6.65 3.5 3.5 0 0 1-3.5 4.5M9.5 4.5v15M14.5 4.5v15M6 9.5h3.5M14.5 14.5H18"/>`},check:{viewBox:"0 0 24 24",body:`<path ${shared} d="m5 12 4.25 4.25L19 6.5"/>`},code:{viewBox:"0 0 24 24",body:`<path ${shared} d="m8.5 7-5 5 5 5M15.5 7l5 5-5 5M13.5 4l-3 16"/>`},database:{viewBox:"0 0 24 24",body:`<ellipse ${shared} cx="12" cy="5" rx="7.5" ry="3"/><path ${shared} d="M4.5 5v7c0 1.66 3.36 3 7.5 3s7.5-1.34 7.5-3V5M4.5 12v7c0 1.66 3.36 3 7.5 3s7.5-1.34 7.5-3v-7"/>`},document:{viewBox:"0 0 24 24",body:`<path ${shared} d="M6 2.75h8l4 4V21.25H6zM14 2.75v4h4M9 11h6M9 15h6"/>`},globe:{viewBox:"0 0 24 24",body:`<circle ${shared} cx="12" cy="12" r="9"/><path ${shared} d="M3 12h18M12 3c2.4 2.45 3.5 5.45 3.5 9S14.4 18.55 12 21M12 3C9.6 5.45 8.5 8.45 8.5 12s1.1 6.55 3.5 9"/>`},search:{viewBox:"0 0 24 24",body:`<circle ${shared} cx="10.5" cy="10.5" r="6.5"/><path ${shared} d="m15.25 15.25 5 5"/>`},server:{viewBox:"0 0 24 24",body:`<rect ${shared} x="3" y="3.5" width="18" height="7" rx="2"/><rect ${shared} x="3" y="13.5" width="18" height="7" rx="2"/><path ${shared} d="M7 7h.01M7 17h.01M11 7h6M11 17h6"/>`},shield:{viewBox:"0 0 24 24",body:`<path ${shared} d="M12 2.75 20 6v5.5c0 5.25-3.35 8.2-8 10-4.65-1.8-8-4.75-8-10V6z"/>`},user:{viewBox:"0 0 24 24",body:`<circle ${shared} cx="12" cy="8" r="4"/><path ${shared} d="M4.5 21c.5-4.2 3-6.5 7.5-6.5s7 2.3 7.5 6.5"/>`}});function sanitizeIcon(icon){const dangerous=/<\s*(script|style|foreignObject|iframe|object|embed|image|use|a)\b|on[a-z]+\s*=|(?:xlink:)?href\s*=|style\s*=|javascript:|url\s*\(/i;if(dangerous.test(icon.body)){throw new Error("Icon body contains executable or externally embedded SVG content")}if(!/^[-+.\d\s]+$/.test(icon.viewBox.trim())){throw new Error(`Invalid icon viewBox: ${icon.viewBox}`)}return icon}var defaultLabelFontSize=22;var defaultLabelWeight=600;var defaultLineHeightRatio=1.35;var defaultRowGap=8;var iconLabelGap=12;function characterWidthRatio(fontFamily){return fontFamily==="mono"?0.62:0.56}function estimateDiagramTextWidth(text,fontSize,fontFamily="default"){return text.length*fontSize*characterWidthRatio(fontFamily)}function wrapDiagramText(text,maxWidth,fontSize,fontFamily="default"){const explicitLines=text.split(`
3
3
  `);const maxCharacters=Math.max(1,Math.floor(maxWidth/(fontSize*characterWidthRatio(fontFamily))));const lines=[];for(const explicitLine of explicitLines){if(explicitLine.length<=maxCharacters){lines.push(explicitLine);continue}const words=explicitLine.split(/\s+/);let current="";for(const word of words){const candidate=current===""?word:`${current} ${word}`;if(candidate.length<=maxCharacters||current===""){current=candidate}else{lines.push(current);current=word}}if(current!=="")lines.push(current)}return lines.length===0?[""]:lines}function resolveRows(shape){if(shape.labelRows!==undefined){return shape.labelRows.map((row)=>({text:row.text,fontSize:row.fontSize??defaultLabelFontSize,fontFamily:row.fontFamily??"default",weight:row.weight??defaultLabelWeight,lineHeight:(row.fontSize??defaultLabelFontSize)*defaultLineHeightRatio}))}if(shape.label===undefined)return[];const fontSize=shape.labelFontSize??defaultLabelFontSize;return[{text:shape.label,fontSize,fontFamily:shape.labelFontFamily??"default",weight:shape.labelWeight??defaultLabelWeight,lineHeight:fontSize*defaultLineHeightRatio}]}function layoutBoxContent(shape,resolvedIconSize){const textWidth=Math.max(1,shape.width-32);const pendingRows=resolveRows(shape).map((row)=>{const lines=wrapDiagramText(row.text,textWidth,row.fontSize,row.fontFamily);const height=lines.length*row.lineHeight;return{...row,lines,height}});const rowGap=shape.labelRows===undefined?0:shape.labelRowGap??defaultRowGap;const rowsHeight=pendingRows.reduce((total,row)=>total+row.height,0)+Math.max(0,pendingRows.length-1)*rowGap;const hasIcon=resolvedIconSize!==undefined;const gap=hasIcon&&pendingRows.length>0?iconLabelGap:0;const contentHeight=(resolvedIconSize??0)+gap+rowsHeight;let cursorY=shape.y+(shape.height-contentHeight)/2;const icon=resolvedIconSize===undefined?undefined:{x:shape.x+(shape.width-resolvedIconSize)/2,y:cursorY,size:resolvedIconSize};if(hasIcon)cursorY+=resolvedIconSize+gap;const rows=pendingRows.map((row)=>{const resolved={...row,y:cursorY};cursorY+=row.height+rowGap;return resolved});return{...icon===undefined?{}:{icon},rows}}import{readFile}from"fs/promises";import{extname,isAbsolute}from"path";import{fileURLToPath}from"url";import{Resvg}from"@resvg/resvg-js";var NebulaSans_Bold_default="./NebulaSans-Bold-26se8aek.otf";var NebulaSans_Bold_default2="./NebulaSans-Bold-bcz7y08t.woff2";var NebulaSans_Book_default="./NebulaSans-Book-8cenzchw.otf";var NebulaSans_Book_default2="./NebulaSans-Book-5ax05zvn.woff2";var tones=["neutral","blue","orange","green","red","purple","yellow"];var defaults={light:{background:"#ffffff",foreground:"#18181b",muted:"#71717a",stroke:"#27272a",tones:{neutral:{fill:"#f4f4f5",stroke:"#52525b",text:"#18181b"},blue:{fill:"#dbeafe",stroke:"#2563eb",text:"#1e3a8a"},orange:{fill:"#ffedd5",stroke:"#ea580c",text:"#7c2d12"},green:{fill:"#dcfce7",stroke:"#16a34a",text:"#14532d"},red:{fill:"#fee2e2",stroke:"#dc2626",text:"#7f1d1d"},purple:{fill:"#f3e8ff",stroke:"#9333ea",text:"#581c87"},yellow:{fill:"#fef9c3",stroke:"#ca8a04",text:"#713f12"}}},dark:{background:"#09090b",foreground:"#fafafa",muted:"#a1a1aa",stroke:"#d4d4d8",tones:{neutral:{fill:"#27272a",stroke:"#a1a1aa",text:"#fafafa"},blue:{fill:"#172554",stroke:"#60a5fa",text:"#dbeafe"},orange:{fill:"#431407",stroke:"#fb923c",text:"#ffedd5"},green:{fill:"#052e16",stroke:"#4ade80",text:"#dcfce7"},red:{fill:"#450a0a",stroke:"#f87171",text:"#fee2e2"},purple:{fill:"#3b0764",stroke:"#c084fc",text:"#f3e8ff"},yellow:{fill:"#422006",stroke:"#facc15",text:"#fef9c3"}}}};function mergeTheme(base,override){if(override===undefined)return base;return{background:override.background??base.background,foreground:override.foreground??base.foreground,muted:override.muted??base.muted,stroke:override.stroke??base.stroke,tones:Object.fromEntries(tones.map((tone)=>[tone,{fill:override.tones?.[tone]?.fill??base.tones[tone].fill,stroke:override.tones?.[tone]?.stroke??base.tones[tone].stroke,text:override.tones?.[tone]?.text??base.tones[tone].text}]))}}function resolveTheme(mode,config){return mergeTheme(defaults[mode],config.theme?.[mode])}var bundledAssetPath=(asset)=>isAbsolute(asset)?asset:fileURLToPath(new URL(asset,import.meta.url));var defaultFont=Object.freeze({family:"Nebula Sans",files:Object.freeze([Object.freeze({embed:true,path:bundledAssetPath(NebulaSans_Book_default2),style:"normal",weight:400}),Object.freeze({embed:true,path:bundledAssetPath(NebulaSans_Bold_default2),style:"normal",weight:700}),Object.freeze({embed:false,path:bundledAssetPath(NebulaSans_Book_default),style:"normal",weight:400}),Object.freeze({embed:false,path:bundledAssetPath(NebulaSans_Bold_default),style:"normal",weight:700})])});var escapeXml=(value)=>value.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&apos;");function fontMime(filePath){switch(extname(filePath).toLowerCase()){case".otf":return"font/otf";case".woff":return"font/woff";case".woff2":return"font/woff2";default:return"font/ttf"}}async function fontCss(font){if(font.files===undefined)return"";const faces=await Promise.all(font.files.filter((file)=>file.embed===true).map(async(file)=>{const encoded=(await readFile(file.path)).toString("base64");return`@font-face{font-family:"${escapeXml(font.family)}";src:url(data:${fontMime(file.path)};base64,${encoded});font-weight:${file.weight??400};font-style:${file.style??"normal"};}`}));return faces.join("")}function textSvg(options){const lines=options.lines??wrapDiagramText(options.text,options.width,options.fontSize);const lineHeight=options.lineHeight??options.fontSize*1.25;const anchor=options.align;const x=anchor==="middle"?options.x+options.width/2:anchor==="end"?options.x+options.width:options.x;const dominantBaseline=options.centerLineBoxes?"central":"hanging";return`<text x="${x}" y="${options.y}" text-anchor="${anchor}" dominant-baseline="${dominantBaseline}" fill="${options.color}" opacity="${options.opacity}" font-family="${escapeXml(options.family)}" font-size="${options.fontSize}" font-weight="${options.weight}">${lines.map((line,index)=>options.centerLineBoxes?`<tspan x="${x}" y="${options.y+(index+0.5)*lineHeight}">${escapeXml(line)}</tspan>`:`<tspan x="${x}" dy="${index===0?0:lineHeight}">${escapeXml(line)}</tspan>`).join("")}</text>`}function iconSvg(options){const icon=sanitizeIcon(options.icon);const parts=icon.viewBox.trim().split(/\s+/).map(Number);const width=(parts[2]??24)-(parts[0]??0);const height=(parts[3]??24)-(parts[1]??0);const scale=options.size/Math.max(width,height);return`<g color="${options.color}" opacity="${options.opacity}" transform="translate(${options.x} ${options.y}) scale(${scale}) translate(${-Number(parts[0]??0)} ${-Number(parts[1]??0)})">${icon.body}</g>`}function boxSvg(shape,theme,families,icons){const tone=theme.tones[shape.tone??"neutral"];const strokeWidth=shape.strokeWidth??2;const opacity=shape.opacity??1;const radius=shape.type==="ellipse"?0:Math.min(shape.radius??22,shape.height/2);const geometry=shape.type==="ellipse"?`<ellipse cx="${shape.x+shape.width/2}" cy="${shape.y+shape.height/2}" rx="${shape.width/2}" ry="${shape.height/2}" fill="${shape.fill===false?"none":tone.fill}" stroke="${tone.stroke}" stroke-width="${strokeWidth}"/>`:`<rect x="${shape.x}" y="${shape.y}" width="${shape.width}" height="${shape.height}" rx="${radius}" fill="${shape.fill===false?"none":tone.fill}" stroke="${tone.stroke}" stroke-width="${strokeWidth}"/>`;const icon=shape.icon===undefined?undefined:icons[shape.icon];if(shape.icon!==undefined&&icon===undefined){throw new Error(`Unknown icon "${shape.icon}" on shape ${shape.id}`)}const iconSize=Math.min(shape.iconSize??52,shape.height*0.45,shape.width*0.32);const content=layoutBoxContent(shape,icon===undefined?undefined:iconSize);const iconMarkup=icon===undefined||content.icon===undefined?"":iconSvg({icon,x:content.icon.x,y:content.icon.y,size:content.icon.size,color:tone.text,opacity:1});const labelMarkup=content.rows.map((row)=>textSvg({text:row.text,x:shape.x+16,y:row.y,width:shape.width-32,fontSize:row.fontSize,weight:row.weight,align:"middle",color:tone.text,opacity:1,family:families[row.fontFamily],lineHeight:row.lineHeight,lines:row.lines,centerLineBoxes:true})).join("");return`<g data-shape-id="${escapeXml(shape.id)}" opacity="${opacity}">${geometry}${iconMarkup}${labelMarkup}</g>`}function pointForAnchor(shape,anchor,toward,position){const center={x:shape.x+shape.width/2,y:shape.y+shape.height/2};let resolved=anchor??"auto";if(resolved==="auto"){const dx=toward.x-center.x;const dy=toward.y-center.y;resolved=Math.abs(dx/shape.width)>=Math.abs(dy/shape.height)?dx>=0?"right":"left":dy>=0?"bottom":"top"}const resolvedPosition=position??0.5;if(shape.type==="ellipse"){const projected=(resolvedPosition-0.5)*2;const radial=Math.sqrt(Math.max(0,1-projected*projected))/2;const normalized=resolved==="top"?{x:resolvedPosition,y:0.5-radial}:resolved==="bottom"?{x:resolvedPosition,y:0.5+radial}:resolved==="left"?{x:0.5-radial,y:resolvedPosition}:{x:0.5+radial,y:resolvedPosition};return{x:shape.x+shape.width*normalized.x,y:shape.y+shape.height*normalized.y,normalized}}switch(resolved){case"top":return{x:shape.x+shape.width*resolvedPosition,y:shape.y,normalized:{x:resolvedPosition,y:0}};case"right":return{x:shape.x+shape.width,y:shape.y+shape.height*resolvedPosition,normalized:{x:1,y:resolvedPosition}};case"bottom":return{x:shape.x+shape.width*resolvedPosition,y:shape.y+shape.height,normalized:{x:resolvedPosition,y:1}};case"left":return{x:shape.x,y:shape.y+shape.height*resolvedPosition,normalized:{x:0,y:resolvedPosition}}}}function resolveEdge(spec,edge){const boxes=new Map(spec.shapes.filter((shape)=>shape.type==="rect"||shape.type==="ellipse").map((shape)=>[shape.id,shape]));const from=boxes.get(edge.from);const to=boxes.get(edge.to);if(from===undefined||to===undefined){throw new Error(`Edge ${edge.id} references a missing box`)}const fromCenter={x:from.x+from.width/2,y:from.y+from.height/2};const toCenter={x:to.x+to.width/2,y:to.y+to.height/2};const start=pointForAnchor(from,edge.start,toCenter,edge.startPosition);const end=pointForAnchor(to,edge.end,fromCenter,edge.endPosition);const dx=end.x-start.x;const dy=end.y-start.y;const length=Math.hypot(dx,dy)||1;const bend=edge.bend??0;return{edge,from,to,start,end,control:{x:(start.x+end.x)/2+-dy/length*bend,y:(start.y+end.y)/2+dx/length*bend}}}function resolveEdgeLabel(resolved){const{edge,start,end,control}=resolved;const t=edge.labelPosition??0.5;const oneMinusT=1-t;const point={x:oneMinusT*oneMinusT*start.x+2*oneMinusT*t*control.x+t*t*end.x,y:oneMinusT*oneMinusT*start.y+2*oneMinusT*t*control.y+t*t*end.y};const tangent={x:2*oneMinusT*(control.x-start.x)+2*t*(end.x-control.x),y:2*oneMinusT*(control.y-start.y)+2*t*(end.y-control.y)};const length=Math.hypot(tangent.x,tangent.y)||1;const offset=edge.labelOffset??-14;return{x:point.x+-tangent.y/length*offset,y:point.y+tangent.x/length*offset}}function edgeSvg(resolved,theme,families,strokeWidth){const{edge,start,end,control}=resolved;const toneName=edge.tone??"neutral";const tone=theme.tones[toneName];const marker=edge.arrowhead==="none"?"":edge.arrowhead==="triangle"?`url(#arrow-triangle-${toneName})`:`url(#arrow-open-${toneName})`;const path=`M ${start.x} ${start.y} Q ${control.x} ${control.y} ${end.x} ${end.y}`;const labelPoint=resolveEdgeLabel(resolved);const label=edge.label===undefined?"":`<text x="${labelPoint.x}" y="${labelPoint.y}" text-anchor="middle" dominant-baseline="central" fill="${tone.text}" stroke="${theme.background}" stroke-width="6" paint-order="stroke" font-family="${escapeXml(families[edge.labelFontFamily??"default"])}" font-size="${edge.labelFontSize??18}" font-weight="${edge.labelWeight??600}">${escapeXml(edge.label)}</text>`;return`<g data-edge-id="${escapeXml(edge.id)}"><path d="${path}" fill="none" stroke="${tone.stroke}" stroke-width="${strokeWidth}" stroke-linecap="round" marker-end="${marker}"/>${label}</g>`}function shapeSvg(shape,theme,families,icons){if(shape.type==="rect"||shape.type==="ellipse"){return boxSvg(shape,theme,families,icons)}if(shape.type==="line"){return`<line data-shape-id="${escapeXml(shape.id)}" x1="${shape.x}" y1="${shape.y}" x2="${shape.x2}" y2="${shape.y2}" stroke="${theme.tones[shape.tone??"neutral"].stroke}" stroke-width="${shape.strokeWidth??3}" stroke-linecap="round" opacity="${shape.opacity??1}"/>`}const text=shape;return textSvg({text:text.text,x:text.x,y:text.y,width:text.width??Math.max(text.text.length*(text.fontSize??24)*0.58,12),fontSize:text.fontSize??24,weight:text.weight??500,align:text.align??"start",color:theme.tones[text.tone??"neutral"].text,opacity:text.opacity??1,family:families[text.fontFamily??"default"]})}async function renderSvg(spec,mode,config,options={}){const edgeStrokeWidth=options.edgeStrokeWidth??3;if(!Number.isFinite(edgeStrokeWidth)||edgeStrokeWidth<0.5||edgeStrokeWidth>4)throw new Error("Edge stroke width must be between 0.5 and 4");const theme=resolveTheme(mode,config);const font=config.font??defaultFont;const families={default:font.family,mono:font.monoFamily??"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, monospace"};const icons=config.icons??{};const embeddedFonts=await fontCss(font);const markerDefinitions=Object.entries(theme.tones).map(([toneName,tone])=>`<marker id="arrow-open-${toneName}" markerWidth="12" markerHeight="12" refX="10" refY="6" orient="auto" markerUnits="strokeWidth"><path d="M2 2 10 6 2 10" fill="none" stroke="${tone.stroke}" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></marker><marker id="arrow-triangle-${toneName}" markerWidth="11" markerHeight="11" refX="9" refY="5.5" orient="auto" markerUnits="strokeWidth"><path d="M1 1 10 5.5 1 10z" fill="${tone.stroke}"/></marker>`).join("");const edgeMarkup=(spec.edges??[]).map((edge)=>edgeSvg(resolveEdge(spec,edge),theme,families,edgeStrokeWidth)).join("");const shapeMarkup=spec.shapes.map((shape)=>shapeSvg(shape,theme,families,icons)).join("");const svg=[`<svg xmlns="http://www.w3.org/2000/svg" width="${spec.canvas.width}" height="${spec.canvas.height}" viewBox="0 0 ${spec.canvas.width} ${spec.canvas.height}" role="img" aria-labelledby="diagram-title" color-scheme="${mode}">`,`<title id="diagram-title">${escapeXml(spec.name)}</title>`,`<style>${embeddedFonts}text{font-kerning:normal;text-rendering:geometricPrecision}</style>`,`<rect width="100%" height="100%" fill="${theme.background}"/>`,`<defs>${markerDefinitions}</defs>`,edgeMarkup,shapeMarkup,"</svg>"].join("");return{mode,svg,width:spec.canvas.width,height:spec.canvas.height}}function renderPng(rendered,config,scale=2){const font=config.font??defaultFont;const fontFiles=font.files?.map((file)=>file.path)??[];const renderer=new Resvg(rendered.svg,{fitTo:{mode:"zoom",value:scale},font:{loadSystemFonts:true,...fontFiles.length===0?{}:{fontFiles},defaultFontFamily:font.family}});return renderer.render().asPng()}function boxOutsideCanvas(shape,spec){return shape.x<0||shape.y<0||shape.x+shape.width>spec.canvas.width||shape.y+shape.height>spec.canvas.height}function lintDiagram(spec){const findings=[];const boxes=spec.shapes.filter((shape)=>shape.type==="rect"||shape.type==="ellipse");for(const shape of boxes){if(boxOutsideCanvas(shape,spec)){findings.push({code:"outside-canvas",message:`${shape.id} extends beyond the canvas`,shapeIds:[shape.id]})}const labels=shape.labelRows?.map((row)=>row.text)??(shape.label===undefined?[]:[shape.label]);const longLabel=labels.find((label)=>label.length>32);if(longLabel!==undefined){findings.push({code:"long-label",message:`${shape.id} has a ${longLabel.length}-character label; prefer a short noun phrase`,shapeIds:[shape.id]})}const iconSize=shape.icon===undefined?undefined:Math.min(shape.iconSize??52,shape.height*0.45,shape.width*0.32);const content=layoutBoxContent(shape,iconSize);const contentTop=content.icon?.y??content.rows[0]?.y;const finalRow=content.rows.at(-1);const contentBottom=finalRow===undefined?content.icon===undefined?undefined:content.icon.y+content.icon.size:finalRow.y+finalRow.height;const contentWidth=Math.max(1,shape.width-32);const exceedsWidth=content.rows.some((row)=>row.lines.some((line)=>estimateDiagramTextWidth(line,row.fontSize,row.fontFamily)>contentWidth));if(contentTop!==undefined&&contentBottom!==undefined&&(contentTop<shape.y||contentBottom>shape.y+shape.height||exceedsWidth)){findings.push({code:"label-overflow",message:`${shape.id} label and icon content exceeds the box bounds; increase the box or reduce authored sizes`,shapeIds:[shape.id]})}if(shape.width<120||shape.height<64){findings.push({code:"small-target",message:`${shape.id} is small enough to make its label or icon hard to scan`,shapeIds:[shape.id]})}}if(boxes.length>9){findings.push({code:"too-many-elements",message:`The diagram has ${boxes.length} primary shapes; consider a higher-level visual`,shapeIds:boxes.map((shape)=>shape.id)})}const sharedTerminals=new Map;for(const edge of spec.edges??[]){const resolved=resolveEdge(spec,edge);for(const terminal of[{kind:"start",point:resolved.start,shapeId:edge.from},{kind:"end",point:resolved.end,shapeId:edge.to}]){const key=`${terminal.kind}:${terminal.shapeId}:${terminal.point.x.toFixed(3)}:${terminal.point.y.toFixed(3)}`;const group=sharedTerminals.get(key)??[];group.push({edgeId:edge.id,shapeId:terminal.shapeId});sharedTerminals.set(key,group)}const length=Math.hypot(resolved.end.x-resolved.start.x,resolved.end.y-resolved.start.y);if(length<96){findings.push({code:"short-arrow",message:`${edge.id} is ${Math.round(length)}px long; leave more space between connected shapes`,shapeIds:[edge.from,edge.to]})}if(edge.label!==undefined&&edge.label.length>24){findings.push({code:"long-edge-label",message:`${edge.id} has a long connector label; prefer one short relation`,shapeIds:[edge.from,edge.to]})}}for(const group of sharedTerminals.values()){if(group.length<2)continue;findings.push({code:"shared-edge-port",message:`${group.map(({edgeId})=>edgeId).join(", ")} share one connector port; set distinct startPosition or endPosition values`,shapeIds:[group[0].shapeId]})}return findings}var diagramVersion=1;var stackLayoutDefaults={gap:160,padding:64,align:"center"};var coordinatePrecision=3;var coordinateScale=10**coordinatePrecision;class StackLayoutError extends Error{issues;constructor(issues){super(`Invalid stack layout:
4
4
  ${issues.map((issue)=>`- ${issue}`).join(`
5
5
  `)}`);this.name="StackLayoutError";this.issues=issues}}function coordinateFromUnits(value){return value/coordinateScale}function normalizedScaledCoordinate(value){const scaled=value*coordinateScale;return normalizedGridValue(scaled)}function normalizedGridValue(value){const nearest=Math.round(value);return Math.abs(value-nearest)<=0.000000001?nearest:value}function floorGridValue(value){return Math.floor(normalizedGridValue(value))}function ceilGridValue(value){return Math.ceil(normalizedGridValue(value))}function coordinateUnits(value,label,positive,rounding,issues){if(!Number.isFinite(value)||(positive?value<=0:value<0)){issues.push(positive?`${label} must be positive`:`${label} must not be negative`);return 0}const scaled=normalizedScaledCoordinate(value);const units=rounding==="ceil"?ceilGridValue(scaled):floorGridValue(scaled);if(!Number.isSafeInteger(units)){issues.push(`${label} must be a finite coordinate within the supported range`);return 0}if(positive&&units<1){issues.push(`${label} must occupy at least ${coordinateFromUnits(1)}px in the layout grid`);return 0}return units}function positionedShape(shape,mainPosition,crossPosition,horizontal){return{...shape,x:coordinateFromUnits(horizontal?mainPosition:crossPosition),y:coordinateFromUnits(horizontal?crossPosition:mainPosition)}}function authoredMainSize(shape,horizontal){return horizontal?shape.width:shape.height}function emittedMainPlacement(shapes,horizontal,gap,issues){if(shapes.length===0)return{offsets:[],span:0};const offsets=[];let offset=0;for(const[index,shape]of shapes.entries()){offsets.push(offset);if(index===shapes.length-1)break;const advance=coordinateUnits(authoredMainSize(shape,horizontal)+gap,`space after shape ${shape.id}`,true,"ceil",issues);offset+=advance;if(!Number.isSafeInteger(offset)){issues.push("stack positions exceed the supported coordinate range");return{offsets,span:Number.POSITIVE_INFINITY}}}const last=shapes.at(-1);const span=offset+(last===undefined?0:normalizedScaledCoordinate(authoredMainSize(last,horizontal)));if(!Number.isFinite(span)||!Number.isSafeInteger(Math.ceil(span))){issues.push("stack extent exceeds the supported coordinate range")}return{offsets,span}}function clampedGridPosition(ideal,minimum,maximum){return Math.min(maximum,Math.max(minimum,Math.round(ideal)))}function resolvedAnchors(fromIndex,toIndex,horizontal){const forward=fromIndex<toIndex;if(horizontal){return forward?{start:"right",end:"left"}:{start:"left",end:"right"}}return forward?{start:"bottom",end:"top"}:{start:"top",end:"bottom"}}function resolvedEdge(edge,indexes,horizontal){const fromIndex=indexes.get(edge.from);const toIndex=indexes.get(edge.to);if(fromIndex===undefined||toIndex===undefined){throw new StackLayoutError([`edge ${edge.id} must reference shapes that belong to the stack`])}const anchors=resolvedAnchors(fromIndex,toIndex,horizontal);return{...edge,start:anchors.start,end:anchors.end,bend:0}}function stackStructureIssues(source){const issues=[];if(source.shapes.length<1||source.shapes.length>9){issues.push("stack layouts must contain between 1 and 9 shapes")}const indexes=new Map;const recordIds=new Set;for(const[index,shape]of source.shapes.entries()){if(recordIds.has(shape.id)){issues.push(`shape id ${shape.id} is duplicated`)}else{indexes.set(shape.id,index);recordIds.add(shape.id)}}const connectedPairs=new Set;for(const stackEdge of source.edges??[]){const edge=stackEdge;if(recordIds.has(edge.id)){issues.push(`edge id ${edge.id} is duplicated`)}recordIds.add(edge.id);const fromIndex=indexes.get(edge.from);const toIndex=indexes.get(edge.to);if(fromIndex===undefined){issues.push(`edge ${edge.id} has unknown from id ${edge.from}`)}if(toIndex===undefined){issues.push(`edge ${edge.id} has unknown to id ${edge.to}`)}if(fromIndex!==undefined&&toIndex!==undefined){if(fromIndex===toIndex){issues.push(`edge ${edge.id} cannot connect a shape to itself`)}else{if(Math.abs(fromIndex-toIndex)!==1){issues.push(`edge ${edge.id} must connect adjacent stack shapes`)}const pair=[fromIndex,toIndex].sort((left,right)=>left-right).join(":");if(connectedPairs.has(pair)){issues.push(`edge ${edge.id} duplicates a connection between the same stack shapes`)}connectedPairs.add(pair)}}if(edge.start!==undefined&&edge.start!=="auto"){issues.push(`edge ${edge.id}.start must be auto or omitted in a stack layout`)}if(edge.end!==undefined&&edge.end!=="auto"){issues.push(`edge ${edge.id}.end must be auto or omitted in a stack layout`)}if(edge.bend!==undefined&&edge.bend!==0){issues.push(`edge ${edge.id}.bend must be 0 or omitted in a stack layout`)}}return issues}function resolveStackLayout(source){const issues=[...stackStructureIssues(source)];const horizontal=source.layout.direction==="horizontal";coordinateUnits(source.canvas.width,"canvas width",true,"floor",issues);coordinateUnits(source.canvas.height,"canvas height",true,"floor",issues);const gapValue=source.layout.gap??stackLayoutDefaults.gap;coordinateUnits(gapValue,"stack gap",false,"ceil",issues);const paddingValue=source.canvas.padding??stackLayoutDefaults.padding;const padding=coordinateUnits(paddingValue,"canvas padding",false,"ceil",issues);for(const shape of source.shapes){coordinateUnits(shape.width,`shape ${shape.id} width`,true,"ceil",issues);coordinateUnits(shape.height,`shape ${shape.id} height`,true,"ceil",issues)}const align=source.layout.align??stackLayoutDefaults.align;const canvasMainValue=horizontal?source.canvas.width:source.canvas.height;const canvasCrossValue=horizontal?source.canvas.height:source.canvas.width;const mainPlacement=emittedMainPlacement(source.shapes,horizontal,gapValue,issues);const maximumMainStart=floorGridValue(normalizedScaledCoordinate(canvasMainValue-paddingValue)-mainPlacement.span);if(padding>maximumMainStart){const requiredMain=ceilGridValue(mainPlacement.span);const availableMain=floorGridValue(normalizedScaledCoordinate(canvasMainValue-paddingValue*2));issues.push(`${source.layout.direction} stack needs ${coordinateFromUnits(requiredMain)}px but only ${coordinateFromUnits(availableMain)}px remain inside ${paddingValue}px padding`)}const crossStarts=source.shapes.map((shape)=>{const authoredSize=horizontal?shape.height:shape.width;const maximum=floorGridValue(normalizedScaledCoordinate(canvasCrossValue-paddingValue-authoredSize));if(padding>maximum){const requiredCross=ceilGridValue(normalizedScaledCoordinate(authoredSize));const availableCross=floorGridValue(normalizedScaledCoordinate(canvasCrossValue-paddingValue*2));issues.push(`shape ${shape.id} needs ${coordinateFromUnits(requiredCross)}px on the cross axis but only ${coordinateFromUnits(availableCross)}px remain inside ${paddingValue}px padding`)}return{authoredSize,maximum}});if(issues.length>0)throw new StackLayoutError(issues);const mainStart=clampedGridPosition((normalizedScaledCoordinate(canvasMainValue)-mainPlacement.span)/2,padding,maximumMainStart);const shapes=source.shapes.map((shape,index)=>{const crossStart=crossStarts[index];if(crossStart===undefined){throw new StackLayoutError([`shape ${shape.id} has no cross-axis placement`])}const crossPosition=align==="start"?padding:align==="end"?crossStart.maximum:clampedGridPosition(normalizedScaledCoordinate((canvasCrossValue-crossStart.authoredSize)/2),padding,crossStart.maximum);const mainPosition=mainStart+(mainPlacement.offsets[index]??0);const positioned=positionedShape(shape,mainPosition,crossPosition,horizontal);return positioned});const indexes=new Map(shapes.map((shape,index)=>[shape.id,index]));const edges=source.edges?.map((edge)=>resolvedEdge(edge,indexes,horizontal));return{...source.$schema===undefined?{}:{$schema:source.$schema},version:source.version,name:source.name,canvas:{width:source.canvas.width,height:source.canvas.height,padding:paddingValue},shapes,...edges===undefined?{}:{edges}}}function resolveDiagramSource(source){return"layout"in source?resolveStackLayout(source):source}var tones2=new Set(["neutral","blue","orange","green","red","purple","yellow"]);var anchors=new Set(["auto","top","right","bottom","left"]);var fontFamilies=new Set(["default","mono"]);var stackDirections=new Set(["horizontal","vertical"]);var stackAlignments=new Set(["start","center","end"]);var idPattern=/^[A-Za-z0-9][A-Za-z0-9_-]*$/;var namePattern=/^[a-z0-9]+(?:-[a-z0-9]+)*$/;class DiagramValidationError extends Error{issues;constructor(issues){super(`Invalid diagram specification:
@@ -34,5 +34,8 @@ Ink: ${input.ink}
34
34
  `)+`Judge this rendered ${input.purpose} against the style contract.`,type:"text"},{data:input.png,mediaType:"image/png",type:"file"}],role:"user"}],model:gateway.languageModel(input.model),output,providerOptions:{gateway:{disallowPromptTraining:true,tags:["slopcamera","icon-critique","v1"],zeroDataRetention:true}},system:input.purpose==="mark"?MARK_CRITIQUE_SYSTEM:input.context==="inline"?ILLUSTRATION_CRITIQUE_SYSTEM+INLINE_CRITIQUE_CLAUSE:ILLUSTRATION_CRITIQUE_SYSTEM,temperature:0});return parseIconCritique(isRecord2(result)?result.output:undefined,resolvedModelId(isRecord2(result)?result.response:undefined))}catch(error){if(error instanceof SlopcameraCloudError)throw error;throw new SlopcameraCloudError("GENERATION_FAILED","The icon critique request failed; it was not retried.")}finally{clearTimeout(timer);input.signal?.removeEventListener("abort",abort)}}var markPreviewSmallSizes=[16,32];async function renderIconPreview(svg,purpose){try{const sharp=(await import("sharp")).default;const source=sharp(Buffer.from(svg),{density:96,failOn:"error",limitInputPixels:vectorizeHardLimits.maxDecodedPixels});if(purpose==="illustration"){return Uint8Array.from(await source.resize(iconPreviewMaximumEdge,iconPreviewMaximumEdge,{fit:"inside"}).flatten({background:slopcameraIconPanel}).png({compressionLevel:9}).toBuffer())}const large=await source.clone().resize(iconPreviewMaximumEdge,iconPreviewMaximumEdge,{fit:"inside"}).flatten({background:slopcameraIconPanel}).png({compressionLevel:9}).toBuffer();const smallRenders=[];let cursor=16;for(const size of markPreviewSmallSizes){const rendered=await sharp(Buffer.from(svg),{density:96,failOn:"error",limitInputPixels:vectorizeHardLimits.maxDecodedPixels}).resize(size,size,{fit:"inside"}).flatten({background:slopcameraIconPanel}).png({compressionLevel:9}).toBuffer();smallRenders.push({input:await sharp({create:{background:{b:251,channels:3,g:248,r:247},channels:3,height:size+32,width:size+32}}).composite([{input:rendered,left:16,top:16}]).png().toBuffer(),left:iconPreviewMaximumEdge+16,top:cursor});cursor+=size+48}return Uint8Array.from(await sharp({create:{background:{b:251,channels:3,g:248,r:247},channels:3,height:Math.max(iconPreviewMaximumEdge,cursor+16),width:iconPreviewMaximumEdge+16+96}}).composite([{input:large,left:0,top:0},...smallRenders]).png({compressionLevel:9}).toBuffer())}catch(error){throw new SlopcameraCloudError("GENERATION_FAILED","The canonical icon SVG could not be rendered for critique.",{cause:error})}}async function writeAtomically(path,value){const absolutePath=resolve(path);await mkdir(dirname(absolutePath),{recursive:true});const temporaryPath=`${absolutePath}.${randomUUID()}.tmp`;try{await writeFile(temporaryPath,value,{flag:"wx"});await rename(temporaryPath,absolutePath);return absolutePath}catch(error){await rm(temporaryPath,{force:true}).catch(()=>{return});throw new SlopcameraCloudError("OUTPUT_WRITE_FAILED",`Slopcamera could not atomically write ${absolutePath}.`,{cause:error})}}function validateCandidatePool(value,rounds){const pool=value??1;if(!Number.isInteger(pool)||pool<1||pool>slopcameraIconMaximumRounds||pool>rounds){invalidArgument(`candidatePool must be an integer from 1 through ${Math.min(rounds,slopcameraIconMaximumRounds)}.`)}return pool}function validateIconContext(value){if(value===undefined)return;if(typeof value!=="string"||!slopcameraIconContexts.includes(value)){invalidArgument(`context must be one of: ${slopcameraIconContexts.join(", ")}.`)}return value}async function collectSlopcameraIconCandidates(input,dependencies={}){const subject=validateSubject(input.subject);const model=validateIconModel(input.model??"recraft/recraft-v4.1-utility","model");const rounds=validateRounds(input.rounds);const purpose=input.purpose??"illustration";if(purpose!=="illustration"&&purpose!=="mark"){invalidArgument("purpose must be illustration or mark.")}const context=validateIconContext(input.context);const ink=normalizedHexColor(input.ink??slopcameraIconDefaultInk);const pool=validateCandidatePool(input.candidatePool,rounds);const critiqueModel=input.critiqueModel===undefined?slopcameraIconCritiqueDefaultModel:validateIconModel(input.critiqueModel,"critiqueModel");const critiqueEnabled=rounds>1||input.critiqueModel!==undefined;const generate=dependencies.generate??generateSlopcameraImage;const vectorize=dependencies.vectorize??vectorizeImage;const critique=dependencies.critique??((critiqueInput)=>critiqueIconRaster(critiqueInput,dependencies));const limits=resolveVectorizeLimits({});const attempts=[];const candidates=[];const eligible=[];let feedback=input.initialFeedback?.trim()||undefined;let lastError;for(let round=1;round<=rounds;round+=1){if(input.signal?.aborted===true){throw new SlopcameraCloudError("GENERATION_FAILED","Icon generation was cancelled.")}const prompt=iconPromptFor(subject,{ink,purpose,...context===undefined?{}:{context},...feedback===undefined?{}:{feedback}});let candidate;let extraction;let metrics;let attemptRequestId="";let attemptProblems=[];try{const generated=await generate({model,prompt,...input.signal===undefined?{}:{signal:input.signal}},dependencies);attemptRequestId=generated.requestId;const bytes=Buffer.from(generated.image.base64,"base64");const raster=await loadRaster(Uint8Array.from(bytes),limits,new VectorizeDeadline(limits.maxDurationMs));extraction=extractIconLineArt(raster.pixels,raster.width,raster.height,{hardEdges:true,ink});const png=await encodeTracePng(extraction.pixels,extraction.width,extraction.height);const traced=await vectorize(png,{...input.inheritedFileDescriptors===undefined?{}:{inheritedFileDescriptors:input.inheritedFileDescriptors}});metrics=measureIconCandidateMetrics(extraction,traced.svg,traced.receipt.pathCount);const visualProblems=iconVisualGateProblems(purpose,{...extraction,strokePx:metrics.strokePx},traced.receipt.pathCount,context);if(visualProblems.length>0){feedback=visualProblems.join("; ");attemptProblems=visualProblems;throw new SlopcameraCloudError("GENERATION_INVALID_RESPONSE",`Generated ${purpose} failed its visual gate: ${feedback}.`)}candidate={png,requestId:generated.requestId,svg:traced.svg,vectorize:traced.receipt,warnings:generated.warnings}}catch(error){lastError=error;attempts.push({...attemptProblems.length===0?{}:{problems:attemptProblems},requestId:attemptRequestId,round,status:"failed",warnings:[]});continue}let review=null;let critiqueError;if(critiqueEnabled){try{const preview=dependencies.rasterize===undefined?await renderIconPreview(candidate.svg,purpose):await dependencies.rasterize(candidate.svg);review=await critique({...context===undefined?{}:{context},ink,model:critiqueModel,png:preview,purpose,...input.signal===undefined?{}:{signal:input.signal},subject})}catch(error){critiqueError=error instanceof SlopcameraCloudError?error.code:"critique-failed";review=null}}const record={candidate,critique:review,extraction,metrics,round};candidates.push(record);attempts.push({...critiqueError===undefined?{}:{critiqueError},...review===null?{}:{critiqueModel:review.resolvedModel??critiqueModel},metrics,...review===null?{}:{pass:review.pass},...review===null?{}:{problems:review.problems},requestId:candidate.requestId,round,...review===null?{}:{score:review.score},status:"candidate",svgSha256:createHash("sha256").update(candidate.svg).digest("hex"),vectorize:candidate.vectorize,warnings:candidate.warnings});if(review!==null&&!review.pass){feedback=[...review.problems,review.promptFix].filter((part)=>part.length>0).join("; ")}if(review===null||review.pass||input.requireCritiquePass===false){eligible.push(record);if(eligible.length>=pool&&(review===null||review.pass))break}}if(candidates.length===0){if(lastError instanceof Error)throw lastError;throw new SlopcameraCloudError("GENERATION_FAILED","Every icon generation attempt failed.")}return{attempts,candidates,eligible,resolved:{context,critiqueModel,ink,model,purpose,rounds,subject}}}async function generateSlopcameraIcon(input,dependencies={}){if(typeof input.outputPath!=="string"||input.outputPath.length<1||input.outputPath.length>4096||input.outputPath.includes("\x00")||!input.outputPath.toLowerCase().endsWith(".svg")){invalidArgument("outputPath must be a bounded local path ending in .svg.")}const{attempts,eligible,resolved}=await collectSlopcameraIconCandidates({...input.candidatePool===undefined?{}:{candidatePool:input.candidatePool},...input.context===undefined?{}:{context:input.context},...input.critiqueModel===undefined?{}:{critiqueModel:input.critiqueModel},...input.inheritedFileDescriptors===undefined?{}:{inheritedFileDescriptors:input.inheritedFileDescriptors},...input.ink===undefined?{}:{ink:input.ink},...input.model===undefined?{}:{model:input.model},...input.purpose===undefined?{}:{purpose:input.purpose},...input.rounds===undefined?{}:{rounds:input.rounds},...input.signal===undefined?{}:{signal:input.signal},subject:input.subject},dependencies);if(eligible.length===0){throw new SlopcameraCloudError("GENERATION_INVALID_RESPONSE",`Every generated ${resolved.purpose} failed its design critique.`)}const selected=[...eligible].sort((left,right)=>(right.critique?.score??-1)-(left.critique?.score??-1)||right.round-left.round)[0];const attemptList=[...attempts];const selectedAttempt=attemptList.findIndex((attempt)=>attempt.round===selected.round&&attempt.status==="candidate");if(selectedAttempt>=0){attemptList[selectedAttempt]={...attemptList[selectedAttempt],status:"selected"}}const outputPath=await writeAtomically(input.outputPath,selected.candidate.svg);const receipt={attempts:attemptList,ink:resolved.ink,model:resolved.model,outputPath,purpose:resolved.purpose,receiptVersion:1,rounds:resolved.rounds,selectedRound:selected.round,subject:resolved.subject,svgSha256:createHash("sha256").update(selected.candidate.svg).digest("hex")};if(input.keepRaster===true){const rasterPath=input.outputPath.replace(/\.svg$/iu,".lineart.png");return{...receipt,rasterPath:await writeAtomically(rasterPath,selected.candidate.png)}}return receipt}import{createHash as createHash2,randomUUID as randomUUID2}from"crypto";import{link,mkdir as mkdir2,rm as rm2,writeFile as writeFile2}from"fs/promises";import{dirname as dirname2,join,resolve as resolve2}from"path";import sharp from"sharp";var slopcameraGalleryKinds=Object.freeze(["image","texture","skybox","backdrop","sprite"]);var slopcameraGalleryAxes=Object.freeze(["style","palette","material","lighting","mood","detail"]);var slopcameraGalleryLimits=Object.freeze({candidates:16,concurrency:4,subjectBytes:2048,candidatePromptBytes:slopcameraMaximumPromptBytes,variantBytes:1024,idLength:64,cellEdgeMin:64,cellEdgeMax:1024,cellEdgeDefault:512,labelHeight:28,cellGap:8,galleryPixels:33554432,candidatePixels:33554432,candidateEdge:8192});var GALLERY_KIND_CONTRACTS={image:{aspect:[1,1],frame:(subject)=>subject,rules:"Clean readable composition; no text, captions, borders, or watermark."},texture:{aspect:[1,1],frame:(subject)=>`Seamless tileable texture of ${subject}.`,rules:"Flat orthographic top-down material surface, uniform diffuse lighting, "+"edge-to-edge surface detail that tiles in both directions; no shadows, "+"no specular highlights, no vignette, no borders, no objects, no text."},skybox:{aspect:[2,1],frame:(subject)=>`Seamless equirectangular 360-degree panorama of ${subject}.`,rules:"Full spherical environment in 2:1 equirectangular projection, continuous "+"horizon exactly at the vertical center, left and right edges wrapping "+"seamlessly; no seams, no text, no watermark, no foreground frame."},backdrop:{aspect:[16,9],frame:(subject)=>`Flat scenic backdrop plate of ${subject}.`,rules:"Edge-to-edge environment plate for compositing behind foreground "+"subjects, consistent perspective and lighting across the frame; no "+"borders, no text, no watermark."},sprite:{aspect:[1,1],frame:(subject)=>`A single ${subject} on a plain solid neutral background.`,rules:"One centered subject, fully visible with a clean silhouette, flat even "+"lighting; no shadows, no extra objects, no text, no watermark."}};var GALLERY_AXIS_DEFAULTS={style:["photorealistic","stylized painterly","flat minimal","hand-drawn"],palette:["warm earthy palette","cool desaturated palette","neutral grayscale palette","vivid saturated palette"],material:["rough weathered surface","smooth polished surface","organic natural surface","synthetic industrial surface"],lighting:["soft diffuse lighting","dramatic directional lighting","flat ambient lighting","golden-hour lighting"],mood:["serene calm mood","dramatic mood","playful mood","mysterious mood"],detail:["minimal sparse detail","balanced detail","intricate dense detail"]};var SKYBOX_AXIS_DEFAULTS={material:["clear air","light haze","thin clouds","dense dramatic clouds"],lighting:["golden hour","overcast midday","clear night sky","midday sun"]};function axisValues(kind,axis){return kind==="skybox"?SKYBOX_AXIS_DEFAULTS[axis]??GALLERY_AXIS_DEFAULTS[axis]:GALLERY_AXIS_DEFAULTS[axis]}function invalidArgument2(message){throw new SlopcameraCloudError("INVALID_ARGUMENT",message)}function isRecord3(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function boundedText2(value,name,maximumBytes){if(typeof value!=="string"||value.trim().length===0||/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u.test(value)||Buffer.byteLength(value,"utf8")>maximumBytes){invalidArgument2(`${name} must be non-empty text no more than ${maximumBytes} UTF-8 bytes.`)}return value.trim()}function galleryCandidateId(value){const id=boundedText2(value,"Candidate id",slopcameraGalleryLimits.idLength);if(!/^[a-z0-9][a-z0-9._-]*$/iu.test(id)){invalidArgument2("Candidate id must start with an alphanumeric and contain only alphanumerics, '.', '_', or '-'.")}return id}function slug(value){const slugged=value.toLowerCase().split(/[^a-z0-9]+/u).filter((part)=>part.length>0).join("-").slice(0,slopcameraGalleryLimits.idLength);return slugged.length===0?"candidate":slugged}function galleryKind(value){const kind=value??"image";if(typeof kind!=="string"||!slopcameraGalleryKinds.includes(kind)){invalidArgument2(`kind must be one of: ${slopcameraGalleryKinds.join(", ")}.`)}return kind}function galleryPromptFor(subject,kind,variant){const contract=GALLERY_KIND_CONTRACTS[kind];const sections=[contract.frame(subject),`Rules: ${contract.rules}`];const direction=variant?.trim();if(direction!==undefined&&direction.length>0){sections.push(`Variation direction: ${direction}.`)}return sections.join(`
35
35
 
36
36
  `)}function axisSpec(value){if(typeof value==="string"){const axis2=value.trim();if(!slopcameraGalleryAxes.includes(axis2)){invalidArgument2(`vary axis must be one of: ${slopcameraGalleryAxes.join(", ")}.`)}return{axis:axis2}}if(!isRecord3(value))invalidArgument2("vary entries must be axis names or {axis, values} objects.");const axis=value.axis;if(!slopcameraGalleryAxes.includes(axis)){invalidArgument2(`vary axis must be one of: ${slopcameraGalleryAxes.join(", ")}.`)}const values=value.values;if(values!==undefined){if(!Array.isArray(values)||values.length<1||values.length>slopcameraGalleryLimits.candidates){invalidArgument2("vary values must be a bounded non-empty list.")}return{axis,values:values.map((item)=>boundedText2(item,"vary value",slopcameraGalleryLimits.variantBytes))}}return{axis}}function explicitCandidate(value){if(!isRecord3(value))invalidArgument2("candidates entries must be {id, prompt|variant} objects.");const id=galleryCandidateId(value.id);const prompt=value.prompt;const variant=value.variant;if(prompt!==undefined&&variant!==undefined){invalidArgument2("A candidate supplies prompt or variant, not both.")}if(prompt===undefined&&variant===undefined){invalidArgument2("A candidate requires a prompt or a variant.")}return{id,...prompt===undefined?{}:{prompt:boundedText2(prompt,"candidate prompt",slopcameraGalleryLimits.candidatePromptBytes)},...variant===undefined?{}:{variant:boundedText2(variant,"candidate variant",slopcameraGalleryLimits.variantBytes)}}}function planSlopcameraGallery(input){if(!isRecord3(input))invalidArgument2("Gallery input must be an object.");const subject=boundedText2(input.subject,"subject",slopcameraGalleryLimits.subjectBytes);const kind=galleryKind(input.kind);const aspect=GALLERY_KIND_CONTRACTS[kind].aspect;const vary=(input.vary??[]).map(axisSpec);const explicit=input.candidates?.map(explicitCandidate);if(explicit!==undefined&&vary.length>0){invalidArgument2("candidates and vary are mutually exclusive.")}if(explicit!==undefined&&input.count!==undefined){invalidArgument2("candidates and count are mutually exclusive.")}if(vary.length>slopcameraGalleryAxes.length||new Set(vary.map((spec)=>spec.axis)).size!==vary.length){invalidArgument2("vary axes must be unique.")}const count=input.count;if(count!==undefined&&(!Number.isInteger(count)||count<1||count>slopcameraGalleryLimits.candidates)){invalidArgument2(`count must be an integer from 1 through ${slopcameraGalleryLimits.candidates}.`)}const tiled=input.tiled;if(tiled!==undefined&&typeof tiled!=="boolean"){invalidArgument2("tiled must be a boolean when set.")}const axes=vary.map((spec)=>({axis:spec.axis,values:spec.values??axisValues(kind,spec.axis).slice(0,slopcameraGalleryLimits.candidates)}));const prompts=[];if(explicit!==undefined){if(explicit.length<1||explicit.length>slopcameraGalleryLimits.candidates){invalidArgument2(`candidates must contain 1 through ${slopcameraGalleryLimits.candidates} entries.`)}for(const candidate of explicit){prompts.push({id:candidate.id,prompt:candidate.prompt??galleryPromptFor(subject,kind,candidate.variant),label:candidate.id})}}else if(axes.length>0){const total=axes.reduce((product,spec)=>product*spec.values.length,1);if(total<1||total>slopcameraGalleryLimits.candidates){invalidArgument2(`vary expands to ${String(total)} candidates; the bound is ${slopcameraGalleryLimits.candidates}.`)}const seen=new Set;for(let combination=0;combination<total;combination++){let remainder=combination;const parts=[];for(let index=axes.length-1;index>=0;index--){const spec=axes[index];const value=spec.values[remainder%spec.values.length];remainder=Math.floor(remainder/spec.values.length);parts.unshift(`${spec.axis}: ${value}`)}const direction=parts.join("; ");let id=slug(parts.map((part)=>part.split(": ")[1]).join("-"));if(seen.has(id))id=`${id}-${String(combination+1)}`;seen.add(id);prompts.push({id,prompt:galleryPromptFor(subject,kind,direction),label:id})}}else{const requested=count??4;for(let index=0;index<requested;index++){const id=`candidate-${String(index+1)}`;prompts.push({id,prompt:galleryPromptFor(subject,kind),label:id})}}return{subject,kind,aspect,axes,candidates:prompts.map((candidate,index)=>({index:index+1,...candidate})),tiled:tiled??kind==="texture"}}function parseSlopcameraGalleryVary(value){const specs=[];for(const part of value.split(";")){const trimmed=part.trim();if(trimmed==="")continue;const[axis,values]=trimmed.split("=",2);if(!slopcameraGalleryAxes.includes(axis.trim())){invalidArgument2(`vary axis must be one of: ${slopcameraGalleryAxes.join(", ")}.`)}if(values===undefined){specs.push({axis:axis.trim()});continue}const list=values.split(",").map((item)=>item.trim()).filter((item)=>item.length>0);if(list.length===0||list.length>slopcameraGalleryLimits.candidates){invalidArgument2("vary values must be a non-empty bounded comma-separated list.")}specs.push({axis:axis.trim(),values:list})}if(specs.length===0){invalidArgument2("vary requires at least one axis, e.g. 'style; palette=warm,cool'.")}return specs}var FONT_5X7={" ":["00000","00000","00000","00000","00000","00000","00000"],"0":["01110","10001","10011","10101","11001","10001","01110"],"1":["00100","01100","00100","00100","00100","00100","01110"],"2":["01110","10001","00001","00010","00100","01000","11111"],"3":["11111","00010","00100","00010","00001","10001","01110"],"4":["00010","00110","01010","11111","00010","00010","00010"],"5":["11111","10000","11110","00001","00001","10001","01110"],"6":["00110","01000","10000","11110","10001","10001","01110"],"7":["11111","00001","00010","00100","01000","01000","01000"],"8":["01110","10001","10001","01110","10001","10001","01110"],"9":["01110","10001","10001","01111","00001","00010","01100"],a:["00000","00000","01110","00001","01111","10001","01111"],b:["10000","10000","10110","11001","10001","10001","11110"],c:["00000","00000","01110","10000","10000","10001","01110"],d:["00001","00001","01101","10011","10001","10001","01111"],e:["00000","00000","01110","10001","11111","10000","01110"],f:["00110","01001","01000","11100","01000","01000","01000"],g:["00000","01111","10001","10001","01111","00001","01110"],h:["10000","10000","10110","11001","10001","10001","10001"],i:["00100","00000","01100","00100","00100","00100","01110"],j:["00010","00000","00110","00010","00010","10010","01100"],k:["10000","10000","10010","10100","11000","10100","10010"],l:["01100","00100","00100","00100","00100","00100","01110"],m:["00000","00000","11010","10101","10101","10101","10101"],n:["00000","00000","10110","11001","10001","10001","10001"],o:["00000","00000","01110","10001","10001","10001","01110"],p:["00000","00000","11110","10001","11110","10000","10000"],q:["00000","00000","01101","10011","01111","00001","00001"],r:["00000","00000","10110","11001","10000","10000","10000"],s:["00000","00000","01111","10000","01110","00001","11110"],t:["01000","01000","11100","01000","01000","01001","00110"],u:["00000","00000","10001","10001","10001","10011","01101"],v:["00000","00000","10001","10001","10001","01010","00100"],w:["00000","00000","10001","10101","10101","10101","01010"],x:["00000","00000","10001","01010","00100","01010","10001"],y:["00000","00000","10001","10001","01111","00001","01110"],z:["00000","00000","11111","00010","00100","01000","11111"],"#":["01010","01010","11111","01010","11111","01010","01010"],"-":["00000","00000","00000","11111","00000","00000","00000"],_:["00000","00000","00000","00000","00000","00000","11111"],".":["00000","00000","00000","00000","00000","01100","01100"],":":["00000","01100","01100","00000","01100","01100","00000"],"=":["00000","00000","11111","00000","11111","00000","00000"],"/":["00001","00010","00010","00100","01000","01000","10000"],"?":["01110","10001","00001","00010","00100","00000","00100"]};function labelPixels(text,width,height){const scale=2;const rgba=Buffer.alloc(width*height*4);for(let pixel=0;pixel<width*height;pixel++){const index=pixel*4;rgba[index]=18;rgba[index+1]=21;rgba[index+2]=27;rgba[index+3]=255}const draw=(character,originX)=>{const glyph=FONT_5X7[character]??FONT_5X7["?"];const originY=Math.floor((height-7*scale)/2);for(let row=0;row<7;row++){for(let column=0;column<5;column++){if(glyph[row][column]!=="1")continue;for(let dy=0;dy<scale;dy++){for(let dx=0;dx<scale;dx++){const x=originX+column*scale+dx;const y=originY+row*scale+dy;if(x<0||x>=width||y<0||y>=height)continue;const index=(y*width+x)*4;rgba[index]=235;rgba[index+1]=238;rgba[index+2]=244;rgba[index+3]=255}}}}};const advance=6*scale;const maximum=Math.floor((width-8)/advance);const sanitized=text.toLowerCase().replace(/[^a-z0-9 #._:=/?-]/gu,"?").slice(0,Math.max(0,maximum));for(let index=0;index<sanitized.length;index++){draw(sanitized[index],4+index*advance)}return rgba}function mediaExtension(mediaType){if(mediaType==="image/png")return"png";if(mediaType==="image/jpeg")return"jpg";if(mediaType==="image/webp")return"webp";invalidArgument2("Candidate media type is unsupported.");return"png"}async function atomicPublish(path,bytes){const temporaryPath=join(dirname2(path),`.${randomUUID2()}.slopcamera-gallery.tmp`);try{await writeFile2(temporaryPath,bytes,{flag:"wx"});await link(temporaryPath,path)}catch{throw new SlopcameraCloudError("OUTPUT_WRITE_FAILED","Slopcamera could not atomically write a gallery output; existing files are never replaced.")}finally{await rm2(temporaryPath,{force:true}).catch(()=>{return})}}async function generateCandidate(candidate,model,input,dependencies){const generate=dependencies.generate??generateSlopcameraImage;try{const generated=await generate({model,prompt:candidate.prompt,...input.signal===undefined?{}:{signal:input.signal},...input.timeoutMs===undefined?{}:{timeoutMs:input.timeoutMs}},dependencies);const bytes=Buffer.from(generated.image.base64,"base64");return{index:candidate.index,id:candidate.id,label:candidate.label,prompt:candidate.prompt,status:"generated",bytes,mediaType:generated.image.mediaType,requestId:generated.requestId,warnings:generated.warnings}}catch(error){return{index:candidate.index,id:candidate.id,label:candidate.label,prompt:candidate.prompt,status:"failed",error:error instanceof Error?error.message:String(error)}}}async function mapBounded(items,concurrency,worker){const results=new Array(items.length);let next=0;await Promise.all(Array.from({length:Math.min(concurrency,items.length)},async()=>{while(next<items.length){const index=next++;results[index]=await worker(items[index])}}));return results}function galleryModel(value){const model=value??slopcameraImageModels[1];if(typeof model!=="string"||model.length>256||!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(model)){invalidArgument2("model must be a bounded Vercel AI Gateway provider/model id.")}return model}function galleryCellEdge(value){const cellEdge=value??slopcameraGalleryLimits.cellEdgeDefault;if(typeof cellEdge!=="number"||!Number.isInteger(cellEdge)||cellEdge<slopcameraGalleryLimits.cellEdgeMin||cellEdge>slopcameraGalleryLimits.cellEdgeMax){invalidArgument2(`cellEdge must be an integer from ${String(slopcameraGalleryLimits.cellEdgeMin)} through ${String(slopcameraGalleryLimits.cellEdgeMax)}.`)}return cellEdge}function galleryOutputDir(value){if(typeof value!=="string"||value.length<1||value.length>4096||value.includes("\x00")){invalidArgument2("outputDir must be a non-empty bounded local directory path.")}return resolve2(value)}async function generateSlopcameraImageGallery(rawInput,dependencies={}){if(!isRecord3(rawInput))invalidArgument2("Gallery input must be an object.");const input=rawInput;const outputDir=galleryOutputDir(input.outputDir);const model=galleryModel(input.model);const cellEdge=galleryCellEdge(input.cellEdge);const plan=planSlopcameraGallery(input);await mkdir2(outputDir,{recursive:true});const generated=await mapBounded(plan.candidates,slopcameraGalleryLimits.concurrency,async(candidate)=>await generateCandidate(candidate,model,input,dependencies));return await composeSlopcameraImageGallery({candidates:generated,cellEdge,model,outputDir,plan})}async function composeSlopcameraImageGallery(input){const outputDir=galleryOutputDir(input.outputDir);const model=galleryModel(input.model);const cellEdge=galleryCellEdge(input.cellEdge);const{plan}=input;if(!isRecord3(plan)||!Array.isArray(plan.candidates)||plan.candidates.length===0){invalidArgument2("plan must be a non-empty gallery plan from planSlopcameraGallery.")}const generated=input.candidates;await mkdir2(outputDir,{recursive:true});const labelHeight=slopcameraGalleryLimits.labelHeight;const cellWidth=cellEdge;const cellHeight=Math.round(cellEdge*plan.aspect[1]/plan.aspect[0]);const cellBodyHeight=cellHeight+labelHeight;const columns=Math.max(1,Math.ceil(Math.sqrt(generated.length)));const rows=Math.ceil(generated.length/columns);const gap=slopcameraGalleryLimits.cellGap;const sheetWidth=columns*cellWidth+(columns-1)*gap;const sheetHeight=rows*cellBodyHeight+(rows-1)*gap;if(sheetWidth*sheetHeight>slopcameraGalleryLimits.galleryPixels){invalidArgument2("Gallery sheet exceeds its pixel budget; reduce count or cellEdge.")}const receiptCandidates=[];const overlays=[];for(const candidate of generated){const column=(candidate.index-1)%columns;const row=Math.floor((candidate.index-1)/columns);const x=column*(cellWidth+gap);const y=row*(cellBodyHeight+gap);const labelText=candidate.status==="failed"?`#${String(candidate.index)} ${candidate.label} failed`:`#${String(candidate.index)} ${candidate.label}`;overlays.push({input:await sharp(labelPixels(labelText,cellWidth,labelHeight),{raw:{width:cellWidth,height:labelHeight,channels:4}}).png().toBuffer(),left:x,top:y});if(candidate.status==="generated"){if(candidate.bytes===undefined||candidate.mediaType===undefined){invalidArgument2("A generated gallery candidate requires its bytes and media type.")}const path=candidate.path??join(outputDir,`candidate-${String(candidate.index).padStart(2,"0")}-${slug(candidate.id)}.${mediaExtension(candidate.mediaType)}`);if(candidate.path===undefined){await atomicPublish(path,candidate.bytes)}const sha256=createHash2("sha256").update(candidate.bytes).digest("hex");if(candidate.sha256!==undefined&&candidate.sha256!==sha256){invalidArgument2("A pre-published gallery candidate digest does not match its bytes.")}let cellSource;let cellReceipt;if(candidate.cellImage!==undefined){const cellSha256=createHash2("sha256").update(candidate.cellImage.bytes).digest("hex");if(candidate.cellImage.sha256!==undefined&&candidate.cellImage.sha256!==cellSha256){invalidArgument2("A gallery cell image digest does not match its bytes.")}const cellCandidate=sharp(candidate.cellImage.bytes,{limitInputPixels:slopcameraGalleryLimits.candidatePixels,failOn:"warning"});const cellMetadata=await cellCandidate.metadata();if(cellMetadata.width===undefined||cellMetadata.height===undefined||cellMetadata.width>slopcameraGalleryLimits.candidateEdge||cellMetadata.height>slopcameraGalleryLimits.candidateEdge||cellMetadata.width*cellMetadata.height>slopcameraGalleryLimits.candidatePixels){invalidArgument2("A gallery cell image exceeds its raster bounds.")}cellSource=cellCandidate;cellReceipt={sha256:cellSha256,bytes:candidate.cellImage.bytes.byteLength,mediaType:candidate.cellImage.mediaType,...candidate.cellImage.path===undefined?{}:{path:candidate.cellImage.path}}}else{const source=sharp(candidate.bytes,{limitInputPixels:slopcameraGalleryLimits.candidatePixels,failOn:"warning"});const metadata=await source.metadata();if(metadata.width===undefined||metadata.height===undefined||metadata.width>slopcameraGalleryLimits.candidateEdge||metadata.height>slopcameraGalleryLimits.candidateEdge||metadata.width*metadata.height>slopcameraGalleryLimits.candidatePixels){invalidArgument2("A generated candidate exceeds its raster bounds.")}cellSource=source}const resized=await cellSource.resize(cellWidth,cellHeight,{fit:"cover"}).png().toBuffer();const cellImage=plan.tiled&&candidate.cellImage===undefined?await(async()=>{const tile=await sharp(resized).resize(Math.ceil(cellWidth/2),Math.ceil(cellHeight/2),{fit:"fill"}).png().toBuffer();const positions=[0,Math.floor(cellWidth/2)];const rows2=[0,Math.floor(cellHeight/2)];return sharp({create:{width:cellWidth,height:cellHeight,channels:4,background:{r:0,g:0,b:0,alpha:0}}}).composite(rows2.flatMap((top)=>positions.map((left)=>({input:tile,left,top})))).png().toBuffer()})():resized;overlays.push({input:cellImage,left:x,top:y+labelHeight});receiptCandidates.push({index:candidate.index,id:candidate.id,label:candidate.label,prompt:candidate.prompt,status:"generated",path,sha256,bytes:candidate.bytes.byteLength,mediaType:candidate.mediaType,...candidate.requestId===undefined?{}:{requestId:candidate.requestId},...candidate.warnings===undefined?{}:{warnings:candidate.warnings},...candidate.job===undefined?{}:{job:candidate.job},...plan.tiled&&candidate.cellImage===undefined?{tiled:true}:{},...cellReceipt===undefined?{}:{cellImage:cellReceipt},...candidate.scene===undefined?{}:{scene:candidate.scene},cell:{x,y,width:cellWidth,height:cellBodyHeight}})}else{const hasRetainedArtifact=candidate.bytes!==undefined||candidate.mediaType!==undefined||candidate.path!==undefined||candidate.sha256!==undefined;let retainedArtifact;if(hasRetainedArtifact){if(candidate.bytes===undefined||candidate.mediaType===undefined||candidate.path===undefined){invalidArgument2("A failed gallery candidate artifact requires bytes, media type, and path.")}const sha256=createHash2("sha256").update(candidate.bytes).digest("hex");if(candidate.sha256!==undefined&&candidate.sha256!==sha256){invalidArgument2("A failed gallery candidate artifact digest does not match its bytes.")}retainedArtifact={bytes:candidate.bytes.byteLength,mediaType:candidate.mediaType,path:candidate.path,sha256}}const blank=Buffer.alloc(cellWidth*cellHeight*4);for(let pixel=0;pixel<cellWidth*cellHeight;pixel++){const index=pixel*4;blank[index]=48;blank[index+1]=52;blank[index+2]=60;blank[index+3]=255}overlays.push({input:await sharp(blank,{raw:{width:cellWidth,height:cellHeight,channels:4}}).png().toBuffer(),left:x,top:y+labelHeight});receiptCandidates.push({index:candidate.index,id:candidate.id,label:candidate.label,prompt:candidate.prompt,status:"failed",...retainedArtifact,...candidate.requestId===undefined?{}:{requestId:candidate.requestId},...candidate.warnings===undefined?{}:{warnings:candidate.warnings},...candidate.error===undefined?{}:{error:candidate.error},...candidate.job===undefined?{}:{job:candidate.job},...candidate.scene===undefined?{}:{scene:candidate.scene},cell:{x,y,width:cellWidth,height:cellBodyHeight}})}}const sheet=await sharp({create:{width:sheetWidth,height:sheetHeight,channels:4,background:{r:10,g:12,b:16,alpha:255}}}).composite(overlays).png().toBuffer();const galleryPath=join(outputDir,"gallery.png");await atomicPublish(galleryPath,sheet);const gallerySha256=createHash2("sha256").update(sheet).digest("hex");const failed=generated.filter((candidate)=>candidate.status==="failed").length;const receiptPath=join(outputDir,"receipt.json");const receipt={kind:input.receipt?.kind??"slopcamera.image-gallery",schemaVersion:1,subject:plan.subject,galleryKind:input.receipt===undefined?plan.kind:"scene",model,provider:input.receipt===undefined?"vercel-ai-gateway":"local",...input.receipt===undefined?{}:{baseSceneSha256:input.receipt.baseSceneSha256},cell:{width:cellWidth,height:cellHeight,labelHeight},axes:plan.axes,candidates:receiptCandidates,counts:{requested:generated.length,generated:generated.length-failed,failed},gallery:{path:galleryPath,sha256:gallerySha256,bytes:sheet.byteLength,mediaType:"image/png",width:sheetWidth,height:sheetHeight},receiptPath,clientMaxRetries:0};await atomicPublish(receiptPath,`${JSON.stringify(receipt,null,2)}
37
- `);if(failed===generated.length){throw new SlopcameraCloudError("GENERATION_FAILED",`Every gallery candidate failed; see ${receiptPath} for the retained attempt record.`)}return receipt}var slopcameraOperationCodes=["slopcamera.diagram.check","slopcamera.diagram.render","slopcamera.image.vectorize","slopcamera.image.generate","slopcamera.image.icon","slopcamera.image.gallery"];class SlopcameraOperationError extends Error{code;constructor(code,message){super(`[${code}] ${message}`);this.name="SlopcameraOperationError";this.code=code}}var modelSchema={type:"string",minLength:3,maxLength:256,pattern:"^[a-zA-Z0-9][a-zA-Z0-9._-]*/[a-zA-Z0-9][a-zA-Z0-9._:-]*$"};var pathSchema={type:"string",minLength:1,maxLength:4096};function deepFreeze(value){if(typeof value!=="object"||value===null||Object.isFrozen(value)){return value}for(const nested of Object.values(value))deepFreeze(nested);return Object.freeze(value)}var slopcameraOperationRegistry=deepFreeze([{code:"slopcamera.diagram.check",title:"Check diagram",description:"Parse and lint a checked Slopcamera diagram source without changing its files.",execution:"local",authentication:"none",destructive:false,idempotent:true,inputSchema:{type:"object",additionalProperties:false,required:["path"],properties:{path:pathSchema}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1}]},{code:"slopcamera.diagram.render",title:"Render diagram",description:"Render a checked Slopcamera diagram source to its replaceable light, dark, PNG, SVG, and tldraw artifacts.",execution:"local",authentication:"none",destructive:true,idempotent:true,inputSchema:{type:"object",additionalProperties:false,required:["path"],properties:{path:pathSchema,outDirectory:pathSchema,scale:{type:"number",exclusiveMinimum:0,maximum:4}}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1}]},{code:"slopcamera.image.vectorize",title:"Vectorize image",description:"Convert a local caller-owned raster into a bounded inert SVG without authentication or network access.",execution:"local",authentication:"none",destructive:true,idempotent:false,inputSchema:{type:"object",additionalProperties:false,required:["inputPath","outputPath"],properties:{inputPath:pathSchema,outputPath:pathSchema,duotone:{type:"array",minItems:2,maxItems:2,items:{type:"string",pattern:"^#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$"}},alphaCutoff:{type:"integer",minimum:1,maximum:64},timeoutMs:{type:"integer",minimum:1,maximum:300000}}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1}]},{code:"slopcamera.image.generate",title:"Generate image",description:"Generate one bounded image directly through Vercel AI Gateway with an environment credential and no client retry.",execution:"gateway",authentication:"environment",destructive:true,idempotent:false,inputSchema:{type:"object",additionalProperties:false,required:["model","prompt","outputPath"],properties:{model:modelSchema,prompt:{type:"string",minLength:1,maxLength:slopcameraMaximumPromptBytes},outputPath:pathSchema}},resources:[{resource:"local-io",amount:1},{resource:"network",amount:1},{resource:"paid-call",amount:1}],transport:{method:"POST",authority:"https://ai-gateway.vercel.sh/v4/ai",authorization:"bearer",retry:"never"}},{code:"slopcamera.image.icon",title:"Generate line-art icon",description:"Generate one isometric line-art SVG icon: a style-locked Vercel AI Gateway raster normalized to canonical ink-on-transparent pixels, traced locally, and optionally critiqued by a vision model across bounded rounds.",execution:"gateway",authentication:"environment",destructive:true,idempotent:false,inputSchema:{type:"object",additionalProperties:false,required:["subject","outputPath"],properties:{subject:{type:"string",minLength:1,maxLength:slopcameraIconSubjectMaximumBytes},outputPath:pathSchema,model:modelSchema,critiqueModel:modelSchema,ink:{type:"string",pattern:"^#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$"},purpose:{type:"string",enum:["mark","illustration"]},context:{type:"string",enum:[...slopcameraIconContexts]},candidatePool:{type:"integer",minimum:1,maximum:slopcameraIconMaximumRounds},rounds:{type:"integer",minimum:1,maximum:slopcameraIconMaximumRounds},keepRaster:{type:"boolean"}}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1},{resource:"network",amount:1},{resource:"paid-call",amount:1}],transport:{method:"POST",authority:"https://ai-gateway.vercel.sh/v4/ai",authorization:"bearer",retry:"never"}},{code:"slopcamera.image.gallery",title:"Generate image gallery",description:"Generate several bounded Vercel AI Gateway image candidates in parallel and compose a labelled contact sheet with per-candidate provenance for explicit review and selection.",execution:"gateway",authentication:"environment",destructive:true,idempotent:false,inputSchema:{type:"object",additionalProperties:false,required:["subject","outputDir"],properties:{subject:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.subjectBytes},outputDir:pathSchema,kind:{type:"string",enum:[...slopcameraGalleryKinds]},model:modelSchema,count:{type:"integer",minimum:1,maximum:slopcameraGalleryLimits.candidates},vary:{type:"array",maxItems:slopcameraGalleryAxes.length,items:{anyOf:[{type:"string",enum:[...slopcameraGalleryAxes]},{type:"object",additionalProperties:false,required:["axis"],properties:{axis:{type:"string",enum:[...slopcameraGalleryAxes]},values:{type:"array",minItems:1,maxItems:slopcameraGalleryLimits.candidates,items:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.variantBytes}}}}]}},candidates:{type:"array",minItems:1,maxItems:slopcameraGalleryLimits.candidates,items:{type:"object",additionalProperties:false,required:["id"],properties:{id:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.idLength},prompt:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.candidatePromptBytes},variant:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.variantBytes}}}},cellEdge:{type:"integer",minimum:slopcameraGalleryLimits.cellEdgeMin,maximum:slopcameraGalleryLimits.cellEdgeMax},tiled:{type:"boolean"},timeoutMs:{type:"integer",minimum:1000,maximum:30*60000}}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1},{resource:"network",amount:1},{resource:"paid-call",amount:1}],transport:{method:"POST",authority:"https://ai-gateway.vercel.sh/v4/ai",authorization:"bearer",retry:"never"}}]);function operationFailure(message){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT",message)}function isRecord4(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function record(value,allowedKeys){if(!isRecord4(value))operationFailure("Operation input must be an object.");const unknown=Object.keys(value).filter((key)=>!allowedKeys.includes(key));if(unknown.length>0){operationFailure(`Unsupported operation input field: ${unknown[0]}.`)}return value}function pathValue(value,name){if(typeof value!=="string"||value.length<1||value.length>4096||value.includes("\x00")){operationFailure(`${name} must be a non-empty bounded local path.`)}return value}function parseCheck(value){const input=record(value,["path"]);return{path:pathValue(input.path,"path")}}function parseRender(value){const input=record(value,["path","outDirectory","scale"]);const scale=input.scale;if(scale!==undefined&&(typeof scale!=="number"||!Number.isFinite(scale)||scale<=0||scale>4)){operationFailure("scale must be greater than zero and no more than 4.")}return{path:pathValue(input.path,"path"),...input.outDirectory===undefined?{}:{outDirectory:pathValue(input.outDirectory,"outDirectory")},...scale===undefined?{}:{scale}}}function parseVectorize(value){const input=record(value,["inputPath","outputPath","duotone","alphaCutoff","timeoutMs"]);const inputPath=pathValue(input.inputPath,"inputPath");const outputPath=pathValue(input.outputPath,"outputPath");if(!outputPath.toLowerCase().endsWith(".svg")){operationFailure("outputPath must end in .svg.")}const duotone=input.duotone;if(duotone!==undefined&&(!Array.isArray(duotone)||duotone.length!==2||duotone.some((color)=>typeof color!=="string"||!/^#[a-f0-9]{3}(?:[a-f0-9]{3})?$/iu.test(color)))){operationFailure("duotone must contain exactly two #rgb or #rrggbb colors.")}const alphaCutoff=input.alphaCutoff;if(alphaCutoff!==undefined&&(!Number.isInteger(alphaCutoff)||alphaCutoff<1||alphaCutoff>64)){operationFailure("alphaCutoff must be an integer from 1 through 64.")}const timeoutMs=input.timeoutMs;if(timeoutMs!==undefined&&(!Number.isInteger(timeoutMs)||timeoutMs<1||timeoutMs>300000)){operationFailure("timeoutMs must be an integer from 1 through 300000.")}return{inputPath,outputPath,...duotone===undefined?{}:{duotone},...alphaCutoff===undefined?{}:{alphaCutoff},...timeoutMs===undefined?{}:{timeoutMs}}}function parseGenerate(value){const input=record(value,["model","prompt","outputPath"]);if(typeof input.model!=="string"||input.model.length>256||!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(input.model)){operationFailure("model must be a bounded Vercel AI Gateway provider/model id.")}if(typeof input.prompt!=="string"||input.prompt.trim().length<1||/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u.test(input.prompt)||Buffer.byteLength(input.prompt,"utf8")>slopcameraMaximumPromptBytes){operationFailure(`prompt must be non-empty and no more than ${slopcameraMaximumPromptBytes} UTF-8 bytes.`)}const outputPath=pathValue(input.outputPath,"outputPath");if(!/\.(?:jpe?g|png|webp)$/iu.test(outputPath)){operationFailure("outputPath must end in .png, .jpg, .jpeg, or .webp.")}return{model:input.model,prompt:input.prompt,outputPath}}function parseIcon(value){const input=record(value,["subject","outputPath","model","critiqueModel","ink","purpose","context","candidatePool","rounds","keepRaster"]);if(typeof input.subject!=="string"||input.subject.trim().length<1||/[\u0000-\u001f\u007f]/u.test(input.subject)||Buffer.byteLength(input.subject,"utf8")>slopcameraIconSubjectMaximumBytes){operationFailure(`subject must be non-empty and no more than ${slopcameraIconSubjectMaximumBytes} UTF-8 bytes.`)}const outputPath=pathValue(input.outputPath,"outputPath");if(!outputPath.toLowerCase().endsWith(".svg")){operationFailure("outputPath must end in .svg.")}for(const name of["model","critiqueModel"]){const model=input[name];if(model!==undefined&&(typeof model!=="string"||model.length>256||!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(model))){operationFailure(`${name} must be a bounded Vercel AI Gateway provider/model id.`)}}if(input.ink!==undefined&&(typeof input.ink!=="string"||!/^#[a-f0-9]{3}(?:[a-f0-9]{3})?$/iu.test(input.ink))){operationFailure("ink must be a #rgb or #rrggbb color.")}if(input.purpose!==undefined&&input.purpose!=="illustration"&&input.purpose!=="mark"){operationFailure("purpose must be illustration or mark.")}if(input.context!==undefined&&(typeof input.context!=="string"||!slopcameraIconContexts.includes(input.context))){operationFailure(`context must be one of: ${slopcameraIconContexts.join(", ")}.`)}const candidatePool=input.candidatePool;if(candidatePool!==undefined&&(!Number.isInteger(candidatePool)||candidatePool<1||candidatePool>slopcameraIconMaximumRounds)){operationFailure(`candidatePool must be an integer from 1 through ${slopcameraIconMaximumRounds}.`)}const rounds=input.rounds;if(rounds!==undefined&&(!Number.isInteger(rounds)||rounds<1||rounds>slopcameraIconMaximumRounds)){operationFailure(`rounds must be an integer from 1 through ${slopcameraIconMaximumRounds}.`)}if(input.keepRaster!==undefined&&typeof input.keepRaster!=="boolean"){operationFailure("keepRaster must be a boolean.")}return{subject:input.subject,outputPath,...input.model===undefined?{}:{model:input.model},...input.critiqueModel===undefined?{}:{critiqueModel:input.critiqueModel},...input.ink===undefined?{}:{ink:input.ink},...input.purpose===undefined?{}:{purpose:input.purpose},...input.context===undefined?{}:{context:input.context},...candidatePool===undefined?{}:{candidatePool},...rounds===undefined?{}:{rounds},...input.keepRaster===undefined?{}:{keepRaster:input.keepRaster}}}function parseGallery(value){const input=record(value,["subject","outputDir","kind","model","count","vary","candidates","cellEdge","tiled","timeoutMs"]);if(typeof input.subject!=="string"||input.subject.trim().length<1||/[\u0000-\u001f\u007f]/u.test(input.subject)||Buffer.byteLength(input.subject,"utf8")>slopcameraGalleryLimits.subjectBytes){operationFailure(`subject must be non-empty and no more than ${slopcameraGalleryLimits.subjectBytes} UTF-8 bytes.`)}if(input.kind!==undefined&&(typeof input.kind!=="string"||!slopcameraGalleryKinds.includes(input.kind))){operationFailure(`kind must be one of: ${slopcameraGalleryKinds.join(", ")}.`)}if(input.model!==undefined&&(typeof input.model!=="string"||input.model.length>256||!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(input.model))){operationFailure("model must be a bounded Vercel AI Gateway provider/model id.")}if(input.count!==undefined&&(!Number.isInteger(input.count)||input.count<1||input.count>slopcameraGalleryLimits.candidates)){operationFailure(`count must be an integer from 1 through ${slopcameraGalleryLimits.candidates}.`)}if(input.vary!==undefined&&(!Array.isArray(input.vary)||input.vary.length<1||input.vary.length>slopcameraGalleryAxes.length)){operationFailure(`vary must be a list of at most ${slopcameraGalleryAxes.length} axes.`)}if(input.candidates!==undefined&&(!Array.isArray(input.candidates)||input.candidates.length<1||input.candidates.length>slopcameraGalleryLimits.candidates)){operationFailure(`candidates must contain 1 through ${slopcameraGalleryLimits.candidates} entries.`)}if(input.vary!==undefined&&input.candidates!==undefined){operationFailure("vary and candidates are mutually exclusive.")}if(input.count!==undefined&&input.candidates!==undefined){operationFailure("count and candidates are mutually exclusive.")}const cellEdge=input.cellEdge;if(cellEdge!==undefined&&(!Number.isInteger(cellEdge)||cellEdge<slopcameraGalleryLimits.cellEdgeMin||cellEdge>slopcameraGalleryLimits.cellEdgeMax)){operationFailure(`cellEdge must be an integer from ${slopcameraGalleryLimits.cellEdgeMin} through ${slopcameraGalleryLimits.cellEdgeMax}.`)}const timeoutMs=input.timeoutMs;if(timeoutMs!==undefined&&(!Number.isInteger(timeoutMs)||timeoutMs<1000||timeoutMs>30*60000)){operationFailure("timeoutMs must be an integer from 1000 through 1800000.")}if(input.tiled!==undefined&&typeof input.tiled!=="boolean"){operationFailure("tiled must be a boolean when set.")}return{subject:input.subject,outputDir:pathValue(input.outputDir,"outputDir"),...input.kind===undefined?{}:{kind:input.kind},...input.model===undefined?{}:{model:input.model},...input.count===undefined?{}:{count:input.count},...input.vary===undefined?{}:{vary:input.vary},...input.candidates===undefined?{}:{candidates:input.candidates},...cellEdge===undefined?{}:{cellEdge},...input.tiled===undefined?{}:{tiled:input.tiled},...timeoutMs===undefined?{}:{timeoutMs}}}function parseSlopcameraOperationInput(code,input){switch(code){case"slopcamera.diagram.check":return parseCheck(input);case"slopcamera.diagram.render":return parseRender(input);case"slopcamera.image.vectorize":return parseVectorize(input);case"slopcamera.image.generate":return parseGenerate(input);case"slopcamera.image.icon":return parseIcon(input);case"slopcamera.image.gallery":return parseGallery(input);default:throw new SlopcameraOperationError("INVALID_OPERATION","Unknown Slopcamera operation code.")}}function isSlopcameraOperationCode(value){return slopcameraOperationCodes.includes(value)}function slopcameraOperationHostResourceClaims(code){const descriptor=slopcameraOperationRegistry.find((candidate)=>candidate.code===code);if(descriptor===undefined){throw new SlopcameraOperationError("INVALID_OPERATION","Unknown Slopcamera operation code.")}return descriptor.resources}function searchSlopcameraOperations(query="",limit=slopcameraOperationRegistry.length){if(typeof query!=="string"||query.length>200||/[\u0000-\u001f\u007f]/u.test(query)||!Number.isInteger(limit)||limit<1||limit>20){throw new SlopcameraOperationError("INVALID_SEARCH","Search requires a bounded query and a limit from 1 through 20.")}const terms=query.toLowerCase().split(/\s+/u).filter((term)=>term.length>0);return slopcameraOperationRegistry.filter((operation)=>{const haystack=`${operation.code} ${operation.title} ${operation.description}`.toLowerCase();return terms.every((term)=>haystack.includes(term))}).slice(0,limit)}function operationDependenciesWithLease(dependencies,lease){const inheritedFileDescriptors=[...dependencies.inheritedFileDescriptors??[],lease.inheritedFileDescriptor].filter((descriptor,index,descriptors)=>descriptors.indexOf(descriptor)===index);if(inheritedFileDescriptors.length>16||inheritedFileDescriptors.some((descriptor)=>!Number.isSafeInteger(descriptor)||descriptor<0||descriptor>2147483647)){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT","Operation host-resource inheritance exceeds its descriptor bound.")}const{hostResourceCoordinator:_hostResourceCoordinator,signal:_signal,waitTimeoutMilliseconds:_waitTimeoutMilliseconds,...operationDependencies}=dependencies;return{...operationDependencies,inheritedFileDescriptors}}async function withSlopcameraOperationHostAdmission(code,callback,options={}){const coordinator=options.hostResourceCoordinator??createDefaultHostResourceCoordinator();return await coordinator.withLease(slopcameraOperationHostResourceClaims(code),async(lease)=>{await lease.assertOwned();return await callback(lease)},{...options.signal===undefined?{}:{signal:options.signal},...options.waitTimeoutMilliseconds===undefined?{}:{waitTimeoutMilliseconds:options.waitTimeoutMilliseconds}})}var operationBuiltInConfig=Object.freeze({icons:builtInIcons});async function readOperationDiagram(path){const absolutePath=resolve3(path);let value;try{value=JSON.parse(await readFile2(absolutePath,"utf8"))}catch(cause){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT","Diagram source could not be read as JSON.")}const spec=parseDiagramSpec(value);for(const shape of spec.shapes){if((shape.type==="rect"||shape.type==="ellipse")&&shape.icon!==undefined&&!Object.hasOwn(builtInIcons,shape.icon)){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT","Diagram requests an unavailable built-in icon.")}}return{absolutePath,spec}}async function atomicOperationWrite(path,value){const temporaryPath=join2(dirname3(path),`.${randomUUID3()}.slopcamera-operation.tmp`);try{await writeFile3(temporaryPath,value,{flag:"wx"});await rename2(temporaryPath,path)}finally{await rm3(temporaryPath,{force:true}).catch(()=>{return})}}async function checkOperationDiagram(path){const{spec}=await readOperationDiagram(path);return{findings:lintDiagram(spec),configPath:null}}async function renderOperationDiagram(input){const{absolutePath,spec}=await readOperationDiagram(input.path);const outputDirectory=resolve3(input.outDirectory??dirname3(absolutePath));const scale=input.scale??2;const[light,dark]=await Promise.all([renderSvg(spec,"light",operationBuiltInConfig),renderSvg(spec,"dark",operationBuiltInConfig)]);const[lightPng,darkPng]=[renderPng(light,operationBuiltInConfig,scale),renderPng(dark,operationBuiltInConfig,scale)];const artifacts={spec:absolutePath,tldr:join2(outputDirectory,`${spec.name}.tldr`),lightSvg:join2(outputDirectory,`${spec.name}.light.svg`),darkSvg:join2(outputDirectory,`${spec.name}.dark.svg`),lightPng:join2(outputDirectory,`${spec.name}.light.png`),darkPng:join2(outputDirectory,`${spec.name}.dark.png`)};await mkdir3(outputDirectory,{recursive:true});await Promise.all([atomicOperationWrite(artifacts.tldr,serializeTldr(spec,operationBuiltInConfig)),atomicOperationWrite(artifacts.lightSvg,light.svg),atomicOperationWrite(artifacts.darkSvg,dark.svg),atomicOperationWrite(artifacts.lightPng,lightPng),atomicOperationWrite(artifacts.darkPng,darkPng)]);return{artifacts,findings:lintDiagram(spec),configPath:null}}async function executeSlopcameraOperationUncoordinated(code,value,dependencies={}){const input=parseSlopcameraOperationInput(code,value);switch(code){case"slopcamera.diagram.check":{const options=input;return await checkOperationDiagram(options.path)}case"slopcamera.diagram.render":{const options=input;return await renderOperationDiagram(options)}case"slopcamera.image.vectorize":{const options=input;const result=await vectorizeImage(options.inputPath,{outputPath:options.outputPath,...options.duotone===undefined?{}:{duotone:options.duotone},...options.alphaCutoff===undefined?{}:{alphaCutoff:options.alphaCutoff},...options.timeoutMs===undefined?{}:{limits:{maxDurationMs:options.timeoutMs}},...dependencies.inheritedFileDescriptors===undefined?{}:{inheritedFileDescriptors:dependencies.inheritedFileDescriptors}});if(result.outputPath===null){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT","Vectorization did not publish its required output.")}return{outputPath:result.outputPath,receipt:result.receipt}}case"slopcamera.image.generate":{const options=input;return await generateSlopcameraImageFile({...options,...dependencies.signal===undefined?{}:{signal:dependencies.signal}},dependencies)}case"slopcamera.image.icon":{const options=input;return await generateSlopcameraIcon({...options,...dependencies.signal===undefined?{}:{signal:dependencies.signal},...dependencies.inheritedFileDescriptors===undefined?{}:{inheritedFileDescriptors:dependencies.inheritedFileDescriptors}},dependencies)}case"slopcamera.image.gallery":{const options=input;return await generateSlopcameraImageGallery({...options,...dependencies.signal===undefined?{}:{signal:dependencies.signal}},dependencies)}default:throw new SlopcameraOperationError("INVALID_OPERATION","Unknown Slopcamera operation code.")}}async function executeSlopcameraOperationWithLease(code,value,lease,dependencies={}){await lease.assertOwned();const available=new Map;for(const claim of lease.claims){if(typeof claim.resource!=="string"||!/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u.test(claim.resource)||!Number.isSafeInteger(claim.amount)||claim.amount<1){throw new SlopcameraOperationError("INVALID_OPERATION","The active host-resource lease contains invalid claims.")}const total=(available.get(claim.resource)??0)+claim.amount;if(!Number.isSafeInteger(total)){throw new SlopcameraOperationError("INVALID_OPERATION","The active host-resource lease contains invalid claims.")}available.set(claim.resource,total)}const missing=slopcameraOperationHostResourceClaims(code).filter((claim)=>(available.get(claim.resource)??0)<claim.amount);if(missing.length>0){throw new SlopcameraOperationError("INVALID_OPERATION",`The active host-resource lease does not cover ${missing.map((claim)=>`${claim.resource}:${String(claim.amount)}`).join(", ")}.`)}return await executeSlopcameraOperationUncoordinated(code,value,operationDependenciesWithLease(dependencies,lease))}async function executeSlopcameraOperation(code,value,dependencies={}){const input=parseSlopcameraOperationInput(code,value);return await withSlopcameraOperationHostAdmission(code,async(lease)=>await executeSlopcameraOperationUncoordinated(code,input,operationDependenciesWithLease(dependencies,lease)),dependencies)}
38
- export{builtInIcons,sanitizeIcon,layoutBoxContent,NebulaSans_Bold_default,NebulaSans_Book_default,resolveEdge,renderSvg,renderPng,lintDiagram,stackLayoutDefaults,StackLayoutError,resolveStackLayout,resolveDiagramSource,DiagramValidationError,parseDiagramSource,parseDiagramSpec,serializeTldr,slopcameraIconDefaultInk,slopcameraIconPanel,slopcameraIconDefaultRounds,slopcameraIconMaximumRounds,slopcameraIconSubjectMaximumBytes,slopcameraIconCritiqueDefaultModel,slopcameraIconCritiqueTimeoutMs,slopcameraIconContexts,slopcameraIconContextProfiles,iconPromptFor,iconVisualGateProblems,estimateIconStrokePixels,measureIconCandidateMetrics,extractIconLineArt,loadIconLanguageRuntime,critiqueIconRaster,renderIconPreview,writeAtomically,collectSlopcameraIconCandidates,generateSlopcameraIcon,slopcameraGalleryKinds,slopcameraGalleryAxes,slopcameraGalleryLimits,galleryCandidateId,galleryPromptFor,planSlopcameraGallery,parseSlopcameraGalleryVary,generateSlopcameraImageGallery,composeSlopcameraImageGallery,slopcameraOperationCodes,SlopcameraOperationError,slopcameraOperationRegistry,parseSlopcameraOperationInput,isSlopcameraOperationCode,slopcameraOperationHostResourceClaims,searchSlopcameraOperations,withSlopcameraOperationHostAdmission,executeSlopcameraOperationWithLease,executeSlopcameraOperation};
37
+ `);if(failed===generated.length){throw new SlopcameraCloudError("GENERATION_FAILED",`Every gallery candidate failed; see ${receiptPath} for the retained attempt record.`)}return receipt}import{canonicalJson,compileProgram,CONSTRUCTION_VERSION,CONSTRUCTION_VERSION_V1,createRecipe,parseProgram,programDigest,RECIPE_VERSION,renderConstruction,replayRecipe}from"@hraness/iconplace";import{COLLECTION_VERSION}from"@hraness/iconplace/collections";import{createSceneRecipe,DEFAULT_SCENE_RENDER,parseScene,replaySceneRecipe,renderScene,SCENE_RECIPE_VERSION,SCENE_VERSION,sceneFromComposition,solveScene}from"@hraness/iconplace/scene";import{createHash as createHash3,randomUUID as randomUUID3}from"crypto";import{constants}from"fs";import{mkdir as mkdir3,open,rename as rename2,rm as rm3,stat}from"fs/promises";import{dirname as dirname3,join as join2,resolve as resolve3}from"path";class BoundedFileError extends Error{code;constructor(code,message){super(message);this.name="BoundedFileError";this.code=code}}function errorCode(error){return typeof error==="object"&&error!==null&&"code"in error?String(error.code):undefined}async function readBoundedFile(path,maximumBytes,label){let handle;try{handle=await open(path,constants.O_RDONLY|constants.O_NONBLOCK)}catch(error){if(errorCode(error)==="ENOENT"){throw new BoundedFileError("SOURCE_NOT_FOUND",`${label} does not exist.`)}throw new BoundedFileError("SOURCE_UNREADABLE",`${label} could not be opened.`)}try{const metadata=await handle.stat();if(!metadata.isFile()){throw new BoundedFileError("SOURCE_NOT_FILE",`${label} must be a regular file.`)}if(metadata.size>maximumBytes){throw new BoundedFileError("SOURCE_TOO_LARGE",`${label} exceeds the ${String(maximumBytes)}-byte limit.`)}const buffer=new Uint8Array(maximumBytes+1);let length=0;for(;;){const{bytesRead}=await handle.read(buffer,length,buffer.length-length,length);if(bytesRead===0)break;length+=bytesRead;if(length>maximumBytes){throw new BoundedFileError("SOURCE_TOO_LARGE",`${label} exceeds the ${String(maximumBytes)}-byte limit.`)}}return buffer.slice(0,length)}finally{await handle.close()}}function decodeUtf8Source(bytes,label){try{return new TextDecoder("utf-8",{fatal:true,ignoreBOM:false}).decode(bytes)}catch{throw new BoundedFileError("SOURCE_UNREADABLE",`${label} must be UTF-8 text.`)}}function sha256Hex(value){return createHash3("sha256").update(value).digest("hex")}async function publishReplaceableFile(path,value){const directory=dirname3(path);await mkdir3(directory,{recursive:true});const temporaryPath=join2(directory,`.slopcamera-${randomUUID3()}.tmp`);try{const handle=await open(temporaryPath,"wx");try{await handle.writeFile(value);await handle.sync()}finally{await handle.close()}await rename2(temporaryPath,path)}finally{await rm3(temporaryPath,{force:true}).catch(()=>{return})}}async function hasPathCollision(paths){const spellings=new Set;const identities=new Set;for(const path of paths){if(path===undefined)continue;const absolute=resolve3(path);if(spellings.has(absolute))return true;spellings.add(absolute);let identity;try{const metadata=await stat(absolute,{bigint:true});identity=`${String(metadata.dev)}:${String(metadata.ino)}`}catch(error){if(errorCode(error)==="ENOENT"||errorCode(error)==="ENOTDIR")continue;throw new BoundedFileError("SOURCE_UNREADABLE","A declared path could not be inspected.")}if(identities.has(identity))return true;identities.add(identity)}return false}var slopcameraIconEngine=Object.freeze({package:"@hraness/iconplace",version:"0.1.0"});var slopcameraIconSceneLimits=Object.freeze({sourceBytes:1024*1024,outputBytes:4*1024*1024,sizeMin:16,sizeMax:1024,diagnostics:64,notes:32});var slopcameraIconPalettes=Object.freeze(["original","ink","earth","night"]);var slopcameraIconLanguages=Object.freeze(["outline","sketch","pen","crosshatch","engraving","stipple","halftone","glyph","flat","shaded","figure","cutpaper","woodcut","offset"]);var slopcameraIconDefaultLanguage="outline";class SlopcameraIconError extends Error{code;constructor(code,message){super(message);this.name="SlopcameraIconError";this.code=code}}function invalidSource(message){throw new SlopcameraIconError("INVALID_ICON_SOURCE",message)}function invalidInput(message){throw new SlopcameraIconError("INVALID_ICON_INPUT",message)}function libraryMessage(error){const message=error instanceof Error?error.message:String(error);const printable=[...message].filter((character)=>{const code=character.codePointAt(0)??0;return code>=32&&code!==127}).join("");return printable.length>240?`${printable.slice(0,237)}...`:printable}function isRecord4(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function parseSourceJson(bytes){let value;try{value=JSON.parse(decodeUtf8Source(bytes,"Icon source"))}catch(error){if(error instanceof BoundedFileError)throw error;invalidSource("Icon source is not valid JSON.")}if(!isRecord4(value)||typeof value.version!=="string"){invalidSource("Icon source must be a JSON object with a version field.")}return value}function loadIconSource(bytes){const value=parseSourceJson(bytes);const version=value.version;try{if(version===SCENE_VERSION){return{form:"scene",format:"scene",scene:parseScene(value)}}if(version===COLLECTION_VERSION){return{form:"scene",format:"collection",scene:parseScene(sceneFromComposition(value))}}if(version===CONSTRUCTION_VERSION||version===CONSTRUCTION_VERSION_V1){return{form:"program",format:"program",drawing:compileProgram(parseProgram(value))}}if(version===SCENE_RECIPE_VERSION){const replayed=replaySceneRecipe(value);return{form:"scene",format:"scene-recipe",scene:replayed.recipe.scene,sources:replayed.recipe.sources,replay:{recipe:replayed.recipe,svg:replayed.svg,width:replayed.width,height:replayed.height,options:replayed.options,style:replayed.style,notes:replayed.notes}}}if(version===RECIPE_VERSION){const replayed=replayRecipe(value);return{form:"program",format:"program-recipe",drawing:replayed.drawing,replay:{svg:replayed.svg,style:replayed.style}}}}catch(error){invalidSource(`Icon source was rejected: ${libraryMessage(error)}`)}return invalidSource("Icon source version must be a scene, collection, construction program, or recipe version.")}function geometryOf(drawing){const{facts}=drawing;return{regions:facts.regions,components:facts.components,apertures:facts.apertures,vertices:facts.vertices,inkArea:facts.inkArea,bounds:[facts.bounds[0],facts.bounds[1],facts.bounds[2],facts.bounds[3]]}}function stableDocumentText(value){return`${JSON.stringify(JSON.parse(canonicalJson(value)),null,2)}
38
+ `}var allowedSvgElements=new Set(["svg","g","defs","clipPath","mask","title","desc","path","rect","circle","ellipse","line","polyline","polygon"]);var allowedSvgAttributes=new Set(["xmlns","width","height","viewBox","role","id","d","fill","fill-rule","fill-opacity","clip-path","clip-rule","mask","opacity","stroke","stroke-width","stroke-linecap","stroke-linejoin","stroke-dasharray","stroke-opacity","stroke-miterlimit","transform","x","y","rx","ry","cx","cy","r","x1","y1","x2","y2","points","preserveAspectRatio"]);function assertInertIconSvg(svg){if(Buffer.byteLength(svg,"utf8")>slopcameraIconSceneLimits.outputBytes){throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT","Rendered SVG exceeds the output byte limit.")}if(!svg.startsWith("<svg ")||!svg.trimEnd().endsWith("</svg>")){throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT","Rendered output is not a single SVG document.")}if(/<!|<\?|&(?!(?:amp|lt|gt|quot|apos|#\d{1,7}|#x[0-9a-f]{1,6});)/iu.test(svg)){throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT","Rendered SVG contains declarations or unknown entities.")}const ids=new Set;const references=[];for(const tag of scanSvgTags(svg)){if(!allowedSvgElements.has(tag.name)){throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT",`Rendered SVG contains a disallowed <${tag.name}> element.`)}for(const[attributeName,value]of tag.attributes){if(!allowedSvgAttributes.has(attributeName)){throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT",`Rendered SVG contains a disallowed ${attributeName} attribute.`)}if(attributeName==="id")ids.add(value);references.push(...urlReferences(value))}}for(const target of references){if(!/^#[A-Za-z0-9_-]+$/u.test(target)||!ids.has(target.slice(1))){throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT","Rendered SVG references a non-local resource.")}}}var isSvgSpace=(character)=>character===" "||character==="\t"||character===`
39
+ `||character==="\r";var isSvgNameStart=(character)=>character!==undefined&&/^[A-Za-z]$/u.test(character);var isSvgNameCharacter=(character)=>character!==undefined&&/^[\w:.-]$/u.test(character);var isSvgAttributeNameCharacter=(character)=>character!==undefined&&!isSvgSpace(character)&&character!=="="&&character!=="/"&&character!==">";function scanSvgTags(svg){const malformed=()=>{throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT","Rendered SVG contains a malformed element.")};const tags=[];let index=svg.indexOf("<");while(index!==-1){let cursor=index+1;if(svg[cursor]==="/"){cursor+=1;if(!isSvgNameStart(svg[cursor]))malformed();while(isSvgNameCharacter(svg[cursor]))cursor+=1;while(isSvgSpace(svg[cursor]))cursor+=1;if(svg[cursor]!==">")malformed();index=svg.indexOf("<",cursor+1);continue}if(!isSvgNameStart(svg[cursor]))malformed();const nameStart=cursor;while(isSvgNameCharacter(svg[cursor]))cursor+=1;const name=svg.slice(nameStart,cursor);const attributes=[];for(;;){const spaceStart=cursor;while(isSvgSpace(svg[cursor]))cursor+=1;if(svg[cursor]==="/"&&svg[cursor+1]===">"){cursor+=1;break}if(svg[cursor]===">")break;if(cursor===spaceStart)malformed();const attributeStart=cursor;while(isSvgAttributeNameCharacter(svg[cursor]))cursor+=1;if(cursor===attributeStart||svg[cursor]!=="="||svg[cursor+1]!=='"')malformed();const valueStart=cursor+2;const valueEnd=svg.indexOf('"',valueStart);if(valueEnd===-1)malformed();const value=svg.slice(valueStart,valueEnd);if(value.includes("<"))malformed();attributes.push([svg.slice(attributeStart,cursor),value]);cursor=valueEnd+1}tags.push({name,attributes});index=svg.indexOf("<",cursor+1)}return tags}function urlReferences(value){const targets=[];let index=value.indexOf("url(");while(index!==-1){const close=value.indexOf(")",index+4);if(close===-1){throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT","Rendered SVG references a non-local resource.")}targets.push(value.slice(index+4,close));index=value.indexOf("url(",close+1)}return targets}function svgDimensions(svg){const root=/^<svg\b[^>]*>/u.exec(svg)?.[0]??"";const width=Number(/\swidth="(\d+)"/u.exec(root)?.[1]);const height=Number(/\sheight="(\d+)"/u.exec(root)?.[1]);if(!Number.isSafeInteger(width)||!Number.isSafeInteger(height)||width<1||height<1){throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT","Rendered SVG does not declare integer dimensions.")}return{width,height}}function parseSize(value,fallback){const size=value??fallback;if(!Number.isSafeInteger(size)||size<slopcameraIconSceneLimits.sizeMin||size>slopcameraIconSceneLimits.sizeMax){invalidInput(`size must be an integer from ${String(slopcameraIconSceneLimits.sizeMin)} through ${String(slopcameraIconSceneLimits.sizeMax)}.`)}return size}async function readIconSource(path){const bytes=await readBoundedFile(path,slopcameraIconSceneLimits.sourceBytes,"Icon source");return{bytes,record:{path,sha256:sha256Hex(bytes),bytes:bytes.byteLength}}}async function publish(path,text){const bytes=Buffer.from(text,"utf8");if(bytes.byteLength>slopcameraIconSceneLimits.outputBytes){throw new SlopcameraIconError("UNSAFE_ICON_OUTPUT","Icon output exceeds the output byte limit.")}await publishReplaceableFile(path,bytes);return{path,sha256:sha256Hex(bytes),bytes:bytes.byteLength}}function requireExtension(path,extension,label){if(!path.toLowerCase().endsWith(extension))invalidInput(`${label} must end in ${extension}.`)}async function composeSlopcameraIcon(input){if(input.outputPath!==undefined){requireExtension(input.outputPath,".json","outputPath");if(await hasPathCollision([input.sourcePath,input.outputPath])){invalidInput("outputPath must differ from sourcePath.")}}const{bytes,record}=await readIconSource(input.sourcePath);const loaded=loadIconSource(bytes);let document;let drawing;let documentDigest;let diagnostics;let elementCount;let title;try{if(loaded.form==="scene"){const solution=solveScene(loaded.scene,loaded.sources);document=solution.scene;drawing=solution.drawing;documentDigest=createSceneRecipe(solution.scene,DEFAULT_SCENE_RENDER).digests.scene;elementCount=solution.scene.nodes.length;title=solution.scene.title;diagnostics=solution.diagnostics.map((diagnostic)=>({code:diagnostic.code,message:libraryMessage(diagnostic.message),target:diagnostic.node}))}else{document=loaded.drawing.program;drawing=loaded.drawing;documentDigest=programDigest(loaded.drawing.program);elementCount=loaded.drawing.program.parts.length;title=loaded.drawing.program.title;diagnostics=loaded.drawing.issues.map((issue)=>({code:issue.code,message:libraryMessage(issue.message),target:issue.part??null}))}}catch(error){if(error instanceof SlopcameraIconError)throw error;invalidSource(`Icon source could not be solved: ${libraryMessage(error)}`)}const output=input.outputPath===undefined?null:await publish(input.outputPath,stableDocumentText(document));return{receiptVersion:1,operation:"slopcamera.icon.compose",engine:slopcameraIconEngine,source:{...record,format:loaded.format},form:loaded.form,title,elementCount,digests:{document:documentDigest,geometry:drawing.digest},geometry:geometryOf(drawing),diagnostics:diagnostics.slice(0,slopcameraIconSceneLimits.diagnostics),output}}async function renderSlopcameraIcon(input){requireExtension(input.outputPath,".svg","outputPath");if(input.recipePath!==undefined)requireExtension(input.recipePath,".json","recipePath");if(await hasPathCollision([input.sourcePath,input.outputPath,input.recipePath])){invalidInput("sourcePath, outputPath and recipePath must name different files.")}const{bytes,record}=await readIconSource(input.sourcePath);const loaded=loadIconSource(bytes);const replayed=loaded.format==="scene-recipe"||loaded.format==="program-recipe";if(replayed&&(input.size!==undefined||input.background!==undefined||input.palette!==undefined||input.language!==undefined)){invalidInput("A recipe fixes its render settings; omit size, background, palette and language.")}if(loaded.form==="scene"&&input.language!==undefined){invalidInput("language applies only to construction programs; scenes use their family's language.")}if(loaded.form==="program"&&input.palette!==undefined){invalidInput("palette applies only to scenes.")}if(input.palette!==undefined&&!slopcameraIconPalettes.includes(input.palette)){invalidInput(`palette must be one of ${slopcameraIconPalettes.join(", ")}.`)}if(input.language!==undefined&&!slopcameraIconLanguages.includes(input.language)){invalidInput(`language must be one of ${slopcameraIconLanguages.join(", ")}.`)}let svg;let width;let height;let recipeValue;let digests;let render;let notes;let title;try{if(loaded.form==="scene"){let recipe2;let options;let language;if(loaded.replay!==undefined){({recipe:recipe2,svg,width,height,options,notes}=loaded.replay);language=loaded.replay.style.language}else{options={size:parseSize(input.size,DEFAULT_SCENE_RENDER.size),background:input.background??DEFAULT_SCENE_RENDER.background,palette:input.palette??DEFAULT_SCENE_RENDER.palette};const drawn=renderScene(loaded.scene,options);recipe2=createSceneRecipe(loaded.scene,options,drawn.solution.sources,drawn.style);({svg,width,height,notes}=drawn);language=drawn.style.language}recipeValue=recipe2;digests={document:recipe2.digests.scene,geometry:recipe2.digests.geometry,svg:recipe2.digests.svg};render={size:options.size,background:options.background,palette:options.palette,language};title=loaded.scene.title}else{const style=loaded.replay?.style??{language:input.language??slopcameraIconDefaultLanguage,outputPx:parseSize(input.size,512),background:input.background??false};const drawn=loaded.replay??renderConstruction(loaded.drawing,style);const recipe2=createRecipe(loaded.drawing,style);svg=drawn.svg;({width,height}=svgDimensions(svg));recipeValue=recipe2;digests={document:recipe2.digests.program,geometry:recipe2.digests.geometry,svg:recipe2.digests.svg};render={size:style.outputPx??width,background:style.background??false,palette:null,language:style.language};notes="notes"in drawn?drawn.notes:[];title=loaded.drawing.program.title}}catch(error){if(error instanceof SlopcameraIconError)throw error;invalidSource(`Icon source could not be drawn: ${libraryMessage(error)}`)}assertInertIconSvg(svg);const output=await publish(input.outputPath,svg);const recipe=input.recipePath===undefined?null:await publish(input.recipePath,stableDocumentText(recipeValue));return{receiptVersion:1,operation:"slopcamera.icon.render",engine:slopcameraIconEngine,source:{...record,format:loaded.format},form:loaded.form,replayed,title,render,width,height,digests,output,recipe,notes:notes.slice(0,slopcameraIconSceneLimits.notes).map(libraryMessage)}}import{beatGrid,importMidi}from"@hraness/soundfish/midi";import{compose,verify}from"@hraness/soundfish/protocol";import{applyTemplate}from"@hraness/soundfish/templates";var slopcameraSoundtrackEngine=Object.freeze({package:"@hraness/soundfish",version:"0.7.0"});var slopcameraSoundtrackLimits=Object.freeze({sourceBytes:1024*1024,outputBytes:4*1024*1024,sections:512,warnings:64,maxTimeUs:3600000000,minBpm:20,maxBpm:400,minBeatsPerBar:1,maxBeatsPerBar:32});var slopcameraSoundtrackFormats=Object.freeze(["compose","song","json","midi"]);class SlopcameraSoundtrackError extends Error{code;constructor(code,message){super(message);this.name="SlopcameraSoundtrackError";this.code=code}}function invalidSource2(message){throw new SlopcameraSoundtrackError("INVALID_SOUNDTRACK_SOURCE",message)}function invalidInput2(message){throw new SlopcameraSoundtrackError("INVALID_SOUNDTRACK_INPUT",message)}function printable(value,limit=240){const text=[...value].filter((character)=>{const code=character.codePointAt(0)??0;return code>=32&&code!==127}).join("");return text.length>limit?`${text.slice(0,limit-3)}...`:text}function libraryFailure(result,action){return invalidSource2(`${action}: ${printable(result.error.code,64)}: ${printable(result.error.message)}`)}function isRecord5(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function isMidi(bytes){return bytes.length>=4&&bytes[0]===77&&bytes[1]===84&&bytes[2]===104&&bytes[3]===100}function detectSlopcameraSoundtrackFormat(bytes){if(isMidi(bytes))return"midi";const text=decodeUtf8Source(bytes,"Soundtrack source");if(text.trimStart().startsWith("{"))return"json";return/^[ \t]*section[ \t]/mu.test(text)?"song":"compose"}async function guarded(work,action){try{return await work()}catch(error){if(error instanceof SlopcameraSoundtrackError||error instanceof BoundedFileError)throw error;return invalidSource2(`${action}: ${printable(error instanceof Error?error.message:String(error))}`)}}async function loadScore(bytes,requested){const format=requested??detectSlopcameraSoundtrackFormat(bytes);if(format==="midi"){if(!isMidi(bytes))invalidSource2("A MIDI source must be a Standard MIDI file.");const result2=await guarded(async()=>await importMidi(bytes.slice()),"MIDI import failed");if(!result2.ok)libraryFailure(result2,"MIDI import failed");return{format,document:result2.document,warnings:result2.warnings.map((warning)=>({code:printable(warning.code,64),message:printable(warning.message)}))}}const text=decodeUtf8Source(bytes,"Soundtrack source");if(format==="json"){let value;try{value=JSON.parse(text)}catch{invalidSource2("Soundtrack JSON is not valid JSON.")}if(!isRecord5(value))invalidSource2("Soundtrack JSON must be an object.");return{format,document:value,warnings:[]}}if(format==="song"){const result2=await guarded(async()=>await applyTemplate("songs/source",{sources:[{kind:"songs",name:"source",text}]}),"Song compose failed");if(!result2.ok)libraryFailure(result2,"Song compose failed");if(!("document"in result2))invalidSource2("Song compose returned no document.");return{format,document:result2.document,warnings:result2.warnings.map((message)=>({code:"song",message:printable(message)}))}}const result=await guarded(async()=>await compose(text),"Compose failed");if(!result.ok)libraryFailure(result,"Compose failed");return{format,document:result.document,warnings:[]}}async function readScore(path,format){if(format!==undefined&&!slopcameraSoundtrackFormats.includes(format)){invalidInput2(`format must be one of ${slopcameraSoundtrackFormats.join(", ")}.`)}const bytes=await readBoundedFile(path,slopcameraSoundtrackLimits.sourceBytes,"Soundtrack source");const score=await loadScore(bytes,format);return{score,source:{path,sha256:sha256Hex(bytes),bytes:bytes.byteLength,format:score.format}}}async function gridOf(document){const grid=await guarded(async()=>await beatGrid(document),"Beat grid failed");if(!grid.ok)libraryFailure(grid,"Beat grid failed");return grid}function outOfRange(message){throw new SlopcameraSoundtrackError("SOUNDTRACK_OUT_OF_RANGE",message)}function soundtrackBeatTimeUs(beat,bpm){return Math.round(beat*60000000/bpm)}function checkedTiming(grid){const limits=slopcameraSoundtrackLimits;if(!Number.isFinite(grid.bpm)||grid.bpm<limits.minBpm||grid.bpm>limits.maxBpm){outOfRange(`Tempo ${String(grid.bpm)} BPM is outside ${String(limits.minBpm)}\u2013${String(limits.maxBpm)} BPM.`)}if(!Number.isSafeInteger(grid.beatsPerBar)||grid.beatsPerBar<limits.minBeatsPerBar||grid.beatsPerBar>limits.maxBeatsPerBar){outOfRange(`Meter of ${String(grid.beatsPerBar)} beats per bar is outside ${String(limits.minBeatsPerBar)}\u2013${String(limits.maxBeatsPerBar)}.`)}if(!Number.isFinite(grid.secondsPerBeat)||Math.abs(grid.secondsPerBeat-60/grid.bpm)>0.000001){outOfRange("The beat grid's beat length disagrees with its tempo.")}return{bpm:grid.bpm,beatsPerBar:grid.beatsPerBar}}function durationUsOf(grid,bpm){if(!Number.isSafeInteger(grid.beats)||grid.beats<1)outOfRange("The score has no beats.");const durationUs=soundtrackBeatTimeUs(grid.beats,bpm);if(durationUs>slopcameraSoundtrackLimits.maxTimeUs){outOfRange("The score is longer than the one-hour timeline bound.")}return durationUs}async function publishJson(path,value){const bytes=Buffer.from(`${JSON.stringify(value,null,2)}
40
+ `,"utf8");if(bytes.byteLength>slopcameraSoundtrackLimits.outputBytes){outOfRange("Soundtrack output exceeds the output byte limit.")}await publishReplaceableFile(path,bytes);return{path,sha256:sha256Hex(bytes),bytes:bytes.byteLength}}async function checkOutputPath(sourcePath,outputPath){if(outputPath===undefined)return;if(!outputPath.toLowerCase().endsWith(".json"))invalidInput2("outputPath must end in .json.");if(await hasPathCollision([sourcePath,outputPath]))invalidInput2("outputPath must differ from sourcePath.")}async function composeSlopcameraSoundtrack(input){await checkOutputPath(input.sourcePath,input.outputPath);const{score,source}=await readScore(input.sourcePath,input.format);const verified=await guarded(async()=>await verify(score.document),"Verification failed");if(!verified.ok)libraryFailure(verified,"Verification failed");const grid=await gridOf(score.document);const{bpm,beatsPerBar}=checkedTiming(grid);const durationUs=durationUsOf(grid,bpm);const output=input.outputPath===undefined?null:await publishJson(input.outputPath,score.document);return{receiptVersion:1,operation:"slopcamera.soundtrack.compose",engine:slopcameraSoundtrackEngine,source,kind:verified.kind,title:printable(grid.title,256),digest:verified.digest,contentId:verified.kind==="loop"?verified.musicCid:verified.arrangementCid,bpm,beatsPerBar,bars:grid.bars,durationUs,tracks:verified.kind==="loop"?verified.tracks:null,sections:verified.kind==="song"?verified.sections:null,loops:verified.kind==="song"?verified.loops:null,warnings:score.warnings.slice(0,slopcameraSoundtrackLimits.warnings),output}}function projectSlopcameraSoundtrackGrid(grid,digest,startUs=0){if(!Number.isSafeInteger(startUs)||startUs<0||startUs>slopcameraSoundtrackLimits.maxTimeUs){invalidInput2(`startUs must be an integer from 0 through ${String(slopcameraSoundtrackLimits.maxTimeUs)}.`)}const{bpm,beatsPerBar}=checkedTiming(grid);const durationUs=durationUsOf(grid,bpm);if(startUs+durationUs>slopcameraSoundtrackLimits.maxTimeUs){outOfRange("startUs plus the score duration exceeds the one-hour timeline bound.")}if(grid.sections.length===0||grid.sections.length>slopcameraSoundtrackLimits.sections){outOfRange(`A score must have 1\u2013${String(slopcameraSoundtrackLimits.sections)} sections in play order.`)}let previousEndBeat=0;const sections=grid.sections.map((section)=>{if(!Number.isSafeInteger(section.startBeat)||!Number.isSafeInteger(section.endBeat)||section.startBeat!==previousEndBeat||section.endBeat<=section.startBeat||section.endBeat>grid.beats){outOfRange("Beat grid sections must tile the score in play order.")}previousEndBeat=section.endBeat;return{index:section.index,label:printable(section.label,128),repeat:section.repeat,startBar:section.startBar,endBar:section.endBar,startBeat:section.startBeat,endBeat:section.endBeat,startUs:startUs+soundtrackBeatTimeUs(section.startBeat,bpm),endUs:startUs+soundtrackBeatTimeUs(section.endBeat,bpm)}});if(previousEndBeat!==grid.beats)outOfRange("Beat grid sections must cover the whole score.");return{schemaVersion:1,kind:"slopcamera.soundtrack-grid",digest,title:printable(grid.title,256),music:{bpm,beatOffsetUs:startUs,beatsPerBar},beatUnit:grid.beatUnit,swing:grid.swing,bars:grid.bars,beats:grid.beats,startUs,durationUs,endUs:startUs+durationUs,sections}}async function deriveSlopcameraSoundtrackGrid(input){await checkOutputPath(input.sourcePath,input.outputPath);const startUs=input.startUs??0;const{score,source}=await readScore(input.sourcePath,input.format);const verified=await guarded(async()=>await verify(score.document),"Verification failed");if(!verified.ok)libraryFailure(verified,"Verification failed");const grid=await gridOf(score.document);const projected=projectSlopcameraSoundtrackGrid(grid,verified.digest,startUs);const output=input.outputPath===undefined?null:await publishJson(input.outputPath,projected);const{kind:_kind,schemaVersion:_schemaVersion,...fields}=projected;return{receiptVersion:1,operation:"slopcamera.soundtrack.grid",engine:slopcameraSoundtrackEngine,source,scoreKind:verified.kind,...fields,warnings:score.warnings.slice(0,slopcameraSoundtrackLimits.warnings),output}}var slopcameraOperationCodes=["slopcamera.diagram.check","slopcamera.diagram.render","slopcamera.image.vectorize","slopcamera.image.generate","slopcamera.image.icon","slopcamera.image.gallery","slopcamera.icon.compose","slopcamera.icon.render","slopcamera.soundtrack.compose","slopcamera.soundtrack.grid"];class SlopcameraOperationError extends Error{code;constructor(code,message){super(`[${code}] ${message}`);this.name="SlopcameraOperationError";this.code=code}}var modelSchema={type:"string",minLength:3,maxLength:256,pattern:"^[a-zA-Z0-9][a-zA-Z0-9._-]*/[a-zA-Z0-9][a-zA-Z0-9._:-]*$"};var pathSchema={type:"string",minLength:1,maxLength:4096};var localOperationResources=[{resource:"cpu",amount:1},{resource:"local-io",amount:1}];var soundtrackFormatSchema={type:"string",enum:slopcameraSoundtrackFormats};function deepFreeze(value){if(typeof value!=="object"||value===null||Object.isFrozen(value)){return value}for(const nested of Object.values(value))deepFreeze(nested);return Object.freeze(value)}var slopcameraOperationRegistry=deepFreeze([{code:"slopcamera.diagram.check",title:"Check diagram",description:"Parse and lint a checked Slopcamera diagram source without changing its files.",execution:"local",authentication:"none",destructive:false,idempotent:true,inputSchema:{type:"object",additionalProperties:false,required:["path"],properties:{path:pathSchema}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1}]},{code:"slopcamera.diagram.render",title:"Render diagram",description:"Render a checked Slopcamera diagram source to its replaceable light, dark, PNG, SVG, and tldraw artifacts.",execution:"local",authentication:"none",destructive:true,idempotent:true,inputSchema:{type:"object",additionalProperties:false,required:["path"],properties:{path:pathSchema,outDirectory:pathSchema,scale:{type:"number",exclusiveMinimum:0,maximum:4}}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1}]},{code:"slopcamera.image.vectorize",title:"Vectorize image",description:"Convert a local caller-owned raster into a bounded inert SVG without authentication or network access.",execution:"local",authentication:"none",destructive:true,idempotent:false,inputSchema:{type:"object",additionalProperties:false,required:["inputPath","outputPath"],properties:{inputPath:pathSchema,outputPath:pathSchema,duotone:{type:"array",minItems:2,maxItems:2,items:{type:"string",pattern:"^#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$"}},alphaCutoff:{type:"integer",minimum:1,maximum:64},timeoutMs:{type:"integer",minimum:1,maximum:300000}}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1}]},{code:"slopcamera.image.generate",title:"Generate image",description:"Generate one bounded image directly through Vercel AI Gateway with an environment credential and no client retry.",execution:"gateway",authentication:"environment",destructive:true,idempotent:false,inputSchema:{type:"object",additionalProperties:false,required:["model","prompt","outputPath"],properties:{model:modelSchema,prompt:{type:"string",minLength:1,maxLength:slopcameraMaximumPromptBytes},outputPath:pathSchema}},resources:[{resource:"local-io",amount:1},{resource:"network",amount:1},{resource:"paid-call",amount:1}],transport:{method:"POST",authority:"https://ai-gateway.vercel.sh/v4/ai",authorization:"bearer",retry:"never"}},{code:"slopcamera.image.icon",title:"Generate line-art icon",description:"Generate one isometric line-art SVG icon: a style-locked Vercel AI Gateway raster normalized to canonical ink-on-transparent pixels, traced locally, and optionally critiqued by a vision model across bounded rounds.",execution:"gateway",authentication:"environment",destructive:true,idempotent:false,inputSchema:{type:"object",additionalProperties:false,required:["subject","outputPath"],properties:{subject:{type:"string",minLength:1,maxLength:slopcameraIconSubjectMaximumBytes},outputPath:pathSchema,model:modelSchema,critiqueModel:modelSchema,ink:{type:"string",pattern:"^#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$"},purpose:{type:"string",enum:["mark","illustration"]},context:{type:"string",enum:[...slopcameraIconContexts]},candidatePool:{type:"integer",minimum:1,maximum:slopcameraIconMaximumRounds},rounds:{type:"integer",minimum:1,maximum:slopcameraIconMaximumRounds},keepRaster:{type:"boolean"}}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1},{resource:"network",amount:1},{resource:"paid-call",amount:1}],transport:{method:"POST",authority:"https://ai-gateway.vercel.sh/v4/ai",authorization:"bearer",retry:"never"}},{code:"slopcamera.image.gallery",title:"Generate image gallery",description:"Generate several bounded Vercel AI Gateway image candidates in parallel and compose a labelled contact sheet with per-candidate provenance for explicit review and selection.",execution:"gateway",authentication:"environment",destructive:true,idempotent:false,inputSchema:{type:"object",additionalProperties:false,required:["subject","outputDir"],properties:{subject:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.subjectBytes},outputDir:pathSchema,kind:{type:"string",enum:[...slopcameraGalleryKinds]},model:modelSchema,count:{type:"integer",minimum:1,maximum:slopcameraGalleryLimits.candidates},vary:{type:"array",maxItems:slopcameraGalleryAxes.length,items:{anyOf:[{type:"string",enum:[...slopcameraGalleryAxes]},{type:"object",additionalProperties:false,required:["axis"],properties:{axis:{type:"string",enum:[...slopcameraGalleryAxes]},values:{type:"array",minItems:1,maxItems:slopcameraGalleryLimits.candidates,items:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.variantBytes}}}}]}},candidates:{type:"array",minItems:1,maxItems:slopcameraGalleryLimits.candidates,items:{type:"object",additionalProperties:false,required:["id"],properties:{id:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.idLength},prompt:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.candidatePromptBytes},variant:{type:"string",minLength:1,maxLength:slopcameraGalleryLimits.variantBytes}}}},cellEdge:{type:"integer",minimum:slopcameraGalleryLimits.cellEdgeMin,maximum:slopcameraGalleryLimits.cellEdgeMax},tiled:{type:"boolean"},timeoutMs:{type:"integer",minimum:1000,maximum:30*60000}}},resources:[{resource:"cpu",amount:1},{resource:"local-io",amount:1},{resource:"network",amount:1},{resource:"paid-call",amount:1}],transport:{method:"POST",authority:"https://ai-gateway.vercel.sh/v4/ai",authorization:"bearer",retry:"never"}},{code:"slopcamera.icon.compose",title:"Compose icon scene",description:"Parse and solve a local vector icon scene, collection, construction program, or recipe, and report its digests and geometry. Optionally write the canonical solved document. Local and deterministic.",execution:"local",authentication:"none",destructive:true,idempotent:true,inputSchema:{type:"object",additionalProperties:false,required:["sourcePath"],properties:{sourcePath:pathSchema,outputPath:pathSchema}},resources:[...localOperationResources]},{code:"slopcamera.icon.render",title:"Render icon scene",description:"Draw a local vector icon scene or construction program to an inert SVG, or replay a recipe and require its recorded digests. Optionally write a replayable recipe. Local and deterministic.",execution:"local",authentication:"none",destructive:true,idempotent:true,inputSchema:{type:"object",additionalProperties:false,required:["sourcePath","outputPath"],properties:{sourcePath:pathSchema,outputPath:pathSchema,recipePath:pathSchema,size:{type:"integer",minimum:slopcameraIconSceneLimits.sizeMin,maximum:slopcameraIconSceneLimits.sizeMax},background:{type:"boolean"},palette:{type:"string",enum:slopcameraIconPalettes},language:{type:"string",enum:slopcameraIconLanguages}}},resources:[...localOperationResources]},{code:"slopcamera.soundtrack.compose",title:"Compose soundtrack score",description:"Parse and verify a local loop or song from compose text, song text, score JSON, or a Standard MIDI file, and report its canonical digest, tempo, and length. Optionally write the score document. Renders no audio.",execution:"local",authentication:"none",destructive:true,idempotent:true,inputSchema:{type:"object",additionalProperties:false,required:["sourcePath"],properties:{sourcePath:pathSchema,outputPath:pathSchema,format:soundtrackFormatSchema}},resources:[...localOperationResources]},{code:"slopcamera.soundtrack.grid",title:"Derive soundtrack beat grid",description:"Derive bpm, beatOffsetUs, beatsPerBar, and section cue times from a local loop, song, or Standard MIDI file, in the music timing HTML scene requests accept. Optionally write the grid. Renders no audio.",execution:"local",authentication:"none",destructive:true,idempotent:true,inputSchema:{type:"object",additionalProperties:false,required:["sourcePath"],properties:{sourcePath:pathSchema,outputPath:pathSchema,format:soundtrackFormatSchema,startUs:{type:"integer",minimum:0,maximum:slopcameraSoundtrackLimits.maxTimeUs}}},resources:[...localOperationResources]}]);function operationFailure(message){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT",message)}function isRecord6(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function record(value,allowedKeys){if(!isRecord6(value))operationFailure("Operation input must be an object.");const unknown=Object.keys(value).filter((key)=>!allowedKeys.includes(key));if(unknown.length>0){operationFailure(`Unsupported operation input field: ${unknown[0]}.`)}return value}function pathValue(value,name){if(typeof value!=="string"||value.length<1||value.length>4096||value.includes("\x00")){operationFailure(`${name} must be a non-empty bounded local path.`)}return value}function parseCheck(value){const input=record(value,["path"]);return{path:pathValue(input.path,"path")}}function parseRender(value){const input=record(value,["path","outDirectory","scale"]);const scale=input.scale;if(scale!==undefined&&(typeof scale!=="number"||!Number.isFinite(scale)||scale<=0||scale>4)){operationFailure("scale must be greater than zero and no more than 4.")}return{path:pathValue(input.path,"path"),...input.outDirectory===undefined?{}:{outDirectory:pathValue(input.outDirectory,"outDirectory")},...scale===undefined?{}:{scale}}}function parseVectorize(value){const input=record(value,["inputPath","outputPath","duotone","alphaCutoff","timeoutMs"]);const inputPath=pathValue(input.inputPath,"inputPath");const outputPath=pathValue(input.outputPath,"outputPath");if(!outputPath.toLowerCase().endsWith(".svg")){operationFailure("outputPath must end in .svg.")}const duotone=input.duotone;if(duotone!==undefined&&(!Array.isArray(duotone)||duotone.length!==2||duotone.some((color)=>typeof color!=="string"||!/^#[a-f0-9]{3}(?:[a-f0-9]{3})?$/iu.test(color)))){operationFailure("duotone must contain exactly two #rgb or #rrggbb colors.")}const alphaCutoff=input.alphaCutoff;if(alphaCutoff!==undefined&&(!Number.isInteger(alphaCutoff)||alphaCutoff<1||alphaCutoff>64)){operationFailure("alphaCutoff must be an integer from 1 through 64.")}const timeoutMs=input.timeoutMs;if(timeoutMs!==undefined&&(!Number.isInteger(timeoutMs)||timeoutMs<1||timeoutMs>300000)){operationFailure("timeoutMs must be an integer from 1 through 300000.")}return{inputPath,outputPath,...duotone===undefined?{}:{duotone},...alphaCutoff===undefined?{}:{alphaCutoff},...timeoutMs===undefined?{}:{timeoutMs}}}function parseGenerate(value){const input=record(value,["model","prompt","outputPath"]);if(typeof input.model!=="string"||input.model.length>256||!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(input.model)){operationFailure("model must be a bounded Vercel AI Gateway provider/model id.")}if(typeof input.prompt!=="string"||input.prompt.trim().length<1||/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u.test(input.prompt)||Buffer.byteLength(input.prompt,"utf8")>slopcameraMaximumPromptBytes){operationFailure(`prompt must be non-empty and no more than ${slopcameraMaximumPromptBytes} UTF-8 bytes.`)}const outputPath=pathValue(input.outputPath,"outputPath");if(!/\.(?:jpe?g|png|webp)$/iu.test(outputPath)){operationFailure("outputPath must end in .png, .jpg, .jpeg, or .webp.")}return{model:input.model,prompt:input.prompt,outputPath}}function parseIcon(value){const input=record(value,["subject","outputPath","model","critiqueModel","ink","purpose","context","candidatePool","rounds","keepRaster"]);if(typeof input.subject!=="string"||input.subject.trim().length<1||/[\u0000-\u001f\u007f]/u.test(input.subject)||Buffer.byteLength(input.subject,"utf8")>slopcameraIconSubjectMaximumBytes){operationFailure(`subject must be non-empty and no more than ${slopcameraIconSubjectMaximumBytes} UTF-8 bytes.`)}const outputPath=pathValue(input.outputPath,"outputPath");if(!outputPath.toLowerCase().endsWith(".svg")){operationFailure("outputPath must end in .svg.")}for(const name of["model","critiqueModel"]){const model=input[name];if(model!==undefined&&(typeof model!=="string"||model.length>256||!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(model))){operationFailure(`${name} must be a bounded Vercel AI Gateway provider/model id.`)}}if(input.ink!==undefined&&(typeof input.ink!=="string"||!/^#[a-f0-9]{3}(?:[a-f0-9]{3})?$/iu.test(input.ink))){operationFailure("ink must be a #rgb or #rrggbb color.")}if(input.purpose!==undefined&&input.purpose!=="illustration"&&input.purpose!=="mark"){operationFailure("purpose must be illustration or mark.")}if(input.context!==undefined&&(typeof input.context!=="string"||!slopcameraIconContexts.includes(input.context))){operationFailure(`context must be one of: ${slopcameraIconContexts.join(", ")}.`)}const candidatePool=input.candidatePool;if(candidatePool!==undefined&&(!Number.isInteger(candidatePool)||candidatePool<1||candidatePool>slopcameraIconMaximumRounds)){operationFailure(`candidatePool must be an integer from 1 through ${slopcameraIconMaximumRounds}.`)}const rounds=input.rounds;if(rounds!==undefined&&(!Number.isInteger(rounds)||rounds<1||rounds>slopcameraIconMaximumRounds)){operationFailure(`rounds must be an integer from 1 through ${slopcameraIconMaximumRounds}.`)}if(input.keepRaster!==undefined&&typeof input.keepRaster!=="boolean"){operationFailure("keepRaster must be a boolean.")}return{subject:input.subject,outputPath,...input.model===undefined?{}:{model:input.model},...input.critiqueModel===undefined?{}:{critiqueModel:input.critiqueModel},...input.ink===undefined?{}:{ink:input.ink},...input.purpose===undefined?{}:{purpose:input.purpose},...input.context===undefined?{}:{context:input.context},...candidatePool===undefined?{}:{candidatePool},...rounds===undefined?{}:{rounds},...input.keepRaster===undefined?{}:{keepRaster:input.keepRaster}}}function parseGallery(value){const input=record(value,["subject","outputDir","kind","model","count","vary","candidates","cellEdge","tiled","timeoutMs"]);if(typeof input.subject!=="string"||input.subject.trim().length<1||/[\u0000-\u001f\u007f]/u.test(input.subject)||Buffer.byteLength(input.subject,"utf8")>slopcameraGalleryLimits.subjectBytes){operationFailure(`subject must be non-empty and no more than ${slopcameraGalleryLimits.subjectBytes} UTF-8 bytes.`)}if(input.kind!==undefined&&(typeof input.kind!=="string"||!slopcameraGalleryKinds.includes(input.kind))){operationFailure(`kind must be one of: ${slopcameraGalleryKinds.join(", ")}.`)}if(input.model!==undefined&&(typeof input.model!=="string"||input.model.length>256||!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(input.model))){operationFailure("model must be a bounded Vercel AI Gateway provider/model id.")}if(input.count!==undefined&&(!Number.isInteger(input.count)||input.count<1||input.count>slopcameraGalleryLimits.candidates)){operationFailure(`count must be an integer from 1 through ${slopcameraGalleryLimits.candidates}.`)}if(input.vary!==undefined&&(!Array.isArray(input.vary)||input.vary.length<1||input.vary.length>slopcameraGalleryAxes.length)){operationFailure(`vary must be a list of at most ${slopcameraGalleryAxes.length} axes.`)}if(input.candidates!==undefined&&(!Array.isArray(input.candidates)||input.candidates.length<1||input.candidates.length>slopcameraGalleryLimits.candidates)){operationFailure(`candidates must contain 1 through ${slopcameraGalleryLimits.candidates} entries.`)}if(input.vary!==undefined&&input.candidates!==undefined){operationFailure("vary and candidates are mutually exclusive.")}if(input.count!==undefined&&input.candidates!==undefined){operationFailure("count and candidates are mutually exclusive.")}const cellEdge=input.cellEdge;if(cellEdge!==undefined&&(!Number.isInteger(cellEdge)||cellEdge<slopcameraGalleryLimits.cellEdgeMin||cellEdge>slopcameraGalleryLimits.cellEdgeMax)){operationFailure(`cellEdge must be an integer from ${slopcameraGalleryLimits.cellEdgeMin} through ${slopcameraGalleryLimits.cellEdgeMax}.`)}const timeoutMs=input.timeoutMs;if(timeoutMs!==undefined&&(!Number.isInteger(timeoutMs)||timeoutMs<1000||timeoutMs>30*60000)){operationFailure("timeoutMs must be an integer from 1000 through 1800000.")}if(input.tiled!==undefined&&typeof input.tiled!=="boolean"){operationFailure("tiled must be a boolean when set.")}return{subject:input.subject,outputDir:pathValue(input.outputDir,"outputDir"),...input.kind===undefined?{}:{kind:input.kind},...input.model===undefined?{}:{model:input.model},...input.count===undefined?{}:{count:input.count},...input.vary===undefined?{}:{vary:input.vary},...input.candidates===undefined?{}:{candidates:input.candidates},...cellEdge===undefined?{}:{cellEdge},...input.tiled===undefined?{}:{tiled:input.tiled},...timeoutMs===undefined?{}:{timeoutMs}}}function optionalPathValue(value,name){return value===undefined?undefined:pathValue(value,name)}function requireSuffix(path,suffix,name){if(path!==undefined&&!path.toLowerCase().endsWith(suffix)){operationFailure(`${name} must end in ${suffix}.`)}}function parseIconCompose(value){const input=record(value,["sourcePath","outputPath"]);const outputPath=optionalPathValue(input.outputPath,"outputPath");requireSuffix(outputPath,".json","outputPath");return{sourcePath:pathValue(input.sourcePath,"sourcePath"),...outputPath===undefined?{}:{outputPath}}}function parseIconRender(value){const input=record(value,["sourcePath","outputPath","recipePath","size","background","palette","language"]);const outputPath=pathValue(input.outputPath,"outputPath");requireSuffix(outputPath,".svg","outputPath");const recipePath=optionalPathValue(input.recipePath,"recipePath");requireSuffix(recipePath,".json","recipePath");const{size,background,palette,language}=input;if(size!==undefined&&(!Number.isSafeInteger(size)||size<slopcameraIconSceneLimits.sizeMin||size>slopcameraIconSceneLimits.sizeMax)){operationFailure(`size must be an integer from ${slopcameraIconSceneLimits.sizeMin} through ${slopcameraIconSceneLimits.sizeMax}.`)}if(background!==undefined&&typeof background!=="boolean"){operationFailure("background must be a boolean.")}if(palette!==undefined&&!slopcameraIconPalettes.includes(palette)){operationFailure(`palette must be one of ${slopcameraIconPalettes.join(", ")}.`)}if(language!==undefined&&(typeof language!=="string"||!slopcameraIconLanguages.includes(language))){operationFailure(`language must be one of ${slopcameraIconLanguages.join(", ")}.`)}return{sourcePath:pathValue(input.sourcePath,"sourcePath"),outputPath,...recipePath===undefined?{}:{recipePath},...size===undefined?{}:{size},...background===undefined?{}:{background},...palette===undefined?{}:{palette},...language===undefined?{}:{language}}}function parseSoundtrackFormat(value){if(value===undefined)return;if(!slopcameraSoundtrackFormats.includes(value)){operationFailure(`format must be one of ${slopcameraSoundtrackFormats.join(", ")}.`)}return value}function parseSoundtrackCompose(value){const input=record(value,["sourcePath","outputPath","format"]);const outputPath=optionalPathValue(input.outputPath,"outputPath");requireSuffix(outputPath,".json","outputPath");const format=parseSoundtrackFormat(input.format);return{sourcePath:pathValue(input.sourcePath,"sourcePath"),...outputPath===undefined?{}:{outputPath},...format===undefined?{}:{format}}}function parseSoundtrackGrid(value){const input=record(value,["sourcePath","outputPath","format","startUs"]);const outputPath=optionalPathValue(input.outputPath,"outputPath");requireSuffix(outputPath,".json","outputPath");const format=parseSoundtrackFormat(input.format);const startUs=input.startUs;if(startUs!==undefined&&(!Number.isSafeInteger(startUs)||startUs<0||startUs>slopcameraSoundtrackLimits.maxTimeUs)){operationFailure(`startUs must be an integer from 0 through ${slopcameraSoundtrackLimits.maxTimeUs}.`)}return{sourcePath:pathValue(input.sourcePath,"sourcePath"),...outputPath===undefined?{}:{outputPath},...format===undefined?{}:{format},...startUs===undefined?{}:{startUs}}}function parseSlopcameraOperationInput(code,input){switch(code){case"slopcamera.diagram.check":return parseCheck(input);case"slopcamera.diagram.render":return parseRender(input);case"slopcamera.image.vectorize":return parseVectorize(input);case"slopcamera.image.generate":return parseGenerate(input);case"slopcamera.image.icon":return parseIcon(input);case"slopcamera.image.gallery":return parseGallery(input);case"slopcamera.icon.compose":return parseIconCompose(input);case"slopcamera.icon.render":return parseIconRender(input);case"slopcamera.soundtrack.compose":return parseSoundtrackCompose(input);case"slopcamera.soundtrack.grid":return parseSoundtrackGrid(input);default:throw new SlopcameraOperationError("INVALID_OPERATION","Unknown Slopcamera operation code.")}}function isSlopcameraOperationCode(value){return slopcameraOperationCodes.includes(value)}function slopcameraOperationHostResourceClaims(code){const descriptor=slopcameraOperationRegistry.find((candidate)=>candidate.code===code);if(descriptor===undefined){throw new SlopcameraOperationError("INVALID_OPERATION","Unknown Slopcamera operation code.")}return descriptor.resources}function searchSlopcameraOperations(query="",limit=slopcameraOperationRegistry.length){if(typeof query!=="string"||query.length>200||/[\u0000-\u001f\u007f]/u.test(query)||!Number.isInteger(limit)||limit<1||limit>20){throw new SlopcameraOperationError("INVALID_SEARCH","Search requires a bounded query and a limit from 1 through 20.")}const terms=query.toLowerCase().split(/\s+/u).filter((term)=>term.length>0);return slopcameraOperationRegistry.filter((operation)=>{const haystack=`${operation.code} ${operation.title} ${operation.description}`.toLowerCase();return terms.every((term)=>haystack.includes(term))}).slice(0,limit)}function operationDependenciesWithLease(dependencies,lease){const inheritedFileDescriptors=[...dependencies.inheritedFileDescriptors??[],lease.inheritedFileDescriptor].filter((descriptor,index,descriptors)=>descriptors.indexOf(descriptor)===index);if(inheritedFileDescriptors.length>16||inheritedFileDescriptors.some((descriptor)=>!Number.isSafeInteger(descriptor)||descriptor<0||descriptor>2147483647)){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT","Operation host-resource inheritance exceeds its descriptor bound.")}const{hostResourceCoordinator:_hostResourceCoordinator,signal:_signal,waitTimeoutMilliseconds:_waitTimeoutMilliseconds,...operationDependencies}=dependencies;return{...operationDependencies,inheritedFileDescriptors}}async function withSlopcameraOperationHostAdmission(code,callback,options={}){const coordinator=options.hostResourceCoordinator??createDefaultHostResourceCoordinator();return await coordinator.withLease(slopcameraOperationHostResourceClaims(code),async(lease)=>{await lease.assertOwned();return await callback(lease)},{...options.signal===undefined?{}:{signal:options.signal},...options.waitTimeoutMilliseconds===undefined?{}:{waitTimeoutMilliseconds:options.waitTimeoutMilliseconds}})}var operationBuiltInConfig=Object.freeze({icons:builtInIcons});async function readOperationDiagram(path){const absolutePath=resolve4(path);let value;try{value=JSON.parse(await readFile2(absolutePath,"utf8"))}catch(cause){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT","Diagram source could not be read as JSON.")}const spec=parseDiagramSpec(value);for(const shape of spec.shapes){if((shape.type==="rect"||shape.type==="ellipse")&&shape.icon!==undefined&&!Object.hasOwn(builtInIcons,shape.icon)){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT","Diagram requests an unavailable built-in icon.")}}return{absolutePath,spec}}async function atomicOperationWrite(path,value){const temporaryPath=join3(dirname4(path),`.${randomUUID4()}.slopcamera-operation.tmp`);try{await writeFile3(temporaryPath,value,{flag:"wx"});await rename3(temporaryPath,path)}finally{await rm4(temporaryPath,{force:true}).catch(()=>{return})}}async function checkOperationDiagram(path){const{spec}=await readOperationDiagram(path);return{findings:lintDiagram(spec),configPath:null}}async function renderOperationDiagram(input){const{absolutePath,spec}=await readOperationDiagram(input.path);const outputDirectory=resolve4(input.outDirectory??dirname4(absolutePath));const scale=input.scale??2;const[light,dark]=await Promise.all([renderSvg(spec,"light",operationBuiltInConfig),renderSvg(spec,"dark",operationBuiltInConfig)]);const[lightPng,darkPng]=[renderPng(light,operationBuiltInConfig,scale),renderPng(dark,operationBuiltInConfig,scale)];const artifacts={spec:absolutePath,tldr:join3(outputDirectory,`${spec.name}.tldr`),lightSvg:join3(outputDirectory,`${spec.name}.light.svg`),darkSvg:join3(outputDirectory,`${spec.name}.dark.svg`),lightPng:join3(outputDirectory,`${spec.name}.light.png`),darkPng:join3(outputDirectory,`${spec.name}.dark.png`)};await mkdir4(outputDirectory,{recursive:true});await Promise.all([atomicOperationWrite(artifacts.tldr,serializeTldr(spec,operationBuiltInConfig)),atomicOperationWrite(artifacts.lightSvg,light.svg),atomicOperationWrite(artifacts.darkSvg,dark.svg),atomicOperationWrite(artifacts.lightPng,lightPng),atomicOperationWrite(artifacts.darkPng,darkPng)]);return{artifacts,findings:lintDiagram(spec),configPath:null}}async function executeSlopcameraOperationUncoordinated(code,value,dependencies={}){const input=parseSlopcameraOperationInput(code,value);switch(code){case"slopcamera.diagram.check":{const options=input;return await checkOperationDiagram(options.path)}case"slopcamera.diagram.render":{const options=input;return await renderOperationDiagram(options)}case"slopcamera.image.vectorize":{const options=input;const result=await vectorizeImage(options.inputPath,{outputPath:options.outputPath,...options.duotone===undefined?{}:{duotone:options.duotone},...options.alphaCutoff===undefined?{}:{alphaCutoff:options.alphaCutoff},...options.timeoutMs===undefined?{}:{limits:{maxDurationMs:options.timeoutMs}},...dependencies.inheritedFileDescriptors===undefined?{}:{inheritedFileDescriptors:dependencies.inheritedFileDescriptors}});if(result.outputPath===null){throw new SlopcameraOperationError("INVALID_OPERATION_INPUT","Vectorization did not publish its required output.")}return{outputPath:result.outputPath,receipt:result.receipt}}case"slopcamera.image.generate":{const options=input;return await generateSlopcameraImageFile({...options,...dependencies.signal===undefined?{}:{signal:dependencies.signal}},dependencies)}case"slopcamera.image.icon":{const options=input;return await generateSlopcameraIcon({...options,...dependencies.signal===undefined?{}:{signal:dependencies.signal},...dependencies.inheritedFileDescriptors===undefined?{}:{inheritedFileDescriptors:dependencies.inheritedFileDescriptors}},dependencies)}case"slopcamera.image.gallery":{const options=input;return await generateSlopcameraImageGallery({...options,...dependencies.signal===undefined?{}:{signal:dependencies.signal}},dependencies)}case"slopcamera.icon.compose":{const options=input;return await composeSlopcameraIcon({sourcePath:resolve4(options.sourcePath),...options.outputPath===undefined?{}:{outputPath:resolve4(options.outputPath)}})}case"slopcamera.icon.render":{const options=input;return await renderSlopcameraIcon({...options,sourcePath:resolve4(options.sourcePath),outputPath:resolve4(options.outputPath),...options.recipePath===undefined?{}:{recipePath:resolve4(options.recipePath)}})}case"slopcamera.soundtrack.compose":{const options=input;return await composeSlopcameraSoundtrack({...options,sourcePath:resolve4(options.sourcePath),...options.outputPath===undefined?{}:{outputPath:resolve4(options.outputPath)}})}case"slopcamera.soundtrack.grid":{const options=input;return await deriveSlopcameraSoundtrackGrid({...options,sourcePath:resolve4(options.sourcePath),...options.outputPath===undefined?{}:{outputPath:resolve4(options.outputPath)}})}default:throw new SlopcameraOperationError("INVALID_OPERATION","Unknown Slopcamera operation code.")}}async function executeSlopcameraOperationWithLease(code,value,lease,dependencies={}){await lease.assertOwned();const available=new Map;for(const claim of lease.claims){if(typeof claim.resource!=="string"||!/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u.test(claim.resource)||!Number.isSafeInteger(claim.amount)||claim.amount<1){throw new SlopcameraOperationError("INVALID_OPERATION","The active host-resource lease contains invalid claims.")}const total=(available.get(claim.resource)??0)+claim.amount;if(!Number.isSafeInteger(total)){throw new SlopcameraOperationError("INVALID_OPERATION","The active host-resource lease contains invalid claims.")}available.set(claim.resource,total)}const missing=slopcameraOperationHostResourceClaims(code).filter((claim)=>(available.get(claim.resource)??0)<claim.amount);if(missing.length>0){throw new SlopcameraOperationError("INVALID_OPERATION",`The active host-resource lease does not cover ${missing.map((claim)=>`${claim.resource}:${String(claim.amount)}`).join(", ")}.`)}return await executeSlopcameraOperationUncoordinated(code,value,operationDependenciesWithLease(dependencies,lease))}async function executeSlopcameraOperation(code,value,dependencies={}){const input=parseSlopcameraOperationInput(code,value);return await withSlopcameraOperationHostAdmission(code,async(lease)=>await executeSlopcameraOperationUncoordinated(code,input,operationDependenciesWithLease(dependencies,lease)),dependencies)}
41
+ export{builtInIcons,sanitizeIcon,layoutBoxContent,NebulaSans_Bold_default,NebulaSans_Book_default,resolveEdge,renderSvg,renderPng,lintDiagram,stackLayoutDefaults,StackLayoutError,resolveStackLayout,resolveDiagramSource,DiagramValidationError,parseDiagramSource,parseDiagramSpec,serializeTldr,slopcameraIconDefaultInk,slopcameraIconPanel,slopcameraIconDefaultRounds,slopcameraIconMaximumRounds,slopcameraIconSubjectMaximumBytes,slopcameraIconCritiqueDefaultModel,slopcameraIconCritiqueTimeoutMs,slopcameraIconContexts,slopcameraIconContextProfiles,iconPromptFor,iconVisualGateProblems,estimateIconStrokePixels,measureIconCandidateMetrics,extractIconLineArt,loadIconLanguageRuntime,critiqueIconRaster,renderIconPreview,writeAtomically,collectSlopcameraIconCandidates,generateSlopcameraIcon,slopcameraGalleryKinds,slopcameraGalleryAxes,slopcameraGalleryLimits,galleryCandidateId,galleryPromptFor,planSlopcameraGallery,parseSlopcameraGalleryVary,generateSlopcameraImageGallery,composeSlopcameraImageGallery,BoundedFileError,slopcameraIconEngine,slopcameraIconSceneLimits,slopcameraIconPalettes,slopcameraIconLanguages,slopcameraIconDefaultLanguage,SlopcameraIconError,assertInertIconSvg,composeSlopcameraIcon,renderSlopcameraIcon,slopcameraSoundtrackEngine,slopcameraSoundtrackLimits,slopcameraSoundtrackFormats,SlopcameraSoundtrackError,detectSlopcameraSoundtrackFormat,soundtrackBeatTimeUs,composeSlopcameraSoundtrack,projectSlopcameraSoundtrackGrid,deriveSlopcameraSoundtrackGrid,slopcameraOperationCodes,SlopcameraOperationError,slopcameraOperationRegistry,parseSlopcameraOperationInput,isSlopcameraOperationCode,slopcameraOperationHostResourceClaims,searchSlopcameraOperations,withSlopcameraOperationHostAdmission,executeSlopcameraOperationWithLease,executeSlopcameraOperation};