@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,1142 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstat, realpath } from "node:fs/promises";
3
+ import {
4
+ isAbsolute,
5
+ relative,
6
+ resolve,
7
+ } from "node:path";
8
+
9
+ import { z } from "zod";
10
+
11
+ import type { ApplicationContext } from "../application/context";
12
+ import { ApplicationError } from "../application/errors";
13
+ import {
14
+ GatewayMediaSourceReferenceSchema,
15
+ GatewayOperationNameSchema,
16
+ GatewayOperationResultSchema,
17
+ GatewayPortRequestSchema,
18
+ GatewayRequestIdSchema,
19
+ type ApplicationGatewayPort,
20
+ type GatewayMediaSourceReference,
21
+ type GatewayOperationResult,
22
+ type GatewayPortDispatch,
23
+ type GatewayPortPrepare,
24
+ type GatewayPortReconcile,
25
+ type GatewayPortRequest,
26
+ } from "../application/gateway-port";
27
+ import {
28
+ bindRepositoryMedia,
29
+ loadRepositoryMedia,
30
+ } from "../application/operations";
31
+ import {
32
+ RepositoryRelativePathSchema,
33
+ Sha256Schema,
34
+ } from "../contracts";
35
+ import {
36
+ canonicalJson,
37
+ sha256Hex,
38
+ } from "../core/canonical-json";
39
+ import { createNodeBundleFileSystem } from "../core/storage";
40
+ import type { GatewayMediaArtifactBundle } from "./gateway-media-artifacts";
41
+ import type {
42
+ GatewayMediaDispatchEvent,
43
+ GatewayMediaInput,
44
+ GatewayMediaService,
45
+ } from "./gateway-media-service";
46
+ import {
47
+ GATEWAY_MEDIA_UPLOAD_POLICY,
48
+ validateGatewayMediaSourceUrl,
49
+ } from "./gateway-media-service";
50
+ import { gatewayMediaBytesMatchType } from "./gateway-media-signature";
51
+ import {
52
+ gatewayProviderOptionsSummary,
53
+ type GatewayProviderOptions,
54
+ } from "./gateway-provider-options";
55
+ import { withMutationLock } from "./mutation-lock";
56
+ import {
57
+ ensurePhysicalPrivateDirectoryWithin,
58
+ ensurePrivateDirectory,
59
+ } from "./paths";
60
+
61
+ const GATEWAY_REQUEST_DIGEST_DOMAIN =
62
+ "studio.gateway-application-request/v1";
63
+ const GATEWAY_FAILURE_DIGEST_DOMAIN =
64
+ "studio.gateway-application-failure/v1";
65
+ const GATEWAY_CONFLICT_DIGEST_DOMAIN =
66
+ "studio.gateway-application-conflict/v1";
67
+ const GATEWAY_JOURNAL_FILE = "request.json";
68
+ const MAXIMUM_GATEWAY_SOURCE_BYTES = 512 * 1024 * 1024;
69
+ const MAXIMUM_GATEWAY_RECEIPT_BYTES = 256 * 1024;
70
+
71
+ const GatewayJournalSchema = z.strictObject({
72
+ chargeMayHaveOccurred: z.boolean(),
73
+ createdAt: z.string().datetime({ offset: true }),
74
+ failureSha256: Sha256Schema.optional(),
75
+ kind: z.union([
76
+ z.literal("slopcamera.gateway-workflow-request"),
77
+ z.literal("studio.gateway-workflow-request"),
78
+ ]),
79
+ model: z.string().min(3).max(256),
80
+ operation: GatewayOperationNameSchema,
81
+ requestId: GatewayRequestIdSchema,
82
+ requestSha256: Sha256Schema,
83
+ result: GatewayOperationResultSchema.optional(),
84
+ schemaVersion: z.literal(1),
85
+ sourceBindings: z.array(GatewayMediaSourceReferenceSchema).max(65).optional(),
86
+ state: z.enum(["prepared", "dispatched", "completed"]),
87
+ updatedAt: z.string().datetime({ offset: true }),
88
+ }).superRefine((journal, context) => {
89
+ if (
90
+ (journal.state === "completed") !== (journal.result !== undefined)
91
+ || journal.chargeMayHaveOccurred === (journal.state === "prepared")
92
+ || (
93
+ journal.result !== undefined
94
+ && (
95
+ journal.result.operation !== journal.operation
96
+ || journal.result.model !== journal.model
97
+ || journal.result.requestId !== journal.requestId
98
+ )
99
+ )
100
+ ) {
101
+ context.addIssue({
102
+ code: "custom",
103
+ message: "Gateway workflow journal state is inconsistent.",
104
+ });
105
+ }
106
+ });
107
+
108
+ type GatewayJournal = z.infer<typeof GatewayJournalSchema>;
109
+
110
+ export interface GatewayApplicationMediaFacts {
111
+ readonly durationSeconds?: number;
112
+ readonly height?: number;
113
+ readonly width?: number;
114
+ }
115
+
116
+ export interface GatewayApplicationMediaInspectionInput {
117
+ readonly data: Uint8Array;
118
+ readonly mediaType: string;
119
+ readonly path: string;
120
+ }
121
+
122
+ export type GatewayApplicationMediaInspector = (
123
+ inputs: readonly GatewayApplicationMediaInspectionInput[],
124
+ signal: AbortSignal,
125
+ hostResourceLease: ApplicationContext["hostResourceLease"],
126
+ ) => Promise<readonly GatewayApplicationMediaFacts[]>;
127
+
128
+ export type GatewayApplicationProviderOptionsResolver = (
129
+ reference: Readonly<{
130
+ readonly namespaces: readonly string[];
131
+ readonly sha256: string;
132
+ }>,
133
+ signal: AbortSignal,
134
+ ) => Promise<GatewayProviderOptions | undefined>;
135
+
136
+ export interface GatewayApplicationServiceCallbacks {
137
+ readonly beforePublication: () => Promise<void>;
138
+ readonly onDispatch: (event: GatewayMediaDispatchEvent) => Promise<void>;
139
+ }
140
+
141
+ export type GatewayApplicationServiceFactory = (
142
+ callbacks: GatewayApplicationServiceCallbacks,
143
+ hostResourceLease: ApplicationContext["hostResourceLease"],
144
+ ) => Promise<GatewayMediaService>;
145
+
146
+ export interface CreateGatewayApplicationPortOptions {
147
+ readonly application: ApplicationContext;
148
+ readonly createService: GatewayApplicationServiceFactory;
149
+ readonly inspectMedia: GatewayApplicationMediaInspector;
150
+ readonly now?: () => Date;
151
+ readonly resolveProviderOptions?: GatewayApplicationProviderOptionsResolver;
152
+ }
153
+
154
+ interface LoadedGatewaySource {
155
+ readonly data: Uint8Array;
156
+ readonly source: GatewayMediaSourceReference;
157
+ }
158
+
159
+ interface PreparedGatewayRequest {
160
+ readonly loaded: readonly LoadedGatewaySource[];
161
+ readonly request: GatewayPortRequest;
162
+ }
163
+
164
+ function throwIfAborted(signal: AbortSignal): void {
165
+ if (signal.aborted) {
166
+ throw new ApplicationError("cancelled", "Gateway operation was cancelled.");
167
+ }
168
+ }
169
+
170
+ function noEntry(error: unknown): boolean {
171
+ return error instanceof Error
172
+ && "code" in error
173
+ && error.code === "ENOENT";
174
+ }
175
+
176
+ function requestSha256(request: GatewayPortRequest): string {
177
+ return sha256Hex(
178
+ `${GATEWAY_REQUEST_DIGEST_DOMAIN}\0${canonicalJson(request)}`,
179
+ );
180
+ }
181
+
182
+ function failureSha256(error: unknown): string {
183
+ const source = error instanceof Error
184
+ ? `${error.name}\0${error.message}`
185
+ : typeof error;
186
+ return sha256Hex(`${GATEWAY_FAILURE_DIGEST_DOMAIN}\0${source}`);
187
+ }
188
+
189
+ function conflictSha256(reason: string): string {
190
+ return sha256Hex(`${GATEWAY_CONFLICT_DIGEST_DOMAIN}\0${reason}`);
191
+ }
192
+
193
+ function journalMatches(
194
+ journal: GatewayJournal,
195
+ request: GatewayPortRequest,
196
+ requestId: string,
197
+ digest: string,
198
+ ): boolean {
199
+ return journal.requestId === requestId
200
+ && journal.requestSha256 === digest
201
+ && journal.operation === request.operation
202
+ && journal.model === request.request.model
203
+ && (
204
+ journal.sourceBindings === undefined
205
+ || canonicalJson(journal.sourceBindings) === canonicalJson(gatewaySources(request))
206
+ );
207
+ }
208
+
209
+ async function gatewayRequestDirectory(
210
+ application: ApplicationContext,
211
+ requestId: string,
212
+ ): Promise<string> {
213
+ await ensurePrivateDirectory(application.paths.privateRoot);
214
+ const root = await ensurePhysicalPrivateDirectoryWithin(
215
+ application.paths.privateRoot,
216
+ "gateway-workflow-requests",
217
+ );
218
+ return await ensurePhysicalPrivateDirectoryWithin(root, requestId);
219
+ }
220
+
221
+ async function readJournal(
222
+ directory: string,
223
+ ): Promise<GatewayJournal | null> {
224
+ const fileSystem = createNodeBundleFileSystem(directory);
225
+ let source: string;
226
+ try {
227
+ source = await fileSystem.readText(GATEWAY_JOURNAL_FILE);
228
+ } catch (error) {
229
+ if (noEntry(error)) return null;
230
+ throw error;
231
+ }
232
+ try {
233
+ return GatewayJournalSchema.parse(JSON.parse(source) as unknown);
234
+ } catch {
235
+ throw new ApplicationError(
236
+ "conflict",
237
+ "The durable Gateway request journal is invalid.",
238
+ );
239
+ }
240
+ }
241
+
242
+ async function writeJournal(
243
+ directory: string,
244
+ journal: GatewayJournal,
245
+ ): Promise<GatewayJournal> {
246
+ const parsed = GatewayJournalSchema.parse(journal);
247
+ await createNodeBundleFileSystem(directory).writeTextAtomic(
248
+ GATEWAY_JOURNAL_FILE,
249
+ `${canonicalJson(parsed)}\n`,
250
+ );
251
+ return parsed;
252
+ }
253
+
254
+ function journalIdentity(
255
+ journal: GatewayJournal,
256
+ ): Omit<
257
+ GatewayJournal,
258
+ | "chargeMayHaveOccurred"
259
+ | "failureSha256"
260
+ | "result"
261
+ | "state"
262
+ | "updatedAt"
263
+ > {
264
+ return {
265
+ createdAt: journal.createdAt,
266
+ kind: journal.kind,
267
+ model: journal.model,
268
+ operation: journal.operation,
269
+ requestId: journal.requestId,
270
+ requestSha256: journal.requestSha256,
271
+ schemaVersion: journal.schemaVersion,
272
+ ...(journal.sourceBindings === undefined
273
+ ? {}
274
+ : { sourceBindings: journal.sourceBindings }),
275
+ };
276
+ }
277
+
278
+ function gatewaySources(
279
+ request: GatewayPortRequest,
280
+ ): readonly GatewayMediaSourceReference[] {
281
+ switch (request.operation) {
282
+ case "image":
283
+ return [
284
+ ...(request.request.images ?? []),
285
+ ...(request.request.mask === undefined ? [] : [request.request.mask]),
286
+ ];
287
+ case "video":
288
+ return [
289
+ ...(request.request.promptImage === undefined
290
+ ? []
291
+ : [request.request.promptImage]),
292
+ ...(request.request.frames ?? []).map(frame => frame.source),
293
+ ...(request.request.references ?? []),
294
+ ];
295
+ case "speech":
296
+ return [];
297
+ case "transcription":
298
+ return [request.request.audio];
299
+ }
300
+ }
301
+
302
+ function replaceGatewaySources(
303
+ request: GatewayPortRequest,
304
+ sources: readonly GatewayMediaSourceReference[],
305
+ ): GatewayPortRequest {
306
+ let index = 0;
307
+ const next = (): GatewayMediaSourceReference => {
308
+ const source = sources[index];
309
+ index += 1;
310
+ if (source === undefined) {
311
+ throw new ApplicationError(
312
+ "internal",
313
+ "Gateway preparation lost a media source.",
314
+ );
315
+ }
316
+ return source;
317
+ };
318
+ let replaced: GatewayPortRequest;
319
+ switch (request.operation) {
320
+ case "image":
321
+ replaced = GatewayPortRequestSchema.parse({
322
+ operation: request.operation,
323
+ request: {
324
+ ...request.request,
325
+ ...(request.request.images === undefined
326
+ ? {}
327
+ : { images: request.request.images.map(next) }),
328
+ ...(request.request.mask === undefined ? {} : { mask: next() }),
329
+ },
330
+ });
331
+ break;
332
+ case "video":
333
+ replaced = GatewayPortRequestSchema.parse({
334
+ operation: request.operation,
335
+ request: {
336
+ ...request.request,
337
+ ...(request.request.promptImage === undefined
338
+ ? {}
339
+ : { promptImage: next() }),
340
+ ...(request.request.frames === undefined
341
+ ? {}
342
+ : {
343
+ frames: request.request.frames.map(frame => ({
344
+ ...frame,
345
+ source: next(),
346
+ })),
347
+ }),
348
+ ...(request.request.references === undefined
349
+ ? {}
350
+ : { references: request.request.references.map(next) }),
351
+ },
352
+ });
353
+ break;
354
+ case "speech":
355
+ replaced = request;
356
+ break;
357
+ case "transcription":
358
+ replaced = GatewayPortRequestSchema.parse({
359
+ operation: request.operation,
360
+ request: {
361
+ ...request.request,
362
+ audio: next(),
363
+ },
364
+ });
365
+ break;
366
+ }
367
+ if (index !== sources.length) {
368
+ throw new ApplicationError(
369
+ "internal",
370
+ "Gateway preparation returned an inconsistent media-source count.",
371
+ );
372
+ }
373
+ return replaced;
374
+ }
375
+
376
+ async function readBoundSource(
377
+ application: ApplicationContext,
378
+ source: GatewayMediaSourceReference,
379
+ signal: AbortSignal,
380
+ requireMediaSignature = true,
381
+ ): Promise<LoadedGatewaySource> {
382
+ const loaded = await loadRepositoryMedia(
383
+ application,
384
+ {
385
+ bytes: source.bytes,
386
+ path: source.path,
387
+ sha256: source.sha256,
388
+ },
389
+ signal,
390
+ MAXIMUM_GATEWAY_SOURCE_BYTES,
391
+ );
392
+ throwIfAborted(signal);
393
+ if (
394
+ requireMediaSignature
395
+ && !gatewayMediaBytesMatchType(loaded.data, source.mediaType)
396
+ ) {
397
+ throw new ApplicationError(
398
+ "conflict",
399
+ "Gateway media no longer matches its exact content identity.",
400
+ { path: source.path },
401
+ );
402
+ }
403
+ return { data: loaded.data, source };
404
+ }
405
+
406
+ async function prepareRequestMedia(
407
+ options: CreateGatewayApplicationPortOptions,
408
+ request: GatewayPortRequest,
409
+ signal: AbortSignal,
410
+ hostResourceLease: ApplicationContext["hostResourceLease"],
411
+ ): Promise<PreparedGatewayRequest> {
412
+ const sources = gatewaySources(request);
413
+ const loaded: LoadedGatewaySource[] = [];
414
+ for (const source of sources) {
415
+ loaded.push(await readBoundSource(options.application, source, signal));
416
+ }
417
+ if (loaded.length === 0) return { loaded, request };
418
+ const facts = await options.inspectMedia(
419
+ loaded.map(item => ({
420
+ data: item.data,
421
+ mediaType: item.source.mediaType,
422
+ path: item.source.path,
423
+ })),
424
+ signal,
425
+ hostResourceLease,
426
+ );
427
+ throwIfAborted(signal);
428
+ if (facts.length !== loaded.length) {
429
+ throw new ApplicationError(
430
+ "invalid-data",
431
+ "Gateway media inspection returned an inconsistent result count.",
432
+ );
433
+ }
434
+ const preparedSources = loaded.map((item, index) =>
435
+ GatewayMediaSourceReferenceSchema.parse({
436
+ ...item.source,
437
+ facts: facts[index],
438
+ }));
439
+ return {
440
+ loaded: loaded.map((item, index) => ({
441
+ data: item.data,
442
+ source: preparedSources[index]!,
443
+ })),
444
+ request: replaceGatewaySources(request, preparedSources),
445
+ };
446
+ }
447
+
448
+ async function resolveProviderOptions(
449
+ options: CreateGatewayApplicationPortOptions,
450
+ request: GatewayPortRequest,
451
+ signal: AbortSignal,
452
+ ): Promise<GatewayProviderOptions | undefined> {
453
+ const expected = request.request.providerOptions;
454
+ if (expected === undefined) return undefined;
455
+ throwIfAborted(signal);
456
+ const resolved = await options.resolveProviderOptions?.(expected, signal);
457
+ throwIfAborted(signal);
458
+ if (resolved === undefined) {
459
+ throw new ApplicationError(
460
+ "authorization-required",
461
+ "This exact Gateway request requires its digest-matching provider-options file.",
462
+ {
463
+ namespaces: expected.namespaces,
464
+ providerOptionsSha256: expected.sha256,
465
+ },
466
+ );
467
+ }
468
+ const actual = gatewayProviderOptionsSummary(resolved);
469
+ if (
470
+ actual.sha256 !== expected.sha256
471
+ || canonicalJson(actual.namespaces) !== canonicalJson(expected.namespaces)
472
+ ) {
473
+ throw new ApplicationError(
474
+ "authorization-required",
475
+ "The supplied provider-options file does not match this exact Gateway request.",
476
+ {
477
+ expectedNamespaces: expected.namespaces,
478
+ expectedSha256: expected.sha256,
479
+ suppliedNamespaces: actual.namespaces,
480
+ suppliedSha256: actual.sha256,
481
+ },
482
+ );
483
+ }
484
+ return resolved;
485
+ }
486
+
487
+ function serviceInput(
488
+ item: LoadedGatewaySource,
489
+ url?: string,
490
+ ): GatewayMediaInput {
491
+ const facts = item.source.facts;
492
+ return {
493
+ ...(url === undefined ? { data: item.data } : { url }),
494
+ ...(facts === undefined
495
+ ? {}
496
+ : {
497
+ facts: {
498
+ ...(facts.durationSeconds === undefined
499
+ ? {}
500
+ : { durationSeconds: facts.durationSeconds }),
501
+ ...(facts.height === undefined
502
+ ? {}
503
+ : { height: facts.height }),
504
+ ...(facts.width === undefined
505
+ ? {}
506
+ : { width: facts.width }),
507
+ },
508
+ }),
509
+ mediaType: item.source.mediaType,
510
+ };
511
+ }
512
+
513
+ function serviceOperation(
514
+ operation: GatewayPortRequest["operation"],
515
+ ): GatewayMediaDispatchEvent["operation"] {
516
+ switch (operation) {
517
+ case "image": return "image.generate";
518
+ case "video": return "video.generate";
519
+ case "speech": return "speech.generate";
520
+ case "transcription": return "transcription.create";
521
+ }
522
+ }
523
+
524
+ function serviceConsent(now: Date) {
525
+ return {
526
+ acknowledgedAt: now.toISOString(),
527
+ allowCloudUpload: true,
528
+ policy: GATEWAY_MEDIA_UPLOAD_POLICY,
529
+ } as const;
530
+ }
531
+
532
+ async function executeService(
533
+ service: GatewayMediaService,
534
+ prepared: PreparedGatewayRequest,
535
+ providerOptions: GatewayProviderOptions | undefined,
536
+ signal: AbortSignal,
537
+ now: Date,
538
+ resolveSourceUrl?: GatewayPortDispatch["resolveSourceUrl"],
539
+ ): Promise<Readonly<{
540
+ bundle: GatewayMediaArtifactBundle;
541
+ transcript?: Readonly<{
542
+ readonly durationInSeconds?: number;
543
+ readonly language?: string;
544
+ readonly segments: readonly unknown[];
545
+ readonly text: string;
546
+ }>;
547
+ }>> {
548
+ const inputs: GatewayMediaInput[] = [];
549
+ for (const loaded of prepared.loaded) {
550
+ throwIfAborted(signal);
551
+ const url = prepared.request.operation === "video" && resolveSourceUrl !== undefined
552
+ ? await resolveSourceUrl(
553
+ GatewayMediaSourceReferenceSchema.parse(loaded.source),
554
+ loaded.data.slice(),
555
+ signal,
556
+ )
557
+ : undefined;
558
+ throwIfAborted(signal);
559
+ inputs.push(serviceInput(
560
+ loaded,
561
+ url === undefined ? undefined : validateGatewayMediaSourceUrl(url),
562
+ ));
563
+ }
564
+ let index = 0;
565
+ const next = (): GatewayMediaInput => {
566
+ const input = inputs[index];
567
+ index += 1;
568
+ if (input === undefined) {
569
+ throw new ApplicationError(
570
+ "internal",
571
+ "Gateway dispatch lost one prepared media source.",
572
+ );
573
+ }
574
+ return input;
575
+ };
576
+ const execution = {
577
+ signal,
578
+ ...(prepared.request.request.timeoutMs === undefined
579
+ ? {}
580
+ : { timeoutMs: prepared.request.request.timeoutMs }),
581
+ };
582
+ let result: Readonly<{
583
+ bundle: GatewayMediaArtifactBundle;
584
+ transcript?: Readonly<{
585
+ readonly durationInSeconds?: number;
586
+ readonly language?: string;
587
+ readonly segments: readonly unknown[];
588
+ readonly text: string;
589
+ }>;
590
+ }>;
591
+ switch (prepared.request.operation) {
592
+ case "image": {
593
+ const request = prepared.request.request;
594
+ const bundle = await service.generateImage({
595
+ ...(request.aspectRatio === undefined
596
+ ? {}
597
+ : { aspectRatio: request.aspectRatio }),
598
+ consent: serviceConsent(now),
599
+ images: (request.images ?? []).map(() => next()),
600
+ ...(request.mask === undefined ? {} : { mask: next() }),
601
+ ...(request.maxImagesPerCall === undefined
602
+ ? {}
603
+ : { maxImagesPerCall: request.maxImagesPerCall }),
604
+ ...(request.maxOutputTokens === undefined
605
+ ? {}
606
+ : { maxOutputTokens: request.maxOutputTokens }),
607
+ model: request.model,
608
+ ...(request.n === undefined ? {} : { n: request.n }),
609
+ prompt: request.prompt,
610
+ ...(providerOptions === undefined ? {} : { providerOptions }),
611
+ ...(request.seed === undefined ? {} : { seed: request.seed }),
612
+ ...(request.size === undefined ? {} : { size: request.size }),
613
+ ...(request.stopSequences === undefined
614
+ ? {}
615
+ : { stopSequences: request.stopSequences }),
616
+ ...(request.temperature === undefined
617
+ ? {}
618
+ : { temperature: request.temperature }),
619
+ }, execution);
620
+ result = { bundle };
621
+ break;
622
+ }
623
+ case "video": {
624
+ const request = prepared.request.request;
625
+ const promptImage = request.promptImage === undefined
626
+ ? undefined
627
+ : next();
628
+ const frameImages = (request.frames ?? []).map(frame => ({
629
+ frameType: frame.frameType,
630
+ image: next(),
631
+ }));
632
+ const inputReferences = (request.references ?? []).map(() => next());
633
+ const bundle = await service.generateVideo({
634
+ ...(request.aspectRatio === undefined
635
+ ? {}
636
+ : { aspectRatio: request.aspectRatio }),
637
+ consent: serviceConsent(now),
638
+ ...(request.durationSeconds === undefined
639
+ ? {}
640
+ : { duration: request.durationSeconds }),
641
+ ...(request.fps === undefined ? {} : { fps: request.fps }),
642
+ frameImages,
643
+ ...(request.generateAudio === undefined
644
+ ? {}
645
+ : { generateAudio: request.generateAudio }),
646
+ inputReferences,
647
+ ...(request.maxVideosPerCall === undefined
648
+ ? {}
649
+ : { maxVideosPerCall: request.maxVideosPerCall }),
650
+ model: request.model,
651
+ ...(request.n === undefined ? {} : { n: request.n }),
652
+ prompt: request.prompt,
653
+ ...(promptImage === undefined
654
+ ? {}
655
+ : { promptImage }),
656
+ ...(providerOptions === undefined ? {} : { providerOptions }),
657
+ ...(request.resolution === undefined
658
+ ? {}
659
+ : { resolution: request.resolution }),
660
+ ...(request.seed === undefined ? {} : { seed: request.seed }),
661
+ }, execution);
662
+ result = { bundle };
663
+ break;
664
+ }
665
+ case "speech": {
666
+ const request = prepared.request.request;
667
+ const bundle = await service.generateSpeech({
668
+ consent: serviceConsent(now),
669
+ ...(request.instructions === undefined
670
+ ? {}
671
+ : { instructions: request.instructions }),
672
+ ...(request.language === undefined ? {} : { language: request.language }),
673
+ model: request.model,
674
+ ...(request.outputFormat === undefined
675
+ ? {}
676
+ : { outputFormat: request.outputFormat }),
677
+ ...(providerOptions === undefined ? {} : { providerOptions }),
678
+ ...(request.speed === undefined ? {} : { speed: request.speed }),
679
+ text: request.text,
680
+ ...(request.voice === undefined ? {} : { voice: request.voice }),
681
+ }, execution);
682
+ result = { bundle };
683
+ break;
684
+ }
685
+ case "transcription": {
686
+ const request = prepared.request.request;
687
+ const transcript = await service.transcribe({
688
+ audio: next(),
689
+ consent: serviceConsent(now),
690
+ model: request.model,
691
+ ...(providerOptions === undefined ? {} : { providerOptions }),
692
+ }, execution);
693
+ result = {
694
+ bundle: transcript.artifact,
695
+ transcript,
696
+ };
697
+ break;
698
+ }
699
+ }
700
+ if (index !== prepared.loaded.length) {
701
+ throw new ApplicationError(
702
+ "internal",
703
+ "Gateway dispatch did not consume every prepared media source.",
704
+ );
705
+ }
706
+ return result;
707
+ }
708
+
709
+ function repositoryRelativePath(
710
+ repositoryRoot: string,
711
+ path: string,
712
+ ): string {
713
+ const root = resolve(repositoryRoot);
714
+ const candidate = isAbsolute(path)
715
+ ? resolve(path)
716
+ : resolve(root, path);
717
+ const fromRoot = relative(root, candidate);
718
+ return RepositoryRelativePathSchema.parse(fromRoot);
719
+ }
720
+
721
+ async function verifiedBundleReferences(
722
+ application: ApplicationContext,
723
+ bundle: GatewayMediaArtifactBundle,
724
+ ): Promise<Readonly<{
725
+ outputs: GatewayOperationResult["outputs"];
726
+ receipt: GatewayOperationResult["receipt"];
727
+ }>> {
728
+ const finalizationSignal = new AbortController().signal;
729
+ const outputs: GatewayOperationResult["outputs"][number][] = [];
730
+ for (const output of bundle.outputs) {
731
+ const path = repositoryRelativePath(
732
+ application.paths.repositoryRoot,
733
+ output.path,
734
+ );
735
+ const verified = await bindRepositoryMedia(
736
+ application,
737
+ {
738
+ bytes: output.bytes,
739
+ path,
740
+ sha256: output.sha256,
741
+ },
742
+ finalizationSignal,
743
+ MAXIMUM_GATEWAY_SOURCE_BYTES,
744
+ );
745
+ outputs.push({
746
+ ...verified.artifact,
747
+ mediaType: output.mediaType,
748
+ });
749
+ }
750
+ const receiptPath = repositoryRelativePath(
751
+ application.paths.repositoryRoot,
752
+ bundle.receiptPath,
753
+ );
754
+ const receipt = (
755
+ await bindRepositoryMedia(
756
+ application,
757
+ { path: receiptPath },
758
+ finalizationSignal,
759
+ MAXIMUM_GATEWAY_RECEIPT_BYTES,
760
+ )
761
+ ).artifact;
762
+ return {
763
+ outputs,
764
+ receipt,
765
+ };
766
+ }
767
+
768
+ async function operationResult(
769
+ application: ApplicationContext,
770
+ request: GatewayPortRequest,
771
+ requestId: string,
772
+ serviceResult: Awaited<ReturnType<typeof executeService>>,
773
+ ): Promise<GatewayOperationResult> {
774
+ const expectedOperation = serviceOperation(request.operation);
775
+ const receipt = serviceResult.bundle.receipt;
776
+ if (
777
+ receipt.operation !== expectedOperation
778
+ || receipt.model !== request.request.model
779
+ || receipt.localValidation.status === "decode-failed"
780
+ ) {
781
+ throw new ApplicationError(
782
+ "invalid-data",
783
+ "Gateway artifacts do not contain a valid authoritative receipt for the exact request.",
784
+ { requestId },
785
+ );
786
+ }
787
+ const references = await verifiedBundleReferences(
788
+ application,
789
+ serviceResult.bundle,
790
+ );
791
+ return GatewayOperationResultSchema.parse({
792
+ model: request.request.model,
793
+ operation: request.operation,
794
+ outputs: references.outputs,
795
+ receipt: references.receipt,
796
+ requestId,
797
+ ...(request.operation === "transcription"
798
+ ? {
799
+ transcript: {
800
+ characters: serviceResult.transcript?.text.length ?? 0,
801
+ durationSeconds:
802
+ serviceResult.transcript?.durationInSeconds ?? 0,
803
+ ...(serviceResult.transcript?.language === undefined
804
+ ? {}
805
+ : { language: serviceResult.transcript.language }),
806
+ segments: serviceResult.transcript?.segments.length ?? 0,
807
+ textSha256: createHash("sha256")
808
+ .update(serviceResult.transcript?.text ?? "", "utf8")
809
+ .digest("hex"),
810
+ },
811
+ }
812
+ : {}),
813
+ });
814
+ }
815
+
816
+ async function verifyCompletedResult(
817
+ application: ApplicationContext,
818
+ result: GatewayOperationResult,
819
+ signal: AbortSignal,
820
+ ): Promise<void> {
821
+ for (const output of result.outputs) {
822
+ await readBoundSource(
823
+ application,
824
+ GatewayMediaSourceReferenceSchema.parse(output),
825
+ signal,
826
+ /^(?:audio|image|video)\//u.test(output.mediaType),
827
+ );
828
+ }
829
+ await bindRepositoryMedia(
830
+ application,
831
+ result.receipt,
832
+ signal,
833
+ MAXIMUM_GATEWAY_RECEIPT_BYTES,
834
+ );
835
+ throwIfAborted(signal);
836
+ }
837
+
838
+ function preDispatchError(error: unknown): ApplicationError {
839
+ if (error instanceof ApplicationError) return error;
840
+ return new ApplicationError(
841
+ "unavailable",
842
+ "Gateway media preparation failed before paid dispatch.",
843
+ );
844
+ }
845
+
846
+ export function createGatewayApplicationPort(
847
+ options: CreateGatewayApplicationPortOptions,
848
+ ): ApplicationGatewayPort {
849
+ const now = options.now ?? (() => new Date());
850
+ return {
851
+ prepare: async (input: GatewayPortPrepare) => {
852
+ const request = GatewayPortRequestSchema.parse(input.request);
853
+ throwIfAborted(input.signal);
854
+ await resolveProviderOptions(options, request, input.signal);
855
+ return (await prepareRequestMedia(
856
+ options,
857
+ request,
858
+ input.signal,
859
+ input.hostResourceLease,
860
+ )).request;
861
+ },
862
+ dispatch: async (input: GatewayPortDispatch) => {
863
+ const request = GatewayPortRequestSchema.parse(input.request);
864
+ const requestId = GatewayRequestIdSchema.parse(input.requestId);
865
+ const digest = requestSha256(request);
866
+ throwIfAborted(input.signal);
867
+ const directory = await gatewayRequestDirectory(
868
+ options.application,
869
+ requestId,
870
+ );
871
+ return await withMutationLock(directory, {
872
+ command: `gateway workflow dispatch ${requestId}`,
873
+ label: `Gateway workflow request ${requestId}`,
874
+ now,
875
+ }, async lease => {
876
+ let journal = await readJournal(directory);
877
+ if (
878
+ journal !== null
879
+ && !journalMatches(journal, request, requestId, digest)
880
+ ) {
881
+ throw new ApplicationError(
882
+ "conflict",
883
+ "Gateway request ID is already bound to different exact input.",
884
+ { requestId },
885
+ );
886
+ }
887
+ if (journal?.state === "completed") {
888
+ try {
889
+ await verifyCompletedResult(
890
+ options.application,
891
+ journal.result!,
892
+ input.signal,
893
+ );
894
+ } catch {
895
+ throwIfAborted(input.signal);
896
+ throw new ApplicationError(
897
+ "conflict",
898
+ "The completed Gateway journal no longer matches its committed artifacts.",
899
+ { requestId },
900
+ );
901
+ }
902
+ return journal.result!;
903
+ }
904
+ if (journal?.state === "dispatched") {
905
+ throw new ApplicationError(
906
+ "ambiguous",
907
+ "This exact Gateway request was already dispatched and has no completed local journal result.",
908
+ { requestId },
909
+ );
910
+ }
911
+
912
+ throwIfAborted(input.signal);
913
+ const providerOptions = await resolveProviderOptions(
914
+ options,
915
+ request,
916
+ input.signal,
917
+ );
918
+ const prepared = await prepareRequestMedia(
919
+ options,
920
+ request,
921
+ input.signal,
922
+ input.hostResourceLease,
923
+ );
924
+ if (canonicalJson(prepared.request) !== canonicalJson(request)) {
925
+ throw new ApplicationError(
926
+ "conflict",
927
+ "Gateway media facts changed after the exact node plan was approved.",
928
+ { requestId },
929
+ );
930
+ }
931
+ const createdAt = journal?.createdAt ?? now().toISOString();
932
+ journal = await writeJournal(directory, {
933
+ chargeMayHaveOccurred: false,
934
+ createdAt,
935
+ kind: "slopcamera.gateway-workflow-request",
936
+ model: request.request.model,
937
+ operation: request.operation,
938
+ requestId,
939
+ requestSha256: digest,
940
+ schemaVersion: 1,
941
+ ...(input.resolveSourceUrl === undefined || request.operation !== "video"
942
+ ? {}
943
+ : { sourceBindings: prepared.loaded.map(item => item.source) }),
944
+ state: "prepared",
945
+ updatedAt: now().toISOString(),
946
+ });
947
+ const persistDispatched = async (
948
+ failure?: unknown,
949
+ ): Promise<void> => {
950
+ journal = await writeJournal(directory, {
951
+ ...journalIdentity(journal!),
952
+ chargeMayHaveOccurred: true,
953
+ ...(failure === undefined
954
+ ? {}
955
+ : { failureSha256: failureSha256(failure) }),
956
+ state: "dispatched",
957
+ updatedAt: now().toISOString(),
958
+ });
959
+ };
960
+ try {
961
+ const service = await options.createService({
962
+ beforePublication: input.beforePublication,
963
+ onDispatch: async event => {
964
+ throwIfAborted(input.signal);
965
+ if (
966
+ journal?.state !== "prepared"
967
+ || event.model !== request.request.model
968
+ || event.operation !== serviceOperation(request.operation)
969
+ ) {
970
+ throw new ApplicationError(
971
+ "conflict",
972
+ "Gateway service dispatch did not match its durable prepared request.",
973
+ { requestId },
974
+ );
975
+ }
976
+ await lease.assertOwned();
977
+ await input.beforeDispatch?.();
978
+ throwIfAborted(input.signal);
979
+ await lease.assertOwned();
980
+ await persistDispatched();
981
+ },
982
+ }, input.hostResourceLease);
983
+ const executed = await executeService(
984
+ service,
985
+ prepared,
986
+ providerOptions,
987
+ input.signal,
988
+ now(),
989
+ input.resolveSourceUrl === undefined
990
+ ? undefined
991
+ : async (source, data, signal) => {
992
+ throwIfAborted(signal);
993
+ await lease.assertOwned();
994
+ const url = await input.resolveSourceUrl!(source, data, signal);
995
+ throwIfAborted(signal);
996
+ await lease.assertOwned();
997
+ return url;
998
+ },
999
+ );
1000
+ if (journal.state !== "dispatched") {
1001
+ await persistDispatched(
1002
+ new Error("Gateway service returned without a dispatch event."),
1003
+ );
1004
+ throw new ApplicationError(
1005
+ "ambiguous",
1006
+ "Gateway service returned paid output without its durable dispatch transition.",
1007
+ { requestId },
1008
+ );
1009
+ }
1010
+ const result = await operationResult(
1011
+ options.application,
1012
+ request,
1013
+ requestId,
1014
+ executed,
1015
+ );
1016
+ journal = await writeJournal(directory, {
1017
+ ...journalIdentity(journal),
1018
+ chargeMayHaveOccurred: true,
1019
+ result,
1020
+ state: "completed",
1021
+ updatedAt: now().toISOString(),
1022
+ });
1023
+ return result;
1024
+ } catch (error) {
1025
+ if (journal.state === "dispatched") {
1026
+ await persistDispatched(error).catch(() => undefined);
1027
+ throw new ApplicationError(
1028
+ "ambiguous",
1029
+ "Gateway paid dispatch did not produce a completed authoritative local journal result.",
1030
+ {
1031
+ failureSha256: failureSha256(error),
1032
+ requestId,
1033
+ },
1034
+ );
1035
+ }
1036
+ await lease.assertOwned();
1037
+ journal = await writeJournal(directory, {
1038
+ ...journalIdentity(journal),
1039
+ chargeMayHaveOccurred: false,
1040
+ failureSha256: failureSha256(error),
1041
+ state: "prepared",
1042
+ updatedAt: now().toISOString(),
1043
+ });
1044
+ throw preDispatchError(error);
1045
+ }
1046
+ });
1047
+ },
1048
+ reconcile: async (input: GatewayPortReconcile) => {
1049
+ const request = GatewayPortRequestSchema.parse(input.request);
1050
+ const requestId = GatewayRequestIdSchema.parse(input.requestId);
1051
+ const digest = requestSha256(request);
1052
+ throwIfAborted(input.signal);
1053
+ const directory = await gatewayRequestDirectory(
1054
+ options.application,
1055
+ requestId,
1056
+ );
1057
+ return await withMutationLock(directory, {
1058
+ command: `gateway workflow reconcile ${requestId}`,
1059
+ label: `Gateway workflow request ${requestId}`,
1060
+ now,
1061
+ }, async () => {
1062
+ const journal = await readJournal(directory);
1063
+ if (journal === null) {
1064
+ return {
1065
+ operation: request.operation,
1066
+ requestId,
1067
+ status: "not-dispatched",
1068
+ } as const;
1069
+ }
1070
+ if (!journalMatches(journal, request, requestId, digest)) {
1071
+ return {
1072
+ operation: request.operation,
1073
+ reasonSha256: conflictSha256(
1074
+ `${requestId}\0${digest}\0${journal.requestSha256}`,
1075
+ ),
1076
+ requestId,
1077
+ status: "conflict",
1078
+ } as const;
1079
+ }
1080
+ if (journal.state === "completed") {
1081
+ try {
1082
+ await verifyCompletedResult(
1083
+ options.application,
1084
+ journal.result!,
1085
+ input.signal,
1086
+ );
1087
+ } catch (error) {
1088
+ throwIfAborted(input.signal);
1089
+ return {
1090
+ operation: request.operation,
1091
+ reasonSha256: conflictSha256(
1092
+ `${requestId}\0completed-artifact-integrity\0${failureSha256(error)}`,
1093
+ ),
1094
+ requestId,
1095
+ status: "conflict",
1096
+ } as const;
1097
+ }
1098
+ return {
1099
+ operation: request.operation,
1100
+ requestId,
1101
+ result: journal.result!,
1102
+ status: "completed",
1103
+ } as const;
1104
+ }
1105
+ if (journal.state === "prepared") {
1106
+ return {
1107
+ operation: request.operation,
1108
+ requestId,
1109
+ status: "not-dispatched",
1110
+ } as const;
1111
+ }
1112
+ return {
1113
+ operation: request.operation,
1114
+ requestId,
1115
+ status: "dispatched",
1116
+ } as const;
1117
+ });
1118
+ },
1119
+ };
1120
+ }
1121
+
1122
+ export async function assertGatewayApplicationJournalPrivate(
1123
+ application: ApplicationContext,
1124
+ requestId: string,
1125
+ ): Promise<void> {
1126
+ const directory = await gatewayRequestDirectory(application, requestId);
1127
+ const [physical, details] = await Promise.all([
1128
+ realpath(directory),
1129
+ lstat(directory),
1130
+ ]);
1131
+ if (
1132
+ physical !== directory
1133
+ || details.isSymbolicLink()
1134
+ || !details.isDirectory()
1135
+ || (details.mode & 0o077) !== 0
1136
+ ) {
1137
+ throw new ApplicationError(
1138
+ "unsafe-path",
1139
+ "Gateway workflow journal directory is not private and physical.",
1140
+ );
1141
+ }
1142
+ }