@hraness/slopcamera 3.2.4

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 (441) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +60 -0
  3. package/PRIVACY.md +46 -0
  4. package/README.md +311 -0
  5. package/SECURITY.md +21 -0
  6. package/apps/desktop/README.md +966 -0
  7. package/apps/desktop/analysis/protocol.ts +223 -0
  8. package/apps/desktop/application/capability-binding.ts +594 -0
  9. package/apps/desktop/application/context.ts +97 -0
  10. package/apps/desktop/application/creative-iteration.ts +1385 -0
  11. package/apps/desktop/application/default-registry.ts +146 -0
  12. package/apps/desktop/application/directing-contract.ts +218 -0
  13. package/apps/desktop/application/directing-plan.ts +178 -0
  14. package/apps/desktop/application/errors.ts +18 -0
  15. package/apps/desktop/application/gateway-port.ts +867 -0
  16. package/apps/desktop/application/html-overlay-browser-runtime.ts +687 -0
  17. package/apps/desktop/application/html-overlay-integrity.ts +337 -0
  18. package/apps/desktop/application/html-overlay-renderer.ts +45 -0
  19. package/apps/desktop/application/index.ts +13 -0
  20. package/apps/desktop/application/operation-completion-checkpoint.ts +333 -0
  21. package/apps/desktop/application/operation-effects.ts +94 -0
  22. package/apps/desktop/application/operation.ts +224 -0
  23. package/apps/desktop/application/operations/analysis/faces.ts +244 -0
  24. package/apps/desktop/application/operations/analysis/music.ts +248 -0
  25. package/apps/desktop/application/operations/analysis/project-auto-zooms.ts +302 -0
  26. package/apps/desktop/application/operations/analysis/project-inactivity.ts +381 -0
  27. package/apps/desktop/application/operations/analysis/scenes.ts +272 -0
  28. package/apps/desktop/application/operations/analysis/shared.ts +202 -0
  29. package/apps/desktop/application/operations/derive/edit-batch.ts +967 -0
  30. package/apps/desktop/application/operations/derive/follow-faces.ts +454 -0
  31. package/apps/desktop/application/operations/edit/bind-candidate-revision.ts +91 -0
  32. package/apps/desktop/application/operations/edit/create-candidate-revision.ts +377 -0
  33. package/apps/desktop/application/operations/edit/create-revision.ts +255 -0
  34. package/apps/desktop/application/operations/edit/freeze-revision.ts +182 -0
  35. package/apps/desktop/application/operations/gateway/image.ts +41 -0
  36. package/apps/desktop/application/operations/gateway/index.ts +17 -0
  37. package/apps/desktop/application/operations/gateway/shared.ts +122 -0
  38. package/apps/desktop/application/operations/gateway/speech.ts +41 -0
  39. package/apps/desktop/application/operations/gateway/transcription.ts +42 -0
  40. package/apps/desktop/application/operations/gateway/video.ts +41 -0
  41. package/apps/desktop/application/operations/index.ts +31 -0
  42. package/apps/desktop/application/operations/iteration/create-candidate.ts +240 -0
  43. package/apps/desktop/application/operations/iteration/create-matrix.ts +117 -0
  44. package/apps/desktop/application/operations/iteration/select.ts +155 -0
  45. package/apps/desktop/application/operations/iteration/shared.ts +250 -0
  46. package/apps/desktop/application/operations/media/audio-effects.ts +376 -0
  47. package/apps/desktop/application/operations/media/binding.ts +79 -0
  48. package/apps/desktop/application/operations/media/capabilities.ts +112 -0
  49. package/apps/desktop/application/operations/media/color-grade.ts +343 -0
  50. package/apps/desktop/application/operations/media/html-overlay.ts +802 -0
  51. package/apps/desktop/application/operations/media/index.ts +8 -0
  52. package/apps/desktop/application/operations/media/ingest.ts +303 -0
  53. package/apps/desktop/application/operations/media/overlay.ts +729 -0
  54. package/apps/desktop/application/operations/media/shared.ts +845 -0
  55. package/apps/desktop/application/operations/media/transform-platform.ts +120 -0
  56. package/apps/desktop/application/operations/project/commit-edits.ts +2054 -0
  57. package/apps/desktop/application/operations/project/promote-selection.ts +495 -0
  58. package/apps/desktop/application/operations/project/snapshot.ts +95 -0
  59. package/apps/desktop/application/operations/recording/index.ts +5 -0
  60. package/apps/desktop/application/operations/recording/pause.ts +34 -0
  61. package/apps/desktop/application/operations/recording/resume.ts +34 -0
  62. package/apps/desktop/application/operations/recording/shared.ts +199 -0
  63. package/apps/desktop/application/operations/recording/start.ts +169 -0
  64. package/apps/desktop/application/operations/recording/stop.ts +34 -0
  65. package/apps/desktop/application/operations/render/bind-candidate-output.ts +324 -0
  66. package/apps/desktop/application/operations/render/materialize-selection.ts +322 -0
  67. package/apps/desktop/application/operations/render/project-caption-plan.ts +287 -0
  68. package/apps/desktop/application/operations/render/project-plan.ts +939 -0
  69. package/apps/desktop/application/operations/render/project-spatial-receipt.ts +70 -0
  70. package/apps/desktop/application/operations/render/project.ts +1922 -0
  71. package/apps/desktop/application/operations/shared.ts +67 -0
  72. package/apps/desktop/application/operations/slopcamera-portable.ts +1188 -0
  73. package/apps/desktop/application/operations/slopcamera-visuals.ts +784 -0
  74. package/apps/desktop/application/operations/spatial-project.ts +209 -0
  75. package/apps/desktop/application/operations/spatial-render.ts +415 -0
  76. package/apps/desktop/application/operations/spatial-scene.ts +97 -0
  77. package/apps/desktop/application/operations/studio.ts +143 -0
  78. package/apps/desktop/application/output-publication-lease.ts +163 -0
  79. package/apps/desktop/application/project-publication-lease.ts +233 -0
  80. package/apps/desktop/application/project-store.ts +196 -0
  81. package/apps/desktop/application/receipts.ts +533 -0
  82. package/apps/desktop/application/registry.ts +182 -0
  83. package/apps/desktop/application/spatial-assets.ts +675 -0
  84. package/apps/desktop/application/spatial-compositor-cadence.ts +23 -0
  85. package/apps/desktop/application/spatial-project-authority.ts +35 -0
  86. package/apps/desktop/application/spatial-project-lease.ts +126 -0
  87. package/apps/desktop/application/spatial-project-render-preparation.ts +225 -0
  88. package/apps/desktop/application/spatial-project-store.ts +286 -0
  89. package/apps/desktop/application/spatial-render-projection.ts +201 -0
  90. package/apps/desktop/application/spatial-render.ts +677 -0
  91. package/apps/desktop/application/spatial-spz.ts +44 -0
  92. package/apps/desktop/application/spatial-world-import.ts +135 -0
  93. package/apps/desktop/application/spatial-world-provenance.ts +46 -0
  94. package/apps/desktop/application/studio-port.ts +58 -0
  95. package/apps/desktop/application/verified-receipt-reconciliation.ts +1574 -0
  96. package/apps/desktop/capture/protocol.ts +689 -0
  97. package/apps/desktop/cli/analyzer.ts +406 -0
  98. package/apps/desktop/cli/args.ts +3181 -0
  99. package/apps/desktop/cli/asset-ingest.ts +747 -0
  100. package/apps/desktop/cli/atomic-render-effects.ts +210 -0
  101. package/apps/desktop/cli/atomic-render-platform.ts +205 -0
  102. package/apps/desktop/cli/atomic-render.ts +50 -0
  103. package/apps/desktop/cli/audio-analysis.ts +252 -0
  104. package/apps/desktop/cli/bounded-map.ts +39 -0
  105. package/apps/desktop/cli/bundle-service.ts +256 -0
  106. package/apps/desktop/cli/capabilities.ts +212 -0
  107. package/apps/desktop/cli/capture-bundle.ts +1117 -0
  108. package/apps/desktop/cli/command-host-resources.ts +251 -0
  109. package/apps/desktop/cli/commands.ts +6836 -0
  110. package/apps/desktop/cli/directing-blob.ts +291 -0
  111. package/apps/desktop/cli/directing-media.ts +517 -0
  112. package/apps/desktop/cli/directing-quote.ts +89 -0
  113. package/apps/desktop/cli/directing-service.ts +288 -0
  114. package/apps/desktop/cli/emoji-assets.ts +538 -0
  115. package/apps/desktop/cli/errors.ts +29 -0
  116. package/apps/desktop/cli/face-analysis-service.ts +940 -0
  117. package/apps/desktop/cli/filter-script.ts +76 -0
  118. package/apps/desktop/cli/gateway-application-port.ts +1142 -0
  119. package/apps/desktop/cli/gateway-credential.ts +81 -0
  120. package/apps/desktop/cli/gateway-media-artifacts.ts +723 -0
  121. package/apps/desktop/cli/gateway-media-catalog.ts +922 -0
  122. package/apps/desktop/cli/gateway-media-service.ts +3106 -0
  123. package/apps/desktop/cli/gateway-media-signature.ts +122 -0
  124. package/apps/desktop/cli/gateway-provider-options.ts +562 -0
  125. package/apps/desktop/cli/gateway-scene-provider.ts +391 -0
  126. package/apps/desktop/cli/help.ts +501 -0
  127. package/apps/desktop/cli/html-overlay-gpu.ts +97 -0
  128. package/apps/desktop/cli/html-overlay-renderer.ts +2478 -0
  129. package/apps/desktop/cli/io.ts +290 -0
  130. package/apps/desktop/cli/main.ts +123 -0
  131. package/apps/desktop/cli/media-effects-service.ts +885 -0
  132. package/apps/desktop/cli/media-ingest-model.ts +364 -0
  133. package/apps/desktop/cli/media-ingest-platform.ts +227 -0
  134. package/apps/desktop/cli/media-ingest-program.ts +200 -0
  135. package/apps/desktop/cli/media-ingest.ts +30 -0
  136. package/apps/desktop/cli/music-analysis-service.ts +434 -0
  137. package/apps/desktop/cli/mutation-lock.ts +530 -0
  138. package/apps/desktop/cli/native-assets.d.ts +12 -0
  139. package/apps/desktop/cli/native-media-runtime.macos.ts +7 -0
  140. package/apps/desktop/cli/overlay-playback.ts +177 -0
  141. package/apps/desktop/cli/paths.ts +265 -0
  142. package/apps/desktop/cli/portable-surface.ts +242 -0
  143. package/apps/desktop/cli/project-camera-receipt.ts +112 -0
  144. package/apps/desktop/cli/project-face-camera.ts +394 -0
  145. package/apps/desktop/cli/project-inactivity-service.ts +552 -0
  146. package/apps/desktop/cli/project-media-integrity.ts +121 -0
  147. package/apps/desktop/cli/project-renderer.ts +1526 -0
  148. package/apps/desktop/cli/project-service.ts +519 -0
  149. package/apps/desktop/cli/project-state-transaction.ts +520 -0
  150. package/apps/desktop/cli/query-limits.ts +1 -0
  151. package/apps/desktop/cli/recording-controller.ts +1567 -0
  152. package/apps/desktop/cli/recording-daemon.ts +931 -0
  153. package/apps/desktop/cli/recording-ref.ts +56 -0
  154. package/apps/desktop/cli/renamed-environment.ts +6 -0
  155. package/apps/desktop/cli/renderer.ts +1439 -0
  156. package/apps/desktop/cli/run-cli-test-helper.ts +60 -0
  157. package/apps/desktop/cli/scene-analysis-service.ts +879 -0
  158. package/apps/desktop/cli/spatial-compositor-verifier.ts +213 -0
  159. package/apps/desktop/cli/spatial-project-service.ts +90 -0
  160. package/apps/desktop/cli/spatial-scene-service.ts +105 -0
  161. package/apps/desktop/cli/spatial-world-service.ts +39 -0
  162. package/apps/desktop/cli/speech-analysis-service.ts +682 -0
  163. package/apps/desktop/cli/studio-assemble.ts +58 -0
  164. package/apps/desktop/cli/studio-command.ts +60 -0
  165. package/apps/desktop/cli/studio-custody.ts +60 -0
  166. package/apps/desktop/cli/studio-encode.ts +216 -0
  167. package/apps/desktop/cli/studio-exr.ts +52 -0
  168. package/apps/desktop/cli/studio-files.ts +179 -0
  169. package/apps/desktop/cli/studio-output-validation.ts +162 -0
  170. package/apps/desktop/cli/studio-process.ts +145 -0
  171. package/apps/desktop/cli/studio-runtime.ts +77 -0
  172. package/apps/desktop/cli/studio-scaffold.ts +70 -0
  173. package/apps/desktop/cli/studio-service.ts +301 -0
  174. package/apps/desktop/cli/studio-spatial-asset.ts +248 -0
  175. package/apps/desktop/cli/studio-template-names.ts +3 -0
  176. package/apps/desktop/cli/studio-workflow.ts +19 -0
  177. package/apps/desktop/cli/time.ts +25 -0
  178. package/apps/desktop/cli/workflow-code.ts +584 -0
  179. package/apps/desktop/cli/workflow-runs.ts +576 -0
  180. package/apps/desktop/code/advanced.ts +139 -0
  181. package/apps/desktop/code/application-node-planner.ts +1288 -0
  182. package/apps/desktop/code/compiler.ts +329 -0
  183. package/apps/desktop/code/contracts.ts +13 -0
  184. package/apps/desktop/code/creative-recipes.ts +94 -0
  185. package/apps/desktop/code/define-workflow.ts +115 -0
  186. package/apps/desktop/code/editing.ts +284 -0
  187. package/apps/desktop/code/file-candidate-provenance.ts +420 -0
  188. package/apps/desktop/code/file-candidate.ts +69 -0
  189. package/apps/desktop/code/graph-builder.ts +10 -0
  190. package/apps/desktop/code/host-resource-policy.ts +55 -0
  191. package/apps/desktop/code/plan-contracts.ts +159 -0
  192. package/apps/desktop/code/planning.ts +361 -0
  193. package/apps/desktop/code/public.ts +134 -0
  194. package/apps/desktop/code/reference-projection.ts +62 -0
  195. package/apps/desktop/code/run-contracts.ts +466 -0
  196. package/apps/desktop/code/run-store.ts +2478 -0
  197. package/apps/desktop/code/runtime-identity.ts +328 -0
  198. package/apps/desktop/code/scheduler.ts +3067 -0
  199. package/apps/desktop/code/semantic-builder.ts +1436 -0
  200. package/apps/desktop/code/source-bundle.ts +1641 -0
  201. package/apps/desktop/code/source-typecheck.ts +211 -0
  202. package/apps/desktop/code/testing.ts +79 -0
  203. package/apps/desktop/code/worker-client.ts +1675 -0
  204. package/apps/desktop/code/worker-effects.ts +141 -0
  205. package/apps/desktop/code/worker-entry.ts +435 -0
  206. package/apps/desktop/code/worker-lease-guardian.ts +179 -0
  207. package/apps/desktop/code/worker-process-identity.ts +484 -0
  208. package/apps/desktop/code/worker-protocol.ts +211 -0
  209. package/apps/desktop/code/workflow-effects.ts +132 -0
  210. package/apps/desktop/contracts/analysis.ts +949 -0
  211. package/apps/desktop/contracts/edit.ts +576 -0
  212. package/apps/desktop/contracts/index.ts +9 -0
  213. package/apps/desktop/contracts/media-effects.ts +139 -0
  214. package/apps/desktop/contracts/project-render.ts +644 -0
  215. package/apps/desktop/contracts/project.ts +740 -0
  216. package/apps/desktop/contracts/recording.ts +1434 -0
  217. package/apps/desktop/contracts/render.ts +334 -0
  218. package/apps/desktop/contracts/runtime.ts +155 -0
  219. package/apps/desktop/contracts/spatial-compositor.ts +58 -0
  220. package/apps/desktop/contracts/spatial-project.ts +159 -0
  221. package/apps/desktop/contracts/spatial-world.ts +48 -0
  222. package/apps/desktop/contracts/video-effects.ts +120 -0
  223. package/apps/desktop/core/alignment-apply.ts +400 -0
  224. package/apps/desktop/core/audio-alignment.ts +466 -0
  225. package/apps/desktop/core/auto-zoom.ts +209 -0
  226. package/apps/desktop/core/canonical-json.ts +14 -0
  227. package/apps/desktop/core/emoji.ts +210 -0
  228. package/apps/desktop/core/events.ts +409 -0
  229. package/apps/desktop/core/face-framing.ts +533 -0
  230. package/apps/desktop/core/face-tracks.ts +326 -0
  231. package/apps/desktop/core/inactivity.ts +137 -0
  232. package/apps/desktop/core/index.ts +30 -0
  233. package/apps/desktop/core/intervals.ts +123 -0
  234. package/apps/desktop/core/montage.ts +236 -0
  235. package/apps/desktop/core/music-analysis.ts +518 -0
  236. package/apps/desktop/core/plan.ts +244 -0
  237. package/apps/desktop/core/project-auto-zoom.ts +75 -0
  238. package/apps/desktop/core/project-camera-spatial.ts +676 -0
  239. package/apps/desktop/core/project-camera.ts +403 -0
  240. package/apps/desktop/core/project-captions.ts +888 -0
  241. package/apps/desktop/core/project-inactivity.ts +125 -0
  242. package/apps/desktop/core/project-metadata.ts +927 -0
  243. package/apps/desktop/core/project-plan.ts +375 -0
  244. package/apps/desktop/core/project-render-plan.ts +303 -0
  245. package/apps/desktop/core/project-time.ts +469 -0
  246. package/apps/desktop/core/render-plan.ts +442 -0
  247. package/apps/desktop/core/scene-cache.ts +174 -0
  248. package/apps/desktop/core/scene-sampling.ts +448 -0
  249. package/apps/desktop/core/spatial-compositor.ts +22 -0
  250. package/apps/desktop/core/spatial-durability.ts +99 -0
  251. package/apps/desktop/core/spatial-project.ts +169 -0
  252. package/apps/desktop/core/spatial-shot-clock.ts +32 -0
  253. package/apps/desktop/core/speech-analysis.ts +333 -0
  254. package/apps/desktop/core/storage.ts +970 -0
  255. package/apps/desktop/core/time-map.ts +91 -0
  256. package/apps/desktop/core/time.ts +61 -0
  257. package/apps/desktop/core/video-effects.ts +660 -0
  258. package/apps/desktop/dist/cli/NebulaSans-Bold-26se8aek.otf +0 -0
  259. package/apps/desktop/dist/cli/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  260. package/apps/desktop/dist/cli/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  261. package/apps/desktop/dist/cli/NebulaSans-Book-8cenzchw.otf +0 -0
  262. package/apps/desktop/dist/cli/main.js +5086 -0
  263. package/apps/desktop/html-overlay/catalog.ts +171 -0
  264. package/apps/desktop/html-overlay/contracts.ts +372 -0
  265. package/apps/desktop/html-overlay/execution-profile.ts +77 -0
  266. package/apps/desktop/html-overlay/index.ts +98 -0
  267. package/apps/desktop/html-overlay/libraries.ts +263 -0
  268. package/apps/desktop/html-overlay/random.ts +49 -0
  269. package/apps/desktop/html-overlay/runtime.ts +813 -0
  270. package/apps/desktop/html-overlay/scaffolds.ts +792 -0
  271. package/apps/desktop/html-overlay/spark-runtime.ts +88 -0
  272. package/apps/desktop/html-overlay/spatial-splat-runtime.ts +60 -0
  273. package/apps/desktop/html-overlay/spatial.ts +720 -0
  274. package/apps/desktop/studio/assets/README.md +39 -0
  275. package/apps/desktop/studio/assets/contracts.ts +129 -0
  276. package/apps/desktop/studio/assets/network.ts +64 -0
  277. package/apps/desktop/studio/assets/poly-haven.ts +148 -0
  278. package/apps/desktop/studio/drivers/blender_driver.py +466 -0
  279. package/apps/desktop/studio/drivers/cadquery_driver.py +176 -0
  280. package/apps/desktop/studio/education/driver.py +308 -0
  281. package/apps/desktop/studio/education/lesson.py +180 -0
  282. package/apps/desktop/studio/education/toolkit.py +249 -0
  283. package/apps/desktop/workflows/chaptered-demo.ts +48 -0
  284. package/apps/desktop/workflows/creative-iteration.ts +107 -0
  285. package/apps/desktop/workflows/creative-selection.ts +92 -0
  286. package/apps/desktop/workflows/fragments.ts +486 -0
  287. package/apps/desktop/workflows/index.ts +93 -0
  288. package/apps/desktop/workflows/polished-screen-demo.ts +128 -0
  289. package/apps/desktop/workflows/scene-direction.ts +12 -0
  290. package/apps/desktop/workflows/social-variants.ts +75 -0
  291. package/apps/desktop/workflows/talking-head-cleanup.ts +53 -0
  292. package/dist/NebulaSans-Bold-26se8aek.otf +0 -0
  293. package/dist/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  294. package/dist/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  295. package/dist/NebulaSans-Book-8cenzchw.otf +0 -0
  296. package/dist/cli.js +479 -0
  297. package/dist/code/advanced.js +270 -0
  298. package/dist/code/index.js +2240 -0
  299. package/dist/generate.js +24 -0
  300. package/dist/host-resources.js +26 -0
  301. package/dist/index-42zsesc1.js +2257 -0
  302. package/dist/index-7308egqr.js +48 -0
  303. package/dist/index-8txs6fkn.js +712 -0
  304. package/dist/index-mcy8z0br.js +192 -0
  305. package/dist/index-p63wavx0.js +2029 -0
  306. package/dist/index-r7gdhmsp.js +424 -0
  307. package/dist/index-sh6xbav6.js +1219 -0
  308. package/dist/index-z1w83f81.js +4 -0
  309. package/dist/index-z7239b4h.js +2363 -0
  310. package/dist/index-zfeg9hmw.js +2013 -0
  311. package/dist/index.js +241 -0
  312. package/dist/operations.js +29 -0
  313. package/dist/skill-install-dh0ntqba.js +10 -0
  314. package/dist/vectorize/worker.js +142 -0
  315. package/dist/workflow.js +16 -0
  316. package/docs/README.md +38 -0
  317. package/docs/studio.md +215 -0
  318. package/examples/studio/blender/README.md +26 -0
  319. package/examples/studio/blender/character.py +152 -0
  320. package/examples/studio/blender/cloth.py +101 -0
  321. package/examples/studio/blender/color_chart.py +29 -0
  322. package/examples/studio/blender/fluid.py +78 -0
  323. package/examples/studio/blender/import_model.py +74 -0
  324. package/examples/studio/blender/product.py +53 -0
  325. package/examples/studio/blender/shaded_street.py +481 -0
  326. package/examples/studio/blender/studio_scene.py +147 -0
  327. package/examples/studio/cadquery/README.md +13 -0
  328. package/examples/studio/cadquery/bracket.py +36 -0
  329. package/examples/studio/cadquery/import_step.py +12 -0
  330. package/examples/studio/education/README.md +46 -0
  331. package/examples/studio/education/lesson.json +99 -0
  332. package/examples/studio/education/scene.py +7 -0
  333. package/examples/studio/hybrid-scene.ts +96 -0
  334. package/examples/studio/native-workflow.ts +14 -0
  335. package/examples/studio/vgpu/README.md +64 -0
  336. package/examples/studio/vgpu/heat-field.mjs +290 -0
  337. package/package.json +304 -0
  338. package/packages/scene/src/index.ts +1 -0
  339. package/packages/scene/src/scene.ts +215 -0
  340. package/schema/diagram.schema.json +334 -0
  341. package/skills/slopcamera/SKILL.md +45 -0
  342. package/skills/slopcamera/agents/openai.yaml +4 -0
  343. package/skills/slopcamera/references/customization.md +77 -0
  344. package/skills/slopcamera/references/diagrams.md +153 -0
  345. package/skills/slopcamera/references/directed-scenes.md +42 -0
  346. package/skills/slopcamera/references/directing-video.md +18 -0
  347. package/skills/slopcamera/references/educational-video.md +26 -0
  348. package/skills/slopcamera/references/gateway-media.md +134 -0
  349. package/skills/slopcamera/references/install.md +62 -0
  350. package/skills/slopcamera/references/native-studio.md +31 -0
  351. package/skills/slopcamera/references/reference-led-3d.md +140 -0
  352. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-1.jpg +0 -0
  353. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-2.jpg +0 -0
  354. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-1.png +0 -0
  355. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-2.png +0 -0
  356. package/skills/slopcamera/references/rubber-stamp-field-notes.md +144 -0
  357. package/skills/slopcamera/references/vectorization.md +29 -0
  358. package/skills/slopcamera/references/video-projects.md +187 -0
  359. package/skills/slopcamera/references/visual-communication.md +120 -0
  360. package/skills/slopcamera/references/workflows-sdk.md +45 -0
  361. package/skills/slopcamera/scripts/compose-rubber-stamp-field-note.ts +229 -0
  362. package/src/artifacts.ts +106 -0
  363. package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
  364. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
  365. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
  366. package/src/assets/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
  367. package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
  368. package/src/assets/fonts/nebula-sans/PROVENANCE.md +21 -0
  369. package/src/assets.d.ts +9 -0
  370. package/src/cli.ts +601 -0
  371. package/src/cloud-errors.ts +26 -0
  372. package/src/code/advanced.ts +10 -0
  373. package/src/code/boundary.ts +21 -0
  374. package/src/code/canonical-json.ts +129 -0
  375. package/src/code/compiler.ts +953 -0
  376. package/src/code/contracts.ts +576 -0
  377. package/src/code/define-workflow.ts +334 -0
  378. package/src/code/errors.ts +41 -0
  379. package/src/code/graph-builder.ts +945 -0
  380. package/src/code/index.ts +121 -0
  381. package/src/code/json-snapshot.ts +899 -0
  382. package/src/code/json-utf8.ts +88 -0
  383. package/src/code/portable-builder.ts +136 -0
  384. package/src/code/projection.ts +378 -0
  385. package/src/code/public-operations.ts +450 -0
  386. package/src/code/runtime.ts +580 -0
  387. package/src/code/sha256.ts +36 -0
  388. package/src/config.ts +180 -0
  389. package/src/desktop.ts +253 -0
  390. package/src/fs.ts +10 -0
  391. package/src/generate.ts +704 -0
  392. package/src/host-resource-posix.ts +161 -0
  393. package/src/host-resources.ts +1749 -0
  394. package/src/icons.ts +58 -0
  395. package/src/index.ts +200 -0
  396. package/src/label-layout.ts +130 -0
  397. package/src/layout.ts +413 -0
  398. package/src/lint.ts +127 -0
  399. package/src/mcp/boundary.ts +354 -0
  400. package/src/mcp/index.ts +33 -0
  401. package/src/mcp/server.ts +272 -0
  402. package/src/mcp/tools.ts +963 -0
  403. package/src/mcp/types.ts +71 -0
  404. package/src/operations.ts +775 -0
  405. package/src/parse.ts +861 -0
  406. package/src/process-environment.ts +17 -0
  407. package/src/render.ts +437 -0
  408. package/src/skill-install.ts +49 -0
  409. package/src/spatial-scene/authoring.ts +27 -0
  410. package/src/spatial-scene/camera-track.ts +83 -0
  411. package/src/spatial-scene/contracts.ts +277 -0
  412. package/src/spatial-scene/evaluate.ts +145 -0
  413. package/src/spatial-scene/gltf.ts +558 -0
  414. package/src/spatial-scene/identity.ts +260 -0
  415. package/src/spatial-scene/index.ts +10 -0
  416. package/src/spatial-scene/inspect.ts +68 -0
  417. package/src/spatial-scene/math.ts +280 -0
  418. package/src/spatial-scene/patch.ts +131 -0
  419. package/src/spatial-scene/time.ts +53 -0
  420. package/src/studio/contracts.ts +129 -0
  421. package/src/studio/index.ts +2 -0
  422. package/src/studio/plan.ts +156 -0
  423. package/src/studio/shared.ts +41 -0
  424. package/src/theme.ts +68 -0
  425. package/src/tldr.ts +474 -0
  426. package/src/types.ts +212 -0
  427. package/src/vectorize/archive.ts +101 -0
  428. package/src/vectorize/command.ts +797 -0
  429. package/src/vectorize/index.ts +27 -0
  430. package/src/vectorize/limits.ts +61 -0
  431. package/src/vectorize/metrics.ts +351 -0
  432. package/src/vectorize/pixels.ts +323 -0
  433. package/src/vectorize/supervisor.ts +339 -0
  434. package/src/vectorize/svg.ts +188 -0
  435. package/src/vectorize/tool.ts +542 -0
  436. package/src/vectorize/types.ts +113 -0
  437. package/src/vectorize/vectorize.ts +634 -0
  438. package/src/vectorize/worker-protocol.ts +40 -0
  439. package/src/vectorize/worker.ts +209 -0
  440. package/src/version.ts +1 -0
  441. package/src/workflow.ts +409 -0
@@ -0,0 +1,775 @@
1
+ import { randomUUID } from "node:crypto"
2
+ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises"
3
+ import { dirname, join, resolve } from "node:path"
4
+ import { builtInIcons } from "./icons.js"
5
+ import { lintDiagram } from "./lint.js"
6
+ import { parseDiagramSpec } from "./parse.js"
7
+ import { renderPng, renderSvg } from "./render.js"
8
+ import { serializeTldr } from "./tldr.js"
9
+ import type { DiagramConfig, LintFinding, RenderArtifacts } from "./types.js"
10
+ import {
11
+ generateSlopcameraImageFile,
12
+ slopcameraMaximumPromptBytes,
13
+ type GeneratedSlopcameraImageFile,
14
+ type SlopcameraGenerateDependencies,
15
+ type SlopcameraImageModel,
16
+ } from "./generate.js"
17
+ import {
18
+ vectorizeImage,
19
+ type VectorizeReceipt,
20
+ } from "./vectorize/index.js"
21
+ import {
22
+ createDefaultHostResourceCoordinator,
23
+ type HostResourceClaim,
24
+ type HostResourceCoordinator,
25
+ type HostResourceLease,
26
+ } from "./host-resources.js"
27
+
28
+ export const slopcameraOperationCodes = [
29
+ "slopcamera.diagram.check",
30
+ "slopcamera.diagram.render",
31
+ "slopcamera.image.vectorize",
32
+ "slopcamera.image.generate",
33
+ ] as const
34
+
35
+ export type SlopcameraOperationCode = (typeof slopcameraOperationCodes)[number]
36
+
37
+ export interface SlopcameraOperationDescriptor {
38
+ readonly code: SlopcameraOperationCode
39
+ readonly title: string
40
+ readonly description: string
41
+ readonly execution: "gateway" | "local"
42
+ readonly authentication: "environment" | "none"
43
+ readonly destructive: boolean
44
+ readonly idempotent: boolean
45
+ readonly inputSchema: Readonly<Record<string, unknown>>
46
+ /** Immutable operation-owned physical host admission claims. */
47
+ readonly resources: readonly HostResourceClaim[]
48
+ readonly transport?: {
49
+ readonly method: "POST"
50
+ readonly authority: "https://ai-gateway.vercel.sh/v4/ai"
51
+ readonly authorization: "bearer"
52
+ readonly retry: "never"
53
+ }
54
+ }
55
+
56
+ export class SlopcameraOperationError extends Error {
57
+ readonly code:
58
+ | "INVALID_OPERATION"
59
+ | "INVALID_OPERATION_INPUT"
60
+ | "INVALID_SEARCH"
61
+
62
+ constructor(
63
+ code: SlopcameraOperationError["code"],
64
+ message: string,
65
+ ) {
66
+ super(`[${code}] ${message}`)
67
+ this.name = "SlopcameraOperationError"
68
+ this.code = code
69
+ }
70
+ }
71
+
72
+ const modelSchema = {
73
+ type: "string",
74
+ minLength: 3,
75
+ maxLength: 256,
76
+ pattern: "^[a-zA-Z0-9][a-zA-Z0-9._-]*/[a-zA-Z0-9][a-zA-Z0-9._:-]*$",
77
+ } as const
78
+
79
+ const pathSchema = {
80
+ type: "string",
81
+ minLength: 1,
82
+ maxLength: 4_096,
83
+ } as const
84
+
85
+ function deepFreeze<T>(value: T): T {
86
+ if (typeof value !== "object" || value === null || Object.isFrozen(value)) {
87
+ return value
88
+ }
89
+ for (const nested of Object.values(value)) deepFreeze(nested)
90
+ return Object.freeze(value)
91
+ }
92
+
93
+ export const slopcameraOperationRegistry: readonly SlopcameraOperationDescriptor[] =
94
+ deepFreeze([
95
+ {
96
+ code: "slopcamera.diagram.check",
97
+ title: "Check diagram",
98
+ description:
99
+ "Parse and lint a checked Slopcamera diagram source without changing its files.",
100
+ execution: "local",
101
+ authentication: "none",
102
+ destructive: false,
103
+ idempotent: true,
104
+ inputSchema: {
105
+ type: "object",
106
+ additionalProperties: false,
107
+ required: ["path"],
108
+ properties: { path: pathSchema },
109
+ },
110
+ resources: [
111
+ { resource: "cpu", amount: 1 },
112
+ { resource: "local-io", amount: 1 },
113
+ ],
114
+ },
115
+ {
116
+ code: "slopcamera.diagram.render",
117
+ title: "Render diagram",
118
+ description:
119
+ "Render a checked Slopcamera diagram source to its replaceable light, dark, PNG, SVG, and tldraw artifacts.",
120
+ execution: "local",
121
+ authentication: "none",
122
+ destructive: true,
123
+ idempotent: true,
124
+ inputSchema: {
125
+ type: "object",
126
+ additionalProperties: false,
127
+ required: ["path"],
128
+ properties: {
129
+ path: pathSchema,
130
+ outDirectory: pathSchema,
131
+ scale: {
132
+ type: "number",
133
+ exclusiveMinimum: 0,
134
+ maximum: 4,
135
+ },
136
+ },
137
+ },
138
+ resources: [
139
+ { resource: "cpu", amount: 1 },
140
+ { resource: "local-io", amount: 1 },
141
+ ],
142
+ },
143
+ {
144
+ code: "slopcamera.image.vectorize",
145
+ title: "Vectorize image",
146
+ description:
147
+ "Convert a local caller-owned raster into a bounded inert SVG without authentication or network access.",
148
+ execution: "local",
149
+ authentication: "none",
150
+ destructive: true,
151
+ idempotent: false,
152
+ inputSchema: {
153
+ type: "object",
154
+ additionalProperties: false,
155
+ required: ["inputPath", "outputPath"],
156
+ properties: {
157
+ inputPath: pathSchema,
158
+ outputPath: pathSchema,
159
+ duotone: {
160
+ type: "array",
161
+ minItems: 2,
162
+ maxItems: 2,
163
+ items: {
164
+ type: "string",
165
+ pattern: "^#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$",
166
+ },
167
+ },
168
+ alphaCutoff: { type: "integer", minimum: 1, maximum: 64 },
169
+ timeoutMs: { type: "integer", minimum: 1, maximum: 300_000 },
170
+ },
171
+ },
172
+ resources: [
173
+ { resource: "cpu", amount: 1 },
174
+ { resource: "local-io", amount: 1 },
175
+ ],
176
+ },
177
+ {
178
+ code: "slopcamera.image.generate",
179
+ title: "Generate image",
180
+ description:
181
+ "Generate one bounded image directly through Vercel AI Gateway with an environment credential and no client retry.",
182
+ execution: "gateway",
183
+ authentication: "environment",
184
+ destructive: true,
185
+ idempotent: false,
186
+ inputSchema: {
187
+ type: "object",
188
+ additionalProperties: false,
189
+ required: ["model", "prompt", "outputPath"],
190
+ properties: {
191
+ model: modelSchema,
192
+ prompt: {
193
+ type: "string",
194
+ minLength: 1,
195
+ maxLength: slopcameraMaximumPromptBytes,
196
+ },
197
+ outputPath: pathSchema,
198
+ },
199
+ },
200
+ resources: [
201
+ { resource: "local-io", amount: 1 },
202
+ { resource: "network", amount: 1 },
203
+ { resource: "paid-call", amount: 1 },
204
+ ],
205
+ transport: {
206
+ method: "POST",
207
+ authority: "https://ai-gateway.vercel.sh/v4/ai",
208
+ authorization: "bearer",
209
+ retry: "never",
210
+ },
211
+ },
212
+ ] satisfies readonly SlopcameraOperationDescriptor[])
213
+
214
+ export interface CheckSlopcameraOperationInput {
215
+ readonly path: string
216
+ }
217
+
218
+ export interface RenderSlopcameraOperationInput extends CheckSlopcameraOperationInput {
219
+ readonly outDirectory?: string
220
+ readonly scale?: number
221
+ }
222
+
223
+ export interface VectorizeSlopcameraOperationInput {
224
+ readonly inputPath: string
225
+ readonly outputPath: string
226
+ readonly duotone?: readonly [string, string]
227
+ readonly alphaCutoff?: number
228
+ readonly timeoutMs?: number
229
+ }
230
+
231
+ export interface GenerateSlopcameraOperationInput {
232
+ readonly model: SlopcameraImageModel
233
+ readonly prompt: string
234
+ readonly outputPath: string
235
+ }
236
+
237
+ export interface SlopcameraOperationInputMap {
238
+ readonly "slopcamera.diagram.check": CheckSlopcameraOperationInput
239
+ readonly "slopcamera.diagram.render": RenderSlopcameraOperationInput
240
+ readonly "slopcamera.image.vectorize": VectorizeSlopcameraOperationInput
241
+ readonly "slopcamera.image.generate": GenerateSlopcameraOperationInput
242
+ }
243
+
244
+ export interface SlopcameraOperationResultMap {
245
+ readonly "slopcamera.diagram.check": {
246
+ readonly findings: readonly LintFinding[]
247
+ readonly configPath: null
248
+ }
249
+ readonly "slopcamera.diagram.render": {
250
+ readonly artifacts: RenderArtifacts
251
+ readonly findings: readonly LintFinding[]
252
+ readonly configPath: null
253
+ }
254
+ readonly "slopcamera.image.vectorize": {
255
+ readonly outputPath: string
256
+ readonly receipt: VectorizeReceipt
257
+ }
258
+ readonly "slopcamera.image.generate": GeneratedSlopcameraImageFile
259
+ }
260
+
261
+ function operationFailure(message: string): never {
262
+ throw new SlopcameraOperationError("INVALID_OPERATION_INPUT", message)
263
+ }
264
+
265
+ function isRecord(value: unknown): value is Record<string, unknown> {
266
+ return typeof value === "object" && value !== null && !Array.isArray(value)
267
+ }
268
+
269
+ function record(
270
+ value: unknown,
271
+ allowedKeys: readonly string[],
272
+ ): Record<string, unknown> {
273
+ if (!isRecord(value)) operationFailure("Operation input must be an object.")
274
+ const unknown = Object.keys(value).filter((key) => !allowedKeys.includes(key))
275
+ if (unknown.length > 0) {
276
+ operationFailure(`Unsupported operation input field: ${unknown[0]}.`)
277
+ }
278
+ return value
279
+ }
280
+
281
+ function pathValue(value: unknown, name: string): string {
282
+ if (
283
+ typeof value !== "string" ||
284
+ value.length < 1 ||
285
+ value.length > 4_096 ||
286
+ value.includes("\0")
287
+ ) {
288
+ operationFailure(`${name} must be a non-empty bounded local path.`)
289
+ }
290
+ return value
291
+ }
292
+
293
+ function parseCheck(value: unknown): CheckSlopcameraOperationInput {
294
+ const input = record(value, ["path"])
295
+ return { path: pathValue(input.path, "path") }
296
+ }
297
+
298
+ function parseRender(value: unknown): RenderSlopcameraOperationInput {
299
+ const input = record(value, ["path", "outDirectory", "scale"])
300
+ const scale = input.scale
301
+ if (
302
+ scale !== undefined &&
303
+ (typeof scale !== "number" ||
304
+ !Number.isFinite(scale) ||
305
+ scale <= 0 ||
306
+ scale > 4)
307
+ ) {
308
+ operationFailure("scale must be greater than zero and no more than 4.")
309
+ }
310
+ return {
311
+ path: pathValue(input.path, "path"),
312
+ ...(input.outDirectory === undefined
313
+ ? {}
314
+ : { outDirectory: pathValue(input.outDirectory, "outDirectory") }),
315
+ ...(scale === undefined ? {} : { scale }),
316
+ }
317
+ }
318
+
319
+ function parseVectorize(value: unknown): VectorizeSlopcameraOperationInput {
320
+ const input = record(value, [
321
+ "inputPath",
322
+ "outputPath",
323
+ "duotone",
324
+ "alphaCutoff",
325
+ "timeoutMs",
326
+ ])
327
+ const inputPath = pathValue(input.inputPath, "inputPath")
328
+ const outputPath = pathValue(input.outputPath, "outputPath")
329
+ if (!outputPath.toLowerCase().endsWith(".svg")) {
330
+ operationFailure("outputPath must end in .svg.")
331
+ }
332
+ const duotone = input.duotone
333
+ if (
334
+ duotone !== undefined &&
335
+ (!Array.isArray(duotone) ||
336
+ duotone.length !== 2 ||
337
+ duotone.some(
338
+ (color) =>
339
+ typeof color !== "string" ||
340
+ !/^#[a-f0-9]{3}(?:[a-f0-9]{3})?$/iu.test(color),
341
+ ))
342
+ ) {
343
+ operationFailure("duotone must contain exactly two #rgb or #rrggbb colors.")
344
+ }
345
+ const alphaCutoff = input.alphaCutoff
346
+ if (
347
+ alphaCutoff !== undefined &&
348
+ (!Number.isInteger(alphaCutoff) ||
349
+ (alphaCutoff as number) < 1 ||
350
+ (alphaCutoff as number) > 64)
351
+ ) {
352
+ operationFailure("alphaCutoff must be an integer from 1 through 64.")
353
+ }
354
+ const timeoutMs = input.timeoutMs
355
+ if (
356
+ timeoutMs !== undefined &&
357
+ (!Number.isInteger(timeoutMs) ||
358
+ (timeoutMs as number) < 1 ||
359
+ (timeoutMs as number) > 300_000)
360
+ ) {
361
+ operationFailure("timeoutMs must be an integer from 1 through 300000.")
362
+ }
363
+ return {
364
+ inputPath,
365
+ outputPath,
366
+ ...(duotone === undefined
367
+ ? {}
368
+ : { duotone: duotone as unknown as readonly [string, string] }),
369
+ ...(alphaCutoff === undefined ? {} : { alphaCutoff: alphaCutoff as number }),
370
+ ...(timeoutMs === undefined ? {} : { timeoutMs: timeoutMs as number }),
371
+ }
372
+ }
373
+
374
+ function parseGenerate(value: unknown): GenerateSlopcameraOperationInput {
375
+ const input = record(value, ["model", "prompt", "outputPath"])
376
+ if (
377
+ typeof input.model !== "string" ||
378
+ input.model.length > 256 ||
379
+ !/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(input.model)
380
+ ) {
381
+ operationFailure("model must be a bounded Vercel AI Gateway provider/model id.")
382
+ }
383
+ if (
384
+ typeof input.prompt !== "string" ||
385
+ input.prompt.trim().length < 1 ||
386
+ /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u.test(input.prompt) ||
387
+ Buffer.byteLength(input.prompt, "utf8") > slopcameraMaximumPromptBytes
388
+ ) {
389
+ operationFailure(
390
+ `prompt must be non-empty and no more than ${slopcameraMaximumPromptBytes} UTF-8 bytes.`,
391
+ )
392
+ }
393
+ const outputPath = pathValue(input.outputPath, "outputPath")
394
+ if (!/\.(?:jpe?g|png|webp)$/iu.test(outputPath)) {
395
+ operationFailure("outputPath must end in .png, .jpg, .jpeg, or .webp.")
396
+ }
397
+ return {
398
+ model: input.model as SlopcameraImageModel,
399
+ prompt: input.prompt,
400
+ outputPath,
401
+ }
402
+ }
403
+
404
+ export function parseSlopcameraOperationInput<C extends SlopcameraOperationCode>(
405
+ code: C,
406
+ input: unknown,
407
+ ): SlopcameraOperationInputMap[C] {
408
+ switch (code) {
409
+ case "slopcamera.diagram.check":
410
+ return parseCheck(input) as SlopcameraOperationInputMap[C]
411
+ case "slopcamera.diagram.render":
412
+ return parseRender(input) as SlopcameraOperationInputMap[C]
413
+ case "slopcamera.image.vectorize":
414
+ return parseVectorize(input) as SlopcameraOperationInputMap[C]
415
+ case "slopcamera.image.generate":
416
+ return parseGenerate(input) as SlopcameraOperationInputMap[C]
417
+ default:
418
+ throw new SlopcameraOperationError(
419
+ "INVALID_OPERATION",
420
+ "Unknown Slopcamera operation code.",
421
+ )
422
+ }
423
+ }
424
+
425
+ export function isSlopcameraOperationCode(
426
+ value: string,
427
+ ): value is SlopcameraOperationCode {
428
+ return slopcameraOperationCodes.includes(value as SlopcameraOperationCode)
429
+ }
430
+
431
+ export function slopcameraOperationHostResourceClaims(
432
+ code: SlopcameraOperationCode,
433
+ ): readonly HostResourceClaim[] {
434
+ const descriptor = slopcameraOperationRegistry.find(
435
+ (candidate) => candidate.code === code,
436
+ )
437
+ if (descriptor === undefined) {
438
+ throw new SlopcameraOperationError(
439
+ "INVALID_OPERATION",
440
+ "Unknown Slopcamera operation code.",
441
+ )
442
+ }
443
+ return descriptor.resources
444
+ }
445
+
446
+ export function searchSlopcameraOperations(
447
+ query = "",
448
+ limit = slopcameraOperationRegistry.length,
449
+ ): readonly SlopcameraOperationDescriptor[] {
450
+ if (
451
+ typeof query !== "string" ||
452
+ query.length > 200 ||
453
+ /[\u0000-\u001f\u007f]/u.test(query) ||
454
+ !Number.isInteger(limit) ||
455
+ limit < 1 ||
456
+ limit > 20
457
+ ) {
458
+ throw new SlopcameraOperationError(
459
+ "INVALID_SEARCH",
460
+ "Search requires a bounded query and a limit from 1 through 20.",
461
+ )
462
+ }
463
+ const terms = query
464
+ .toLowerCase()
465
+ .split(/\s+/u)
466
+ .filter((term) => term.length > 0)
467
+ return slopcameraOperationRegistry
468
+ .filter((operation) => {
469
+ const haystack =
470
+ `${operation.code} ${operation.title} ${operation.description}`.toLowerCase()
471
+ return terms.every((term) => haystack.includes(term))
472
+ })
473
+ .slice(0, limit)
474
+ }
475
+
476
+ export interface SlopcameraOperationDependencies extends SlopcameraGenerateDependencies {
477
+ /** Callback-scoped host authority inherited by operation subprocesses. */
478
+ readonly inheritedFileDescriptors?: readonly number[]
479
+ /** Optional coordinator override for deterministic hosts and tests. */
480
+ readonly hostResourceCoordinator?: HostResourceCoordinator
481
+ readonly signal?: AbortSignal
482
+ readonly waitTimeoutMilliseconds?: number
483
+ }
484
+
485
+ export interface SlopcameraOperationHostAdmissionOptions {
486
+ readonly hostResourceCoordinator?: HostResourceCoordinator
487
+ readonly signal?: AbortSignal
488
+ readonly waitTimeoutMilliseconds?: number
489
+ }
490
+
491
+ function operationDependenciesWithLease(
492
+ dependencies: SlopcameraOperationDependencies,
493
+ lease: HostResourceLease,
494
+ ): SlopcameraOperationDependencies {
495
+ const inheritedFileDescriptors = [
496
+ ...(dependencies.inheritedFileDescriptors ?? []),
497
+ lease.inheritedFileDescriptor,
498
+ ].filter((descriptor, index, descriptors) => (
499
+ descriptors.indexOf(descriptor) === index
500
+ ))
501
+ if (
502
+ inheritedFileDescriptors.length > 16
503
+ || inheritedFileDescriptors.some((descriptor) => (
504
+ !Number.isSafeInteger(descriptor)
505
+ || descriptor < 0
506
+ || descriptor > 2_147_483_647
507
+ ))
508
+ ) {
509
+ throw new SlopcameraOperationError(
510
+ "INVALID_OPERATION_INPUT",
511
+ "Operation host-resource inheritance exceeds its descriptor bound.",
512
+ )
513
+ }
514
+ const {
515
+ hostResourceCoordinator: _hostResourceCoordinator,
516
+ signal: _signal,
517
+ waitTimeoutMilliseconds: _waitTimeoutMilliseconds,
518
+ ...operationDependencies
519
+ } = dependencies
520
+ return {
521
+ ...operationDependencies,
522
+ inheritedFileDescriptors,
523
+ }
524
+ }
525
+
526
+ export async function withSlopcameraOperationHostAdmission<T>(
527
+ code: SlopcameraOperationCode,
528
+ callback: (lease: HostResourceLease) => T | Promise<T>,
529
+ options: SlopcameraOperationHostAdmissionOptions = {},
530
+ ): Promise<T> {
531
+ const coordinator = options.hostResourceCoordinator
532
+ ?? createDefaultHostResourceCoordinator()
533
+ return await coordinator.withLease(
534
+ slopcameraOperationHostResourceClaims(code),
535
+ async (lease) => {
536
+ await lease.assertOwned()
537
+ return await callback(lease)
538
+ },
539
+ {
540
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
541
+ ...(options.waitTimeoutMilliseconds === undefined
542
+ ? {}
543
+ : { waitTimeoutMilliseconds: options.waitTimeoutMilliseconds }),
544
+ },
545
+ )
546
+ }
547
+
548
+ const operationBuiltInConfig: DiagramConfig = Object.freeze({
549
+ icons: builtInIcons,
550
+ })
551
+
552
+ async function readOperationDiagram(path: string) {
553
+ const absolutePath = resolve(path)
554
+ let value: unknown
555
+ try {
556
+ value = JSON.parse(await readFile(absolutePath, "utf8"))
557
+ } catch (cause) {
558
+ throw new SlopcameraOperationError(
559
+ "INVALID_OPERATION_INPUT",
560
+ "Diagram source could not be read as JSON.",
561
+ )
562
+ }
563
+ const spec = parseDiagramSpec(value)
564
+ for (const shape of spec.shapes) {
565
+ if (
566
+ (shape.type === "rect" || shape.type === "ellipse") &&
567
+ shape.icon !== undefined &&
568
+ !Object.hasOwn(builtInIcons, shape.icon)
569
+ ) {
570
+ throw new SlopcameraOperationError(
571
+ "INVALID_OPERATION_INPUT",
572
+ "Diagram requests an unavailable built-in icon.",
573
+ )
574
+ }
575
+ }
576
+ return { absolutePath, spec }
577
+ }
578
+
579
+ async function atomicOperationWrite(
580
+ path: string,
581
+ value: string | Uint8Array,
582
+ ): Promise<void> {
583
+ const temporaryPath = join(
584
+ dirname(path),
585
+ `.${randomUUID()}.slopcamera-operation.tmp`,
586
+ )
587
+ try {
588
+ await writeFile(temporaryPath, value, { flag: "wx" })
589
+ await rename(temporaryPath, path)
590
+ } finally {
591
+ await rm(temporaryPath, { force: true }).catch(() => undefined)
592
+ }
593
+ }
594
+
595
+ async function checkOperationDiagram(path: string) {
596
+ const { spec } = await readOperationDiagram(path)
597
+ return {
598
+ findings: lintDiagram(spec),
599
+ configPath: null,
600
+ } as const
601
+ }
602
+
603
+ async function renderOperationDiagram(
604
+ input: RenderSlopcameraOperationInput,
605
+ ) {
606
+ const { absolutePath, spec } = await readOperationDiagram(input.path)
607
+ const outputDirectory = resolve(input.outDirectory ?? dirname(absolutePath))
608
+ const scale = input.scale ?? 2
609
+ const [light, dark] = await Promise.all([
610
+ renderSvg(spec, "light", operationBuiltInConfig),
611
+ renderSvg(spec, "dark", operationBuiltInConfig),
612
+ ])
613
+ const [lightPng, darkPng] = [
614
+ renderPng(light, operationBuiltInConfig, scale),
615
+ renderPng(dark, operationBuiltInConfig, scale),
616
+ ]
617
+ const artifacts = {
618
+ spec: absolutePath,
619
+ tldr: join(outputDirectory, `${spec.name}.tldr`),
620
+ lightSvg: join(outputDirectory, `${spec.name}.light.svg`),
621
+ darkSvg: join(outputDirectory, `${spec.name}.dark.svg`),
622
+ lightPng: join(outputDirectory, `${spec.name}.light.png`),
623
+ darkPng: join(outputDirectory, `${spec.name}.dark.png`),
624
+ } satisfies RenderArtifacts
625
+ await mkdir(outputDirectory, { recursive: true })
626
+ await Promise.all([
627
+ atomicOperationWrite(
628
+ artifacts.tldr,
629
+ serializeTldr(spec, operationBuiltInConfig),
630
+ ),
631
+ atomicOperationWrite(artifacts.lightSvg, light.svg),
632
+ atomicOperationWrite(artifacts.darkSvg, dark.svg),
633
+ atomicOperationWrite(artifacts.lightPng, lightPng),
634
+ atomicOperationWrite(artifacts.darkPng, darkPng),
635
+ ])
636
+ return {
637
+ artifacts,
638
+ findings: lintDiagram(spec),
639
+ configPath: null,
640
+ } as const
641
+ }
642
+
643
+ async function executeSlopcameraOperationUncoordinated<
644
+ C extends SlopcameraOperationCode,
645
+ >(
646
+ code: C,
647
+ value: unknown,
648
+ dependencies: SlopcameraOperationDependencies = {},
649
+ ): Promise<SlopcameraOperationResultMap[C]> {
650
+ const input = parseSlopcameraOperationInput(code, value)
651
+ switch (code) {
652
+ case "slopcamera.diagram.check": {
653
+ const options = input as CheckSlopcameraOperationInput
654
+ return (await checkOperationDiagram(options.path)) as SlopcameraOperationResultMap[C]
655
+ }
656
+ case "slopcamera.diagram.render": {
657
+ const options = input as RenderSlopcameraOperationInput
658
+ return (await renderOperationDiagram(options)) as SlopcameraOperationResultMap[C]
659
+ }
660
+ case "slopcamera.image.vectorize": {
661
+ const options = input as VectorizeSlopcameraOperationInput
662
+ const result = await vectorizeImage(options.inputPath, {
663
+ outputPath: options.outputPath,
664
+ ...(options.duotone === undefined ? {} : { duotone: options.duotone }),
665
+ ...(options.alphaCutoff === undefined
666
+ ? {}
667
+ : { alphaCutoff: options.alphaCutoff }),
668
+ ...(options.timeoutMs === undefined
669
+ ? {}
670
+ : { limits: { maxDurationMs: options.timeoutMs } }),
671
+ ...(dependencies.inheritedFileDescriptors === undefined
672
+ ? {}
673
+ : {
674
+ inheritedFileDescriptors:
675
+ dependencies.inheritedFileDescriptors,
676
+ }),
677
+ })
678
+ if (result.outputPath === null) {
679
+ throw new SlopcameraOperationError(
680
+ "INVALID_OPERATION_INPUT",
681
+ "Vectorization did not publish its required output.",
682
+ )
683
+ }
684
+ return {
685
+ outputPath: result.outputPath,
686
+ receipt: result.receipt,
687
+ } as SlopcameraOperationResultMap[C]
688
+ }
689
+ case "slopcamera.image.generate": {
690
+ const options = input as GenerateSlopcameraOperationInput
691
+ return (await generateSlopcameraImageFile(
692
+ {
693
+ ...options,
694
+ ...(dependencies.signal === undefined
695
+ ? {}
696
+ : { signal: dependencies.signal }),
697
+ },
698
+ dependencies,
699
+ )) as SlopcameraOperationResultMap[C]
700
+ }
701
+ default:
702
+ throw new SlopcameraOperationError(
703
+ "INVALID_OPERATION",
704
+ "Unknown Slopcamera operation code.",
705
+ )
706
+ }
707
+ }
708
+
709
+ /** Execute one operation under authority already held by a workflow node. */
710
+ export async function executeSlopcameraOperationWithLease<
711
+ C extends SlopcameraOperationCode,
712
+ >(
713
+ code: C,
714
+ value: unknown,
715
+ lease: HostResourceLease,
716
+ dependencies: SlopcameraOperationDependencies = {},
717
+ ): Promise<SlopcameraOperationResultMap[C]> {
718
+ await lease.assertOwned()
719
+ const available = new Map<string, number>()
720
+ for (const claim of lease.claims) {
721
+ if (
722
+ typeof claim.resource !== "string"
723
+ || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u.test(claim.resource)
724
+ || !Number.isSafeInteger(claim.amount)
725
+ || claim.amount < 1
726
+ ) {
727
+ throw new SlopcameraOperationError(
728
+ "INVALID_OPERATION",
729
+ "The active host-resource lease contains invalid claims.",
730
+ )
731
+ }
732
+ const total = (available.get(claim.resource) ?? 0) + claim.amount
733
+ if (!Number.isSafeInteger(total)) {
734
+ throw new SlopcameraOperationError(
735
+ "INVALID_OPERATION",
736
+ "The active host-resource lease contains invalid claims.",
737
+ )
738
+ }
739
+ available.set(claim.resource, total)
740
+ }
741
+ const missing = slopcameraOperationHostResourceClaims(code).filter(
742
+ claim => (available.get(claim.resource) ?? 0) < claim.amount,
743
+ )
744
+ if (missing.length > 0) {
745
+ throw new SlopcameraOperationError(
746
+ "INVALID_OPERATION",
747
+ `The active host-resource lease does not cover ${missing
748
+ .map(claim => `${claim.resource}:${String(claim.amount)}`)
749
+ .join(", ")}.`,
750
+ )
751
+ }
752
+ return await executeSlopcameraOperationUncoordinated(
753
+ code,
754
+ value,
755
+ operationDependenciesWithLease(dependencies, lease),
756
+ )
757
+ }
758
+
759
+ /** Execute one direct SDK operation under machine-wide resource admission. */
760
+ export async function executeSlopcameraOperation<C extends SlopcameraOperationCode>(
761
+ code: C,
762
+ value: unknown,
763
+ dependencies: SlopcameraOperationDependencies = {},
764
+ ): Promise<SlopcameraOperationResultMap[C]> {
765
+ const input = parseSlopcameraOperationInput(code, value)
766
+ return await withSlopcameraOperationHostAdmission(
767
+ code,
768
+ async (lease) => await executeSlopcameraOperationUncoordinated(
769
+ code,
770
+ input,
771
+ operationDependenciesWithLease(dependencies, lease),
772
+ ),
773
+ dependencies,
774
+ )
775
+ }