@hraness/slopcamera 3.2.8 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +29 -9
  2. package/apps/desktop/application/context.ts +6 -0
  3. package/apps/desktop/application/default-registry.ts +26 -0
  4. package/apps/desktop/application/operation.ts +14 -1
  5. package/apps/desktop/application/operations/index.ts +4 -0
  6. package/apps/desktop/application/operations/spatial-behavior.ts +151 -0
  7. package/apps/desktop/application/operations/spatial-direction.ts +222 -0
  8. package/apps/desktop/application/operations/spatial-rendered-audit.ts +174 -0
  9. package/apps/desktop/application/operations/spatial-review.ts +194 -0
  10. package/apps/desktop/application/operations/spatial-scene.ts +25 -1
  11. package/apps/desktop/application/registry.ts +2 -2
  12. package/apps/desktop/application/spatial-asset-admission.ts +201 -0
  13. package/apps/desktop/application/spatial-assets.ts +160 -31
  14. package/apps/desktop/application/spatial-render.ts +217 -20
  15. package/apps/desktop/application/spatial-rendered-audit.ts +273 -0
  16. package/apps/desktop/application/spatial-review.ts +361 -0
  17. package/apps/desktop/application/spatial-spz.ts +48 -3
  18. package/apps/desktop/application/spatial-world-import.ts +26 -5
  19. package/apps/desktop/application/spatial-world-metadata.ts +105 -0
  20. package/apps/desktop/cli/args.ts +514 -11
  21. package/apps/desktop/cli/capability-manifest.ts +374 -0
  22. package/apps/desktop/cli/cinema-renderer.ts +608 -0
  23. package/apps/desktop/cli/command-host-resources.ts +29 -1
  24. package/apps/desktop/cli/commands.ts +1188 -4
  25. package/apps/desktop/cli/gateway-review-provider.ts +334 -0
  26. package/apps/desktop/cli/help.ts +172 -6
  27. package/apps/desktop/cli/main.ts +3 -3
  28. package/apps/desktop/cli/portable-surface.ts +6 -1
  29. package/apps/desktop/cli/spatial-asset-service.ts +124 -0
  30. package/apps/desktop/cli/spatial-design-service.ts +237 -0
  31. package/apps/desktop/cli/spatial-generate-service.ts +370 -0
  32. package/apps/desktop/cli/spatial-scene-service.ts +268 -4
  33. package/apps/desktop/cli/workflow-code.ts +1 -1
  34. package/apps/desktop/code/semantic-builder.ts +24 -0
  35. package/apps/desktop/contracts/cinema.ts +736 -0
  36. package/apps/desktop/contracts/index.ts +1 -0
  37. package/apps/desktop/contracts/spatial-asset.ts +16 -0
  38. package/apps/desktop/contracts/spatial-world.ts +26 -3
  39. package/apps/desktop/core/cinema-plan.ts +1320 -0
  40. package/apps/desktop/core/index.ts +1 -0
  41. package/apps/desktop/core/storage.ts +75 -0
  42. package/apps/desktop/dist/cli/main.js +725 -273
  43. package/apps/desktop/html-overlay/spatial.ts +619 -57
  44. package/apps/desktop/workflows/cinematic-world.ts +127 -0
  45. package/apps/desktop/workflows/index.ts +6 -0
  46. package/dist/cli.js +25 -429
  47. package/dist/code/advanced.js +1 -269
  48. package/dist/code/index.js +16 -2239
  49. package/dist/generate.js +1 -23
  50. package/dist/host-resources.js +1 -25
  51. package/dist/index-0bbesn4m.js +35 -0
  52. package/dist/index-296qhpf2.js +3 -0
  53. package/dist/index-3cxf2c58.js +3 -0
  54. package/dist/index-77fjfg9f.js +3 -0
  55. package/dist/index-80a36bc0.js +3 -0
  56. package/dist/index-a3vvs3rf.js +3 -0
  57. package/dist/index-b3geqczn.js +5 -0
  58. package/dist/index-cgpkyjqa.js +3 -0
  59. package/dist/index-f0ptv8dm.js +7 -0
  60. package/dist/index-grk47tgs.js +3 -0
  61. package/dist/index-qry58nj2.js +10 -0
  62. package/dist/index.js +1 -226
  63. package/dist/operations.js +1 -28
  64. package/dist/skill-install-gx7afxsd.js +2 -0
  65. package/dist/vectorize/worker.js +1 -141
  66. package/dist/workflow.js +1 -15
  67. package/docs/README.md +5 -1
  68. package/package.json +7 -5
  69. package/skills/slopcamera/SKILL.md +6 -1
  70. package/skills/slopcamera/references/directed-scenes.md +22 -2
  71. package/skills/slopcamera/references/gateway-media.md +15 -1
  72. package/skills/slopcamera/references/image-galleries.md +166 -0
  73. package/skills/slopcamera/references/install.md +1 -1
  74. package/skills/slopcamera/references/parametric-design.md +14 -0
  75. package/skills/slopcamera/references/scene-building.md +32 -0
  76. package/skills/slopcamera/references/social-collage-banners.md +204 -0
  77. package/skills/slopcamera/references/workflows-sdk.md +3 -3
  78. package/skills/slopcamera/scripts/compose-social-collage-banner.ts +728 -0
  79. package/src/capability-manifest.ts +361 -0
  80. package/src/cli.ts +222 -4
  81. package/src/code/canonical-json.ts +9 -0
  82. package/src/generate.ts +2 -2
  83. package/src/icon.ts +1111 -0
  84. package/src/image-gallery.ts +1049 -0
  85. package/src/index.ts +11 -0
  86. package/src/mcp/boundary.ts +11 -11
  87. package/src/mcp/index.ts +3 -0
  88. package/src/mcp/server.ts +2 -1
  89. package/src/mcp/tools.ts +1642 -130
  90. package/src/mcp/types.ts +19 -0
  91. package/src/operations.ts +412 -0
  92. package/src/portable-capability-manifest.ts +67 -0
  93. package/src/scene-gallery.ts +184 -0
  94. package/src/spatial-scene/asset-admission.ts +183 -0
  95. package/src/spatial-scene/audit-rendered.ts +692 -0
  96. package/src/spatial-scene/audit.ts +617 -0
  97. package/src/spatial-scene/behavior-audit.ts +252 -0
  98. package/src/spatial-scene/behavior-bake.ts +233 -0
  99. package/src/spatial-scene/behavior-fns.ts +585 -0
  100. package/src/spatial-scene/behavior-gallery.ts +109 -0
  101. package/src/spatial-scene/behavior-stdlib.ts +323 -0
  102. package/src/spatial-scene/behavior-trace.ts +325 -0
  103. package/src/spatial-scene/behavior.ts +618 -0
  104. package/src/spatial-scene/build.ts +632 -0
  105. package/src/spatial-scene/camera-rig.ts +125 -0
  106. package/src/spatial-scene/camera-track.ts +4 -2
  107. package/src/spatial-scene/character.ts +124 -0
  108. package/src/spatial-scene/contracts.ts +75 -7
  109. package/src/spatial-scene/design-templates.ts +351 -0
  110. package/src/spatial-scene/design.ts +327 -0
  111. package/src/spatial-scene/direction-compile.ts +584 -0
  112. package/src/spatial-scene/direction.ts +122 -0
  113. package/src/spatial-scene/effects.ts +149 -0
  114. package/src/spatial-scene/evaluate.ts +109 -29
  115. package/src/spatial-scene/gallery.ts +277 -0
  116. package/src/spatial-scene/generate.ts +239 -0
  117. package/src/spatial-scene/geometry-native.ts +165 -0
  118. package/src/spatial-scene/geometry.ts +1216 -0
  119. package/src/spatial-scene/gltf.ts +600 -77
  120. package/src/spatial-scene/identity.ts +55 -2
  121. package/src/spatial-scene/index.ts +36 -0
  122. package/src/spatial-scene/inspect.ts +35 -6
  123. package/src/spatial-scene/material-lighting.ts +609 -0
  124. package/src/spatial-scene/math.ts +21 -4
  125. package/src/spatial-scene/motion-evidence.ts +88 -0
  126. package/src/spatial-scene/parametric.ts +765 -0
  127. package/src/spatial-scene/particle-preparation.ts +183 -0
  128. package/src/spatial-scene/particle.ts +195 -0
  129. package/src/spatial-scene/patch.ts +109 -15
  130. package/src/spatial-scene/performance.ts +1613 -0
  131. package/src/spatial-scene/probe.ts +137 -0
  132. package/src/spatial-scene/recipe-pack.ts +86 -0
  133. package/src/spatial-scene/render-effects.ts +240 -0
  134. package/src/spatial-scene/review.ts +639 -0
  135. package/src/spatial-scene/simulation-bake.ts +206 -0
  136. package/src/spatial-scene/simulation.ts +187 -0
  137. package/src/spatial-scene/solve.ts +366 -0
  138. package/src/spatial-scene/temporal-audit.ts +354 -0
  139. package/src/version.ts +1 -1
  140. package/dist/index-42zsesc1.js +0 -2257
  141. package/dist/index-7131pg1c.js +0 -1820
  142. package/dist/index-7308egqr.js +0 -48
  143. package/dist/index-8txs6fkn.js +0 -712
  144. package/dist/index-fava6pge.js +0 -192
  145. package/dist/index-h1k0fnjq.js +0 -2363
  146. package/dist/index-r7gdhmsp.js +0 -424
  147. package/dist/index-sh6xbav6.js +0 -1219
  148. package/dist/index-z1w83f81.js +0 -4
  149. package/dist/index-zfnddgay.js +0 -2029
  150. package/dist/skill-install-dh0ntqba.js +0 -10
@@ -0,0 +1,7 @@
1
+ // @bun
2
+ import{bundledSkillPath,installSkill,pathExists}from"./index-grk47tgs.js";import{SPATIAL_AUDIT_LIMITS,SPATIAL_SCENE_LIMITS,SPATIAL_TEMPORAL_AUDIT_LIMITS,SpatialDigestSchema,SpatialGalleryAxisSchema,SpatialPatchOperationSchema,SpatialSceneError,SpatialTemporalContactsFileSchema,applySpatialScenePatch,auditSpatialBehaviorTrace,auditSpatialScene,auditSpatialTemporalEvidence,checkSpatialBehavior,checkSpatialDirection,checkSpatialRenderEffects,compileSpatialDirection,createSpatialEvaluationContext,diffSpatialScenes,evaluateSpatialScene,evaluateSpatialSceneInContext,inspectSpatialScene,normalizeSpatialAuditAssetBounds,parseSpatialScene,parseSpatialValue,planSpatialDirectionGallery,planSpatialRenderEffects,spatialBehaviorFnSignatures,spatialSceneSha256,spatialValueSha256}from"./index-cgpkyjqa.js";import{PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS,PORTABLE_SLOPCAMERA_OPERATION_KINDS,SlopcameraCodeError,boundedCanonicalJsonSha256,canonicalJson,canonicalJsonSha256,compareUtf16Strings,createBoundedJsonValueSnapshot,deepFreezeJson}from"./index-3cxf2c58.js";import{SlopcameraWorkflowError,defineSlopcameraWorkflow,runSlopcameraWorkflow}from"./index-296qhpf2.js";import{DiagramValidationError,SlopcameraOperationError,StackLayoutError,builtInIcons,executeSlopcameraOperation,generateSlopcameraIcon,generateSlopcameraImageGallery,lintDiagram,parseDiagramSource,parseDiagramSpec,parseSlopcameraOperationInput,renderPng,renderSvg,resolveDiagramSource,resolveEdge,resolveStackLayout,sanitizeIcon,searchSlopcameraOperations,serializeTldr,slopcameraOperationCodes,slopcameraOperationRegistry,stackLayoutDefaults,withSlopcameraOperationHostAdmission}from"./index-0bbesn4m.js";import{VectorizeError,vectorizeHardLimits,vectorizeImage}from"./index-qry58nj2.js";import{SlopcameraCloudError,generateSlopcameraImage,generateSlopcameraImageFile,slopcameraGatewayCredentialStatus}from"./index-77fjfg9f.js";import{HostResourceError,createDefaultHostResourceCoordinator}from"./index-b3geqczn.js";import{mkdir,readFile as readFile2,rename,rm,writeFile}from"fs/promises";import{basename,dirname as dirname2,join,resolve as resolve2}from"path";import{readFile}from"fs/promises";import{dirname,extname,isAbsolute,resolve}from"path";import{pathToFileURL}from"url";var configNames=[{current:"slopcamera.config.ts",retired:"diagram.config.ts"},{current:"slopcamera.config.mjs",retired:"diagram.config.mjs"},{current:"slopcamera.config.js",retired:"diagram.config.js"},{current:"slopcamera.config.json",retired:"diagram.config.json"}];function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function parseFont(value,at){if(!isRecord(value)||typeof value.family!=="string"||value.family.trim()===""){throw new Error(`${at} must have a non-empty family`)}if(value.files!==undefined&&!Array.isArray(value.files)){throw new Error(`${at}.files must be an array`)}if(value.monoFamily!==undefined&&(typeof value.monoFamily!=="string"||value.monoFamily.trim()==="")){throw new Error(`${at}.monoFamily must be a non-empty string when present`)}const files=(value.files??[]).map((file,index)=>{if(!isRecord(file)||typeof file.path!=="string"||file.path.trim()===""){throw new Error(`${at}.files[${index}].path must be a non-empty string`)}if(file.weight!==undefined&&(typeof file.weight!=="number"||!Number.isFinite(file.weight))){throw new Error(`${at}.files[${index}].weight must be a finite number`)}if(file.style!==undefined&&file.style!=="normal"&&file.style!=="italic"){throw new Error(`${at}.files[${index}].style must be normal or italic`)}if(file.embed!==undefined&&typeof file.embed!=="boolean"){throw new Error(`${at}.files[${index}].embed must be a boolean`)}const style=file.style;return{path:file.path,...file.weight===undefined?{}:{weight:file.weight},...style===undefined?{}:{style},...file.embed===undefined?{}:{embed:file.embed}}});return{family:value.family,...value.monoFamily===undefined?{}:{monoFamily:value.monoFamily},...files.length===0?{}:{files}}}function parseIcons(value,at){if(!isRecord(value))throw new Error(`${at} must be an object`);return Object.fromEntries(Object.entries(value).map(([name,icon])=>{if(!isRecord(icon)||typeof icon.viewBox!=="string"||typeof icon.body!=="string"){throw new Error(`${at}.${name} must have string viewBox and body fields`)}return[name,sanitizeIcon({viewBox:icon.viewBox,body:icon.body})]}))}function parseTheme(value,at){if(!isRecord(value))throw new Error(`${at} must be an object`);const scalarKeys=["background","foreground","muted","stroke"];for(const key of scalarKeys){if(value[key]!==undefined&&typeof value[key]!=="string"){throw new Error(`${at}.${key} must be a CSS color string`)}}if(value.tones!==undefined&&!isRecord(value.tones)){throw new Error(`${at}.tones must be an object`)}return value}function parseConfig(value){if(!isRecord(value))throw new Error("Slopcamera config must export an object");const font=value.font===undefined?undefined:parseFont(value.font,"font");const icons=value.icons===undefined?undefined:parseIcons(value.icons,"icons");let theme;if(value.theme!==undefined){if(!isRecord(value.theme))throw new Error("theme must be an object");theme={...value.theme.light===undefined?{}:{light:parseTheme(value.theme.light,"theme.light")},...value.theme.dark===undefined?{}:{dark:parseTheme(value.theme.dark,"theme.dark")}}}return{...font===undefined?{}:{font},...icons===undefined?{}:{icons:{...builtInIcons,...icons}},...theme===undefined?{}:{theme}}}async function discoverConfig(directory){let current=null;for(const names of configNames){const candidate=resolve(directory,names.current);if(await pathExists(candidate)){current=candidate;break}}if(current!==null)return current;for(const names of configNames){const candidate=resolve(directory,names.retired);if(await pathExists(candidate)){const replacement=resolve(directory,names.current);throw new Error(`Legacy Slopcamera config found at ${candidate}. Rename it to ${replacement}; Slopcamera does not auto-load diagram.config.*.`)}}return null}async function loadDiagramConfig(options){const filePath=options.explicitPath===undefined?await discoverConfig(options.searchDirectory):resolve(options.explicitPath);if(filePath===null){return{filePath:null,baseDirectory:options.searchDirectory,value:{icons:builtInIcons}}}if(!await pathExists(filePath))throw new Error(`Config does not exist: ${filePath}`);const raw=extname(filePath)===".json"?JSON.parse(await readFile(filePath,"utf8")):(await import(`${pathToFileURL(filePath).href}?v=${Date.now()}`)).default;const value=parseConfig(raw);const baseDirectory=dirname(filePath);const font=value.font===undefined?undefined:{...value.font,...value.font.files===undefined?{}:{files:value.font.files.map((file)=>({...file,path:isAbsolute(file.path)?file.path:resolve(baseDirectory,file.path)}))}};return{filePath,baseDirectory,value:{...value,icons:{...builtInIcons,...value.icons},...font===undefined?{}:{font}}}}async function atomicWrite(filePath,data){const temporary=`${filePath}.tmp-${process.pid}-${crypto.randomUUID()}`;try{await writeFile(temporary,data);await rename(temporary,filePath)}catch(error){await rm(temporary,{force:true});throw error}}async function readDiagramFile(filePath){const absolutePath=resolve2(filePath);let parsed;try{parsed=JSON.parse(await readFile2(absolutePath,"utf8"))}catch(error){throw new Error(`Could not read diagram JSON at ${absolutePath}`,{cause:error})}return{absolutePath,spec:parseDiagramSpec(parsed)}}async function checkDiagramFile(options){const{absolutePath,spec}=await readDiagramFile(options.filePath);const config=await loadDiagramConfig({...options.configPath===undefined?{}:{explicitPath:options.configPath},searchDirectory:dirname2(absolutePath)});for(const shape of spec.shapes){if((shape.type==="rect"||shape.type==="ellipse")&&shape.icon!==undefined&&config.value.icons?.[shape.icon]===undefined){throw new Error(`Unknown icon "${shape.icon}" on shape ${shape.id}`)}}return{findings:lintDiagram(spec),configPath:config.filePath}}async function renderDiagramFile(options){const{absolutePath,spec}=await readDiagramFile(options.filePath);const outDirectory=resolve2(options.outDirectory??dirname2(absolutePath));const config=await loadDiagramConfig({...options.configPath===undefined?{}:{explicitPath:options.configPath},searchDirectory:dirname2(absolutePath)});const scale=options.scale??2;if(!Number.isFinite(scale)||scale<=0||scale>8){throw new Error("PNG scale must be greater than zero and no more than 8")}const[light,dark]=await Promise.all([renderSvg(spec,"light",config.value),renderSvg(spec,"dark",config.value)]);const[lightPng,darkPng]=[renderPng(light,config.value,scale),renderPng(dark,config.value,scale)];const artifacts={spec:absolutePath,tldr:join(outDirectory,`${spec.name}.tldr`),lightSvg:join(outDirectory,`${spec.name}.light.svg`),darkSvg:join(outDirectory,`${spec.name}.dark.svg`),lightPng:join(outDirectory,`${spec.name}.light.png`),darkPng:join(outDirectory,`${spec.name}.dark.png`)};await mkdir(outDirectory,{recursive:true});await Promise.all([atomicWrite(artifacts.tldr,serializeTldr(spec,config.value)),atomicWrite(artifacts.lightSvg,light.svg),atomicWrite(artifacts.darkSvg,dark.svg),atomicWrite(artifacts.lightPng,lightPng),atomicWrite(artifacts.darkPng,darkPng)]);return{artifacts,findings:lintDiagram(spec),configPath:config.filePath}}function artifactSummary(artifacts){return[`Rendered ${basename(artifacts.spec)}`,` ${artifacts.tldr}`,` ${artifacts.lightSvg}`,` ${artifacts.darkSvg}`,` ${artifacts.lightPng}`,` ${artifacts.darkPng}`].join(`
3
+ `)}import{rename as rename2,rm as rm2,writeFile as writeFile2}from"fs/promises";import{dirname as dirname4,join as join3}from"path";import{open,mkdir as mkdir2,realpath,stat}from"fs/promises";import{basename as basename2,dirname as dirname3,isAbsolute as isAbsolute2,join as join2,relative,resolve as resolve3,win32}from"path";var mcpSourceByteLimit=1024*1024;class WorkspaceBoundaryError extends Error{code;constructor(code,message){super(message);this.name="WorkspaceBoundaryError";this.code=code}}function filesystemCode(error){if(typeof error==="object"&&error!==null&&"code"in error&&typeof error.code==="string"){return error.code}return}function normalizeRelativePath(value,options){if(value.length===0||value.includes("\x00")){throw new WorkspaceBoundaryError("INVALID_PATH","Path must be a non-empty root-relative path.")}if(isAbsolute2(value)||win32.isAbsolute(value)||/^[A-Za-z]:/.test(value)){throw new WorkspaceBoundaryError("INVALID_PATH","Absolute paths are not allowed.")}const segments=value.split(/[\\/]/).filter((segment)=>segment!==""&&segment!==".");if(segments.includes("..")){throw new WorkspaceBoundaryError("INVALID_PATH","Parent-directory traversal is not allowed.")}if(segments.length===0){if(!options.allowRoot){throw new WorkspaceBoundaryError("INVALID_PATH","Path must identify a file below the root.")}return{native:".",portable:"."}}return{native:segments.join("/"),portable:segments.join("/")}}function isConfined(rootDirectory,target){const fromRoot=relative(rootDirectory,target);return fromRoot===""||!fromRoot.startsWith("..")&&!isAbsolute2(fromRoot)}async function readUtf8WithCap(filePath,sourceLabel){let handle;try{handle=await open(filePath,"r");const metadata=await handle.stat();if(!metadata.isFile()){throw new WorkspaceBoundaryError("SOURCE_NOT_FILE",`${sourceLabel} must be a regular file.`)}if(metadata.size>mcpSourceByteLimit){throw new WorkspaceBoundaryError("SOURCE_TOO_LARGE",`${sourceLabel} exceeds the ${mcpSourceByteLimit}-byte limit.`)}const buffer=Buffer.allocUnsafe(mcpSourceByteLimit+1);let bytesRead=0;while(bytesRead<=mcpSourceByteLimit){const next=await handle.read(buffer,bytesRead,mcpSourceByteLimit+1-bytesRead,null);if(next.bytesRead===0)break;bytesRead+=next.bytesRead}if(bytesRead>mcpSourceByteLimit){throw new WorkspaceBoundaryError("SOURCE_TOO_LARGE",`${sourceLabel} exceeds the ${mcpSourceByteLimit}-byte limit.`)}try{return new TextDecoder("utf-8",{fatal:true}).decode(buffer.subarray(0,bytesRead))}catch{throw new WorkspaceBoundaryError("SOURCE_ENCODING",`${sourceLabel} must contain valid UTF-8.`)}}catch(error){if(error instanceof WorkspaceBoundaryError)throw error;const code=filesystemCode(error);if(code==="ENOENT"){throw new WorkspaceBoundaryError("SOURCE_NOT_FOUND",`${sourceLabel} does not exist.`)}throw new WorkspaceBoundaryError("FILESYSTEM_ERROR",`${sourceLabel} could not be read.`)}finally{await handle?.close()}}class WorkspaceBoundary{rootDirectory;constructor(rootDirectory){this.rootDirectory=rootDirectory}static async create(rootDirectory){let resolvedRoot;try{resolvedRoot=await realpath(resolve3(rootDirectory));if(!(await stat(resolvedRoot)).isDirectory()){throw new WorkspaceBoundaryError("OUTPUT_NOT_DIRECTORY","MCP root must be a directory.")}}catch(error){if(error instanceof WorkspaceBoundaryError)throw error;throw new WorkspaceBoundaryError("FILESYSTEM_ERROR","MCP root could not be opened.")}return new WorkspaceBoundary(resolvedRoot)}assertConfined(target){if(!isConfined(this.rootDirectory,target)){throw new WorkspaceBoundaryError("PATH_OUTSIDE_ROOT","Path resolves outside the MCP root.")}}toRelativePath(absolutePath){this.assertConfined(absolutePath);const fromRoot=relative(this.rootDirectory,absolutePath);return fromRoot===""?".":fromRoot.split("\\").join("/")}async readSource(value,sourceLabel="Diagram source"){const normalized=normalizeRelativePath(value,{allowRoot:false});const lexicalPath=resolve3(this.rootDirectory,normalized.native);this.assertConfined(lexicalPath);let canonicalPath;try{canonicalPath=await realpath(lexicalPath)}catch(error){if(filesystemCode(error)==="ENOENT"){throw new WorkspaceBoundaryError("SOURCE_NOT_FOUND",`${sourceLabel} does not exist.`)}throw new WorkspaceBoundaryError("FILESYSTEM_ERROR",`${sourceLabel} could not be resolved.`)}this.assertConfined(canonicalPath);return{absolutePath:canonicalPath,relativePath:this.toRelativePath(canonicalPath),text:await readUtf8WithCap(canonicalPath,sourceLabel)}}async resolveInputFile(value,maximumBytes){const normalized=normalizeRelativePath(value,{allowRoot:false});const lexicalPath=resolve3(this.rootDirectory,normalized.native);this.assertConfined(lexicalPath);let canonicalPath;try{canonicalPath=await realpath(lexicalPath);this.assertConfined(canonicalPath);const metadata=await stat(canonicalPath);if(!metadata.isFile()){throw new WorkspaceBoundaryError("SOURCE_NOT_FILE","Input must be a regular file.")}if(!Number.isSafeInteger(maximumBytes)||maximumBytes<1||metadata.size>maximumBytes){throw new WorkspaceBoundaryError("SOURCE_TOO_LARGE",`Input exceeds the ${maximumBytes}-byte limit.`)}}catch(error){if(error instanceof WorkspaceBoundaryError)throw error;if(filesystemCode(error)==="ENOENT"){throw new WorkspaceBoundaryError("SOURCE_NOT_FOUND","Input does not exist.")}throw new WorkspaceBoundaryError("FILESYSTEM_ERROR","Input could not be resolved.")}return{absolutePath:canonicalPath,relativePath:this.toRelativePath(canonicalPath)}}async prepareOutputFile(value){const normalized=normalizeRelativePath(value,{allowRoot:false});const fileName=basename2(normalized.native);if(fileName==="."||fileName===".."||fileName.length===0){throw new WorkspaceBoundaryError("INVALID_PATH","Output path must identify a file below the root.")}const directory=await this.prepareOutputDirectory(dirname3(normalized.native));const absolutePath=join2(directory.absolutePath,fileName);this.assertConfined(absolutePath);return{absolutePath,relativePath:this.toRelativePath(absolutePath)}}async prepareOutputDirectory(value){const normalized=normalizeRelativePath(value,{allowRoot:true});const lexicalPath=resolve3(this.rootDirectory,normalized.native);this.assertConfined(lexicalPath);let ancestor=lexicalPath;for(;;){try{const canonicalAncestor=await realpath(ancestor);this.assertConfined(canonicalAncestor);break}catch(error){if(error instanceof WorkspaceBoundaryError)throw error;if(filesystemCode(error)!=="ENOENT"){throw new WorkspaceBoundaryError("FILESYSTEM_ERROR","Output directory could not be resolved.")}const parent=dirname3(ancestor);if(parent===ancestor){throw new WorkspaceBoundaryError("PATH_OUTSIDE_ROOT","Output directory resolves outside the MCP root.")}ancestor=parent}}try{await mkdir2(lexicalPath,{recursive:true});const canonicalPath=await realpath(lexicalPath);this.assertConfined(canonicalPath);if(!(await stat(canonicalPath)).isDirectory()){throw new WorkspaceBoundaryError("OUTPUT_NOT_DIRECTORY","Output path must be a directory.")}return{absolutePath:canonicalPath,relativePath:this.toRelativePath(canonicalPath)}}catch(error){if(error instanceof WorkspaceBoundaryError)throw error;throw new WorkspaceBoundaryError("FILESYSTEM_ERROR","Output directory could not be created.")}}}var mcpMaximumScale=4;var mcpMaximumRenderedPixels=16777216;var mcpMaximumShapes=64;var mcpMaximumEdges=128;var mcpMaximumReturnedFindings=40;var mcpMaximumReturnedEntities=256;var mcpMaximumReturnedAuditSamples=8192;var mcpMaximumReturnedDiffEntries=1024;var defaultScale=2;var maximumShapeIdsPerFinding=12;var builtInConfig=Object.freeze({icons:builtInIcons});var findingSchema={type:"object",additionalProperties:false,required:["code","message","shapeIds"],properties:{code:{type:"string"},message:{type:"string"},shapeIds:{type:"array",items:{type:"string"}}}};var scenePathSchema={type:"string",description:"Root-relative path to a spatial scene JSON source (1 MiB maximum)."};var sceneCameraIdSchema={type:"string",maxLength:128,pattern:"^camera_[a-zA-Z0-9][a-zA-Z0-9_-]*$",description:"Identifier of a camera declared by the scene (camera_\u2026)."};var entityTruncationSummarySchema={type:"object",additionalProperties:false,required:["entityCount","returnedEntityCount","entitiesTruncated"],properties:{entityCount:{type:"integer",minimum:0},returnedEntityCount:{type:"integer",minimum:0},entitiesTruncated:{type:"boolean"}}};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 slopcameraMcpTools=deepFreeze([{name:"check_diagram",title:"Check diagram",description:"Parse and lint one root-relative Slopcamera diagram source without changing files. Uses only built-in icons and themes.",inputSchema:{type:"object",additionalProperties:false,required:["path"],properties:{path:{type:"string",description:"Root-relative path to a diagram JSON source (1 MiB maximum)."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","findings","summary"],properties:{ok:{const:true},source:{type:"string"},findings:{type:"array",items:findingSchema},summary:{type:"object",additionalProperties:false,required:["shapeCount","edgeCount","findingCount","returnedFindingCount","findingsTruncated"],properties:{shapeCount:{type:"integer",minimum:0},edgeCount:{type:"integer",minimum:0},findingCount:{type:"integer",minimum:0},returnedFindingCount:{type:"integer",minimum:0},findingsTruncated:{type:"boolean"}}}}},annotations:{title:"Check diagram",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"render_diagram",title:"Render diagram",description:"Render one root-relative Slopcamera diagram source with built-in icons and themes, overwriting its paired .tldr, light/dark SVG, and light/dark PNG artifacts.",inputSchema:{type:"object",additionalProperties:false,required:["path"],properties:{path:{type:"string",description:"Root-relative path to a diagram JSON source (1 MiB maximum)."},out_dir:{type:"string",description:"Optional root-relative output directory. Defaults to the source directory."},scale:{type:"number",exclusiveMinimum:0,maximum:mcpMaximumScale,default:defaultScale,description:"PNG scale. The scaled canvas may contain at most 16,777,216 pixels."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","scale","findings","artifacts","summary"],properties:{ok:{const:true},source:{type:"string"},scale:{type:"number"},findings:{type:"array",items:findingSchema},artifacts:{type:"object",additionalProperties:false,required:["tldr","lightSvg","darkSvg","lightPng","darkPng"],properties:{tldr:{type:"string"},lightSvg:{type:"string"},darkSvg:{type:"string"},lightPng:{type:"string"},darkPng:{type:"string"}}},summary:{type:"object",additionalProperties:false,required:["shapeCount","edgeCount","findingCount","returnedFindingCount","findingsTruncated"],properties:{shapeCount:{type:"integer",minimum:0},edgeCount:{type:"integer",minimum:0},findingCount:{type:"integer",minimum:0},returnedFindingCount:{type:"integer",minimum:0},findingsTruncated:{type:"boolean"}}}}},annotations:{title:"Render diagram",readOnlyHint:false,destructiveHint:true,idempotentHint:true,openWorldHint:false}},{name:"search_slopcamera",title:"Search Slopcamera operations",description:"Search the fixed semantic Slopcamera operation registry by bounded text. This never executes code or changes files.",inputSchema:{type:"object",additionalProperties:false,properties:{query:{type:"string",maxLength:200,description:"Optional terms matched against operation codes and descriptions."},limit:{type:"integer",minimum:1,maximum:20,default:4}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","operations"],properties:{ok:{const:true},operations:{type:"array",maxItems:20,items:{type:"object",required:["code","title","description","execution","authentication","inputSchema"]}}}},annotations:{title:"Search Slopcamera operations",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"execute_slopcamera",title:"Execute Slopcamera operation",description:"Execute one exact operation code with typed JSON input. Never accepts or evaluates source code. Local paths remain confined to the configured workspace root.",inputSchema:{type:"object",additionalProperties:false,required:["operation","input"],properties:{operation:{type:"string",enum:slopcameraOperationCodes},input:{type:"object",description:"Typed input matching the selected operation's registry schema."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","operation","result"],properties:{ok:{const:true},operation:{type:"string",enum:slopcameraOperationCodes},result:{type:"object"}}},annotations:{title:"Execute Slopcamera operation",readOnlyHint:false,destructiveHint:true,idempotentHint:false,openWorldHint:true}},{name:"check_scene",title:"Check scene",description:"Parse and validate one root-relative Slopcamera spatial scene JSON source without changing files.",inputSchema:{type:"object",additionalProperties:false,required:["path"],properties:{path:scenePathSchema}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","sceneId","sceneSha256","summary"],properties:{ok:{const:true},source:{type:"string"},sceneId:{type:"string"},sceneSha256:{type:"string"},summary:{type:"object",additionalProperties:false,required:["durationUs","entityCount","cameraCount","assetCount","animationCount","generatorCount","overrideCount"],properties:{durationUs:{type:"integer",minimum:0},entityCount:{type:"integer",minimum:0},cameraCount:{type:"integer",minimum:0},assetCount:{type:"integer",minimum:0},animationCount:{type:"integer",minimum:0},generatorCount:{type:"integer",minimum:0},overrideCount:{type:"integer",minimum:0}}}}},annotations:{title:"Check scene",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"inspect_scene",title:"Inspect scene",description:"Snapshot one root-relative spatial scene's entities, editable controls, placements, assets, and generators without changing files.",inputSchema:{type:"object",additionalProperties:false,required:["path"],properties:{path:scenePathSchema}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","inspection","summary"],properties:{ok:{const:true},source:{type:"string"},inspection:{type:"object"},summary:entityTruncationSummarySchema}},annotations:{title:"Inspect scene",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"audit_scene",title:"Audit scene",description:"Sample one root-relative spatial scene against a camera and report per-entity geometric coverage, visibility findings, and bounds gaps. Optional asset_bounds accepts a Record<assetId,{min,max}> map, a slopcamera.spatial-asset-admission document, a {manifest,facts} pair, or an array of those.",inputSchema:{type:"object",additionalProperties:false,required:["path","camera_id"],properties:{path:scenePathSchema,camera_id:sceneCameraIdSchema,times_us:{type:"array",items:{type:"integer",minimum:0,maximum:SPATIAL_SCENE_LIMITS.durationUs},minItems:1,maxItems:SPATIAL_AUDIT_LIMITS.samples,description:"Optional sample times in microseconds. Defaults to evenly spaced coverage of the scene duration."},asset_bounds:{description:"Optional decoded scene-space asset bounds: a Record<assetId,{min,max}> map, a slopcamera.spatial-asset-admission document, a {manifest,facts} pair, or an array of those documents."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","report","summary"],properties:{ok:{const:true},source:{type:"string"},report:{type:"object"},summary:{type:"object",additionalProperties:false,required:["findingCount","returnedFindingCount","findingsTruncated","entityCount","returnedEntityCount","entitiesTruncated"],properties:{findingCount:{type:"integer",minimum:0},returnedFindingCount:{type:"integer",minimum:0},findingsTruncated:{type:"boolean"},entityCount:{type:"integer",minimum:0},returnedEntityCount:{type:"integer",minimum:0},entitiesTruncated:{type:"boolean"}}}}},annotations:{title:"Audit scene",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"diff_scenes",title:"Diff scenes",description:"Compare two root-relative spatial scene JSON sources and report added, removed, and changed collection entries without changing files.",inputSchema:{type:"object",additionalProperties:false,required:["path","other"],properties:{path:scenePathSchema,other:{type:"string",description:"Root-relative path to the second spatial scene JSON source (1 MiB maximum)."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","other","sceneSha256","otherSha256","diff","summary"],properties:{ok:{const:true},source:{type:"string"},other:{type:"string"},sceneSha256:{type:"string"},otherSha256:{type:"string"},diff:{type:"array"},summary:{type:"object",additionalProperties:false,required:["entryCount","returnedEntryCount","diffTruncated"],properties:{entryCount:{type:"integer",minimum:0},returnedEntryCount:{type:"integer",minimum:0},diffTruncated:{type:"boolean"}}}}},annotations:{title:"Diff scenes",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"evaluate_scene",title:"Evaluate scene",description:"Evaluate one root-relative spatial scene at one camera and integer microsecond time into an immutable snapshot without changing files.",inputSchema:{type:"object",additionalProperties:false,required:["path","camera_id","time_us"],properties:{path:scenePathSchema,camera_id:sceneCameraIdSchema,time_us:{type:"integer",minimum:0,maximum:SPATIAL_SCENE_LIMITS.durationUs,description:"Evaluation time in integer microseconds."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","snapshot","summary"],properties:{ok:{const:true},source:{type:"string"},snapshot:{type:"object"},summary:entityTruncationSummarySchema}},annotations:{title:"Evaluate scene",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"check_scene_direction",title:"Check scene direction",description:"Validate one authored direction document against one root-relative spatial scene: stale project digests, unresolved entity references, and intervals outside scene duration report as errors without compiling or changing files.",inputSchema:{type:"object",additionalProperties:false,required:["scene","direction"],properties:{scene:{...scenePathSchema,description:"Root-relative path to the spatial scene JSON source (1 MiB maximum)."},direction:{type:"string",description:"Root-relative path to the slopcamera.spatial-direction JSON document."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","report","summary"],properties:{ok:{const:true},source:{type:"string"},report:{type:"object"},summary:{type:"object",additionalProperties:false,required:["findingCount","returnedFindingCount","findingsTruncated","errorCount","warningCount"],properties:{findingCount:{type:"integer",minimum:0},returnedFindingCount:{type:"integer",minimum:0},findingsTruncated:{type:"boolean"},errorCount:{type:"integer",minimum:0},warningCount:{type:"integer",minimum:0}}}}},annotations:{title:"Check scene direction",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"plan_scene_direction",title:"Plan scene direction",description:"Compile one authored direction document into a deterministic, unverified proposal document \u2014 performance actions, camera rigs, shots and looks bound to the actual scene digest. Proposals are advisory only; nothing is applied to the scene.",inputSchema:{type:"object",additionalProperties:false,required:["scene","direction"],properties:{scene:{...scenePathSchema,description:"Root-relative path to the spatial scene JSON source (1 MiB maximum)."},direction:{type:"string",description:"Root-relative path to the slopcamera.spatial-direction JSON document."},camera_id:{...sceneCameraIdSchema,description:"Optional camera used to resolve coverage; defaults to the sole or first sorted scene camera."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","compilation","summary"],properties:{ok:{const:true},source:{type:"string"},compilation:{type:"object"},summary:{type:"object",additionalProperties:false,required:["advisoryCount","unresolvedIntentCount","proposalCounts"],properties:{advisoryCount:{type:"integer",minimum:0},unresolvedIntentCount:{type:"integer",minimum:0},proposalCounts:{type:"object",additionalProperties:false,required:["performance","cameraRigs","shots","lookIntents"],properties:{performance:{type:"integer",minimum:0},cameraRigs:{type:"integer",minimum:0},shots:{type:"integer",minimum:0},lookIntents:{type:"integer",minimum:0}}}}}}},annotations:{title:"Plan scene direction",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"plan_scene_gallery",title:"Plan scene gallery",description:"Compile a bounded set of single-axis direction variants into separate content-addressed candidate compilations plus a preview-reel plan. The planner never selects or promotes a candidate.",inputSchema:{type:"object",additionalProperties:false,required:["scene","direction","axis"],properties:{scene:{...scenePathSchema,description:"Root-relative path to the spatial scene JSON source (1 MiB maximum)."},direction:{type:"string",description:"Root-relative path to the slopcamera.spatial-direction JSON document."},axis:{type:"string",enum:[...SpatialGalleryAxisSchema.options],description:"Variation axis for the bounded candidate set."},camera_id:{...sceneCameraIdSchema,description:"Optional camera used to resolve coverage."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","gallery","summary"],properties:{ok:{const:true},source:{type:"string"},gallery:{type:"object"},summary:{type:"object",additionalProperties:false,required:["axis","candidateCount","selected"],properties:{axis:{type:"string"},candidateCount:{type:"integer",minimum:0},selected:{const:false}}}}},annotations:{title:"Plan scene gallery",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"check_scene_effects",title:"Check scene effects",description:"Validate one slopcamera.spatial-render-effects document or {document, documentSha256} binding against one scene: scene-digest bindings, entity and asset closure, and nested plan/particle/simulation digests report as findings before any host work.",inputSchema:{type:"object",additionalProperties:false,required:["scene","effects"],properties:{scene:{...scenePathSchema,description:"Root-relative path to the spatial scene JSON source (1 MiB maximum)."},effects:{type:"string",description:"Root-relative path to the render-effects document or binding JSON."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","report","summary"],properties:{ok:{const:true},source:{type:"string"},report:{type:"object"},summary:{type:"object",additionalProperties:false,required:["findingCount","returnedFindingCount","findingsTruncated","errorCount","warningCount"],properties:{findingCount:{type:"integer",minimum:0},returnedFindingCount:{type:"integer",minimum:0},findingsTruncated:{type:"boolean"},errorCount:{type:"integer",minimum:0},warningCount:{type:"integer",minimum:0}}}}},annotations:{title:"Check scene effects",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"plan_scene_effects",title:"Plan scene effects",description:"Assemble a canonical {document, documentSha256} render-effects binding for one scene from a draft JSON naming renderPlan, particleSystems and simulationBakes. Entity and asset closure rejects before the document is formed; the scene digest binds here, never by caller assertion.",inputSchema:{type:"object",additionalProperties:false,required:["scene","draft"],properties:{scene:{...scenePathSchema,description:"Root-relative path to the spatial scene JSON source (1 MiB maximum)."},draft:{type:"string",description:"Root-relative path to the effects draft JSON ({renderPlan, particleSystems?, simulationBakes?})."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","binding","summary"],properties:{ok:{const:true},source:{type:"string"},binding:{type:"object"},summary:{type:"object",additionalProperties:false,required:["documentSha256","particleSystemCount","simulationBakeCount"],properties:{documentSha256:{type:"string"},particleSystemCount:{type:"integer",minimum:0},simulationBakeCount:{type:"integer",minimum:0}}}}},annotations:{title:"Plan scene effects",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"check_scene_behavior",title:"Check scene behavior",description:"Validate one slopcamera.spatial-behavior document against one scene: bake-safe organism profile (input/const/fn/repeat/each/organism cells only), manifest-closure digests, entity and scene-digest bindings, channel declarations, fn-catalog resolution, wiring, and budget bounds report as findings before any host work.",inputSchema:{type:"object",additionalProperties:false,required:["scene","behavior"],properties:{scene:{...scenePathSchema,description:"Root-relative path to the spatial scene JSON source (1 MiB maximum)."},behavior:{type:"string",description:"Root-relative path to the spatial behavior document JSON."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","report","summary"],properties:{ok:{const:true},source:{type:"string"},report:{type:"object"},summary:{type:"object",additionalProperties:false,required:["findingCount","returnedFindingCount","findingsTruncated","errorCount","warningCount"],properties:{findingCount:{type:"integer",minimum:0},returnedFindingCount:{type:"integer",minimum:0},findingsTruncated:{type:"boolean"},errorCount:{type:"integer",minimum:0},warningCount:{type:"integer",minimum:0}}}}},annotations:{title:"Check scene behavior",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"audit_scene_behavior",title:"Audit scene behavior trace",description:"Analyze a baked behavior trace for pathological patterns: state thrash (rapid transitions), exact periodicity (trivially cyclic channels), dead channels (constant-valued), and unreachable states (declared in transitions but never visited). Advisory findings for gallery review \u2014 never selects or promotes.",inputSchema:{type:"object",additionalProperties:false,required:["bake"],properties:{bake:{type:"string",description:"Root-relative path to the behavior bake JSON (slopcamera.spatial-behavior-bake)."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","report","summary"],properties:{ok:{const:true},source:{type:"string"},report:{type:"object"},summary:{type:"object",additionalProperties:false,required:["findingCount","channelCount","emittedCount"],properties:{findingCount:{type:"integer",minimum:0},channelCount:{type:"integer",minimum:0},emittedCount:{type:"integer",minimum:0}}}}},annotations:{title:"Audit scene behavior trace",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}},{name:"audit_scene_temporal",title:"Audit scene temporal evidence",description:"Evaluate one root-relative spatial scene at bounded sample times under one camera and report deterministic temporal findings: visibility flicker, transform discontinuity, foot-slide against declared contact windows, camera acceleration/jerk/angular velocity, exposure and focus jumps, and resource spikes.",inputSchema:{type:"object",additionalProperties:false,required:["path","camera_id"],properties:{path:scenePathSchema,camera_id:sceneCameraIdSchema,times_us:{type:"array",items:{type:"integer",minimum:0,maximum:SPATIAL_SCENE_LIMITS.durationUs},minItems:2,maxItems:SPATIAL_TEMPORAL_AUDIT_LIMITS.samples,description:"Optional sample times in microseconds (2\u2013256). Defaults to evenly spaced coverage of the scene duration."},contacts:{type:"string",description:"Optional root-relative path to a {contacts: [...]} ground-contact evidence JSON."},cut_before_us:{type:"array",items:{type:"integer",minimum:0,maximum:SPATIAL_SCENE_LIMITS.durationUs},maxItems:SPATIAL_TEMPORAL_AUDIT_LIMITS.cutBoundaries,description:"Optional intentional cut boundaries; discontinuities exactly at a cut are not findings."}}},outputSchema:{type:"object",additionalProperties:false,required:["ok","source","report","summary"],properties:{ok:{const:true},source:{type:"string"},report:{type:"object"},summary:{type:"object",additionalProperties:false,required:["findingCount","returnedFindingCount","findingsTruncated","sampleCount"],properties:{findingCount:{type:"integer",minimum:0},returnedFindingCount:{type:"integer",minimum:0},findingsTruncated:{type:"boolean"},sampleCount:{type:"integer",minimum:2}}}}},annotations:{title:"Audit scene temporal evidence",readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:false}}]);class ToolFailure extends Error{code;issues;constructor(code,message,issues){super(message);this.name="ToolFailure";this.code=code;if(issues!==undefined)this.issues=issues}}function isRecord2(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function safeFragment(value,maximumLength=160){return value.replace(/[\u0000-\u001f\u007f]/g," ").replace(/\s+/g," ").trim().slice(0,maximumLength)}function safeIssues(issues){return issues.slice(0,24).map((issue)=>safeFragment(issue,240))}function rejectUnknownKeys(value,allowed){const unknown=Object.keys(value).filter((key)=>!allowed.has(key));if(unknown.length>0){throw new ToolFailure("INVALID_ARGUMENTS",`Unsupported argument: ${safeFragment(unknown[0]??"unknown")}.`)}}function parsePath(value){if(typeof value!=="string"||value.length===0){throw new ToolFailure("INVALID_ARGUMENTS","path must be a non-empty root-relative string.")}if(!value.toLowerCase().endsWith(".diagram.json")){throw new ToolFailure("INVALID_ARGUMENTS","path must end in .diagram.json.")}return value}function parseCheckArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["path"]));return{path:parsePath(value.path)}}function parseRenderArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["path","out_dir","scale"]));const outDirectory=value.out_dir;if(outDirectory!==undefined&&(typeof outDirectory!=="string"||outDirectory.length===0)){throw new ToolFailure("INVALID_ARGUMENTS","out_dir must be a non-empty root-relative string when present.")}const scale=value.scale??defaultScale;if(typeof scale!=="number"||!Number.isFinite(scale)||scale<=0||scale>mcpMaximumScale){throw new ToolFailure("RENDER_LIMIT",`scale must be greater than zero and no more than ${mcpMaximumScale}.`)}return{path:parsePath(value.path),...outDirectory===undefined?{}:{outDirectory},scale}}function parseSearchArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["query","limit"]));const query=value.query??"";const limit=value.limit??slopcameraOperationCodes.length;if(typeof query!=="string"||query.length>200||/[\u0000-\u001f\u007f]/u.test(query)||!Number.isInteger(limit)||limit<1||limit>20){throw new ToolFailure("INVALID_ARGUMENTS","query must be a bounded string and limit must be an integer from 1 through 20.")}return{query,limit}}function parseExecuteArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["operation","input"]));if(typeof value.operation!=="string"||!slopcameraOperationCodes.includes(value.operation)||!isRecord2(value.input)){throw new ToolFailure("INVALID_ARGUMENTS","operation must be an exact Slopcamera operation code and input must be an object.")}return{operation:value.operation,input:value.input}}var sceneCameraIdPattern=/^camera_[a-zA-Z0-9][a-zA-Z0-9_-]*$/u;function parseScenePath(value,label){if(typeof value!=="string"||value.length===0){throw new ToolFailure("INVALID_ARGUMENTS",`${label} must be a non-empty root-relative string.`)}if(!value.toLowerCase().endsWith(".json")){throw new ToolFailure("INVALID_ARGUMENTS",`${label} must end in .json.`)}return value}function parseSceneCameraId(value){if(typeof value!=="string"||value.length>128||!sceneCameraIdPattern.test(value)){throw new ToolFailure("INVALID_ARGUMENTS","camera_id must be a scene camera identifier (camera_ followed by letters, digits, _ or -).")}return value}function parseSceneSourceArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["path"]));return{path:parseScenePath(value.path,"path")}}function parseAuditSceneArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["path","camera_id","times_us","asset_bounds"]));let timesUs;if(value.times_us!==undefined){if(!Array.isArray(value.times_us)||value.times_us.length===0||value.times_us.length>SPATIAL_AUDIT_LIMITS.samples||value.times_us.some((timeUs)=>!Number.isSafeInteger(timeUs)||timeUs<0||timeUs>SPATIAL_SCENE_LIMITS.durationUs)){throw new ToolFailure("INVALID_ARGUMENTS",`times_us must be an array of 1\u2013${SPATIAL_AUDIT_LIMITS.samples} integer microsecond times within the scene duration bound.`)}timesUs=[...value.times_us]}return{path:parseScenePath(value.path,"path"),cameraId:parseSceneCameraId(value.camera_id),...timesUs===undefined?{}:{timesUs},..."asset_bounds"in value?{assetBounds:value.asset_bounds}:{}}}function parseDiffScenesArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["path","other"]));return{path:parseScenePath(value.path,"path"),other:parseScenePath(value.other,"other")}}function parseEvaluateSceneArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["path","camera_id","time_us"]));const timeUs=value.time_us;if(typeof timeUs!=="number"||!Number.isSafeInteger(timeUs)||timeUs<0||timeUs>SPATIAL_SCENE_LIMITS.durationUs){throw new ToolFailure("INVALID_ARGUMENTS",`time_us must be an integer microsecond time from 0 through ${SPATIAL_SCENE_LIMITS.durationUs}.`)}return{path:parseScenePath(value.path,"path"),cameraId:parseSceneCameraId(value.camera_id),timeUs}}function parseSceneDirectionArguments(value,requireAxis){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["scene","direction","camera_id","axis"]));if(requireAxis&&!SpatialGalleryAxisSchema.safeParse(value.axis).success){throw new ToolFailure("INVALID_ARGUMENTS",`axis must be one of ${SpatialGalleryAxisSchema.options.join(", ")}.`)}if(!requireAxis&&value.axis!==undefined){throw new ToolFailure("INVALID_ARGUMENTS","axis is only valid for plan_scene_gallery.")}return{scene:parseScenePath(value.scene,"scene"),direction:parseScenePath(value.direction,"direction"),...value.camera_id===undefined?{}:{cameraId:parseSceneCameraId(value.camera_id)},...value.axis===undefined?{}:{axis:value.axis}}}function parseSceneEffectsArguments(value,effectsKey){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["scene",effectsKey]));return{scene:parseScenePath(value.scene,"scene"),effects:parseScenePath(value[effectsKey],effectsKey)}}function parseSceneBehaviorArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["scene","behavior"]));return{scene:parseScenePath(value.scene,"scene"),behavior:parseScenePath(value.behavior,"behavior")}}function parseSceneBehaviorAuditArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["bake"]));return{bake:parseScenePath(value.bake,"bake")}}function parseSceneTemporalArguments(value){if(!isRecord2(value)){throw new ToolFailure("INVALID_ARGUMENTS","Tool arguments must be an object.")}rejectUnknownKeys(value,new Set(["path","camera_id","times_us","contacts","cut_before_us"]));const boundedTimes=(key,maximum)=>{const entries=value[key];if(entries===undefined)return;if(!Array.isArray(entries)||entries.length===0||entries.length>maximum||entries.some((timeUs)=>!Number.isSafeInteger(timeUs)||timeUs<0||timeUs>SPATIAL_SCENE_LIMITS.durationUs)){throw new ToolFailure("INVALID_ARGUMENTS",`${key} must be an array of 1\u2013${maximum} integer microsecond times within the scene duration bound.`)}return[...entries]};const timesUs=boundedTimes("times_us",SPATIAL_TEMPORAL_AUDIT_LIMITS.samples);const cutBeforeUs=boundedTimes("cut_before_us",SPATIAL_TEMPORAL_AUDIT_LIMITS.cutBoundaries);if(timesUs!==undefined&&timesUs.length<2){throw new ToolFailure("INVALID_ARGUMENTS","times_us must contain at least 2 sample times.")}return{path:parseScenePath(value.path,"path"),cameraId:parseSceneCameraId(value.camera_id),...timesUs===undefined?{}:{timesUs},...value.contacts===undefined?{}:{contacts:parseScenePath(value.contacts,"contacts")},...cutBeforeUs===undefined?{}:{cutBeforeUs}}}function assertBuiltInIcons(spec){for(const shape of spec.shapes){if((shape.type==="rect"||shape.type==="ellipse")&&shape.icon!==undefined&&!Object.hasOwn(builtInIcons,shape.icon)){throw new ToolFailure("UNKNOWN_ICON",`Shape ${safeFragment(shape.id)} requests unavailable built-in icon ${safeFragment(shape.icon)}.`)}}}function assertComplexityLimits(spec){const edgeCount=spec.edges?.length??0;if(spec.shapes.length>mcpMaximumShapes||edgeCount>mcpMaximumEdges){throw new ToolFailure("COMPLEXITY_LIMIT",`Diagram may contain at most ${mcpMaximumShapes} shapes and ${mcpMaximumEdges} edges in MCP mode.`)}}function assertRawComplexityLimits(value){if(!isRecord2(value))return;const shapeCount=Array.isArray(value.shapes)?value.shapes.length:0;const edgeCount=Array.isArray(value.edges)?value.edges.length:0;if(shapeCount>mcpMaximumShapes||edgeCount>mcpMaximumEdges){throw new ToolFailure("COMPLEXITY_LIMIT",`Diagram may contain at most ${mcpMaximumShapes} shapes and ${mcpMaximumEdges} edges in MCP mode.`)}}function assertRenderLimits(spec,scale){const scaledWidth=spec.canvas.width*scale;const scaledHeight=spec.canvas.height*scale;const pixels=Math.ceil(scaledWidth)*Math.ceil(scaledHeight);if(!Number.isFinite(pixels)||scaledWidth<1||scaledHeight<1||pixels>mcpMaximumRenderedPixels){throw new ToolFailure("RENDER_LIMIT",`Scaled canvas must be at least 1 pixel on each axis and no more than ${mcpMaximumRenderedPixels.toLocaleString("en-US")} pixels total.`)}}function boundedSlice(items,maximum){return items.length>maximum?items.slice(0,maximum):items}function publicFinding(finding){return{code:safeFragment(finding.code,64),message:safeFragment(finding.message,240),shapeIds:finding.shapeIds.slice(0,maximumShapeIdsPerFinding).map((shapeId)=>safeFragment(shapeId,120))}}function publicFindings(findings){return findings.slice(0,mcpMaximumReturnedFindings).map(publicFinding)}function diagramSummary(spec,findingCount,returnedFindingCount){return{shapeCount:spec.shapes.length,edgeCount:spec.edges?.length??0,findingCount,returnedFindingCount,findingsTruncated:returnedFindingCount<findingCount}}function successResult(text,structuredContent){return{content:[{type:"text",text}],structuredContent}}function failureResult(error){let code="INTERNAL_ERROR";let message="The tool failed safely.";let issues;if(error instanceof ToolFailure){code=error.code;message=safeFragment(error.message,320);issues=error.issues}else if(error instanceof WorkspaceBoundaryError){code=error.code;message=safeFragment(error.message,320)}else if(error instanceof SlopcameraCloudError){code=error.code;message=safeFragment(error.message.replace(/^\[[A-Z_]+\]\s*/u,""),320)}else if(error instanceof SlopcameraOperationError){code=error.code;message=safeFragment(error.message.replace(/^\[[A-Z_]+\]\s*/u,""),320)}else if(error instanceof VectorizeError){code=`VECTORIZE_${error.code.toUpperCase()}`;message="Local vectorization failed safely."}else if(error instanceof DiagramValidationError){code="INVALID_DIAGRAM";message="Diagram source did not pass validation.";issues=safeIssues(error.issues)}else if(error instanceof SlopcameraCodeError){code=error.code.toUpperCase().replace(/-/g,"_");message=safeFragment(error.message,320)}else if(error instanceof HostResourceError){code=`HOST_RESOURCE_${error.code}`;message="Host-resource admission failed safely."}else if(typeof error==="object"&&error!==null&&"issues"in error&&Array.isArray(error.issues)&&error.issues.every((issue)=>typeof issue==="string")){code="INVALID_LAYOUT";message="Diagram layout could not be resolved.";issues=safeIssues(error.issues)}const issueText=issues===undefined||issues.length===0?"":`
4
+ ${issues.map((issue)=>`- ${issue}`).join(`
5
+ `)}`;return{content:[{type:"text",text:`[${code}] ${message}${issueText}`}],isError:true}}function portableDirectory(filePath){const separator=filePath.lastIndexOf("/");return separator===-1?".":filePath.slice(0,separator)}async function atomicOverwrite(filePath,data){const temporaryPath=join3(dirname4(filePath),`.${crypto.randomUUID()}.slopcamera-mcp.tmp`);try{await writeFile2(temporaryPath,data,{flag:"wx"});try{await rename2(temporaryPath,filePath)}catch(error){const code=typeof error==="object"&&error!==null&&"code"in error&&typeof error.code==="string"?error.code:undefined;if(code!=="EEXIST"&&code!=="EPERM")throw error;await rm2(filePath,{force:true});await rename2(temporaryPath,filePath)}}finally{await rm2(temporaryPath,{force:true})}}async function loadDiagram(boundary,path){const source=await boundary.readSource(path);let parsed;try{parsed=JSON.parse(source.text)}catch{throw new ToolFailure("INVALID_JSON","Diagram source is not valid JSON.")}assertRawComplexityLimits(parsed);const spec=parseDiagramSpec(parsed);assertComplexityLimits(spec);assertBuiltInIcons(spec);return{source,spec}}async function loadScene(boundary,path){const source=await boundary.readSource(path,"Scene source");const parsed=parseJsonText(source.text);try{return{source,scene:parseSpatialScene(parsed)}}catch(error){if(error instanceof SpatialSceneError){const where=error.path==="scene"?"":` at ${error.path}`;throw new ToolFailure("INVALID_SCENE",`Scene source did not pass validation${where}: ${safeFragment(error.message,240)}`)}throw error}}function parseJsonText(text){try{return JSON.parse(text)}catch{throw new ToolFailure("INVALID_JSON","Source is not valid JSON.")}}async function loadJson(boundary,path,label){const source=await boundary.readSource(path,label);return{source,value:parseJsonText(source.text)}}class SlopcameraMcpToolRuntime{boundary;generateDependencies;hostResourceCoordinator;renderQueue=Promise.resolve();constructor(boundary,generateDependencies,hostResourceCoordinator){this.boundary=boundary;this.generateDependencies=generateDependencies;this.hostResourceCoordinator=hostResourceCoordinator}static async create(rootDirectory,generateDependencies={},hostResourceCoordinator){return new SlopcameraMcpToolRuntime(await WorkspaceBoundary.create(rootDirectory),generateDependencies,hostResourceCoordinator??createDefaultHostResourceCoordinator())}async withHostAdmission(operation,callback){return await withSlopcameraOperationHostAdmission(operation,callback,{hostResourceCoordinator:this.hostResourceCoordinator})}async withSceneAdmission(callback){return await this.hostResourceCoordinator.withLease([{resource:"cpu",amount:1},{resource:"local-io",amount:1}],async(lease)=>{await lease.assertOwned();return await callback(lease)})}enqueueRender(operation){const result=this.renderQueue.then(operation,operation);this.renderQueue=result.then(()=>{return},()=>{return});return result}async call(name,argumentsValue){try{if(name==="check_diagram"){const options=parseCheckArguments(argumentsValue);return await this.withHostAdmission("slopcamera.diagram.check",async()=>await this.check(options))}if(name==="render_diagram"){const options=parseRenderArguments(argumentsValue);return await this.enqueueRender(async()=>await this.withHostAdmission("slopcamera.diagram.render",async()=>await this.render(options)))}if(name==="search_slopcamera"){const options=parseSearchArguments(argumentsValue);const operations=searchSlopcameraOperations(options.query,options.limit);return successResult(`Found ${operations.length} Slopcamera operation${operations.length===1?"":"s"}.`,{ok:true,operations})}if(name==="execute_slopcamera"){const options=parseExecuteArguments(argumentsValue);return await this.execute(options)}if(name==="check_scene"){const options=parseSceneSourceArguments(argumentsValue);return await this.withSceneAdmission(async()=>await this.checkScene(options))}if(name==="inspect_scene"){const options=parseSceneSourceArguments(argumentsValue);return await this.withSceneAdmission(async()=>await this.inspectScene(options))}if(name==="audit_scene"){const options=parseAuditSceneArguments(argumentsValue);return await this.withSceneAdmission(async()=>await this.auditScene(options))}if(name==="diff_scenes"){const options=parseDiffScenesArguments(argumentsValue);return await this.withSceneAdmission(async()=>await this.diffScenes(options))}if(name==="evaluate_scene"){const options=parseEvaluateSceneArguments(argumentsValue);return await this.withSceneAdmission(async()=>await this.evaluateScene(options))}if(name==="check_scene_direction"){const options=parseSceneDirectionArguments(argumentsValue,false);return await this.withSceneAdmission(async()=>await this.checkSceneDirection(options))}if(name==="plan_scene_direction"){const options=parseSceneDirectionArguments(argumentsValue,false);return await this.withSceneAdmission(async()=>await this.planSceneDirection(options))}if(name==="plan_scene_gallery"){const options=parseSceneDirectionArguments(argumentsValue,true);return await this.withSceneAdmission(async()=>await this.planSceneGallery(options))}if(name==="check_scene_effects"){const options=parseSceneEffectsArguments(argumentsValue,"effects");return await this.withSceneAdmission(async()=>await this.checkSceneEffects(options))}if(name==="plan_scene_effects"){const options=parseSceneEffectsArguments(argumentsValue,"draft");return await this.withSceneAdmission(async()=>await this.planSceneEffects(options))}if(name==="check_scene_behavior"){const options=parseSceneBehaviorArguments(argumentsValue);return await this.withSceneAdmission(async()=>await this.checkSceneBehavior(options))}if(name==="audit_scene_behavior"){const options=parseSceneBehaviorAuditArguments(argumentsValue);return await this.withSceneAdmission(async()=>await this.auditSceneBehavior(options))}if(name==="audit_scene_temporal"){const options=parseSceneTemporalArguments(argumentsValue);return await this.withSceneAdmission(async()=>await this.auditSceneTemporal(options))}throw new ToolFailure("UNKNOWN_TOOL","Requested tool is not available.")}catch(error){return failureResult(error)}}wrapSemanticResult(operation,result){if(result.isError===true)return result;return{content:result.content,structuredContent:{ok:true,operation,result:result.structuredContent??{}}}}async execute(options){if(options.operation==="slopcamera.diagram.check"){const input=parseSlopcameraOperationInput(options.operation,options.input);return this.wrapSemanticResult(options.operation,await this.withHostAdmission(options.operation,async()=>await this.check({path:input.path})))}if(options.operation==="slopcamera.diagram.render"){const input=parseSlopcameraOperationInput(options.operation,options.input);return this.enqueueRender(async()=>await this.withHostAdmission(options.operation,async()=>this.wrapSemanticResult(options.operation,await this.render({path:input.path,...input.outDirectory===undefined?{}:{outDirectory:input.outDirectory},scale:input.scale??defaultScale}))))}if(options.operation==="slopcamera.image.vectorize"){const input=parseSlopcameraOperationInput(options.operation,options.input);return this.enqueueRender(async()=>await this.withHostAdmission(options.operation,async(lease)=>{const source=await this.boundary.resolveInputFile(input.inputPath,vectorizeHardLimits.maxInputBytes);const output=await this.boundary.prepareOutputFile(input.outputPath);const result=await vectorizeImage(source.absolutePath,{outputPath:output.absolutePath,...input.duotone===undefined?{}:{duotone:input.duotone},...input.alphaCutoff===undefined?{}:{alphaCutoff:input.alphaCutoff},...input.timeoutMs===undefined?{}:{limits:{maxDurationMs:input.timeoutMs}},inheritedFileDescriptors:[lease.inheritedFileDescriptor]});return successResult(`Executed ${options.operation}: ${output.relativePath}`,{ok:true,operation:options.operation,result:{inputPath:source.relativePath,outputPath:output.relativePath,receipt:result.receipt}})}))}if(options.operation==="slopcamera.image.gallery"){const input=parseSlopcameraOperationInput(options.operation,options.input);return await this.withHostAdmission(options.operation,async()=>{const output=await this.boundary.prepareOutputDirectory(input.outputDir);const receipt=await generateSlopcameraImageGallery({...input,outputDir:output.absolutePath},this.generateDependencies);return successResult(`Executed ${options.operation}: ${receipt.counts.generated}/${receipt.counts.requested} candidates in ${output.relativePath}.`,{ok:true,operation:options.operation,result:{...receipt,outputDir:output.relativePath}})})}return await this.withHostAdmission(options.operation,async()=>{const input=parseSlopcameraOperationInput(options.operation,options.input);const output=await this.boundary.prepareOutputFile(input.outputPath);const generated=await generateSlopcameraImageFile({...input,outputPath:output.absolutePath},this.generateDependencies);return successResult(`Executed ${options.operation}: ${output.relativePath} (request ${safeFragment(generated.requestId,256)}).`,{ok:true,operation:options.operation,result:{bytes:generated.bytes,mediaType:generated.mediaType,model:generated.model,outputPath:output.relativePath,provider:generated.provider,requestId:generated.requestId,sha256:generated.sha256,warnings:generated.warnings}})})}async check(options){const{source,spec}=await loadDiagram(this.boundary,options.path);const allFindings=lintDiagram(spec);const findings=publicFindings(allFindings);const summary=diagramSummary(spec,allFindings.length,findings.length);const text=allFindings.length===0?`Checked ${source.relativePath}: no findings.`:`Checked ${source.relativePath}: ${allFindings.length} finding${allFindings.length===1?"":"s"}; ${findings.length} returned in structured content${findings.length<allFindings.length?" (truncated)":""}.`;return successResult(text,{ok:true,source:source.relativePath,findings,summary})}async render(options){const{source,spec}=await loadDiagram(this.boundary,options.path);assertRenderLimits(spec,options.scale);const outputDirectory=await this.boundary.prepareOutputDirectory(options.outDirectory??portableDirectory(source.relativePath));const tldr=serializeTldr(spec,builtInConfig);const[light,dark]=await Promise.all([renderSvg(spec,"light",builtInConfig),renderSvg(spec,"dark",builtInConfig)]);const lightPng=renderPng(light,builtInConfig,options.scale);const darkPng=renderPng(dark,builtInConfig,options.scale);const absoluteArtifacts={spec:source.absolutePath,tldr:join3(outputDirectory.absolutePath,`${spec.name}.tldr`),lightSvg:join3(outputDirectory.absolutePath,`${spec.name}.light.svg`),darkSvg:join3(outputDirectory.absolutePath,`${spec.name}.dark.svg`),lightPng:join3(outputDirectory.absolutePath,`${spec.name}.light.png`),darkPng:join3(outputDirectory.absolutePath,`${spec.name}.dark.png`)};await Promise.all([atomicOverwrite(absoluteArtifacts.tldr,tldr),atomicOverwrite(absoluteArtifacts.lightSvg,light.svg),atomicOverwrite(absoluteArtifacts.darkSvg,dark.svg),atomicOverwrite(absoluteArtifacts.lightPng,lightPng),atomicOverwrite(absoluteArtifacts.darkPng,darkPng)]);const artifacts={tldr:this.boundary.toRelativePath(absoluteArtifacts.tldr),lightSvg:this.boundary.toRelativePath(absoluteArtifacts.lightSvg),darkSvg:this.boundary.toRelativePath(absoluteArtifacts.darkSvg),lightPng:this.boundary.toRelativePath(absoluteArtifacts.lightPng),darkPng:this.boundary.toRelativePath(absoluteArtifacts.darkPng)};const allFindings=lintDiagram(spec);const findings=publicFindings(allFindings);const summary=diagramSummary(spec,allFindings.length,findings.length);const text=[`Rendered ${source.relativePath} with built-in assets:`,...Object.values(artifacts).map((artifact)=>`- ${artifact}`)].join(`
6
+ `);return successResult(text,{ok:true,source:source.relativePath,scale:options.scale,findings,artifacts,summary})}async checkScene(options){const{source,scene}=await loadScene(this.boundary,options.path);const summary={durationUs:scene.durationUs,entityCount:scene.entities.length,cameraCount:scene.cameras.length,assetCount:scene.assets.length,animationCount:scene.animations.length,generatorCount:scene.generators.length,overrideCount:scene.overrides.length};return successResult(`Checked ${source.relativePath}: scene ${safeFragment(scene.sceneId,128)} is valid (${summary.entityCount} entities, ${summary.cameraCount} cameras).`,{ok:true,source:source.relativePath,sceneId:scene.sceneId,sceneSha256:spatialValueSha256(scene),summary})}async inspectScene(options){const{source,scene}=await loadScene(this.boundary,options.path);const inspection=inspectSpatialScene(scene);const entities=boundedSlice(inspection.entities,mcpMaximumReturnedEntities);const summary={entityCount:inspection.entities.length,returnedEntityCount:entities.length,entitiesTruncated:entities.length<inspection.entities.length};return successResult(`Inspected ${source.relativePath}: ${summary.entityCount} entities${summary.entitiesTruncated?`, first ${summary.returnedEntityCount} returned in structured content`:""}.`,{ok:true,source:source.relativePath,inspection:{...inspection,entities},summary})}async auditScene(options){const{source,scene}=await loadScene(this.boundary,options.path);const report=auditSpatialScene(scene,{cameraId:options.cameraId,...options.timesUs===undefined?{}:{timesUs:options.timesUs},...options.assetBounds===undefined?{}:{assetBounds:normalizeSpatialAuditAssetBounds(options.assetBounds)}});let sampleBudget=mcpMaximumReturnedAuditSamples;const entities=[];for(const entity of report.entities){if(entities.length>=mcpMaximumReturnedEntities||entity.samples.length>sampleBudget){break}sampleBudget-=entity.samples.length;entities.push(entity)}const findings=boundedSlice(report.findings,mcpMaximumReturnedFindings);const findingCount=report.findings.length+report.omittedFindings;const summary={findingCount,returnedFindingCount:findings.length,findingsTruncated:findings.length<findingCount,entityCount:report.entities.length,returnedEntityCount:entities.length,entitiesTruncated:entities.length<report.entities.length};return successResult(`Audited ${source.relativePath} under ${options.cameraId}: ${findingCount} finding${findingCount===1?"":"s"} across ${report.entities.length} entities and ${report.timesUs.length} samples${summary.findingsTruncated||summary.entitiesTruncated?" (truncated)":""}.`,{ok:true,source:source.relativePath,report:{...report,entities,findings},summary})}async diffScenes(options){const{source,scene}=await loadScene(this.boundary,options.path);const other=await loadScene(this.boundary,options.other);const entries=diffSpatialScenes(scene,other.scene);const diff=boundedSlice(entries,mcpMaximumReturnedDiffEntries);const summary={entryCount:entries.length,returnedEntryCount:diff.length,diffTruncated:diff.length<entries.length};return successResult(`Diffed ${source.relativePath} against ${other.source.relativePath}: ${summary.entryCount} entr${summary.entryCount===1?"y":"ies"}${summary.diffTruncated?`, first ${summary.returnedEntryCount} returned in structured content`:""}.`,{ok:true,source:source.relativePath,other:other.source.relativePath,sceneSha256:spatialValueSha256(scene),otherSha256:spatialValueSha256(other.scene),diff,summary})}async evaluateScene(options){const{source,scene}=await loadScene(this.boundary,options.path);const snapshot=evaluateSpatialScene(scene,{timeUs:options.timeUs,cameraId:options.cameraId});const entities=boundedSlice(snapshot.entities,mcpMaximumReturnedEntities);const summary={entityCount:snapshot.entities.length,returnedEntityCount:entities.length,entitiesTruncated:entities.length<snapshot.entities.length};return successResult(`Evaluated ${source.relativePath} at timeUs ${options.timeUs} under ${options.cameraId}: ${summary.entityCount} entities${summary.entitiesTruncated?`, first ${summary.returnedEntityCount} returned in structured content`:""}.`,{ok:true,source:source.relativePath,snapshot:{...snapshot,entities},summary})}async checkSceneDirection(options){const{source,scene}=await loadScene(this.boundary,options.scene);const direction=await loadJson(this.boundary,options.direction,"Direction source");const report=checkSpatialDirection({direction:direction.value,scene});const findings=boundedSlice(report.findings,mcpMaximumReturnedFindings);const summary={findingCount:report.findings.length,returnedFindingCount:findings.length,findingsTruncated:findings.length<report.findings.length,errorCount:report.counts.errors,warningCount:report.counts.warnings};return successResult(`Checked direction ${direction.source.relativePath} against ${source.relativePath}: ${summary.findingCount} finding${summary.findingCount===1?"":"s"} (${summary.errorCount} errors).`,{ok:summary.errorCount===0,source:source.relativePath,report:{...report,findings},summary})}async planSceneDirection(options){const{source,scene}=await loadScene(this.boundary,options.scene);const direction=await loadJson(this.boundary,options.direction,"Direction source");const compilation=compileSpatialDirection({direction:direction.value,scene,...options.cameraId===undefined?{}:{cameraId:options.cameraId}});const summary={advisoryCount:compilation.advisories.length,unresolvedIntentCount:compilation.unresolvedIntents.length,proposalCounts:{performance:compilation.proposals.performance.length,cameraRigs:compilation.proposals.cameraRigs.length,shots:compilation.proposals.shots.length,lookIntents:compilation.proposals.lookIntents.length}};return successResult(`Compiled direction ${direction.source.relativePath}: ${compilation.proposals.shots.length} shot proposals, ${compilation.advisories.length} advisories; all proposals remain unverified.`,{ok:true,source:source.relativePath,compilation,summary})}async planSceneGallery(options){const{source,scene}=await loadScene(this.boundary,options.scene);const direction=await loadJson(this.boundary,options.direction,"Direction source");const gallery=planSpatialDirectionGallery({axis:options.axis,direction:direction.value,scene,...options.cameraId===undefined?{}:{cameraId:options.cameraId}});const summary={axis:gallery.axis,candidateCount:gallery.candidates.length,selected:false};return successResult(`Planned a ${gallery.axis} gallery from ${direction.source.relativePath}: ${gallery.candidates.length} content-addressed candidates; none selected.`,{ok:true,source:source.relativePath,gallery,summary})}async checkSceneEffects(options){const{source,scene}=await loadScene(this.boundary,options.scene);const effects=await loadJson(this.boundary,options.effects,"Effects source");const report=checkSpatialRenderEffects({effects:effects.value,scene});const findings=boundedSlice(report.findings,mcpMaximumReturnedFindings);const summary={findingCount:report.findings.length,returnedFindingCount:findings.length,findingsTruncated:findings.length<report.findings.length,errorCount:report.counts.errors,warningCount:report.counts.warnings};return successResult(`Checked effects ${effects.source.relativePath} against ${source.relativePath}: ${summary.findingCount} finding${summary.findingCount===1?"":"s"} (${summary.errorCount} errors).`,{ok:summary.errorCount===0,source:source.relativePath,report:{...report,findings},summary})}async planSceneEffects(options){const{source,scene}=await loadScene(this.boundary,options.scene);const draft=await loadJson(this.boundary,options.effects,"Effects draft");if(!isRecord2(draft.value)){throw new ToolFailure("INVALID_ARGUMENTS","Effects draft must be a JSON object with renderPlan, particleSystems and simulationBakes fields.")}const binding=planSpatialRenderEffects({...draft.value,scene});const summary={documentSha256:binding.documentSha256,particleSystemCount:binding.document.particleSystems.length,simulationBakeCount:binding.document.simulationBakes.length};return successResult(`Bound effects draft ${draft.source.relativePath} to scene ${summary.documentSha256.slice(0,16)}\u2026: ${summary.particleSystemCount} particle systems, ${summary.simulationBakeCount} simulation bakes.`,{ok:true,source:source.relativePath,binding,summary})}async checkSceneBehavior(options){const{source,scene}=await loadScene(this.boundary,options.scene);const behavior=await loadJson(this.boundary,options.behavior,"Behavior source");const report=checkSpatialBehavior({behavior:behavior.value,scene},spatialBehaviorFnSignatures());const findings=boundedSlice(report.findings,mcpMaximumReturnedFindings);const summary={findingCount:report.findings.length,returnedFindingCount:findings.length,findingsTruncated:findings.length<report.findings.length,errorCount:report.counts.errors,warningCount:report.counts.warnings};return successResult(`Checked behavior ${behavior.source.relativePath} against ${source.relativePath}: ${summary.findingCount} finding${summary.findingCount===1?"":"s"} (${summary.errorCount} errors).`,{ok:summary.errorCount===0,source:source.relativePath,report:{...report,findings},summary})}async auditSceneBehavior(options){const bake=await loadJson(this.boundary,options.bake,"Behavior bake source");const report=auditSpatialBehaviorTrace(bake.value);const findings=boundedSlice(report.findings,mcpMaximumReturnedFindings);const summary={findingCount:report.findings.length,channelCount:report.channelCount,emittedCount:report.emittedCount};return successResult(`Audited behavior bake ${bake.source.relativePath}: ${summary.findingCount} finding${summary.findingCount===1?"":"s"} across ${summary.channelCount} channel${summary.channelCount===1?"":"s"}.`,{ok:true,source:bake.source.relativePath,report:{...report,findings},summary})}async auditSceneTemporal(options){const{source,scene}=await loadScene(this.boundary,options.path);const times=options.timesUs??(()=>{const count=Math.min(17,Math.max(2,Math.ceil(scene.durationUs/1e6)+1));return Array.from({length:count},(_value,index)=>Math.floor(scene.durationUs*index/(count-1)))})();const contacts=options.contacts===undefined?[]:parseSpatialValue(SpatialTemporalContactsFileSchema,(await loadJson(this.boundary,options.contacts,"Contacts source")).value,"temporal contacts").contacts;const context=createSpatialEvaluationContext(scene);const snapshots=[...times].sort((left,right)=>left-right).map((timeUs)=>evaluateSpatialSceneInContext(context,{cameraId:options.cameraId,timeUs}));const report=auditSpatialTemporalEvidence({snapshots,options:{contacts,...options.cutBeforeUs===undefined?{}:{cutBeforeUs:[...options.cutBeforeUs]}}});const findings=boundedSlice(report.findings,mcpMaximumReturnedFindings);const findingCount=report.findings.length+report.omittedFindings;const summary={findingCount,returnedFindingCount:findings.length,findingsTruncated:findings.length<findingCount,sampleCount:report.sampleCount};return successResult(`Audited ${source.relativePath} over ${report.sampleCount} samples under ${options.cameraId}: ${findingCount} temporal finding${findingCount===1?"":"s"}${summary.findingsTruncated?" (truncated)":""}.`,{ok:true,source:source.relativePath,report:{...report,findings},summary})}}var SLOPCAMERA_VERSION="3.3.1";var slopcameraMcpProtocolVersion="2025-11-25";var slopcameraMcpServerName="hraness-slopcamera";var maximumMessageBytes=1024*1024;function isRecord3(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function isJsonRpcId(value){return typeof value==="string"||typeof value==="number"&&Number.isSafeInteger(value)}function isInitializeParams(value){return isRecord3(value)&&typeof value.protocolVersion==="string"&&isRecord3(value.capabilities)&&isRecord3(value.clientInfo)&&typeof value.clientInfo.name==="string"&&typeof value.clientInfo.version==="string"}function parseRequest(value){if(!isRecord3(value)||value.jsonrpc!=="2.0"||typeof value.method!=="string"||value.method.length===0||"id"in value&&!isJsonRpcId(value.id)){throw new Error("invalid request")}return{jsonrpc:"2.0",..."id"in value?{id:value.id}:{},method:value.method,..."params"in value?{params:value.params}:{}}}function success(id,result){return{jsonrpc:"2.0",id,result}}function failure(id,code,message){return{jsonrpc:"2.0",id,error:{code,message}}}function parseToolCall(params){if(!isRecord3(params)||typeof params.name!=="string"||params.arguments!==undefined&&!isRecord3(params.arguments)){throw new Error("invalid params")}const unknownKeys=Object.keys(params).filter((key)=>key!=="name"&&key!=="arguments");if(unknownKeys.length>0)throw new Error("invalid params");return{name:params.name,argumentsValue:params.arguments??{}}}class SlopcameraMcpSession{runtime;serverVersion;state="new";constructor(runtime,serverVersion){this.runtime=runtime;this.serverVersion=serverVersion}async handle(value){let request;try{request=parseRequest(value)}catch{return failure(null,-32600,"Invalid Request")}const notification=request.id===undefined;if(request.method==="notifications/initialized"){if(!notification){return failure(request.id,-32600,"Invalid Request")}if(this.state==="initializing")this.state="ready";return null}if(notification)return null;const id=request.id;if(request.method==="initialize"){if(this.state!=="new"||!isInitializeParams(request.params)){return failure(id,-32602,"Invalid initialize parameters")}this.state="initializing";return success(id,{protocolVersion:slopcameraMcpProtocolVersion,capabilities:{tools:{listChanged:false}},serverInfo:{name:slopcameraMcpServerName,version:this.serverVersion},instructions:"Use check_diagram/render_diagram, the read-only scene tools (check_scene, inspect_scene, audit_scene, diff_scenes, evaluate_scene), or search_slopcamera followed by execute_slopcamera with an exact registry code and typed JSON. Local paths are root-relative; source code is never accepted or evaluated."})}if(this.state!=="ready"){return failure(id,-32002,"Server is not initialized")}if(request.method==="ping")return success(id,{});if(request.method==="tools/list"){if(request.params!==undefined&&(!isRecord3(request.params)||Object.keys(request.params).length>0)){return failure(id,-32602,"Invalid tools/list parameters")}return success(id,{tools:slopcameraMcpTools})}if(request.method==="tools/call"){try{const toolCall=parseToolCall(request.params);if(!slopcameraMcpTools.some((tool)=>tool.name===toolCall.name)){return failure(id,-32602,"Unknown tool")}return success(id,await this.runtime.call(toolCall.name,toolCall.argumentsValue))}catch{return failure(id,-32602,"Invalid tools/call parameters")}}return failure(id,-32601,"Method not found")}}async function defaultWriteLine(line){await new Promise((resolve4,reject)=>{process.stdout.write(`${line}
7
+ `,(error)=>{if(error===null||error===undefined)resolve4();else reject(error)})})}function defaultInput(){return process.stdin}async function emitResponse(writeLine,response){await writeLine(JSON.stringify(response))}async function processLine(line,session,writeLine){if(line.byteLength===0)return;let value;try{const text=new TextDecoder("utf-8",{fatal:true}).decode(line);if(text.trim()==="")return;value=JSON.parse(text)}catch{await emitResponse(writeLine,failure(null,-32700,"Parse error"));return}if(Array.isArray(value)){await emitResponse(writeLine,failure(null,-32600,"Invalid Request"));return}const response=await session.handle(value);if(response!==null)await emitResponse(writeLine,response)}async function runMcpServer(options={}){const runtime=await SlopcameraMcpToolRuntime.create(options.rootDirectory??process.cwd(),options.generateDependencies,options.hostResourceCoordinator);const session=new SlopcameraMcpSession(runtime,options.serverVersion??SLOPCAMERA_VERSION);const writeLine=options.writeLine??defaultWriteLine;let buffered=Buffer.alloc(0);for await(const chunk of options.input??defaultInput()){const bytes=typeof chunk==="string"?Buffer.from(chunk,"utf8"):Buffer.from(chunk);buffered=Buffer.concat([buffered,bytes]);if(buffered.byteLength>maximumMessageBytes&&!buffered.includes(10)){buffered=Buffer.alloc(0);await emitResponse(writeLine,failure(null,-32700,"Parse error"));continue}for(;;){const newline=buffered.indexOf(10);if(newline===-1)break;let line=buffered.subarray(0,newline);buffered=buffered.subarray(newline+1);if(line.at(-1)===13)line=line.subarray(0,-1);if(line.byteLength>maximumMessageBytes){await emitResponse(writeLine,failure(null,-32700,"Parse error"))}else{await processLine(line,session,writeLine)}}}if(buffered.byteLength>0){if(buffered.byteLength>maximumMessageBytes){await emitResponse(writeLine,failure(null,-32700,"Parse error"))}else{await processLine(buffered,session,writeLine)}}}import{z}from"zod";var SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS=Object.freeze({bytes:4*1024*1024,commands:256,evidence:64,modules:64,operations:512,profiles:128,requirements:32,tools:128,workflows:128});var identifier=z.string().min(1).max(192).regex(/^[a-z][a-z0-9]*(?:[-_.:/@][a-z0-9]+)*$/u);var commandName=z.string().min(1).max(128).regex(/^[a-z][a-z0-9-]*(?: [a-z][a-z0-9-]*){0,3}$/u);var digest=z.string().regex(/^[a-f0-9]{64}$/u);var positiveSafeInteger=z.number().int().safe().positive();var nonnegativeSafeInteger=z.number().int().safe().nonnegative();var SlopcameraCapabilityEffectSchema=z.enum(["pure","local-read","local-derived-write","project-mutation","paid-cloud","live-control"]);var SlopcameraCapabilityResumeSchema=z.enum(["deterministic","verified-receipt","recoverable-transaction","ambiguous-after-dispatch","non-resumable-live"]);var SlopcameraCapabilityResourceSchema=z.enum(["cpu","local-io","ffmpeg","vision","whisper","network","paid-call","project-render","project-publication","output-publication","capture-device","browser"]);var SlopcameraCapabilityPreparationSchema=z.enum(["project-state","recording-metadata","screen-capture","camera","microphone","system-audio","typed-text","window-metadata","local-media","provider-options"]);var SlopcameraCapabilityOperationSchema=z.strictObject({cache:z.enum(["none","exact-run","content-addressed"]),cancellable:z.boolean(),effect:SlopcameraCapabilityEffectSchema,inputSchemaId:identifier,key:z.string().min(3).max(256).regex(/^[a-z][a-z0-9]*(?:[-_.][a-z0-9]+)*@[1-9][0-9]*$/u),kind:z.string().min(3).max(192).regex(/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*(?:\.[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*)+$/u),lifecycle:z.enum(["pure","local-artifact","project-transaction","paid-dispatch","live-control"]),maxDurationMs:positiveSafeInteger,maxFanOut:nonnegativeSafeInteger,maxInputBytes:nonnegativeSafeInteger,maxOutputBytes:nonnegativeSafeInteger,outputSchemaId:identifier,preparation:z.array(SlopcameraCapabilityPreparationSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.requirements),resources:z.array(z.strictObject({amount:positiveSafeInteger,resource:SlopcameraCapabilityResourceSchema})).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.requirements),resume:SlopcameraCapabilityResumeSchema,version:positiveSafeInteger}).superRefine((operation,context)=>{if(operation.key!==`${operation.kind}@${operation.version}`){context.addIssue({code:"custom",path:["key"],message:"Operation key must match kind and version."})}if(new Set(operation.preparation).size!==operation.preparation.length){context.addIssue({code:"custom",path:["preparation"],message:"Operation preparation entries must be unique."})}const resources=operation.resources.map((claim)=>claim.resource);if(new Set(resources).size!==resources.length){context.addIssue({code:"custom",path:["resources"],message:"Operation resource claims must be unique by resource."})}});var SlopcameraCapabilityWorkflowSchema=z.strictObject({id:identifier,inputSchemaId:identifier,key:z.string().min(3).max(256).regex(/^[a-z][a-z0-9]*(?:[-_.][a-z0-9]+)*@[1-9][0-9]*$/u),version:positiveSafeInteger}).superRefine((workflow,context)=>{if(workflow.key!==`${workflow.id}@${workflow.version}`){context.addIssue({code:"custom",path:["key"],message:"Workflow key must match id and version."})}});var SlopcameraCapabilityToolSchema=z.strictObject({destructive:z.boolean(),idempotent:z.boolean(),name:z.string().min(1).max(128).regex(/^[a-z][a-z0-9_]*$/u),openWorld:z.boolean(),readOnly:z.boolean()}).superRefine((tool,context)=>{if(tool.readOnly&&tool.destructive){context.addIssue({code:"custom",message:"A read-only tool cannot be destructive."})}});var SlopcameraCapabilityCommandSchema=z.strictObject({effect:SlopcameraCapabilityEffectSchema,name:commandName});var SlopcameraCapabilityQualificationSchema=z.strictObject({evidence:z.array(z.string().min(1).max(512)).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.evidence),level:z.enum(["unit","fixture","browser","native","provider"]),status:z.enum(["qualified","conditional","not-qualified"])}).superRefine((qualification,context)=>{if(qualification.status!=="not-qualified"&&qualification.evidence.length===0){context.addIssue({code:"custom",path:["evidence"],message:"Qualified or conditional profiles require evidence references."})}});var SlopcameraCapabilityProfileSchema=z.strictObject({id:identifier,kind:z.enum(["renderer","native-adapter","provider","authoring","interchange"]),qualification:SlopcameraCapabilityQualificationSchema,requirements:z.array(z.strictObject({description:z.string().min(1).max(256),id:identifier,optional:z.boolean()})).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.requirements)});var SlopcameraCapabilityModuleDeclarationSchema=z.strictObject({commands:z.array(SlopcameraCapabilityCommandSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.commands),description:z.string().min(1).max(1024),moduleId:z.string().min(1).max(128).regex(/^slopcamera\.capability\.[a-z][a-z0-9-]*$/u),operationKeys:z.array(z.string().min(3).max(256)).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.operations),profiles:z.array(SlopcameraCapabilityProfileSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.profiles),stability:z.enum(["stable","experimental"]),title:z.string().min(1).max(160),toolNames:z.array(z.string().min(1).max(128)).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.tools),trust:z.enum(["portable","local-effects","trusted-authoring","native-adapter","paid-provider"]),version:positiveSafeInteger,workflowKeys:z.array(z.string().min(3).max(256)).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.workflows)}).superRefine((module,context)=>{if(module.commands.length+module.operationKeys.length+module.profiles.length+module.toolNames.length+module.workflowKeys.length===0){context.addIssue({code:"custom",message:"A capability module must expose at least one command, operation, profile, tool, or workflow."})}for(const[name,values]of[["operationKeys",module.operationKeys],["toolNames",module.toolNames],["workflowKeys",module.workflowKeys]]){if(new Set(values).size!==values.length){context.addIssue({code:"custom",path:[name],message:`${name} must be unique within a capability module.`})}}});var SlopcameraCapabilityModuleSchema=z.strictObject({commands:z.array(SlopcameraCapabilityCommandSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.commands),description:z.string().min(1).max(1024),moduleId:z.string().min(1).max(128).regex(/^slopcamera\.capability\.[a-z][a-z0-9-]*$/u),operations:z.array(SlopcameraCapabilityOperationSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.operations),profiles:z.array(SlopcameraCapabilityProfileSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.profiles),stability:z.enum(["stable","experimental"]),title:z.string().min(1).max(160),tools:z.array(SlopcameraCapabilityToolSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.tools),trust:z.enum(["portable","local-effects","trusted-authoring","native-adapter","paid-provider"]),version:positiveSafeInteger,workflows:z.array(SlopcameraCapabilityWorkflowSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.workflows)}).superRefine((module,context)=>{const identities=[["commands",module.commands.map((value)=>value.name)],["operations",module.operations.map((value)=>value.key)],["profiles",module.profiles.map((value)=>value.id)],["tools",module.tools.map((value)=>value.name)],["workflows",module.workflows.map((value)=>value.key)]];if(identities.every(([,values])=>values.length===0)){context.addIssue({code:"custom",message:"A capability module must expose at least one command, operation, profile, tool, or workflow."})}for(const[name,values]of identities){if(new Set(values).size!==values.length)context.addIssue({code:"custom",path:[name],message:`${name} must be unique within a capability module.`})}});var manifestBodyBaseSchema=z.strictObject({host:z.enum(["portable","local"]),kind:z.literal("slopcamera.capability-manifest"),modules:z.array(SlopcameraCapabilityModuleSchema).min(1).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.modules),schemaVersion:z.literal(1),toolVersion:z.string().min(1).max(128)});function validateManifestOwnership(manifest,context){const ownership=new Map;for(const[moduleIndex,module]of manifest.modules.entries()){for(const identity of[module.moduleId,...module.commands.map((value)=>`command:${value.name}`),...module.operations.map((value)=>`operation:${value.key}`),...module.profiles.map((value)=>`profile:${value.id}`),...module.tools.map((value)=>`tool:${value.name}`),...module.workflows.map((value)=>`workflow:${value.key}`)]){const owner=ownership.get(identity);if(owner!==undefined)context.addIssue({code:"custom",path:["modules",moduleIndex],message:`${identity} is owned by both ${owner} and ${module.moduleId}.`});ownership.set(identity,module.moduleId)}if(manifest.host==="portable"&&module.trust!=="portable"){context.addIssue({code:"custom",path:["modules",moduleIndex,"trust"],message:"Portable manifests may contain only portable capability modules."})}}}var manifestBodySchema=manifestBodyBaseSchema.superRefine(validateManifestOwnership);var SlopcameraCapabilityManifestSchema=manifestBodyBaseSchema.extend({manifestSha256:digest}).superRefine(validateManifestOwnership);var compilerInputSchema=z.strictObject({host:z.enum(["portable","local"]),modules:z.array(SlopcameraCapabilityModuleDeclarationSchema).min(1).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.modules),operations:z.array(SlopcameraCapabilityOperationSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.operations),tools:z.array(SlopcameraCapabilityToolSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.tools),toolVersion:z.string().min(1).max(128),workflows:z.array(SlopcameraCapabilityWorkflowSchema).max(SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.workflows)});function compareBy(key){return(left,right)=>left[key].localeCompare(right[key])}function indexed(values,key,label){const result=new Map;for(const value of values){const identity=key(value);if(result.has(identity))throw new TypeError(`Duplicate ${label}: ${identity}.`);result.set(identity,value)}return result}function assertExactOwnership(label,available,owners){for(const key of available.keys()){if(!owners.has(key))throw new TypeError(`Unowned ${label}: ${key}.`)}for(const key of owners.keys()){if(!available.has(key))throw new TypeError(`Unknown ${label} declared by a capability module: ${key}.`)}}function defineSlopcameraCapabilityModule(input){return deepFreezeJson(SlopcameraCapabilityModuleDeclarationSchema.parse(createBoundedJsonValueSnapshot(input,SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.bytes,"capability module").value))}function compileSlopcameraCapabilityManifest(input){const parsed=compilerInputSchema.parse(createBoundedJsonValueSnapshot(input,SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.bytes,"capability manifest compiler input").value);const operations=indexed(parsed.operations,(value)=>value.key,"operation inventory key");const workflows=indexed(parsed.workflows,(value)=>value.key,"workflow inventory key");const tools=indexed(parsed.tools,(value)=>value.name,"tool inventory name");const operationOwners=new Map;const workflowOwners=new Map;const toolOwners=new Map;const moduleIds=new Set;const commandOwners=new Map;const profileOwners=new Map;const claim=(owners,key,moduleId,label)=>{const owner=owners.get(key);if(owner!==undefined)throw new TypeError(`${label} ${key} is owned by both ${owner} and ${moduleId}.`);owners.set(key,moduleId)};const modules=[...parsed.modules].sort(compareBy("moduleId")).map((module)=>{if(moduleIds.has(module.moduleId))throw new TypeError(`Duplicate capability module: ${module.moduleId}.`);moduleIds.add(module.moduleId);for(const command of module.commands)claim(commandOwners,command.name,module.moduleId,"Command");for(const profile of module.profiles)claim(profileOwners,profile.id,module.moduleId,"Profile");const resolvedOperations=module.operationKeys.map((key)=>{claim(operationOwners,key,module.moduleId,"Operation");const value=operations.get(key);if(value===undefined)throw new TypeError(`Unknown operation declared by ${module.moduleId}: ${key}.`);return value}).sort(compareBy("key"));const resolvedWorkflows=module.workflowKeys.map((key)=>{claim(workflowOwners,key,module.moduleId,"Workflow");const value=workflows.get(key);if(value===undefined)throw new TypeError(`Unknown workflow declared by ${module.moduleId}: ${key}.`);return value}).sort(compareBy("key"));const resolvedTools=module.toolNames.map((name)=>{claim(toolOwners,name,module.moduleId,"Tool");const value=tools.get(name);if(value===undefined)throw new TypeError(`Unknown tool declared by ${module.moduleId}: ${name}.`);return value}).sort(compareBy("name"));const{operationKeys:_operationKeys,toolNames:_toolNames,workflowKeys:_workflowKeys,...metadata}=module;return{...metadata,commands:[...module.commands].sort(compareBy("name")),operations:resolvedOperations,profiles:[...module.profiles].sort(compareBy("id")),tools:resolvedTools,workflows:resolvedWorkflows}});assertExactOwnership("operation",operations,operationOwners);assertExactOwnership("workflow",workflows,workflowOwners);assertExactOwnership("tool",tools,toolOwners);const body=manifestBodySchema.parse({host:parsed.host,kind:"slopcamera.capability-manifest",modules,schemaVersion:1,toolVersion:parsed.toolVersion});return deepFreezeJson(SlopcameraCapabilityManifestSchema.parse({...body,manifestSha256:canonicalJsonSha256(body)}))}function parseSlopcameraCapabilityManifest(input){const manifest=SlopcameraCapabilityManifestSchema.parse(createBoundedJsonValueSnapshot(input,SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS.bytes,"capability manifest").value);const{manifestSha256,...body}=manifest;const actual=canonicalJsonSha256(body);if(actual!==manifestSha256)throw new TypeError(`Capability manifest digest mismatch: expected ${manifestSha256}, received ${actual}.`);return deepFreezeJson(manifest)}var SLOPCAMERA_PORTABLE_CAPABILITY_VERSION="slopcamera-portable-v1";var portableModule=defineSlopcameraCapabilityModule({commands:[],description:"The fixed portable diagram and image operation projection for Bun SDK consumers.",moduleId:"slopcamera.capability.portable-diagram-image",operationKeys:PORTABLE_SLOPCAMERA_OPERATION_KINDS.map((kind)=>`${kind}@2`),profiles:[{id:"portable-bun-v1",kind:"authoring",qualification:{evidence:["src/code/public-operations.ts"],level:"unit",status:"qualified"},requirements:[{description:"Bun 1.3.14 or newer.",id:"bun",optional:false}]}],stability:"stable",title:"Portable diagrams and images",toolNames:[],trust:"portable",version:1,workflowKeys:[]});function operationProjection(kind){const operation=PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS[kind];return{cache:operation.policy.cache,cancellable:operation.policy.cancellable,effect:operation.policy.effect,inputSchemaId:operation.inputSchemaId,key:`${operation.kind}@${operation.version}`,kind:operation.kind,lifecycle:operation.lifecycle,maxDurationMs:operation.policy.maxDurationMs,maxFanOut:operation.policy.maxFanOut,maxInputBytes:operation.policy.maxInputBytes,maxOutputBytes:operation.policy.maxOutputBytes,outputSchemaId:operation.outputSchemaId,preparation:[...operation.policy.preparation],resources:operation.policy.resources.map((claim)=>({...claim})),resume:operation.policy.resume,version:operation.version}}function createPortableSlopcameraCapabilityManifest(){return compileSlopcameraCapabilityManifest({host:"portable",modules:[portableModule],operations:PORTABLE_SLOPCAMERA_OPERATION_KINDS.map(operationProjection),tools:[],toolVersion:SLOPCAMERA_PORTABLE_CAPABILITY_VERSION,workflows:[]})}var slopcameraPortableCapabilityManifest=createPortableSlopcameraCapabilityManifest();import{z as z2}from"zod";var slopcameraSceneGalleryLimits=Object.freeze({variants:16,variantsBytes:1024*1024,idEdge:64,labelEdge:256,summaryEdge:256});var variantId=z2.string().min(1).max(slopcameraSceneGalleryLimits.idEdge).regex(/^[a-z0-9][a-z0-9-]*$/u,"Variant ids are lowercase slugs like dusk or golden-hour-2.");var SceneVariantPatchSchema=z2.strictObject({kind:z2.literal("slopcamera.spatial-scene-patch"),schemaVersion:z2.literal(1),expectedSceneSha256:SpatialDigestSchema.optional(),operations:z2.array(SpatialPatchOperationSchema).min(1).max(SPATIAL_SCENE_LIMITS.patchOperations)});var SceneGalleryVariantSchema=z2.strictObject({id:variantId,label:z2.string().min(1).max(slopcameraSceneGalleryLimits.labelEdge).optional(),patch:SceneVariantPatchSchema});var SlopcameraSceneVariantsSchema=z2.strictObject({kind:z2.literal("slopcamera.scene-variants"),schemaVersion:z2.literal(1),variants:z2.array(SceneGalleryVariantSchema).min(1).max(slopcameraSceneGalleryLimits.variants)});function summarizeSceneVariantPatch(operations){const parts=operations.map((operation)=>{const target=("entityId"in operation?operation.entityId:undefined)??("camera"in operation?operation.camera.cameraId:undefined)??("channel"in operation?operation.channel.channelId:undefined)??("asset"in operation?operation.asset.assetId:undefined)??("generator"in operation?operation.generator.generatorId:undefined)??("entity"in operation?operation.entity.entityId:undefined)??("override"in operation?operation.override.entityId:undefined);return target===undefined?operation.kind:`${operation.kind} ${target}`});const summary=parts.join("; ");return summary.length<=slopcameraSceneGalleryLimits.summaryEdge?summary:`${summary.slice(0,slopcameraSceneGalleryLimits.summaryEdge-1)}\u2026`}function parseSlopcameraSceneVariants(input){const value=createBoundedJsonValueSnapshot(input,slopcameraSceneGalleryLimits.variantsBytes,"scene variants").value;const document=parseSpatialValue(SlopcameraSceneVariantsSchema,value,"scene variants");const ids=new Set;for(const variant of document.variants){if(ids.has(variant.id)){throw new SpatialSceneError("invalid-data",`Duplicate scene variant id ${variant.id}.`,"variants")}ids.add(variant.id)}return document.variants}function planSlopcameraSceneGallery(input){const scene=parseSpatialScene(input.scene);const baseSceneSha256=spatialSceneSha256(scene);const specs=parseSlopcameraSceneVariants(input.variants);const variants=specs.map((spec,offset)=>{const expected=spec.patch.expectedSceneSha256??baseSceneSha256;if(expected!==baseSceneSha256){throw new SpatialSceneError("conflict",`Variant ${spec.id} was authored against a different scene revision.`,"variants")}const patch={...spec.patch,expectedSceneSha256:expected};const result=applySpatialScenePatch(scene,patch);return{diff:result.diff,id:spec.id,index:offset+1,label:spec.label??spec.id,patchSha256:spatialValueSha256(patch),prompt:summarizeSceneVariantPatch(patch.operations),scene:result.scene,sceneSha256:result.sceneSha256}});return{baseSceneSha256,scene,variants}}import{z as z4}from"zod";import{z as z3}from"zod";var STUDIO_LIMITS=Object.freeze({documentBytes:32*1024*1024,documentDepth:32,documentValues:500000,sourceFiles:512,sourceBytes:4*1024**3,outputSpecifications:32,outputFiles:25000,outputBytes:64*1024**3,timeoutSeconds:6*60*60,frames:25000,frameIndexExclusive:1e6,dimension:8192,pixels:33554432,parameterBytes:256*1024,parameterDepth:16,parameterValues:20000});function studioDocument(schema,name){return z3.preprocess((value)=>value===undefined?undefined:createBoundedJsonValueSnapshot(value,STUDIO_LIMITS.documentBytes,name,{maximumDepth:STUDIO_LIMITS.documentDepth,maximumValues:STUDIO_LIMITS.documentValues}).value,schema)}function parseStudioValue(schema,input){try{return deepFreezeJson(schema.parse(input))}catch(error){if(error instanceof SlopcameraCodeError)throw error;throw new SlopcameraCodeError("invalid-data",error instanceof z3.ZodError?error.issues[0]?.message??"Invalid studio document.":"Invalid studio document.")}}function studioHash(domain,value){return boundedCanonicalJsonSha256({domain,value},{maximumBytes:STUDIO_LIMITS.documentBytes,maximumDepth:STUDIO_LIMITS.documentDepth+2,maximumValues:STUDIO_LIMITS.documentValues+4})}var studioCompare=compareUtf16Strings;function studioRequire(condition,message){if(!condition)throw new SlopcameraCodeError("invalid-data",message)}function pathKey(path){return path.toLowerCase()}function assertDistinctPaths(paths){const names=new Set(paths.map(pathKey));studioRequire(names.size===paths.length,"Studio paths collide.");for(const name of names){for(let offset=name.indexOf("/");offset!==-1;offset=name.indexOf("/",offset+1)){studioRequire(!names.has(name.slice(0,offset)),"Studio paths use a file as an ancestor.")}}}var StudioDigestSchema=z4.string().regex(/^[a-f0-9]{64}$/u);var StudioEngineSchema=z4.enum(["blender","manim","cadquery"]);var StudioPathSchema=z4.string().min(1).max(1024).refine((path)=>path.normalize("NFC")===path&&!path.startsWith("/")&&!/[\\:\u0000-\u001f\u007f]/u.test(path)&&path.split("/").every((part)=>part!==""&&part!=="."&&part!==".."&&!/[. ]$/u.test(part)),"Studio paths must be normalized, contained POSIX-relative names.");var identifier2=z4.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,127}$/u);var stableId=z4.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/u);var sourceFile=z4.strictObject({path:StudioPathSchema,sha256:StudioDigestSchema,bytes:z4.number().int().safe().nonnegative().max(STUDIO_LIMITS.sourceBytes)});var sourceBundleShape=z4.strictObject({kind:z4.literal("slopcamera.studio-source-bundle"),schemaVersion:z4.literal(1),engine:StudioEngineSchema,entrypoint:z4.discriminatedUnion("kind",[z4.strictObject({kind:z4.literal("python"),path:StudioPathSchema.refine((path)=>path.endsWith(".py"))}),z4.strictObject({kind:z4.literal("blend"),path:StudioPathSchema.refine((path)=>path.endsWith(".blend"))})]),files:z4.array(sourceFile).min(1).max(STUDIO_LIMITS.sourceFiles)}).superRefine((value,context)=>{const issue=(message)=>context.addIssue({code:"custom",message});try{assertDistinctPaths(value.files.map((file)=>file.path))}catch{issue("Source paths must be distinct and cannot have file ancestors.")}if(value.files.reduce((total,file)=>total+file.bytes,0)>STUDIO_LIMITS.sourceBytes)issue("Source bundle exceeds four GiB.");if(!value.files.some((file)=>file.path===value.entrypoint.path&&file.bytes>0))issue("Entrypoint must name a declared nonempty source file.");if(value.entrypoint.kind==="blend"&&value.engine!=="blender")issue("Blend entrypoints require Blender.")});var sourceBundle=sourceBundleShape.transform((value)=>({...value,files:[...value.files].sort((a,b)=>studioCompare(a.path,b.path))})).pipe(sourceBundleShape);var StudioSourceBundleSchema=studioDocument(sourceBundle,"studio source bundle");var parseStudioSourceBundle=(input)=>parseStudioValue(StudioSourceBundleSchema,input);var StudioSourceSpaceSchema=z4.strictObject({units:z4.enum(["meters","millimeters","centimeters"]),upAxis:z4.enum(["x","y","z"]),handedness:z4.enum(["right","left"])});var StudioOutputRoleSchema=z4.enum(["native-source","model","beauty","auxiliary","simulation-cache","audio"]);var StudioOutputFormatSchema=z4.enum(["py","blend","usd","usda","usdc","glb","step","png","exr","mp4","mov","webm","wav","flac","mp3","cache"]);var raster=z4.strictObject({kind:z4.literal("raster"),colorSpace:z4.enum(["srgb","linear-rec709","data","unspecified"]),alpha:z4.enum(["opaque","straight","premultiplied","none"]),dataType:z4.enum(["uint8","uint16","float16","float32"]),channels:z4.array(z4.string().regex(/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/u)).min(1).max(32),semantic:z4.enum(["color","depth","normal","object-id","mask","custom"]),unit:z4.enum(["unitless","meters","millimeters","centimeters"])}).superRefine((value,context)=>{if(new Set(value.channels).size!==value.channels.length)context.addIssue({code:"custom",message:"Raster channels must be unique."});if(value.semantic!=="color"&&value.colorSpace!=="data")context.addIssue({code:"custom",message:"Non-color raster passes must declare data color space."});if(value.semantic==="color"&&value.colorSpace==="data")context.addIssue({code:"custom",message:"Color output cannot declare data color space."});if(value.semantic!=="depth"&&value.unit!=="unitless")context.addIssue({code:"custom",message:"Only depth passes declare distance units."})});var StudioOutputInterpretationSchema=z4.discriminatedUnion("kind",[raster,z4.strictObject({kind:z4.literal("model"),sourceSpace:StudioSourceSpaceSchema}),z4.strictObject({kind:z4.literal("native-source")}),z4.strictObject({kind:z4.literal("cache"),semantics:z4.literal("opaque-native")}),z4.strictObject({kind:z4.literal("audio"),sampleRate:z4.number().int().min(8000).max(384000),channels:z4.number().int().min(1).max(32)})]);var outputCommon={id:stableId,role:StudioOutputRoleSchema,format:StudioOutputFormatSchema,interpretation:StudioOutputInterpretationSchema};var pattern=z4.string().max(1024).refine((value)=>value.split("%06d").length===2&&!value.replace("%06d","").includes("%")&&StudioPathSchema.safeParse(value.replace("%06d","000000")).success,"Sequence paths require exactly one %06d placeholder in a safe relative path.");function compatibleOutput(value){if(value.role==="native-source")return["py","blend"].includes(value.format)&&value.interpretation.kind==="native-source";if(value.role==="model")return["blend","usd","usda","usdc","glb","step"].includes(value.format)&&value.interpretation.kind==="model";if(value.role==="simulation-cache")return value.format==="cache"&&value.interpretation.kind==="cache";if(value.role==="audio")return["wav","flac","mp3"].includes(value.format)&&value.interpretation.kind==="audio";return["png","exr","mp4","mov","webm"].includes(value.format)&&value.interpretation.kind==="raster"&&(value.role!=="beauty"||value.interpretation.semantic==="color")}var StudioOutputSpecSchema=z4.discriminatedUnion("kind",[z4.strictObject({...outputCommon,kind:z4.literal("file"),path:StudioPathSchema}),z4.strictObject({...outputCommon,kind:z4.literal("sequence"),pathPattern:pattern}),z4.strictObject({...outputCommon,kind:z4.literal("directory"),path:StudioPathSchema})]).superRefine((value,context)=>{const issue=(message)=>context.addIssue({code:"custom",message});if(!compatibleOutput(value))issue("Output role, format, and interpretation disagree.");if(value.kind==="directory"!==(value.format==="cache"))issue("Only native cache outputs use directory declarations.");if(value.kind==="sequence"&&!["png","exr"].includes(value.format))issue("Numbered sequences support PNG or EXR only.");if(value.kind!=="directory"){const path=value.kind==="sequence"?value.pathPattern:value.path;if(!path.endsWith(`.${value.format}`)&&!(value.format==="step"&&path.endsWith(".stp")))issue("Output extension must agree with its declared format.")}if(value.interpretation.kind==="raster"){if(value.format==="png"&&!["uint8","uint16"].includes(value.interpretation.dataType))issue("PNG declares integer sample data.");if(value.format==="exr"&&!["float16","float32"].includes(value.interpretation.dataType))issue("The admitted EXR profile declares floating point sample data.")}});var frameRateShape=z4.strictObject({numerator:z4.number().int().min(1).max(1e6),denominator:z4.number().int().min(1).max(1e6)}).refine((value)=>value.numerator/value.denominator<=240,"Studio cadence exceeds 240 fps.");var frameRate=frameRateShape.transform((value)=>{let{numerator:a,denominator:b}=value;while(b!==0){const remainder=a%b;a=b;b=remainder}return{numerator:value.numerator/a,denominator:value.denominator/a}}).pipe(frameRateShape);var StudioRenderSchema=z4.strictObject({width:z4.number().int().min(1).max(STUDIO_LIMITS.dimension),height:z4.number().int().min(1).max(STUDIO_LIMITS.dimension),frameRate,startFrame:z4.number().int().nonnegative().max(STUDIO_LIMITS.frameIndexExclusive-1),endFrameExclusive:z4.number().int().positive().max(STUDIO_LIMITS.frameIndexExclusive)}).refine((value)=>value.endFrameExclusive>value.startFrame&&value.endFrameExclusive-value.startFrame<=STUDIO_LIMITS.frames&&value.width*value.height<=STUDIO_LIMITS.pixels,"Render requires a bounded, nonempty half-open frame interval and pixel area.");var StudioEngineOptionsSchema=z4.discriminatedUnion("engine",[z4.strictObject({engine:z4.literal("blender"),renderer:z4.enum(["cycles","eevee"]),device:z4.enum(["cpu","gpu"]),samples:z4.number().int().min(1).max(4096),transparent:z4.boolean(),viewTransform:z4.enum(["AgX","Standard"]),denoise:z4.boolean(),seed:z4.number().int().min(0).max(4294967295)}),z4.strictObject({engine:z4.literal("manim"),scene:identifier2,renderer:z4.literal("cairo"),transparent:z4.boolean()}),z4.strictObject({engine:z4.literal("cadquery"),exportVariable:identifier2,tolerance:z4.number().finite().positive().max(1),angularTolerance:z4.number().finite().positive().max(Math.PI)})]);var parameters=z4.preprocess((value)=>value===undefined?undefined:createBoundedJsonValueSnapshot(value,STUDIO_LIMITS.parameterBytes,"studio parameters",{maximumDepth:STUDIO_LIMITS.parameterDepth,maximumValues:STUDIO_LIMITS.parameterValues}).value,z4.record(z4.string(),z4.unknown()));var StudioExecutionProfileSchema=z4.strictObject({trust:z4.literal("trusted-current-user"),isolation:z4.literal("none"),hermetic:z4.literal(false)});var jobShape=z4.strictObject({kind:z4.literal("slopcamera.studio-job"),schemaVersion:z4.literal(1),jobId:z4.string().regex(/^studio_[a-zA-Z0-9][a-zA-Z0-9_-]{0,120}$/u),bundleSha256:StudioDigestSchema,stage:z4.enum(["build","bake","render"]),parameters,engine:StudioEngineOptionsSchema,render:StudioRenderSchema.optional(),outputs:z4.array(StudioOutputSpecSchema).min(1).max(STUDIO_LIMITS.outputSpecifications),limits:z4.strictObject({timeoutSeconds:z4.number().int().min(1).max(STUDIO_LIMITS.timeoutSeconds),maximumOutputBytes:z4.number().int().safe().min(1).max(STUDIO_LIMITS.outputBytes),maximumOutputFiles:z4.number().int().min(1).max(STUDIO_LIMITS.outputFiles)}),execution:StudioExecutionProfileSchema}).superRefine((value,context)=>{if(value.render===undefined&&(value.stage==="render"&&value.engine.engine!=="cadquery"||value.outputs.some((output)=>output.kind==="sequence"||output.interpretation.kind==="raster")))context.addIssue({code:"custom",message:"Raster outputs, render stage, and numbered sequences require explicit dimensions and a frame interval."});if(new Set(value.outputs.map((output)=>output.id)).size!==value.outputs.length)context.addIssue({code:"custom",message:"Output IDs must be unique."});const count=value.outputs.reduce((sum,output)=>sum+(output.kind==="sequence"&&value.render!==undefined?value.render.endFrameExclusive-value.render.startFrame:1),0);if(count>value.limits.maximumOutputFiles)context.addIssue({code:"custom",message:"Declared outputs exceed the job's output-file limit."})});var job=jobShape.transform((value)=>({...value,outputs:[...value.outputs].sort((a,b)=>studioCompare(a.id,b.id))})).pipe(jobShape);var StudioJobSchema=studioDocument(job,"studio job");var parseStudioJob=(input)=>parseStudioValue(StudioJobSchema,input);var StudioCapabilityNameSchema=z4.enum(["python-authoring","blend-authoring","build","bake","render","gpu-render","image-sequence","beauty-video","model-export","auxiliary-passes","native-cache","audio-output"]);var capability=z4.strictObject({name:StudioCapabilityNameSchema,support:z4.enum(["available","unavailable","unverified"]),evidence:z4.enum(["probe","qualification"]),receiptSha256:StudioDigestSchema.optional()}).refine((value)=>value.evidence!=="qualification"||value.receiptSha256!==undefined,"Qualification evidence requires a retained receipt digest.");var runtimeShape=z4.strictObject({kind:z4.literal("slopcamera.studio-runtime"),schemaVersion:z4.literal(1),engine:StudioEngineSchema,tool:z4.strictObject({name:z4.string().min(1).max(128),version:z4.string().min(1).max(512),executableSha256:StudioDigestSchema}),driverSha256:StudioDigestSchema,environment:z4.strictObject({fingerprintSha256:StudioDigestSchema,evidence:z4.literal("observed-package-environment"),hermetic:z4.literal(false)}),capabilities:z4.array(capability).max(12)}).refine((value)=>new Set(value.capabilities.map((item)=>item.name)).size===value.capabilities.length,"Runtime capability names must be unique.");var runtime=runtimeShape.transform((value)=>({...value,capabilities:[...value.capabilities].sort((a,b)=>studioCompare(a.name,b.name))})).pipe(runtimeShape);var StudioRuntimeIdentitySchema=studioDocument(runtime,"studio runtime identity");var parseStudioRuntimeIdentity=(input)=>parseStudioValue(StudioRuntimeIdentitySchema,input);var StudioOutputArtifactSchema=z4.strictObject({outputId:stableId,path:StudioPathSchema,sha256:StudioDigestSchema,bytes:z4.number().int().safe().positive().max(STUDIO_LIMITS.outputBytes),role:StudioOutputRoleSchema,format:StudioOutputFormatSchema,frame:z4.number().int().nonnegative().max(STUDIO_LIMITS.frameIndexExclusive-1).optional()});import{z as z5}from"zod";var studioSourceBundleSha256=(input)=>studioHash("slopcamera.studio-source-bundle/v1",parseStudioSourceBundle(input));var studioJobSha256=(input)=>studioHash("slopcamera.studio-job/v1",parseStudioJob(input));var studioRuntimeSha256=(input)=>studioHash("slopcamera.studio-runtime/v1",parseStudioRuntimeIdentity(input));function studioOutputPath(output,frame){if(output.kind==="sequence"){studioRequire(Number.isInteger(frame)&&frame>=0&&frame<STUDIO_LIMITS.frameIndexExclusive,"Sequence output requires an admitted frame index.");return output.pathPattern.replace("%06d",String(frame).padStart(6,"0"))}studioRequire(frame===undefined,"Only sequence outputs have a frame index.");return output.path}function declaration(job2){const files=[];const directories=[];for(const output of job2.outputs){if(output.kind==="directory")directories.push({id:output.id,path:output.path});else if(output.kind==="file")files.push({id:output.id,path:output.path});else{studioRequire(job2.render!==undefined,"Sequence requires a render interval.");for(let frame=job2.render.startFrame;frame<job2.render.endFrameExclusive;frame++)files.push({id:output.id,path:studioOutputPath(output,frame),frame})}}studioRequire(files.length+directories.length<=job2.limits.maximumOutputFiles,"Declared outputs exceed the output-file budget.");assertDistinctPaths([...files,...directories].map((item)=>item.path));return{files,directories}}function requiredCapabilities(bundle,job2){const values=new Set([bundle.entrypoint.kind==="blend"?"blend-authoring":"python-authoring",job2.stage]);if(job2.engine.engine==="blender"&&job2.engine.device==="gpu"&&job2.stage==="render")values.add("gpu-render");for(const output of job2.outputs){if(output.kind==="sequence")values.add("image-sequence");if(output.role==="beauty"&&["mov","mp4","webm"].includes(output.format))values.add("beauty-video");if(output.role==="model")values.add("model-export");if(output.role==="auxiliary")values.add("auxiliary-passes");if(output.role==="simulation-cache")values.add("native-cache");if(output.role==="audio")values.add("audio-output")}return[...values].sort(studioCompare)}function derivePlan(input){const{bundle,job:job2,runtime:runtime2}=input;const bundleSha256=studioSourceBundleSha256(bundle),jobSha256=studioJobSha256(job2);studioRequire(bundleSha256===job2.bundleSha256,"Job does not bind the exact source bundle.");studioRequire(bundle.engine===job2.engine.engine&&(runtime2===undefined||runtime2.engine===bundle.engine),"Bundle, job, and runtime must use one engine.");studioRequire(bundle.entrypoint.kind!=="blend"||job2.stage==="render","Blend entrypoints support render stage only; explicit Python authoring owns builds and bakes.");const declared=declaration(job2),required=requiredCapabilities(bundle,job2);const capabilityChecks=required.map((name)=>({name,support:runtime2===undefined?"unbound":runtime2.capabilities.find((item)=>item.name===name)?.support??"unverified"}));const readiness=runtime2===undefined?"runtime-unbound":capabilityChecks.some((item)=>item.support==="unavailable")?"capability-unavailable":capabilityChecks.some((item)=>item.support==="unverified")?"capability-unverified":"authorization-required";const body={kind:"slopcamera.studio-plan",schemaVersion:1,bundle,job:job2,...runtime2===undefined?{}:{runtime:runtime2,runtimeSha256:studioRuntimeSha256(runtime2)},bundleSha256,jobSha256,sourceBytes:bundle.files.reduce((total,file)=>total+file.bytes,0),frameCount:job2.render===undefined?0:job2.render.endFrameExclusive-job2.render.startFrame,outputCount:{minimum:declared.files.length+declared.directories.length,maximum:declared.directories.length===0?declared.files.length:job2.limits.maximumOutputFiles},requiredCapabilities:required,capabilityChecks,readiness};return{...body,planSha256:studioHash("slopcamera.studio-plan/v1",body)}}var plan=z5.strictObject({kind:z5.literal("slopcamera.studio-plan"),schemaVersion:z5.literal(1),bundle:StudioSourceBundleSchema,job:StudioJobSchema,runtime:StudioRuntimeIdentitySchema.optional(),runtimeSha256:StudioDigestSchema.optional(),bundleSha256:StudioDigestSchema,jobSha256:StudioDigestSchema,planSha256:StudioDigestSchema,sourceBytes:z5.number().int().safe().nonnegative().max(STUDIO_LIMITS.sourceBytes),frameCount:z5.number().int().nonnegative().max(STUDIO_LIMITS.frames),outputCount:z5.strictObject({minimum:z5.number().int().positive().max(STUDIO_LIMITS.outputFiles),maximum:z5.number().int().positive().max(STUDIO_LIMITS.outputFiles)}),requiredCapabilities:z5.array(StudioCapabilityNameSchema).min(1).max(12),capabilityChecks:z5.array(z5.strictObject({name:StudioCapabilityNameSchema,support:z5.enum(["available","unavailable","unverified","unbound"])})).min(1).max(12),readiness:z5.enum(["runtime-unbound","capability-unavailable","capability-unverified","authorization-required"])}).superRefine((value,context)=>{try{const derived=derivePlan({bundle:value.bundle,job:value.job,...value.runtime===undefined?{}:{runtime:value.runtime}});if(canonicalJson(derived)!==canonicalJson(value))context.addIssue({code:"custom",message:"Studio plan differs from its canonical source, job, runtime, or admission derivation."})}catch(error){context.addIssue({code:"custom",message:error instanceof Error?error.message:"Invalid studio plan."})}});var StudioPlanSchema=studioDocument(plan,"studio plan");var parseStudioPlan=(input)=>parseStudioValue(StudioPlanSchema,input);function planStudioJob(input){const captured=parseStudioValue(studioDocument(z5.strictObject({bundle:StudioSourceBundleSchema,job:StudioJobSchema,runtime:StudioRuntimeIdentitySchema.optional()}),"studio planning input"),input);return parseStudioPlan(derivePlan(captured))}var failure2=z5.strictObject({code:z5.enum(["subprocess","cancelled","deadline","validation","custody","publication","unavailable"]),message:z5.string().min(1).max(2048)});var receiptCommon={kind:z5.literal("slopcamera.studio-receipt"),schemaVersion:z5.literal(1),jobId:z5.string().regex(/^studio_[a-zA-Z0-9][a-zA-Z0-9_-]{0,120}$/u),attemptId:z5.string().regex(/^attempt_[a-zA-Z0-9][a-zA-Z0-9_-]{0,120}$/u),planSha256:StudioDigestSchema,bundleSha256:StudioDigestSchema,jobSha256:StudioDigestSchema,runtime:StudioRuntimeIdentitySchema,runtimeSha256:StudioDigestSchema,startedAt:z5.iso.datetime({offset:true}),finishedAt:z5.iso.datetime({offset:true}),outputs:z5.array(StudioOutputArtifactSchema).max(STUDIO_LIMITS.outputFiles)};var receiptShape=z5.discriminatedUnion("state",[z5.strictObject({...receiptCommon,state:z5.literal("succeeded"),custody:z5.literal("closed"),exitCode:z5.literal(0)}),z5.strictObject({...receiptCommon,state:z5.literal("failed"),custody:z5.literal("closed"),exitCode:z5.number().int().min(-255).max(255).nullable(),failure:failure2}),z5.strictObject({...receiptCommon,state:z5.literal("unknown-custody"),custody:z5.literal("unknown"),exitCode:z5.number().int().min(-255).max(255).nullable(),failure:failure2})]).superRefine((value,context)=>{if(studioRuntimeSha256(value.runtime)!==value.runtimeSha256)context.addIssue({code:"custom",message:"Receipt runtime digest differs from its evidence."});if(Date.parse(value.finishedAt)<Date.parse(value.startedAt))context.addIssue({code:"custom",message:"Receipt finishes before it starts."});try{assertDistinctPaths(value.outputs.map((item)=>item.path))}catch{context.addIssue({code:"custom",message:"Receipt output paths collide."})}if(value.outputs.reduce((sum,item)=>sum+item.bytes,0)>STUDIO_LIMITS.outputBytes)context.addIssue({code:"custom",message:"Receipt exceeds the global output byte bound."})});var receipt=receiptShape.transform((value)=>({...value,outputs:[...value.outputs].sort((a,b)=>studioCompare(a.path,b.path))})).pipe(receiptShape);var StudioReceiptSchema=studioDocument(receipt,"studio receipt");var parseStudioReceipt=(input)=>parseStudioValue(StudioReceiptSchema,input);function validateStudioReceipt(input){const captured=parseStudioValue(studioDocument(z5.strictObject({plan:StudioPlanSchema,receipt:StudioReceiptSchema}),"studio receipt validation input"),input);const{plan:plan2,receipt:receipt2}=captured;studioRequire(receipt2.jobId===plan2.job.jobId&&receipt2.planSha256===plan2.planSha256&&receipt2.jobSha256===plan2.jobSha256&&receipt2.bundleSha256===plan2.bundleSha256,"Receipt identity differs from the exact planned job.");studioRequire(plan2.runtime!==undefined&&receipt2.runtimeSha256===plan2.runtimeSha256&&canonicalJson(receipt2.runtime)===canonicalJson(plan2.runtime),"Execution receipt requires the exact planned runtime binding.");if(receipt2.state==="succeeded")studioRequire(plan2.readiness==="authorization-required","A successful receipt requires available observed runtime capabilities; consent remains host-owned.");studioRequire(receipt2.outputs.length<=plan2.job.limits.maximumOutputFiles&&receipt2.outputs.reduce((total,output)=>total+output.bytes,0)<=plan2.job.limits.maximumOutputBytes,"Receipt exceeds the planned output budget.");const declared=declaration(plan2.job),expected=new Map(declared.files.map((file)=>[file.path,file]));const counts=new Map;for(const artifact of receipt2.outputs){const specification=plan2.job.outputs.find((output)=>output.id===artifact.outputId);studioRequire(specification!==undefined,"Receipt contains an undeclared output ID.");studioRequire(artifact.role===specification.role&&artifact.format===specification.format,"Receipt output role or format differs from its declaration.");if(specification.kind==="directory"){studioRequire(artifact.path.startsWith(`${specification.path}/`)&&artifact.frame===undefined,"Cache artifact must be a file inside its declared directory.")}else{const wanted=expected.get(artifact.path);studioRequire(wanted!==undefined&&wanted.id===artifact.outputId&&artifact.frame===wanted.frame,"Receipt contains an undeclared file or incorrect frame index.");expected.delete(artifact.path)}counts.set(artifact.outputId,(counts.get(artifact.outputId)??0)+1)}if(receipt2.state==="succeeded"){studioRequire(expected.size===0&&declared.directories.every((directory)=>(counts.get(directory.id)??0)>0),"Successful receipt must cover every declared file, frame, and cache directory.")}return deepFreezeJson(receipt2)}function inspectStudioBundle(input){const bundle=parseStudioSourceBundle(input);return deepFreezeJson({engine:bundle.engine,entrypoint:bundle.entrypoint,bundleSha256:studioSourceBundleSha256(bundle),files:bundle.files.length,sourceBytes:bundle.files.reduce((total,file)=>total+file.bytes,0),executed:false,dependencyDiscovery:"explicit-files-only"})}function inspectStudioPlan(input){const plan2=parseStudioPlan(input);return deepFreezeJson({jobId:plan2.job.jobId,stage:plan2.job.stage,engine:plan2.job.engine.engine,planSha256:plan2.planSha256,sourceBytes:plan2.sourceBytes,frameCount:plan2.frameCount,outputCount:plan2.outputCount,readiness:plan2.readiness,capabilityChecks:plan2.capabilityChecks,execution:plan2.job.execution,limits:plan2.job.limits,executed:false,outputs:plan2.job.outputs.map((output)=>({id:output.id,role:output.role,format:output.format,kind:output.kind,path:output.kind==="sequence"?output.pathPattern:output.path}))})}var slopcameraApi=Object.freeze({artifactSummary,builtInIcons,bundledSkillPath,checkDiagramFile,defineSlopcameraWorkflow,DiagramValidationError,generateSlopcameraImage,generateSlopcameraImageFile,generateSlopcameraImageGallery,generateSlopcameraIcon,slopcameraGatewayCredentialStatus,slopcameraMcpProtocolVersion,slopcameraMcpServerName,slopcameraMcpTools,slopcameraOperationRegistry,SlopcameraMcpToolRuntime,installSkill,lintDiagram,mcpMaximumRenderedPixels,mcpMaximumScale,mcpSourceByteLimit,parseDiagramSource,parseDiagramSpec,readDiagramFile,renderDiagramFile,renderPng,renderSvg,resolveEdge,resolveDiagramSource,resolveStackLayout,runSlopcameraWorkflow,runMcpServer,searchSlopcameraOperations,serializeTldr,stackLayoutDefaults,StackLayoutError,SlopcameraWorkflowError,vectorizeImage,WorkspaceBoundary,WorkspaceBoundaryError,executeSlopcameraOperation});var diagramApi=slopcameraApi;export{readDiagramFile,checkDiagramFile,renderDiagramFile,artifactSummary,mcpSourceByteLimit,WorkspaceBoundaryError,WorkspaceBoundary,mcpMaximumScale,mcpMaximumRenderedPixels,slopcameraMcpTools,SlopcameraMcpToolRuntime,SLOPCAMERA_VERSION,slopcameraMcpProtocolVersion,slopcameraMcpServerName,runMcpServer,SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS,SlopcameraCapabilityEffectSchema,SlopcameraCapabilityResumeSchema,SlopcameraCapabilityResourceSchema,SlopcameraCapabilityPreparationSchema,SlopcameraCapabilityOperationSchema,SlopcameraCapabilityWorkflowSchema,SlopcameraCapabilityToolSchema,SlopcameraCapabilityCommandSchema,SlopcameraCapabilityQualificationSchema,SlopcameraCapabilityProfileSchema,SlopcameraCapabilityModuleDeclarationSchema,SlopcameraCapabilityModuleSchema,SlopcameraCapabilityManifestSchema,defineSlopcameraCapabilityModule,compileSlopcameraCapabilityManifest,parseSlopcameraCapabilityManifest,SLOPCAMERA_PORTABLE_CAPABILITY_VERSION,createPortableSlopcameraCapabilityManifest,slopcameraPortableCapabilityManifest,slopcameraSceneGalleryLimits,SlopcameraSceneVariantsSchema,summarizeSceneVariantPatch,parseSlopcameraSceneVariants,planSlopcameraSceneGallery,STUDIO_LIMITS,StudioDigestSchema,StudioEngineSchema,StudioPathSchema,StudioSourceBundleSchema,parseStudioSourceBundle,StudioSourceSpaceSchema,StudioOutputRoleSchema,StudioOutputFormatSchema,StudioOutputInterpretationSchema,StudioOutputSpecSchema,StudioRenderSchema,StudioEngineOptionsSchema,StudioExecutionProfileSchema,StudioJobSchema,parseStudioJob,StudioCapabilityNameSchema,StudioRuntimeIdentitySchema,parseStudioRuntimeIdentity,StudioOutputArtifactSchema,studioSourceBundleSha256,studioJobSha256,studioRuntimeSha256,studioOutputPath,StudioPlanSchema,parseStudioPlan,planStudioJob,StudioReceiptSchema,parseStudioReceipt,validateStudioReceipt,inspectStudioBundle,inspectStudioPlan,slopcameraApi,diagramApi};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{cp,mkdir,rm}from"fs/promises";import{homedir}from"os";import{dirname,join,resolve}from"path";import{fileURLToPath}from"url";import{access}from"fs/promises";async function pathExists(filePath){try{await access(filePath);return true}catch{return false}}function bundledSkillPath(){return resolve(dirname(fileURLToPath(import.meta.url)),"../skills/slopcamera")}function targetRoot(target,scope,projectDirectory){const directory=target==="codex"?".codex":target==="claude"?".claude":".agents";return scope==="user"?join(homedir(),directory,"skills"):join(projectDirectory,directory,"skills")}async function installSkill(options){const source=bundledSkillPath();if(!await pathExists(source))throw new Error(`Bundled skill is missing: ${source}`);const root=targetRoot(options.target,options.scope,resolve(options.projectDirectory??process.cwd()));const legacy=join(root,"diagram");if(await pathExists(legacy)){throw new Error(`Legacy diagram skill found at ${legacy}. Remove or move that directory, then rerun "slopcamera skill install --target ${options.target} --scope ${options.scope}". Slopcamera will not install both skills side by side.`)}const destination=join(root,"slopcamera");if(await pathExists(destination)){if(!options.force){throw new Error(`Skill already exists at ${destination}; pass --force to replace it`)}await rm(destination,{recursive:true,force:true})}await mkdir(dirname(destination),{recursive:true});await cp(source,destination,{recursive:true,errorOnExist:true});return destination}
3
+ export{pathExists,bundledSkillPath,installSkill};
@@ -0,0 +1,10 @@
1
+ // @bun
2
+ var vectorizeProfileNames=["balanced","detailed","photo"];class VectorizeError extends Error{code;details;constructor(code,message,details={},options){super(message,options);this.name="VectorizeError";this.code=code;this.details=details}}var vectorizeHardLimits=Object.freeze({maxDecodedPixels:16777216,maxDimension:4096,maxDurationMs:120000,maxInputBytes:16*1024*1024,maxOutputBytes:2000000,maxPaths:12000});var vectorizeDefaultLimits=Object.freeze({...vectorizeHardLimits,maxDurationMs:30000});var limitNames=Object.keys(vectorizeHardLimits);function resolveVectorizeLimits(input){const resolved={maxDecodedPixels:input?.maxDecodedPixels??vectorizeDefaultLimits.maxDecodedPixels,maxDimension:input?.maxDimension??vectorizeDefaultLimits.maxDimension,maxDurationMs:input?.maxDurationMs??vectorizeDefaultLimits.maxDurationMs,maxInputBytes:input?.maxInputBytes??vectorizeDefaultLimits.maxInputBytes,maxOutputBytes:input?.maxOutputBytes??vectorizeDefaultLimits.maxOutputBytes,maxPaths:input?.maxPaths??vectorizeDefaultLimits.maxPaths};for(const name of limitNames){const value=resolved[name];const hardLimit=vectorizeHardLimits[name];if(!Number.isInteger(value)||value<1||value>hardLimit){throw new VectorizeError("invalid_input",`${name} must be a positive integer no greater than ${hardLimit}.`,{hardLimit,name,value})}}return Object.freeze(resolved)}class VectorizeDeadline{#deadline;constructor(durationMs){this.#deadline=performance.now()+durationMs}assert(stage){if(this.remainingMs()<=0){throw new VectorizeError("timeout",`Vectorization timed out during ${stage}.`,{stage})}}remainingMs(){return Math.max(0,Math.ceil(this.#deadline-performance.now()))}}import{constants}from"fs";import{open,realpath}from"fs/promises";import{resolve}from"path";import sharp from"sharp";import{createHash}from"crypto";function sha256(input){return createHash("sha256").update(input).digest("hex")}function sanitizedTraceRgba(rgba,minimumAlpha){if(rgba.length===0||rgba.length%4!==0){throw new VectorizeError("invalid_input","Trace sanitation requires nonempty RGBA pixels.")}if(!Number.isInteger(minimumAlpha)||minimumAlpha<1||minimumAlpha>64){throw new VectorizeError("invalid_input","alphaCutoff must be an integer from 1 through 64.")}const sanitized=Uint8Array.from(rgba);for(let index=0;index<sanitized.length;index+=4){if(sanitized[index+3]>=minimumAlpha)continue;sanitized[index]=0;sanitized[index+1]=0;sanitized[index+2]=0;sanitized[index+3]=0}return sanitized}function alphaPlaneTraceRgba(rgba){if(rgba.length===0||rgba.length%4!==0){throw new VectorizeError("invalid_input","An alpha trace requires nonempty RGBA pixels.")}const grayscale=new Uint8Array(rgba.length);for(let index=0;index<rgba.length;index+=4){const alpha=rgba[index+3];grayscale[index]=alpha;grayscale[index+1]=alpha;grayscale[index+2]=alpha;grayscale[index+3]=255}return grayscale}function lowAlphaMassRatio(rgba,cutoff){if(rgba.length===0||rgba.length%4!==0){throw new VectorizeError("invalid_input","Low-alpha measurement requires nonempty RGBA pixels.")}if(!Number.isInteger(cutoff)||cutoff<1||cutoff>255){throw new VectorizeError("invalid_input","The low-alpha cutoff must be a byte.")}let lowAlphaMass=0;let visibleAlphaMass=0;for(let index=3;index<rgba.length;index+=4){const alpha=rgba[index];visibleAlphaMass+=alpha;if(alpha>0&&alpha<cutoff)lowAlphaMass+=alpha}return visibleAlphaMass===0?0:lowAlphaMass/visibleAlphaMass}function hasFractionalAlpha(rgba){for(let index=3;index<rgba.length;index+=4){const alpha=rgba[index];if(alpha>0&&alpha<255)return true}return false}function normalizedPremultipliedRmse(source,candidate){assertComparableRgba(source,candidate,"RMSE");let squaredError=0;for(let index=0;index<source.length;index+=4){const sourceAlpha=source[index+3]/255;const candidateAlpha=candidate[index+3]/255;for(let channel=0;channel<3;channel+=1){const difference=source[index+channel]*sourceAlpha-candidate[index+channel]*candidateAlpha;squaredError+=difference*difference}const alphaDifference=source[index+3]-candidate[index+3];squaredError+=alphaDifference*alphaDifference}return Math.sqrt(squaredError/source.length)/255}function normalizedAlphaRmse(source,candidate){assertComparableRgba(source,candidate,"Alpha RMSE");let squaredError=0;for(let index=3;index<source.length;index+=4){const difference=source[index]-candidate[index];squaredError+=difference*difference}return Math.sqrt(squaredError/(source.length/4))/255}function assertComparableRgba(source,candidate,label){if(source.length===0||source.length!==candidate.length||source.length%4!==0){throw new VectorizeError("invalid_input",`${label} inputs must be equally sized nonempty RGBA buffers.`)}}function measureSupport(source,candidate,width,height,dilation=1){if(!Number.isInteger(width)||!Number.isInteger(height)||width<1||height<1||source.length!==width*height*4||candidate.length!==source.length){throw new VectorizeError("invalid_input","Support metrics require equally sized rectangular RGBA buffers.")}if(!Number.isInteger(dilation)||dilation<0||dilation>4){throw new VectorizeError("invalid_input","Support dilation must be an integer from 0 to 4.")}const support=new Uint8Array(width*height);for(let y=0;y<height;y+=1){for(let x=0;x<width;x+=1){let covered=false;for(let dy=-dilation;dy<=dilation&&!covered;dy+=1){for(let dx=-dilation;dx<=dilation;dx+=1){const neighborX=x+dx;const neighborY=y+dy;if(neighborX>=0&&neighborX<width&&neighborY>=0&&neighborY<height&&source[(neighborY*width+neighborX)*4+3]>0){covered=true;break}}}support[y*width+x]=covered?1:0}}let candidateAlphaMass=0;let outsideAlphaMass=0;let recalledAlphaMass=0;let sourceAlphaMass=0;for(let pixel=0;pixel<width*height;pixel+=1){const sourceAlpha=source[pixel*4+3]/255;const candidateAlpha=candidate[pixel*4+3]/255;sourceAlphaMass+=sourceAlpha;candidateAlphaMass+=candidateAlpha;recalledAlphaMass+=Math.min(sourceAlpha,candidateAlpha);if(support[pixel]===0)outsideAlphaMass+=candidateAlpha}if(sourceAlphaMass===0||candidateAlphaMass===0){throw new VectorizeError("quality_limit","Source and candidate must contain visible pixels.")}return{outsideAlphaRatio:outsideAlphaMass/candidateAlphaMass,supportRecall:recalledAlphaMass/sourceAlphaMass}}function parseHexColor(value){const shorthand=value.match(/^#([a-f0-9])([a-f0-9])([a-f0-9])$/iu);if(shorthand!==null){return[Number.parseInt(`${shorthand[1]}${shorthand[1]}`,16),Number.parseInt(`${shorthand[2]}${shorthand[2]}`,16),Number.parseInt(`${shorthand[3]}${shorthand[3]}`,16)]}const full=value.match(/^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/iu);if(full===null){throw new VectorizeError("invalid_input",`Expected a #rgb or #rrggbb color, received ${JSON.stringify(value)}.`)}return[Number.parseInt(full[1],16),Number.parseInt(full[2],16),Number.parseInt(full[3],16)]}function normalizedHexColor(value){return`#${parseHexColor(value).map((channel)=>channel.toString(16).padStart(2,"0")).join("")}`}function srgbToOklab([red,green,blue]){const linear=(channel)=>{const value=channel/255;return value<=0.04045?value/12.92:((value+0.055)/1.055)**2.4};const r=linear(red);const g=linear(green);const b=linear(blue);const l=Math.cbrt(0.4122214708*r+0.5363325363*g+0.0514459929*b);const m=Math.cbrt(0.2119034982*r+0.6806995451*g+0.1073969566*b);const s=Math.cbrt(0.0883024619*r+0.2817188376*g+0.6299787005*b);return[0.2104542553*l+0.793617785*m-0.0040720468*s,1.9779984951*l-2.428592205*m+0.4505937099*s,0.0259040371*l+0.7827717662*m-0.808675766*s]}function oklabDistance(left,right){return Math.hypot(left[0]-right[0],left[1]-right[1],left[2]-right[2])}function otsuDistanceCutoff(colors,primary){const distances=colors.map(({color,mass})=>({distance:oklabDistance(color,primary),mass}));const maximum=Math.max(...distances.map(({distance})=>distance));if(maximum===0)return Number.POSITIVE_INFINITY;const histogram=Array.from({length:256},()=>({mass:0,moment:0}));for(const{distance,mass}of distances){const index=Math.min(255,Math.floor(distance/maximum*255));histogram[index].mass+=mass;histogram[index].moment+=mass*distance}const totalMass=histogram.reduce((sum,bin)=>sum+bin.mass,0);const totalMoment=histogram.reduce((sum,bin)=>sum+bin.moment,0);let nearMass=0;let nearMoment=0;let bestScore=-1;let bestIndex=254;for(let index=0;index<255;index+=1){const bin=histogram[index];nearMass+=bin.mass;nearMoment+=bin.moment;const farMass=totalMass-nearMass;if(nearMass===0||farMass===0)continue;const nearMean=nearMoment/nearMass;const farMean=(totalMoment-nearMoment)/farMass;const score=nearMass*farMass*(nearMean-farMean)**2;if(score>bestScore){bestScore=score;bestIndex=index}}let cutoff=maximum*(bestIndex+1)/255;const nearShare=()=>distances.reduce((sum,{distance,mass})=>sum+(distance<=cutoff?mass:0),0)/totalMass;if(nearShare()<0.5){let cumulativeMass=0;for(const{distance,mass}of[...distances].sort((left,right)=>left.distance-right.distance)){cumulativeMass+=mass;cutoff=distance;if(cumulativeMass>=totalMass/2)break}}return cutoff}function dominantOklabDuotoneModel(rgba){if(rgba.length===0||rgba.length%4!==0){throw new VectorizeError("invalid_input","A duotone model requires nonempty RGBA pixels.")}const bins=new Map;for(let index=0;index<rgba.length;index+=4){const alpha=rgba[index+3]/255;if(alpha===0)continue;const red=rgba[index];const green=rgba[index+1];const blue=rgba[index+2];const key=red>>4<<8|green>>4<<4|blue>>4;const bin=bins.get(key)??{blue:0,green:0,mass:0,red:0};bin.mass+=alpha;bin.red+=red*alpha;bin.green+=green*alpha;bin.blue+=blue*alpha;bins.set(key,bin)}if(bins.size===0){throw new VectorizeError("invalid_input","A duotone model requires visible pixels.")}const colors=[...bins.entries()].map(([key,bin])=>({color:srgbToOklab([bin.red/bin.mass,bin.green/bin.mass,bin.blue/bin.mass]),key,mass:bin.mass})).sort((left,right)=>right.mass-left.mass||left.key-right.key);const primary=colors[0].color;const cutoff=otsuDistanceCutoff(colors,primary);const totalMass=colors.reduce((sum,{mass})=>sum+mass,0);const primaryMass=colors.reduce((sum,{color,mass})=>sum+(oklabDistance(color,primary)<=cutoff?mass:0),0);return{cutoff,primary,primaryShare:primaryMass/totalMass}}function colorBelongsToPrimary(rgb,model){return oklabDistance(srgbToOklab(rgb),model.primary)<=model.cutoff}var allowedFormats=new Set(["avif","gif","heif","jpeg","png","tiff","webp"]);var METRIC_MAX_EDGE=512;var VECTORIZE_SHARP_CONCURRENCY=1;function configureVectorizeSharpConcurrency(){const actual=sharp.concurrency(VECTORIZE_SHARP_CONCURRENCY);if(actual!==VECTORIZE_SHARP_CONCURRENCY){throw new VectorizeError("trace_failed","The vectorization worker could not bind its Sharp CPU budget.")}}async function loadRaster(input,limits,deadline){deadline.assert("input read");const bytes=await readInputBytes(input,limits.maxInputBytes,deadline);deadline.assert("input metadata");try{const metadata=await sharp(bytes,{failOn:"error",limitInputPixels:limits.maxDecodedPixels,sequentialRead:true}).metadata();const format=metadata.format;if(format===undefined||!allowedFormats.has(format)){throw new VectorizeError("invalid_input",`Expected a supported raster image, received ${format??"an unknown format"}.`)}if((metadata.pages??1)!==1){throw new VectorizeError("invalid_input","Animated and multipage raster inputs are rejected.")}if(metadata.width===undefined||metadata.height===undefined||metadata.width<1||metadata.height<1){throw new VectorizeError("invalid_input","Raster dimensions are missing or invalid.")}assertDimensions(metadata.width,metadata.height,limits);const decoded=await sharp(bytes,{failOn:"error",limitInputPixels:limits.maxDecodedPixels,sequentialRead:true}).rotate().ensureAlpha().raw().toBuffer({resolveWithObject:true});const{channels,height,width}=decoded.info;if(channels!==4){throw new VectorizeError("invalid_input","Raster decoding did not produce RGBA pixels.")}assertDimensions(width,height,limits);const pixels=Uint8Array.from(decoded.data);if(!containsVisiblePixel(pixels)){throw new VectorizeError("invalid_input","A fully transparent image cannot be vectorized.")}deadline.assert("raster decode");const scoreScale=Math.min(1,METRIC_MAX_EDGE/Math.max(width,height));const scoreWidth=Math.max(1,Math.round(width*scoreScale));const scoreHeight=Math.max(1,Math.round(height*scoreScale));const scorePixels=scoreWidth===width&&scoreHeight===height?pixels:Uint8Array.from(await sharp(pixels,{raw:{channels:4,height,width}}).resize(scoreWidth,scoreHeight,{fit:"fill",kernel:"lanczos3"}).raw().toBuffer());deadline.assert("metric sample");return{bytes,format,height,inputBytes:bytes.byteLength,pixels,scoreHeight,scorePixels,scoreWidth,sourceSha256:sha256(bytes),width}}catch(error){if(error instanceof VectorizeError)throw error;throw new VectorizeError("invalid_input","Raster input could not be decoded safely.",{},{cause:error})}}async function readInputBytes(input,maximumBytes,deadline){if(typeof input==="string"){return readRegularInput(resolve(input),maximumBytes,deadline)}const view=input instanceof ArrayBuffer?new Uint8Array(input):input;if(view.byteLength===0){throw new VectorizeError("invalid_input","Raster input is empty.")}if(view.byteLength>maximumBytes){throw new VectorizeError("input_limit",`Raster input exceeds the ${maximumBytes}-byte limit.`,{bytes:view.byteLength,maximumBytes})}deadline.assert("input read");const bytes=Uint8Array.from(view);deadline.assert("input read");return bytes}async function readRegularInput(path,maximumBytes,deadline){let handle;try{deadline.assert("input read");const targetPath=await realpath(path);deadline.assert("input read");handle=await open(targetPath,boundedReadFlags());const metadata=await handle.stat();if(!metadata.isFile()){throw new VectorizeError("invalid_input",`Raster input is not a file: ${path}`)}if(metadata.size<1){throw new VectorizeError("invalid_input","Raster input is empty.")}if(metadata.size>maximumBytes){throw new VectorizeError("input_limit",`Raster input exceeds the ${maximumBytes}-byte limit.`,{bytes:metadata.size,maximumBytes})}const chunk=Buffer.allocUnsafe(Math.min(64*1024,maximumBytes+1));const chunks=[];let bytes=0;while(true){deadline.assert("input read");const maximumRead=Math.min(chunk.byteLength,maximumBytes-bytes+1);const{bytesRead}=await handle.read(chunk,0,maximumRead,null);if(bytesRead===0)break;bytes+=bytesRead;if(bytes>maximumBytes){throw new VectorizeError("input_limit",`Raster input exceeds the ${maximumBytes}-byte limit.`,{bytes,maximumBytes})}chunks.push(Buffer.from(chunk.subarray(0,bytesRead)))}if(bytes===0){throw new VectorizeError("invalid_input","Raster input is empty.")}deadline.assert("input read");return Buffer.concat(chunks,bytes)}catch(error){if(error instanceof VectorizeError)throw error;throw new VectorizeError("invalid_input","Raster input could not be read safely.",{},{cause:error})}finally{await handle?.close().catch(()=>{return})}}function assertDimensions(width,height,limits){if(!Number.isInteger(width)||!Number.isInteger(height)||width<1||height<1||width>limits.maxDimension||height>limits.maxDimension||width*height>limits.maxDecodedPixels){throw new VectorizeError("input_limit",`Raster dimensions must fit ${limits.maxDimension}px and ${limits.maxDecodedPixels} decoded pixels.`,{height,width})}}function containsVisiblePixel(rgba){for(let index=3;index<rgba.length;index+=4){if(rgba[index]>0)return true}return false}function boundedReadFlags(){if(process.platform==="win32")return constants.O_RDONLY;return constants.O_RDONLY|constants.O_NONBLOCK|constants.O_NOFOLLOW}async function encodeTracePng(pixels,width,height){return Uint8Array.from(await sharp(pixels,{raw:{channels:4,height,width}}).png({adaptiveFiltering:false,compressionLevel:9,palette:false}).toBuffer())}async function renderSvgRgba(svg,width,height,maxDecodedPixels){try{return Uint8Array.from(await sharp(Buffer.from(svg),{density:72,failOn:"error",limitInputPixels:maxDecodedPixels}).resize(width,height,{fit:"fill"}).ensureAlpha().raw().toBuffer())}catch(error){throw new VectorizeError("trace_failed","Canonical SVG could not be rendered for quality measurement.",{},{cause:error})}}function sharpProvenance(){const sharpVersions=normalizedPixelToolchain(sharp.versions);const sharpVersion=sharpVersions.sharp;const vipsVersion=sharpVersions.vips;if(sharpVersion===undefined||vipsVersion===undefined){throw new VectorizeError("tool_version","Sharp must report its own and libvips version metadata.")}return{sharp:sharpVersion,sharpVersions,vips:vipsVersion}}function normalizedPixelToolchain(versions){const entries=Object.entries(versions).filter((entry)=>entry[1]!==undefined).sort(([left],[right])=>left.localeCompare(right));if(entries.length===0||entries.some(([name,version])=>name.length===0||version.length===0)){throw new VectorizeError("tool_version","Pixel toolchain versions must be nonempty strings.")}return Object.freeze(Object.fromEntries(entries))}import{AsyncLocalStorage}from"async_hooks";import{constants as constants2}from"fs";import{lstat,mkdtemp,open as open2,rmdir,unlink}from"fs/promises";import{join}from"path";var gatewayCredentialNames=new Set(["AI_GATEWAY_API_KEY","VERCEL_OIDC_TOKEN"]);function nonGatewayChildEnvironment(source=process.env){const environment={...source};for(const name of Object.keys(environment)){if(gatewayCredentialNames.has(name.toLocaleUpperCase("en-US"))){delete environment[name]}}return environment}var MAX_COMMAND_OUTPUT_BYTES=64*1024;var PRIMARY_OUTPUT_READ_BYTES=64*1024;var PRIMARY_OUTPUT_POLL_MS=2;var PRIMARY_OUTPUT_EXIT_EMPTY_POLLS=2;var TERMINATION_GRACE_MS=50;var HARD_KILL_WAIT_MS=500;var MAX_INHERITED_FILE_DESCRIPTORS=16;var timeoutMarker=Symbol("bounded-command-timeout");var noCommandFailure=Symbol("no-command-failure");var activePosixProcessGroups=new Set;var workerTerminationForwardingInstalled=false;var inheritedCommandFileDescriptors=new AsyncLocalStorage;function normalizedInheritedFileDescriptors(value){const descriptors=value??[];if(descriptors.length>MAX_INHERITED_FILE_DESCRIPTORS||descriptors.some((descriptor,index)=>!Number.isSafeInteger(descriptor)||descriptor<0||descriptor>2147483647||descriptors.indexOf(descriptor)!==index)){throw new VectorizeError("invalid_input","Inherited vectorizer descriptors must be unique bounded integers.")}return Object.freeze([...descriptors])}async function withInheritedCommandFileDescriptors(descriptors,callback){const normalized=normalizedInheritedFileDescriptors(descriptors);return await inheritedCommandFileDescriptors.run(normalized,async()=>await callback())}function forwardVectorizeWorkerTermination(){if(process.platform==="win32"||workerTerminationForwardingInstalled){return}workerTerminationForwardingInstalled=true;const signals=[["SIGHUP",129],["SIGINT",130],["SIGTERM",143]];for(const[signal,exitCode]of signals){process.once(signal,()=>{for(const pid of activePosixProcessGroups){safelyKillPosixProcessGroupByPid(pid,"SIGKILL")}process.exit(exitCode)})}}async function runBoundedCommand(command,timeoutMs,failureCode,options={}){return runBoundedCommandInternal(command,timeoutMs,failureCode,options)}async function runBoundedPathOutputCommand(commandForOutput,timeoutMs,failureCode,options){if(process.platform==="win32"){throw new VectorizeError("tool_platform","Bounded pathname output is unavailable on Windows.",{platform:process.platform})}assertPositiveLimit(options.maxOutputBytes,"The command primary-output limit must be positive.");if(timeoutMs<1){throw new VectorizeError("timeout","VTracer exceeded the conversion time limit.")}const startedAt=performance.now();let anchorHandle;let directoryHandle;let outputDirectory;let readerHandle;let result;let failure=noCommandFailure;try{outputDirectory=await mkdtemp(join(options.temporaryRoot,"slopcamera-command-output-"));directoryHandle=await open2(outputDirectory,constants2.O_RDONLY|constants2.O_DIRECTORY|constants2.O_NOFOLLOW);await assertOpenedPrivateDirectory(outputDirectory,directoryHandle);const outputPath=join(outputDirectory,"output.svg");await createPrivateFifo(outputPath,remainingCommandTime(startedAt,timeoutMs),failureCode);anchorHandle=await open2(outputPath,constants2.O_RDWR|constants2.O_NONBLOCK|constants2.O_NOFOLLOW);readerHandle=await open2(outputPath,constants2.O_RDONLY|constants2.O_NONBLOCK|constants2.O_NOFOLLOW);await assertOpenedPrivateFifo(outputPath,anchorHandle,readerHandle);await directoryHandle.chmod(320);const commandResult=await runBoundedCommandInternal(commandForOutput(outputPath),remainingCommandTime(startedAt,timeoutMs),failureCode,options,{handle:readerHandle,maximumBytes:options.maxOutputBytes});if(commandResult.primaryOutput===undefined){throw new VectorizeError(failureCode,"VTracer did not expose its bounded primary output.")}result={output:commandResult.primaryOutput,stderr:commandResult.stderr,stdout:commandResult.stdout}}catch(error){failure=error instanceof VectorizeError?error:executionError(failureCode,error)}const cleanupError=await removePrimaryOutputEndpoint(outputDirectory,outputDirectory===undefined?undefined:join(outputDirectory,"output.svg"),readerHandle,anchorHandle,directoryHandle);if(failure!==noCommandFailure){if(cleanupError===undefined)throw failure;throw new VectorizeError(failure instanceof VectorizeError?failure.code:failureCode,`${failure instanceof Error?failure.message:String(failure)} The temporary primary-output endpoint also could not be removed.`,{...failure instanceof VectorizeError?failure.details:{},cleanup:String(cleanupError)},{cause:failure instanceof Error?failure:undefined})}if(cleanupError!==undefined){throw new VectorizeError(failureCode,"The temporary primary-output endpoint could not be removed.",{cleanup:String(cleanupError)},{cause:cleanupError instanceof Error?cleanupError:undefined})}if(result===undefined){throw new VectorizeError(failureCode,"The bounded command completed without a result.")}return result}async function runBoundedCommandInternal(command,timeoutMs,failureCode,options,primaryOutput){if(command.length===0){throw new VectorizeError("invalid_input","A bounded command requires a command.")}if(timeoutMs<1){throw new VectorizeError("timeout","VTracer exceeded the conversion time limit.")}const maxStdoutBytes=options.maxStdoutBytes??MAX_COMMAND_OUTPUT_BYTES;assertPositiveLimit(maxStdoutBytes,"The command stdout limit must be positive.");const inheritedDescriptors=normalizedInheritedFileDescriptors(options.inheritedFileDescriptors??inheritedCommandFileDescriptors.getStore());let child;const ownsProcessGroup=process.platform!=="win32";try{child=Bun.spawn([...command],{detached:ownsProcessGroup,env:nonGatewayChildEnvironment(),stdio:[options.stdin??"ignore","pipe","pipe",...inheritedDescriptors],windowsHide:true})}catch(error){throw executionError(failureCode,error)}if(process.platform!=="win32"){activePosixProcessGroups.add(child.pid)}const streamAbort=new AbortController;let childHasExited=false;const childExitTask=child.exited.then((exitCode)=>{childHasExited=true;if(ownsProcessGroup&&process.platform!=="win32"){safelyKillPosixProcessGroup(child,"SIGKILL")}return exitCode});const stdoutTask=readBoundedText(child.stdout,maxStdoutBytes,streamAbort.signal,"VTracer emitted too much primary output.");const stderrTask=readBoundedText(child.stderr,MAX_COMMAND_OUTPUT_BYTES,streamAbort.signal,"VTracer emitted too much diagnostic output.");const primaryOutputTask=primaryOutput===undefined?Promise.resolve(undefined):readBoundedFifo(primaryOutput.handle,primaryOutput.maximumBytes,streamAbort.signal,()=>childHasExited);const executionTask=Promise.all([childExitTask,stdoutTask,stderrTask,primaryOutputTask]).then(([exitCode,stdout,stderr,boundedPrimaryOutput])=>{if(exitCode!==0){throw new VectorizeError(failureCode,[`Command failed (${exitCode}): ${command[0]??"unknown"}`,stderr.trim()].filter(Boolean).join(`
3
+ `),{exitCode})}return boundedPrimaryOutput===undefined?{stderr,stdout}:{primaryOutput:boundedPrimaryOutput,stderr,stdout}});let timer;const timeoutTask=new Promise((_resolve,reject)=>{timer=setTimeout(()=>reject(timeoutMarker),timeoutMs)});try{return await Promise.race([executionTask,timeoutTask])}catch(error){let cleanupError;try{await terminateAndWait(child,ownsProcessGroup)}catch(caught){cleanupError=caught}finally{streamAbort.abort();await settlesWithin(Promise.allSettled([stdoutTask,stderrTask,primaryOutputTask]),HARD_KILL_WAIT_MS)}if(error===timeoutMarker){throw new VectorizeError("timeout",cleanupError===undefined?"VTracer exceeded the conversion time limit.":"VTracer exceeded the conversion time limit and did not terminate cleanly.",cleanupError===undefined?{}:{cleanup:String(cleanupError)})}if(error instanceof VectorizeError)throw error;if(cleanupError instanceof VectorizeError)throw cleanupError;throw executionError(failureCode,error)}finally{if(timer!==undefined)clearTimeout(timer);activePosixProcessGroups.delete(child.pid)}}function assertPositiveLimit(value,message){if(!Number.isSafeInteger(value)||value<1){throw new VectorizeError("invalid_input",message)}}function remainingCommandTime(startedAt,timeoutMs){return Math.floor(timeoutMs-(performance.now()-startedAt))}async function createPrivateFifo(path,timeoutMs,failureCode){await runBoundedCommandInternal(["mkfifo","-m","600",path],timeoutMs,failureCode,{})}async function assertOpenedPrivateDirectory(path,directory){const[pathMetadata,openedMetadata]=await Promise.all([lstat(path),directory.stat()]);if(!pathMetadata.isDirectory()||!openedMetadata.isDirectory()||pathMetadata.dev!==openedMetadata.dev||pathMetadata.ino!==openedMetadata.ino){throw new VectorizeError("trace_failed","The bounded primary-output directory changed during setup.")}}async function assertOpenedPrivateFifo(path,anchor,reader){const[pathMetadata,anchorMetadata,readerMetadata]=await Promise.all([lstat(path),anchor.stat(),reader.stat()]);if(!pathMetadata.isFIFO()||!anchorMetadata.isFIFO()||!readerMetadata.isFIFO()||pathMetadata.dev!==anchorMetadata.dev||pathMetadata.ino!==anchorMetadata.ino||anchorMetadata.dev!==readerMetadata.dev||anchorMetadata.ino!==readerMetadata.ino){throw new VectorizeError("trace_failed","The bounded primary-output endpoint changed during setup.")}}async function removePrimaryOutputEndpoint(directoryPath,path,reader,anchor,directoryHandle){let cleanupError;if(directoryPath!==undefined&&directoryHandle===undefined){try{await rmdir(directoryPath)}catch(error){cleanupError??=error}}if(directoryPath!==undefined&&directoryHandle!==undefined){await directoryHandle.chmod(448).catch((error)=>{cleanupError??=error});try{const[pathDirectoryMetadata,openedDirectoryMetadata]=await Promise.all([lstat(directoryPath),directoryHandle.stat()]);if(!pathDirectoryMetadata.isDirectory()||!openedDirectoryMetadata.isDirectory()||pathDirectoryMetadata.dev!==openedDirectoryMetadata.dev||pathDirectoryMetadata.ino!==openedDirectoryMetadata.ino){throw new VectorizeError("trace_failed","The bounded primary-output directory changed before cleanup.")}if(path!==undefined&&cleanupError===undefined){const pathMetadata=await lstat(path).catch((error)=>{if(isFileSystemError(error,"ENOENT"))return;throw error});const openedMetadata=await(reader??anchor)?.stat();if(pathMetadata===undefined&&openedMetadata!==undefined){throw new VectorizeError("trace_failed","The bounded primary-output endpoint disappeared before cleanup.")}if(pathMetadata!==undefined){if(!pathMetadata.isFIFO()||openedMetadata!==undefined&&(pathMetadata.dev!==openedMetadata.dev||pathMetadata.ino!==openedMetadata.ino)){throw new VectorizeError("trace_failed","The bounded primary-output endpoint changed before cleanup.")}await unlink(path)}}if(cleanupError===undefined)await rmdir(directoryPath)}catch(error){cleanupError??=error}}const closes=await Promise.allSettled([reader?.close(),anchor?.close(),directoryHandle?.close()]);cleanupError??=closes.find((result)=>result.status==="rejected")?.reason;return cleanupError}async function terminateAndWait(child,ownsProcessGroup){if(process.platform==="win32"){await killWindowsProcessTree(child.pid)}else if(!ownsProcessGroup){safelyKillChild(child,"SIGTERM");await delay(TERMINATION_GRACE_MS);safelyKillChild(child,"SIGKILL")}else{safelyKillPosixProcessGroup(child,"SIGTERM");await delay(TERMINATION_GRACE_MS);safelyKillPosixProcessGroup(child,"SIGKILL")}if(await settlesWithin(child.exited,HARD_KILL_WAIT_MS))return;throw new VectorizeError("trace_failed","VTracer did not exit after forced termination.")}function safelyKillChild(child,signal){try{child.kill(signal)}catch{}}function safelyKillPosixProcessGroup(child,signal){if(!safelyKillPosixProcessGroupByPid(child.pid,signal)){try{child.kill(signal)}catch{}}}function safelyKillPosixProcessGroupByPid(pid,signal){try{process.kill(-pid,signal);return true}catch{return false}}async function killWindowsProcessTree(pid){let killer;try{killer=Bun.spawn(["taskkill.exe","/PID",String(pid),"/T","/F"],{detached:false,env:nonGatewayChildEnvironment(),stderr:"pipe",stdin:"ignore",stdout:"pipe",windowsHide:true})}catch{return}const drain=Promise.all([readBoundedText(killer.stdout,MAX_COMMAND_OUTPUT_BYTES,AbortSignal.timeout(HARD_KILL_WAIT_MS),"Process-tree cleanup emitted too much output."),readBoundedText(killer.stderr,MAX_COMMAND_OUTPUT_BYTES,AbortSignal.timeout(HARD_KILL_WAIT_MS),"Process-tree cleanup emitted too much output.")]);if(!await settlesWithin(Promise.all([killer.exited,drain]),HARD_KILL_WAIT_MS)){try{killer.kill("SIGKILL")}catch{}}}async function settlesWithin(promise,durationMs){return new Promise((resolve2)=>{let finished=false;const timer=setTimeout(()=>finish(false),durationMs);promise.then(()=>finish(true),()=>finish(true));function finish(settled){if(finished)return;finished=true;clearTimeout(timer);resolve2(settled)}})}async function readBoundedText(stream,maximumBytes,signal,limitMessage){const reader=stream.getReader();const chunks=[];let bytes=0;const cancel=()=>{reader.cancel().catch(()=>{return})};signal.addEventListener("abort",cancel,{once:true});try{while(true){const{done,value}=await reader.read();if(done)break;bytes+=value.byteLength;if(bytes>maximumBytes){await reader.cancel();throw new VectorizeError("output_limit",limitMessage,{bytes,maximumBytes})}chunks.push(value)}return Buffer.concat(chunks,bytes).toString("utf8")}finally{signal.removeEventListener("abort",cancel);reader.releaseLock()}}async function readBoundedFifo(handle,maximumBytes,signal,childHasExited){const buffer=Buffer.allocUnsafe(Math.min(PRIMARY_OUTPUT_READ_BYTES,maximumBytes+1));const chunks=[];let bytes=0;let emptyPollsAfterExit=0;while(!signal.aborted){const maximumRead=Math.min(buffer.byteLength,maximumBytes-bytes+1);try{const{bytesRead}=await handle.read(buffer,0,maximumRead,null);if(bytesRead>0){emptyPollsAfterExit=0;bytes+=bytesRead;if(bytes>maximumBytes){throw new VectorizeError("output_limit","VTracer emitted too much primary output.",{bytes,maximumBytes})}chunks.push(Uint8Array.from(buffer.subarray(0,bytesRead)));continue}}catch(error){if(!isWouldBlockError(error))throw error}if(childHasExited()){emptyPollsAfterExit+=1;if(emptyPollsAfterExit>=PRIMARY_OUTPUT_EXIT_EMPTY_POLLS)break}else{emptyPollsAfterExit=0}await delay(PRIMARY_OUTPUT_POLL_MS)}return Buffer.concat(chunks,bytes).toString("utf8")}function isWouldBlockError(error){return isFileSystemError(error)&&["EAGAIN","EINTR","EWOULDBLOCK"].includes(String(error.code))}function isFileSystemError(error,code){return error instanceof Error&&"code"in error&&(code===undefined||error.code===code)}function delay(durationMs){return new Promise((resolve2)=>{setTimeout(resolve2,durationMs)})}function executionError(failureCode,cause){return new VectorizeError(failureCode,"VTracer could not be executed.",{},{cause:cause instanceof Error?cause:new Error(String(cause))})}import{createHash as createHash2,randomUUID}from"crypto";import{constants as constants3}from"fs";import{chmod,mkdir,open as open3,realpath as realpath2,rename,rm,writeFile}from"fs/promises";import{homedir}from"os";import{dirname,join as join2,resolve as resolve2}from"path";import{gunzipSync,inflateRawSync}from"zlib";var MAX_BINARY_BYTES=8*1024*1024;function extractVTracerArchive(archive,format){return format==="tar.gz"?extractTarEntry(gunzipSync(archive,{maxOutputLength:MAX_BINARY_BYTES}),"vtracer"):extractZipEntry(archive,"vtracer.exe")}function extractTarEntry(tar,expectedName){for(let offset=0;offset+512<=tar.length;){const header=tar.subarray(offset,offset+512);if(header.every((byte)=>byte===0))break;const name=readNullTerminatedAscii(header.subarray(0,100));const prefix=readNullTerminatedAscii(header.subarray(345,500));const fullName=prefix===""?name:`${prefix}/${name}`;const sizeText=readNullTerminatedAscii(header.subarray(124,136)).trim();if(!/^[0-7]+$/u.test(sizeText)){throw new VectorizeError("tool_integrity","VTracer tar contains an invalid size.")}const size=Number.parseInt(sizeText,8);if(!Number.isSafeInteger(size)||size<0||size>MAX_BINARY_BYTES){throw new VectorizeError("tool_integrity","VTracer tar entry exceeds its size limit.")}const contentStart=offset+512;const contentEnd=contentStart+size;if(contentEnd>tar.length){throw new VectorizeError("tool_integrity","VTracer tar entry is truncated.")}if(fullName===expectedName||fullName.endsWith(`/${expectedName}`)){return Uint8Array.from(tar.subarray(contentStart,contentEnd))}offset=contentStart+Math.ceil(size/512)*512}throw new VectorizeError("tool_integrity",`VTracer archive omitted ${expectedName}.`)}function extractZipEntry(zip,expectedName){const bytes=Buffer.from(zip);let offset=0;while(offset+30<=bytes.length){const signature=bytes.readUInt32LE(offset);if(signature!==67324752)break;const flags=bytes.readUInt16LE(offset+6);const compression=bytes.readUInt16LE(offset+8);const compressedSize=bytes.readUInt32LE(offset+18);const uncompressedSize=bytes.readUInt32LE(offset+22);const nameLength=bytes.readUInt16LE(offset+26);const extraLength=bytes.readUInt16LE(offset+28);if((flags&1)!==0||(flags&8)!==0){throw new VectorizeError("tool_integrity","VTracer zip uses encryption or an unsupported data descriptor.")}if(uncompressedSize>MAX_BINARY_BYTES){throw new VectorizeError("tool_integrity","VTracer zip entry exceeds its size limit.")}const nameStart=offset+30;const dataStart=nameStart+nameLength+extraLength;const dataEnd=dataStart+compressedSize;if(dataEnd>bytes.length){throw new VectorizeError("tool_integrity","VTracer zip entry is truncated.")}const name=bytes.subarray(nameStart,nameStart+nameLength).toString("utf8");if(name===expectedName||name.endsWith(`/${expectedName}`)){const compressed=bytes.subarray(dataStart,dataEnd);const extracted=compression===0?Buffer.from(compressed):compression===8?inflateRawSync(compressed,{maxOutputLength:MAX_BINARY_BYTES}):undefined;if(extracted===undefined){throw new VectorizeError("tool_integrity",`VTracer zip uses unsupported compression method ${compression}.`)}if(extracted.length!==uncompressedSize){throw new VectorizeError("tool_integrity","VTracer zip size does not match its header.")}return Uint8Array.from(extracted)}offset=dataEnd}throw new VectorizeError("tool_integrity",`VTracer archive omitted ${expectedName}.`)}function readNullTerminatedAscii(bytes){const end=bytes.indexOf(0);return Buffer.from(end===-1?bytes:bytes.subarray(0,end)).toString("ascii")}var VTRACER_VERSION="0.6.4";var frozenRelease=(release)=>Object.freeze(release);var vtracerReleases=Object.freeze({"darwin-arm64":frozenRelease({archiveSha256:"4a597fd2df8b961d60620df40a7436109427d86e5c028758e6e8796b02d3d996",binarySha256:"77e495bbe212448240387fba3b6d8bc62ba20ecfb6f3c22967e51600f1cc6e66",format:"tar.gz",url:`https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-aarch64-apple-darwin.tar.gz`}),"darwin-x64":frozenRelease({archiveSha256:"f0d755292c2602d772d63d658a3498b23eca8b5620d4b92a991bd035d5abed16",binarySha256:"0f9f88f989b757e27973a5c4b42665153070183d0787656ee8af2249ab326b78",format:"tar.gz",url:`https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-x86_64-apple-darwin.tar.gz`}),"linux-arm64":frozenRelease({archiveSha256:"cbd05ad4f491d12dd139ada61485ca1d24db9f981cbe1658632a083cd0ac1a71",binarySha256:"a4b33b6c4066a6b9187802c6efc8b89e211318e12a17164b9d1dd1f29ac5e502",format:"tar.gz",url:`https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-aarch64-unknown-linux-musl.tar.gz`}),"linux-x64":frozenRelease({archiveSha256:"9290ba0c90e224d6d212836dff5491407c1718bcb72f80b2b5a4a01816df5e40",binarySha256:"6f31499257076bd94de3e976844cf7ca5643f1e194a2bf0599b13f3719452aec",format:"tar.gz",url:`https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-x86_64-unknown-linux-musl.tar.gz`}),"win32-x64":frozenRelease({archiveSha256:"6b5bc17a6b017129ee40461df254f65d16f3b494c001a8541d41861066b716bf",binarySha256:"4ad8d35e566cd15caf582063b8349bd082b8fa2bd461e99d116fc63ad8fdeca0",format:"zip",url:`https://github.com/visioncortex/vtracer/releases/download/${VTRACER_VERSION}/vtracer-x86_64-pc-windows-msvc.zip`})});var MAX_ARCHIVE_BYTES=4*1024*1024;var MAX_TOOL_BYTES=16*1024*1024;var FILE_CHUNK_BYTES=64*1024;function renamedEnvironmentValue(canonical){return process.env[canonical]}async function ensureVTracer(deadline,privateDirectory,cacheDirectory){const override=renamedEnvironmentValue("SLOPCAMERA_VTRACER_PATH");if(override!==undefined){return copyAndInspectVTracer(resolve2(override),resolve2(privateDirectory),"override",deadline)}const key=`${process.platform}-${process.arch}`;const release=vtracerReleases[key];if(release===undefined){throw new VectorizeError("tool_platform",`VTracer is not pinned for ${process.platform}/${process.arch}.`,{arch:process.arch,platform:process.platform})}const cacheRoot=resolve2(cacheDirectory??defaultCacheDirectory());const suffix=process.platform==="win32"?".exe":"";const toolPath=join2(cacheRoot,"tools",`vtracer-${VTRACER_VERSION}-${process.platform}-${process.arch}${suffix}`);const cachedHash=await hashCachedTool(toolPath,deadline);if(cachedHash!==release.binarySha256){await removeInvalidCachedTool(toolPath);await installOfficialVTracer(toolPath,release,deadline)}return copyAndInspectVTracer(toolPath,resolve2(privateDirectory),"official-release",deadline,release.binarySha256)}function defaultCacheDirectory(){const explicit=renamedEnvironmentValue("SLOPCAMERA_CACHE_DIR");if(explicit!==undefined&&explicit.trim()!=="")return explicit;if(process.platform==="win32"){return join2(process.env.LOCALAPPDATA??homedir(),"slopcamera")}if(process.platform==="darwin")return join2(homedir(),"Library","Caches","slopcamera");return join2(process.env.XDG_CACHE_HOME??join2(homedir(),".cache"),"slopcamera")}async function installOfficialVTracer(toolPath,release,deadline){deadline.assert("VTracer download");const archive=await downloadBounded(release.url,deadline,MAX_ARCHIVE_BYTES);const archiveSha256=sha256(archive);if(archiveSha256!==release.archiveSha256){throw new VectorizeError("tool_integrity",`VTracer archive checksum mismatch: ${archiveSha256}`,{actual:archiveSha256,expected:release.archiveSha256})}const binary=extractVTracerArchive(archive,release.format);if(binary.byteLength<1||binary.byteLength>MAX_TOOL_BYTES){throw new VectorizeError("tool_integrity","VTracer binary exceeds its verified installation limit.",{bytes:binary.byteLength,maximumBytes:MAX_TOOL_BYTES})}const binarySha256=sha256(binary);if(binarySha256!==release.binarySha256){throw new VectorizeError("tool_integrity",`VTracer binary checksum mismatch: ${binarySha256}`,{actual:binarySha256,expected:release.binarySha256})}deadline.assert("VTracer installation");await mkdir(dirname(toolPath),{recursive:true});const stagedPath=`${toolPath}.${randomUUID()}.tmp`;try{await writeFile(stagedPath,binary,{flag:"wx",mode:448});if(process.platform!=="win32")await chmod(stagedPath,320);deadline.assert("VTracer installation");try{await rename(stagedPath,toolPath)}catch(error){const concurrentHash=await hashCachedTool(toolPath,deadline);if(concurrentHash===release.binarySha256){await rm(stagedPath,{force:true})}else{throw error}}}catch(error){await rm(stagedPath,{force:true});if(error instanceof VectorizeError)throw error;throw new VectorizeError("tool_integrity","Could not publish the verified VTracer binary.",{},{cause:error})}const installedHash=await hashCachedTool(toolPath,deadline);if(installedHash!==release.binarySha256){throw new VectorizeError("tool_integrity","Installed VTracer differs from the verified release binary.",{actual:installedHash,expected:release.binarySha256})}}async function copyAndInspectVTracer(sourcePath,privateDirectory,source,deadline,expectedSha256){deadline.assert("VTracer private copy");await mkdir(privateDirectory,{mode:448,recursive:true});const suffix=process.platform==="win32"?".exe":"";const privatePath=join2(privateDirectory,`vtracer-${randomUUID()}${suffix}`);const failureCode=source==="official-release"?"tool_integrity":"tool_version";let sourceHandle;let targetHandle;let copiedSha256;try{const resolvedSourcePath=await realpath2(sourcePath);deadline.assert("VTracer private copy");sourceHandle=await open3(resolvedSourcePath,boundedReadFlags2());const metadata=await sourceHandle.stat();assertBoundedRegularTool(metadata,sourcePath);targetHandle=await open3(privatePath,"wx",320);copiedSha256=await copyAndHash(sourceHandle,targetHandle,MAX_TOOL_BYTES,deadline);await targetHandle.sync();deadline.assert("VTracer private copy")}catch(error){if(error instanceof VectorizeError)throw error;throw new VectorizeError(failureCode,"VTracer could not be copied into the private conversion directory.",{},{cause:error})}finally{await Promise.allSettled([sourceHandle?.close(),targetHandle?.close()])}try{if(copiedSha256.length===0){throw new VectorizeError(failureCode,"VTracer executable is empty.")}if(expectedSha256!==undefined&&copiedSha256!==expectedSha256){throw new VectorizeError("tool_integrity","VTracer changed before it could be copied for conversion.",{actual:copiedSha256,expected:expectedSha256})}if(process.platform!=="win32")await chmod(privatePath,320);const privateSha256=await hashRegularFile(privatePath,MAX_TOOL_BYTES,deadline,failureCode);if(privateSha256!==copiedSha256){throw new VectorizeError("tool_integrity","The private VTracer copy failed its integrity check.",{actual:privateSha256,expected:copiedSha256})}return inspectVTracer(privatePath,source,deadline,copiedSha256,expectedSha256)}catch(error){await rm(privatePath,{force:true});throw error}}async function inspectVTracer(path,source,deadline,copiedSha256,expectedSha256){deadline.assert("VTracer inspection");const{stderr,stdout}=await runBoundedCommand([path,"--version"],deadline.remainingMs(),"tool_version");if(!new RegExp(`\\b${VTRACER_VERSION.replaceAll(".","\\.")}\\b`,"u").test(`${stdout}
4
+ ${stderr}`)){throw new VectorizeError("tool_version",`Expected VTracer ${VTRACER_VERSION}.`)}const afterInspectionSha256=await hashRegularFile(path,MAX_TOOL_BYTES,deadline,"tool_integrity");if(afterInspectionSha256!==copiedSha256||expectedSha256!==undefined&&afterInspectionSha256!==expectedSha256){throw new VectorizeError("tool_integrity","The private VTracer executable changed during inspection.",{actual:afterInspectionSha256,expected:expectedSha256??copiedSha256})}return{path,sha256:afterInspectionSha256,source,version:VTRACER_VERSION}}async function hashCachedTool(path,deadline){try{return await hashRegularFile(path,MAX_TOOL_BYTES,deadline,"tool_integrity")}catch(error){if(error instanceof VectorizeError&&error.code==="timeout")throw error;if(isFileSystemError2(error,"ENOENT"))return;return}}async function removeInvalidCachedTool(path){try{await rm(path,{force:true})}catch(error){throw new VectorizeError("tool_integrity","Could not remove an invalid cached VTracer binary.",{},{cause:error})}}async function hashRegularFile(path,maximumBytes,deadline,failureCode){let handle;try{deadline.assert("VTracer hash");const resolvedPath=await realpath2(path);deadline.assert("VTracer hash");handle=await open3(resolvedPath,boundedReadFlags2());const metadata=await handle.stat();if(!metadata.isFile()||metadata.size<1||metadata.size>maximumBytes){throw new VectorizeError(failureCode,"VTracer must be a non-empty regular file within its size limit.",{bytes:metadata.size,maximumBytes})}const hash=createHash2("sha256");const buffer=Buffer.allocUnsafe(Math.min(FILE_CHUNK_BYTES,maximumBytes+1));let bytes=0;while(true){deadline.assert("VTracer hash");const maximumRead=Math.min(buffer.byteLength,maximumBytes-bytes+1);const{bytesRead}=await handle.read(buffer,0,maximumRead,null);if(bytesRead===0)break;bytes+=bytesRead;if(bytes>maximumBytes){throw new VectorizeError(failureCode,"VTracer grew beyond its executable size limit while being hashed.",{bytes,maximumBytes})}hash.update(buffer.subarray(0,bytesRead))}deadline.assert("VTracer hash");return hash.digest("hex")}catch(error){if(error instanceof VectorizeError)throw error;throw new VectorizeError(failureCode,"VTracer executable could not be read safely.",{},{cause:error})}finally{await handle?.close().catch(()=>{return})}}async function copyAndHash(source,target,maximumBytes,deadline){const hash=createHash2("sha256");const buffer=Buffer.allocUnsafe(Math.min(FILE_CHUNK_BYTES,maximumBytes+1));let bytes=0;while(true){deadline.assert("VTracer private copy");const maximumRead=Math.min(buffer.byteLength,maximumBytes-bytes+1);const{bytesRead}=await source.read(buffer,0,maximumRead,null);if(bytesRead===0)break;bytes+=bytesRead;if(bytes>maximumBytes){throw new VectorizeError("tool_integrity","VTracer grew beyond its executable size limit while being copied.",{bytes,maximumBytes})}hash.update(buffer.subarray(0,bytesRead));let written=0;while(written<bytesRead){const result=await target.write(buffer,written,bytesRead-written,null);if(result.bytesWritten<1){throw new VectorizeError("tool_integrity","VTracer private copy stopped before completion.")}written+=result.bytesWritten}}return bytes===0?"":hash.digest("hex")}function assertBoundedRegularTool(metadata,path){if(!metadata.isFile()||metadata.size<1||metadata.size>MAX_TOOL_BYTES){throw new VectorizeError("tool_version",`VTracer must be a non-empty regular file: ${path}`,{bytes:metadata.size,maximumBytes:MAX_TOOL_BYTES})}}async function downloadBounded(url,deadline,maximumBytes){const controller=new AbortController;const timer=setTimeout(()=>controller.abort(),deadline.remainingMs());try{const response=await fetch(url,{headers:{"user-agent":"hraness-slopcamera-vectorizer"},redirect:"follow",signal:controller.signal});if(!response.ok||response.body===null){throw new VectorizeError("tool_download",`Could not download VTracer: ${response.status} ${response.statusText}`)}const declaredLength=Number.parseInt(response.headers.get("content-length")??"",10);if(Number.isFinite(declaredLength)&&declaredLength>maximumBytes){throw new VectorizeError("tool_download","VTracer archive exceeds its download limit.")}const chunks=[];const reader=response.body.getReader();let bytes=0;while(true){deadline.assert("VTracer download");const{done,value}=await reader.read();if(done)break;bytes+=value.byteLength;if(bytes>maximumBytes){await reader.cancel();throw new VectorizeError("tool_download","VTracer archive exceeds its download limit.")}chunks.push(value)}return Uint8Array.from(Buffer.concat(chunks,bytes))}catch(error){if(error instanceof VectorizeError)throw error;if(controller.signal.aborted){throw new VectorizeError("timeout","VTracer download exceeded the conversion time limit.")}throw new VectorizeError("tool_download","Could not download VTracer.",{},{cause:error})}finally{clearTimeout(timer)}}function isFileSystemError2(error,code){return error instanceof Error&&"code"in error&&error.code===code}function boundedReadFlags2(){if(process.platform==="win32")return constants3.O_RDONLY;return constants3.O_RDONLY|constants3.O_NONBLOCK|constants3.O_NOFOLLOW}var VECTORIZE_WORKER_PROTOCOL=1;var MAX_VECTORIZE_REQUEST_BYTES=Math.ceil(vectorizeHardLimits.maxInputBytes/3)*4+512*1024;var MAX_VECTORIZE_RESPONSE_BYTES=vectorizeHardLimits.maxOutputBytes*2+512*1024;import{randomUUID as randomUUID2}from"crypto";import{mkdir as mkdir2,rename as rename2,rm as rm3,writeFile as writeFile2}from"fs/promises";import{dirname as dirname3,join as join4,resolve as resolve3}from"path";var PATH_DATA=/^[MmZzLlHhVvCcSsQqTtAaEe0-9+,.\s-]+$/u;var TRANSLATE=/^translate\(\s*[-+0-9.eE]+\s*(?:,\s*|\s+)[-+0-9.eE]+\s*\)$/u;var DANGEROUS_SOURCE=/<!DOCTYPE|<!ENTITY|<\?(?!xml)|<(?:a|animate|embed|filter|foreignObject|iframe|image|link|object|script|set|style|use)\b|(?:href|src)\s*=|\bon[a-z]+\s*=|url\s*\(/iu;function canonicalizeVTracerSvg(sourceSvg,width,height,maxPaths){if(DANGEROUS_SOURCE.test(sourceSvg)){throw new VectorizeError("unsafe_svg","VTracer output contains active or referenced SVG content.")}const paths=[];const pathPattern=/<path\b([^>]*)\/?\s*>/gu;for(const match of sourceSvg.matchAll(pathPattern)){if(paths.length>=maxPaths){throw new VectorizeError("output_limit",`VTracer output exceeds the ${maxPaths}-path limit.`)}const attributes=match[1];const d=attributes.match(/(?:^|\s)d="([^"]*)"/u)?.[1];const fill=attributes.match(/(?:^|\s)fill="([^"]+)"/u)?.[1];const transform=attributes.match(/(?:^|\s)transform="([^"]+)"/u)?.[1];if(d==="")continue;if(d===undefined||d.includes("&")||!PATH_DATA.test(d)){throw new VectorizeError("unsafe_svg","VTracer output contains unsupported path data.")}if(fill===undefined){throw new VectorizeError("unsafe_svg","VTracer output contains a path without a fill.")}if(transform!==undefined&&!TRANSLATE.test(transform)){throw new VectorizeError("unsafe_svg","VTracer output contains an unsupported path transform.")}const normalizedFill=normalizedHexColor(fill);paths.push({d,fill:normalizedFill,rgb:parseHexColor(normalizedFill),...transform===undefined?{}:{transform}})}if(paths.length===0){throw new VectorizeError("trace_failed","VTracer output did not contain visible paths.")}return{paths,svg:buildColorSvg(paths,width,height)}}function buildColorSvg(paths,width,height,duotone){const palette=duotone===undefined?undefined:[normalizedHexColor(duotone.palette[0]),normalizedHexColor(duotone.palette[1])];const body=paths.map(({d,fill,rgb,transform})=>{const outputFill=duotone===undefined||palette===undefined?fill:colorBelongsToPrimary(rgb,duotone.model)?palette[0]:palette[1];return` <path d="${d}"${transform===undefined?"":` transform="${transform}"`} fill="${outputFill}"/>`});const svg=[`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">`,...body,"</svg>",""].join(`
5
+ `);assertSafeCanonicalSvg(svg);return svg}function buildAlphaMaskedSvg(artworkPaths,maskPaths,width,height,duotone){if(maskPaths.some(({rgb})=>rgb[0]!==rgb[1]||rgb[1]!==rgb[2])){throw new VectorizeError("unsafe_svg","An alpha mask may contain only grayscale fills.")}const palette=duotone===undefined?undefined:[normalizedHexColor(duotone.palette[0]),normalizedHexColor(duotone.palette[1])];const maskFingerprint=maskPaths.map(({d,fill,transform})=>`${d}
6
+ ${fill}
7
+ ${transform??""}`).join(`
8
+ `);const maskId=`alpha-${sha256(maskFingerprint).slice(0,16)}`;const svg=[`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">`," <defs>",` <mask id="${maskId}" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse" x="0" y="0" width="${width}" height="${height}" mask-type="luminance">`,` <rect x="0" y="0" width="${width}" height="${height}" fill="#000000"/>`,...maskPaths.map(({d,fill,transform})=>` <path d="${d}"${transform===undefined?"":` transform="${transform}"`} fill="${fill}"/>`)," </mask>"," </defs>",` <g mask="url(#${maskId})">`,...artworkPaths.map(({d,fill,rgb,transform})=>{const outputFill=duotone===undefined||palette===undefined?fill:colorBelongsToPrimary(rgb,duotone.model)?palette[0]:palette[1];return` <path d="${d}"${transform===undefined?"":` transform="${transform}"`} fill="${outputFill}"/>`})," </g>","</svg>",""].join(`
9
+ `);assertSafeCanonicalSvg(svg);return svg}function countSvgPaths(svg){return svg.match(/<path\b/gu)?.length??0}function assertSafeCanonicalSvg(svg){if(/<!DOCTYPE|<!ENTITY|<\?(?!xml)|<(?:a|animate|embed|filter|foreignObject|iframe|image|link|object|script|set|style|use)\b|(?:href|src)\s*=|\bon[a-z]+\s*=/iu.test(svg)){throw new VectorizeError("unsafe_svg","Canonical SVG contains active or external content.")}for(const match of svg.matchAll(/url\(([^)]+)\)/gu)){if(!/^#[a-z0-9-]+$/u.test(match[1])){throw new VectorizeError("unsafe_svg","Canonical SVG contains an external URL.")}if(!svg.includes(`id="${match[1].slice(1)}"`)){throw new VectorizeError("unsafe_svg","Canonical SVG references an unknown local ID.")}}}import{fileURLToPath}from"url";import{mkdtemp as mkdtemp2,rm as rm2}from"fs/promises";import{tmpdir}from"os";import{dirname as dirname2,join as join3}from"path";var vectorizeErrorCodes=new Set(["input_limit","invalid_input","output_limit","quality_limit","timeout","tool_download","tool_integrity","tool_platform","tool_version","trace_failed","unsafe_svg"]);var WORKER_SHUTDOWN_RESERVE_MS=250;var WORKER_RESPONSE_RESERVE_MS=100;async function runVectorizeWorker(input,options){const startedAt=performance.now();const limits=resolveVectorizeLimits(options.limits);if(process.platform==="win32"){throw new VectorizeError("tool_platform","Bounded VTracer streaming is unavailable on Windows.",{platform:process.platform})}const workerInput=encodeInput(input,limits.maxInputBytes);const temporaryRoot=await mkdtemp2(join3(tmpdir(),"slopcamera-vectorize-"));let result;try{result=await executeVectorizeWorker(workerInput,options,limits,startedAt,temporaryRoot)}finally{await removeTemporaryRoot(temporaryRoot)}if(performance.now()-startedAt>=limits.maxDurationMs){throw new VectorizeError("timeout","Vectorization exceeded the conversion time limit during cleanup.")}return result}async function executeVectorizeWorker(workerInput,options,limits,startedAt,temporaryRoot){const preparationRemainingMs=limits.maxDurationMs-(performance.now()-startedAt);if(preparationRemainingMs<=WORKER_SHUTDOWN_RESERVE_MS+WORKER_RESPONSE_RESERVE_MS){throw new VectorizeError("timeout","Vectorization has no remaining budget for isolated worker execution.")}const workerDurationMs=Math.floor(preparationRemainingMs-WORKER_SHUTDOWN_RESERVE_MS-WORKER_RESPONSE_RESERVE_MS);const inheritedFileDescriptors=inheritedDescriptors(options.inheritedFileDescriptors);const workerInheritedFileDescriptors=inheritedFileDescriptors.map((_descriptor,index)=>index+3);const request={input:workerInput,options:cloneOptions(options,workerDurationMs,workerInheritedFileDescriptors),protocol:VECTORIZE_WORKER_PROTOCOL,temporaryRoot};const requestBytes=Buffer.from(JSON.stringify(request));if(requestBytes.byteLength>MAX_VECTORIZE_REQUEST_BYTES){throw new VectorizeError("input_limit","The vectorization worker request exceeds its IPC limit.",{bytes:requestBytes.byteLength,maximumBytes:MAX_VECTORIZE_REQUEST_BYTES})}const remainingMs=limits.maxDurationMs-(performance.now()-startedAt);if(remainingMs<=WORKER_SHUTDOWN_RESERVE_MS){throw new VectorizeError("timeout","Vectorization has no remaining budget for isolated worker startup and cleanup.")}const{stdout}=await runBoundedCommand([process.execPath,workerEntryPath()],Math.floor(remainingMs-WORKER_SHUTDOWN_RESERVE_MS),"trace_failed",{...inheritedFileDescriptors.length===0?{}:{inheritedFileDescriptors},maxStdoutBytes:MAX_VECTORIZE_RESPONSE_BYTES,stdin:requestBytes});if(performance.now()-startedAt>=limits.maxDurationMs){throw new VectorizeError("timeout","Vectorization exceeded the conversion time limit.")}const response=parseResponse(stdout);if(!response.ok){throw new VectorizeError(response.error.code,response.error.message,response.error.details)}assertResult(response.result,limits.maxOutputBytes);if(performance.now()-startedAt>=limits.maxDurationMs){throw new VectorizeError("timeout","Vectorization exceeded the conversion time limit.")}return response.result}async function removeTemporaryRoot(temporaryRoot){try{await rm2(temporaryRoot,{force:true,recursive:true})}catch(error){throw new VectorizeError("trace_failed","The isolated vectorization directory could not be removed.",{temporaryRoot},{cause:error})}}function encodeInput(input,maximumInputBytes){return typeof input==="string"?{kind:"path",value:input}:encodeBytes(input,maximumInputBytes)}function encodeBytes(input,maximumInputBytes){const view=input instanceof ArrayBuffer?new Uint8Array(input):input;if(view.byteLength<1){throw new VectorizeError("invalid_input","Raster input is empty.")}if(view.byteLength>maximumInputBytes){throw new VectorizeError("input_limit",`Raster input exceeds the ${maximumInputBytes}-byte limit.`,{bytes:view.byteLength,maximumBytes:maximumInputBytes})}return{kind:"bytes",value:Buffer.from(view.buffer,view.byteOffset,view.byteLength).toString("base64")}}function cloneOptions(options,workerDurationMs,inheritedFileDescriptors){return{...options.alphaCutoff===undefined?{}:{alphaCutoff:options.alphaCutoff},...options.cacheDirectory===undefined?{}:{cacheDirectory:options.cacheDirectory},...options.duotone===undefined?{}:{duotone:[options.duotone[0],options.duotone[1]]},...inheritedFileDescriptors.length===0?{}:{inheritedFileDescriptors},limits:{...options.limits,maxDurationMs:workerDurationMs},...options.outputPath===undefined?{}:{outputPath:options.outputPath}}}function inheritedDescriptors(value){const descriptors=value??[];if(descriptors.length>16||descriptors.some((descriptor,index)=>!Number.isSafeInteger(descriptor)||descriptor<0||descriptor>2147483647||descriptors.indexOf(descriptor)!==index)){throw new VectorizeError("invalid_input","Inherited vectorizer descriptors must be unique bounded integers.")}return Object.freeze([...descriptors])}function workerEntryPath(){const modulePath=fileURLToPath(import.meta.url);return modulePath.endsWith(".ts")?join3(dirname2(modulePath),"worker.ts"):join3(dirname2(modulePath),"vectorize","worker.js")}function parseResponse(stdout){let parsed;try{parsed=JSON.parse(stdout)}catch(error){throw new VectorizeError("trace_failed","The vectorization worker returned malformed output.",{},{cause:error})}if(!isRecord(parsed)||parsed.protocol!==VECTORIZE_WORKER_PROTOCOL){throw new VectorizeError("trace_failed","The vectorization worker returned an incompatible response.")}if(parsed.ok===true&&isVectorizeResult(parsed.result)){return parsed}if(parsed.ok===false&&isRecord(parsed.error)&&typeof parsed.error.code==="string"&&vectorizeErrorCodes.has(parsed.error.code)&&typeof parsed.error.message==="string"&&isRecord(parsed.error.details)){return parsed}throw new VectorizeError("trace_failed","The vectorization worker returned an invalid response.")}function assertResult(result,maximumOutputBytes){const bytes=Buffer.byteLength(result.svg);if(bytes<1||bytes>maximumOutputBytes||result.receipt.bytes!==bytes||result.receipt.svgSha256.length!==64){throw new VectorizeError("trace_failed","The vectorization worker response violates its output contract.",{bytes,maximumOutputBytes})}}function isVectorizeResult(value){if(!isRecord(value)||value.outputPath!==null&&typeof value.outputPath!=="string"||typeof value.svg!=="string"||!isRecord(value.receipt)){return false}const profile=value.receipt.profile;return typeof value.receipt.bytes==="number"&&typeof value.receipt.svgSha256==="string"&&typeof profile==="string"&&vectorizeProfileNames.includes(profile)}function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}var DEFAULT_ALPHA_CUTOFF=8;var COMPARE_LOW_ALPHA_MASS_RATIO=0.002;var profiles=[{args:["--colormode","color","--hierarchical","stacked","--mode","spline","--filter_speckle","0","--color_precision","8","--gradient_step","4","--segment_length","4.5","--path_precision","4"],name:"balanced"},{args:["--colormode","color","--hierarchical","stacked","--mode","spline","--filter_speckle","0","--color_precision","8","--gradient_step","2","--segment_length","3.5","--path_precision","5"],name:"detailed"},{args:["--preset","photo","--hierarchical","stacked","--filter_speckle","0"],name:"photo"}];var alphaMaskArgs=["--colormode","color","--hierarchical","cutout","--mode","spline","--filter_speckle","0","--color_precision","8","--gradient_step","2","--segment_length","3.5","--path_precision","5","--corner_threshold","30","--splice_threshold","20"];function vectorizeImage(input,options={}){return runVectorizeWorker(input,options)}async function vectorizeImageInProcess(input,options={},temporaryRoot){const limits=resolveVectorizeLimits(options.limits);const deadline=new VectorizeDeadline(limits.maxDurationMs);const alphaCutoff=options.alphaCutoff??DEFAULT_ALPHA_CUTOFF;if(!Number.isInteger(alphaCutoff)||alphaCutoff<1||alphaCutoff>64){throw new VectorizeError("invalid_input","alphaCutoff must be an integer from 1 through 64.")}const duotonePalette=options.duotone===undefined?undefined:[normalizedHexColor(options.duotone[0]),normalizedHexColor(options.duotone[1])];const raster=await loadRaster(input,limits,deadline);if(process.platform==="win32"){throw new VectorizeError("tool_platform","Bounded VTracer streaming is unavailable on Windows.",{platform:process.platform})}const tool=await ensureVTracer(deadline,temporaryRoot,options.cacheDirectory);const errors=[];const candidates=[];const variations=traceVariations(raster.pixels,alphaCutoff);for(const variation of variations){deadline.assert(`${variation.name} trace`);const sourcePath=join4(temporaryRoot,`${variation.name}.png`);await writeFile2(sourcePath,await encodeTracePng(variation.pixels,raster.width,raster.height));const balanced=await attemptCandidate(raster,variation,profiles[0],sourcePath,tool,temporaryRoot,limits,deadline,errors);if(balanced!==undefined)candidates.push(balanced);if(balanced!==undefined&&passesFastQuality(balanced.quality))continue;const detailed=await attemptCandidate(raster,variation,profiles[1],sourcePath,tool,temporaryRoot,limits,deadline,errors);if(detailed!==undefined)candidates.push(detailed);if([balanced,detailed].some((candidate)=>candidate!==undefined&&passesQuality(candidate.quality))){continue}const photo=await attemptCandidate(raster,variation,profiles[2],sourcePath,tool,temporaryRoot,limits,deadline,errors);if(photo!==undefined)candidates.push(photo)}const baseForMask=[...candidates].sort(compareFidelity)[0];if(baseForMask!==undefined&&hasFractionalAlpha(raster.pixels)&&baseForMask.quality.alphaRmse>0.06){const masked=await attemptAlphaMask(raster,baseForMask,tool,temporaryRoot,limits,deadline,errors);if(masked!==undefined)candidates.push(masked)}const eligible=candidates.filter((candidate)=>candidate.bytes<=limits.maxOutputBytes&&candidate.pathCount<=limits.maxPaths&&passesQuality(candidate.quality));if(eligible.length===0){throw new VectorizeError("quality_limit","No adaptive vector candidate passed the fidelity and output gates.",{candidates:candidates.map(candidateSummary),errors})}const selected=selectCandidate(eligible);const duotone=duotonePalette===undefined?undefined:{model:dominantOklabDuotoneModel(raster.pixels),palette:duotonePalette};const svg=selected.maskPaths===undefined?buildColorSvg(selected.artworkPaths,raster.width,raster.height,duotone):buildAlphaMaskedSvg(selected.artworkPaths,selected.maskPaths,raster.width,raster.height,duotone);assertSafeCanonicalSvg(svg);const bytes=Buffer.byteLength(svg);const pathCount=countSvgPaths(svg);if(bytes>limits.maxOutputBytes||pathCount>limits.maxPaths){throw new VectorizeError("output_limit",`Canonical SVG exceeds ${limits.maxOutputBytes} bytes or ${limits.maxPaths} paths.`,{bytes,pathCount})}deadline.assert("output publication");const outputPath=options.outputPath===undefined?null:await writeSvgAtomically(options.outputPath,svg);const pixelToolchain=sharpProvenance();return{outputPath,receipt:{alphaCutoff:selected.alphaCutoff,bytes,candidatesEvaluated:candidates.length,format:raster.format,height:raster.height,inputBytes:raster.inputBytes,outputMode:duotone===undefined?"color":"duotone",pathCount,profile:selected.profile,provenance:{arch:process.arch,platform:process.platform,sharp:pixelToolchain.sharp,sharpVersions:pixelToolchain.sharpVersions,vips:pixelToolchain.vips,vtracerSha256:tool.sha256,vtracerSource:tool.source,vtracerVersion:tool.version},quality:roundedQuality(selected.quality),receiptVersion:1,representation:selected.representation,sourceSha256:raster.sourceSha256,svgSha256:sha256(svg),width:raster.width},svg}}function traceVariations(pixels,alphaCutoff){const sanitized=sanitizedTraceRgba(pixels,alphaCutoff);const output=[];if(containsVisiblePixel2(sanitized)){output.push({alphaCutoff,name:`alpha-${alphaCutoff}`,pixels:sanitized})}if(alphaCutoff>1&&(output.length===0||lowAlphaMassRatio(pixels,alphaCutoff)>=COMPARE_LOW_ALPHA_MASS_RATIO)){output.push({alphaCutoff:1,name:"alpha-1",pixels:sanitizedTraceRgba(pixels,1)})}if(output.length===0){throw new VectorizeError("invalid_input","Alpha sanitation removed every visible pixel.")}return output}function containsVisiblePixel2(pixels){for(let index=3;index<pixels.length;index+=4){if(pixels[index]>0)return true}return false}async function attemptCandidate(raster,variation,profile,sourcePath,tool,temporaryRoot,limits,deadline,errors){try{const raw=await traceRawSvg(tool,sourcePath,profile.args,temporaryRoot,limits.maxOutputBytes,deadline);deadline.assert(`${profile.name} trace`);const canonical=canonicalizeVTracerSvg(raw,raster.width,raster.height,limits.maxPaths);const bytes=Buffer.byteLength(canonical.svg);const pathCount=canonical.paths.length;if(bytes>limits.maxOutputBytes||pathCount>limits.maxPaths){throw new VectorizeError("output_limit",`${profile.name} exceeds vector output limits.`)}const quality=await scoreSvg(canonical.svg,raster,limits.maxDecodedPixels,deadline);return{alphaCutoff:variation.alphaCutoff,artworkPaths:canonical.paths,bytes,pathCount,profile:profile.name,quality,representation:"color-paths",svg:canonical.svg}}catch(error){if(error instanceof VectorizeError&&error.code==="timeout")throw error;errors.push(`${variation.name}/${profile.name}: ${error instanceof Error?error.message:String(error)}`);return}}async function attemptAlphaMask(raster,base,tool,temporaryRoot,limits,deadline,errors){try{const alphaPixels=alphaPlaneTraceRgba(raster.pixels);const sourcePath=join4(temporaryRoot,"alpha-plane.png");await writeFile2(sourcePath,await encodeTracePng(alphaPixels,raster.width,raster.height));const raw=await traceRawSvg(tool,sourcePath,alphaMaskArgs,temporaryRoot,limits.maxOutputBytes,deadline);const mask=canonicalizeVTracerSvg(raw,raster.width,raster.height,limits.maxPaths);const pathCount=base.artworkPaths.length+mask.paths.length;if(pathCount>limits.maxPaths){throw new VectorizeError("output_limit","Alpha-masked output exceeds the path limit.")}const svg=buildAlphaMaskedSvg(base.artworkPaths,mask.paths,raster.width,raster.height);const bytes=Buffer.byteLength(svg);if(bytes>limits.maxOutputBytes){throw new VectorizeError("output_limit","Alpha-masked output exceeds the byte limit.")}const quality=await scoreSvg(svg,raster,limits.maxDecodedPixels,deadline);return{alphaCutoff:base.alphaCutoff,artworkPaths:base.artworkPaths,bytes,maskPaths:mask.paths,pathCount,profile:base.profile,quality,representation:"alpha-mask",svg}}catch(error){if(error instanceof VectorizeError&&error.code==="timeout")throw error;errors.push(`alpha-mask: ${error instanceof Error?error.message:String(error)}`);return}}async function scoreSvg(svg,raster,maxDecodedPixels,deadline){const candidatePixels=await renderSvgRgba(svg,raster.scoreWidth,raster.scoreHeight,maxDecodedPixels);deadline.assert("quality measurement");const support=measureSupport(raster.scorePixels,candidatePixels,raster.scoreWidth,raster.scoreHeight,1);return{alphaRmse:normalizedAlphaRmse(raster.scorePixels,candidatePixels),colorRmse:normalizedPremultipliedRmse(raster.scorePixels,candidatePixels),outsideAlphaRatio:support.outsideAlphaRatio,sampleHeight:raster.scoreHeight,sampleWidth:raster.scoreWidth,supportRecall:support.supportRecall}}async function traceRawSvg(tool,sourcePath,args,temporaryRoot,maximumBytes,deadline){const{output}=await runBoundedPathOutputCommand((outputPath)=>[tool.path,"--input",sourcePath,"--output",outputPath,...args],deadline.remainingMs(),"trace_failed",{maxOutputBytes:maximumBytes,temporaryRoot});if(output.length===0){throw new VectorizeError("trace_failed","VTracer did not emit an SVG.")}return output}function passesFastQuality(quality){return passesQuality(quality)&&quality.colorRmse<=0.12&&quality.alphaRmse<=0.18&&quality.outsideAlphaRatio<=0.02&&quality.supportRecall>=0.97}function passesQuality(quality){return quality.colorRmse<=0.3&&quality.alphaRmse<=0.3&&quality.outsideAlphaRatio<=0.15&&quality.supportRecall>=0.8}function compareFidelity(left,right){return left.quality.colorRmse-right.quality.colorRmse||left.quality.alphaRmse-right.quality.alphaRmse||left.bytes-right.bytes||left.pathCount-right.pathCount||left.profile.localeCompare(right.profile)}function selectCandidate(candidates){const bestRmse=Math.min(...candidates.map(({quality})=>quality.colorRmse));const fidelityWindow=candidates.filter(({quality})=>quality.colorRmse<=bestRmse+0.005);return[...fidelityWindow].sort((left,right)=>left.bytes-right.bytes||left.pathCount-right.pathCount||left.quality.alphaRmse-right.quality.alphaRmse||left.profile.localeCompare(right.profile)||left.representation.localeCompare(right.representation))[0]}function roundedQuality(quality){const rounded=(value)=>Number(value.toFixed(8));return{alphaRmse:rounded(quality.alphaRmse),colorRmse:rounded(quality.colorRmse),outsideAlphaRatio:rounded(quality.outsideAlphaRatio),sampleHeight:quality.sampleHeight,sampleWidth:quality.sampleWidth,supportRecall:rounded(quality.supportRecall)}}function candidateSummary(candidate){return{alphaCutoff:candidate.alphaCutoff,bytes:candidate.bytes,pathCount:candidate.pathCount,profile:candidate.profile,quality:roundedQuality(candidate.quality),representation:candidate.representation}}async function writeSvgAtomically(path,svg){const outputPath=resolve3(path);await mkdir2(dirname3(outputPath),{recursive:true});const temporaryPath=`${outputPath}.${randomUUID2()}.tmp`;try{await writeFile2(temporaryPath,svg,{flag:"wx"});await rename2(temporaryPath,outputPath)}catch(error){await rm3(temporaryPath,{force:true});throw new VectorizeError("output_limit",`Could not atomically write ${outputPath}.`,{},{cause:error})}return outputPath}
10
+ export{vectorizeProfileNames,VectorizeError,vectorizeHardLimits,vectorizeDefaultLimits,resolveVectorizeLimits,VectorizeDeadline,parseHexColor,normalizedHexColor,configureVectorizeSharpConcurrency,loadRaster,encodeTracePng,withInheritedCommandFileDescriptors,forwardVectorizeWorkerTermination,VTRACER_VERSION,vtracerReleases,VECTORIZE_WORKER_PROTOCOL,MAX_VECTORIZE_REQUEST_BYTES,MAX_VECTORIZE_RESPONSE_BYTES,vectorizeImage,vectorizeImageInProcess};