@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.
- package/LICENSE +21 -0
- package/NOTICE.md +60 -0
- package/PRIVACY.md +46 -0
- package/README.md +311 -0
- package/SECURITY.md +21 -0
- package/apps/desktop/README.md +966 -0
- package/apps/desktop/analysis/protocol.ts +223 -0
- package/apps/desktop/application/capability-binding.ts +594 -0
- package/apps/desktop/application/context.ts +97 -0
- package/apps/desktop/application/creative-iteration.ts +1385 -0
- package/apps/desktop/application/default-registry.ts +146 -0
- package/apps/desktop/application/directing-contract.ts +218 -0
- package/apps/desktop/application/directing-plan.ts +178 -0
- package/apps/desktop/application/errors.ts +18 -0
- package/apps/desktop/application/gateway-port.ts +867 -0
- package/apps/desktop/application/html-overlay-browser-runtime.ts +687 -0
- package/apps/desktop/application/html-overlay-integrity.ts +337 -0
- package/apps/desktop/application/html-overlay-renderer.ts +45 -0
- package/apps/desktop/application/index.ts +13 -0
- package/apps/desktop/application/operation-completion-checkpoint.ts +333 -0
- package/apps/desktop/application/operation-effects.ts +94 -0
- package/apps/desktop/application/operation.ts +224 -0
- package/apps/desktop/application/operations/analysis/faces.ts +244 -0
- package/apps/desktop/application/operations/analysis/music.ts +248 -0
- package/apps/desktop/application/operations/analysis/project-auto-zooms.ts +302 -0
- package/apps/desktop/application/operations/analysis/project-inactivity.ts +381 -0
- package/apps/desktop/application/operations/analysis/scenes.ts +272 -0
- package/apps/desktop/application/operations/analysis/shared.ts +202 -0
- package/apps/desktop/application/operations/derive/edit-batch.ts +967 -0
- package/apps/desktop/application/operations/derive/follow-faces.ts +454 -0
- package/apps/desktop/application/operations/edit/bind-candidate-revision.ts +91 -0
- package/apps/desktop/application/operations/edit/create-candidate-revision.ts +377 -0
- package/apps/desktop/application/operations/edit/create-revision.ts +255 -0
- package/apps/desktop/application/operations/edit/freeze-revision.ts +182 -0
- package/apps/desktop/application/operations/gateway/image.ts +41 -0
- package/apps/desktop/application/operations/gateway/index.ts +17 -0
- package/apps/desktop/application/operations/gateway/shared.ts +122 -0
- package/apps/desktop/application/operations/gateway/speech.ts +41 -0
- package/apps/desktop/application/operations/gateway/transcription.ts +42 -0
- package/apps/desktop/application/operations/gateway/video.ts +41 -0
- package/apps/desktop/application/operations/index.ts +31 -0
- package/apps/desktop/application/operations/iteration/create-candidate.ts +240 -0
- package/apps/desktop/application/operations/iteration/create-matrix.ts +117 -0
- package/apps/desktop/application/operations/iteration/select.ts +155 -0
- package/apps/desktop/application/operations/iteration/shared.ts +250 -0
- package/apps/desktop/application/operations/media/audio-effects.ts +376 -0
- package/apps/desktop/application/operations/media/binding.ts +79 -0
- package/apps/desktop/application/operations/media/capabilities.ts +112 -0
- package/apps/desktop/application/operations/media/color-grade.ts +343 -0
- package/apps/desktop/application/operations/media/html-overlay.ts +802 -0
- package/apps/desktop/application/operations/media/index.ts +8 -0
- package/apps/desktop/application/operations/media/ingest.ts +303 -0
- package/apps/desktop/application/operations/media/overlay.ts +729 -0
- package/apps/desktop/application/operations/media/shared.ts +845 -0
- package/apps/desktop/application/operations/media/transform-platform.ts +120 -0
- package/apps/desktop/application/operations/project/commit-edits.ts +2054 -0
- package/apps/desktop/application/operations/project/promote-selection.ts +495 -0
- package/apps/desktop/application/operations/project/snapshot.ts +95 -0
- package/apps/desktop/application/operations/recording/index.ts +5 -0
- package/apps/desktop/application/operations/recording/pause.ts +34 -0
- package/apps/desktop/application/operations/recording/resume.ts +34 -0
- package/apps/desktop/application/operations/recording/shared.ts +199 -0
- package/apps/desktop/application/operations/recording/start.ts +169 -0
- package/apps/desktop/application/operations/recording/stop.ts +34 -0
- package/apps/desktop/application/operations/render/bind-candidate-output.ts +324 -0
- package/apps/desktop/application/operations/render/materialize-selection.ts +322 -0
- package/apps/desktop/application/operations/render/project-caption-plan.ts +287 -0
- package/apps/desktop/application/operations/render/project-plan.ts +939 -0
- package/apps/desktop/application/operations/render/project-spatial-receipt.ts +70 -0
- package/apps/desktop/application/operations/render/project.ts +1922 -0
- package/apps/desktop/application/operations/shared.ts +67 -0
- package/apps/desktop/application/operations/slopcamera-portable.ts +1188 -0
- package/apps/desktop/application/operations/slopcamera-visuals.ts +784 -0
- package/apps/desktop/application/operations/spatial-project.ts +209 -0
- package/apps/desktop/application/operations/spatial-render.ts +415 -0
- package/apps/desktop/application/operations/spatial-scene.ts +97 -0
- package/apps/desktop/application/operations/studio.ts +143 -0
- package/apps/desktop/application/output-publication-lease.ts +163 -0
- package/apps/desktop/application/project-publication-lease.ts +233 -0
- package/apps/desktop/application/project-store.ts +196 -0
- package/apps/desktop/application/receipts.ts +533 -0
- package/apps/desktop/application/registry.ts +182 -0
- package/apps/desktop/application/spatial-assets.ts +675 -0
- package/apps/desktop/application/spatial-compositor-cadence.ts +23 -0
- package/apps/desktop/application/spatial-project-authority.ts +35 -0
- package/apps/desktop/application/spatial-project-lease.ts +126 -0
- package/apps/desktop/application/spatial-project-render-preparation.ts +225 -0
- package/apps/desktop/application/spatial-project-store.ts +286 -0
- package/apps/desktop/application/spatial-render-projection.ts +201 -0
- package/apps/desktop/application/spatial-render.ts +677 -0
- package/apps/desktop/application/spatial-spz.ts +44 -0
- package/apps/desktop/application/spatial-world-import.ts +135 -0
- package/apps/desktop/application/spatial-world-provenance.ts +46 -0
- package/apps/desktop/application/studio-port.ts +58 -0
- package/apps/desktop/application/verified-receipt-reconciliation.ts +1574 -0
- package/apps/desktop/capture/protocol.ts +689 -0
- package/apps/desktop/cli/analyzer.ts +406 -0
- package/apps/desktop/cli/args.ts +3181 -0
- package/apps/desktop/cli/asset-ingest.ts +747 -0
- package/apps/desktop/cli/atomic-render-effects.ts +210 -0
- package/apps/desktop/cli/atomic-render-platform.ts +205 -0
- package/apps/desktop/cli/atomic-render.ts +50 -0
- package/apps/desktop/cli/audio-analysis.ts +252 -0
- package/apps/desktop/cli/bounded-map.ts +39 -0
- package/apps/desktop/cli/bundle-service.ts +256 -0
- package/apps/desktop/cli/capabilities.ts +212 -0
- package/apps/desktop/cli/capture-bundle.ts +1117 -0
- package/apps/desktop/cli/command-host-resources.ts +251 -0
- package/apps/desktop/cli/commands.ts +6836 -0
- package/apps/desktop/cli/directing-blob.ts +291 -0
- package/apps/desktop/cli/directing-media.ts +517 -0
- package/apps/desktop/cli/directing-quote.ts +89 -0
- package/apps/desktop/cli/directing-service.ts +288 -0
- package/apps/desktop/cli/emoji-assets.ts +538 -0
- package/apps/desktop/cli/errors.ts +29 -0
- package/apps/desktop/cli/face-analysis-service.ts +940 -0
- package/apps/desktop/cli/filter-script.ts +76 -0
- package/apps/desktop/cli/gateway-application-port.ts +1142 -0
- package/apps/desktop/cli/gateway-credential.ts +81 -0
- package/apps/desktop/cli/gateway-media-artifacts.ts +723 -0
- package/apps/desktop/cli/gateway-media-catalog.ts +922 -0
- package/apps/desktop/cli/gateway-media-service.ts +3106 -0
- package/apps/desktop/cli/gateway-media-signature.ts +122 -0
- package/apps/desktop/cli/gateway-provider-options.ts +562 -0
- package/apps/desktop/cli/gateway-scene-provider.ts +391 -0
- package/apps/desktop/cli/help.ts +501 -0
- package/apps/desktop/cli/html-overlay-gpu.ts +97 -0
- package/apps/desktop/cli/html-overlay-renderer.ts +2478 -0
- package/apps/desktop/cli/io.ts +290 -0
- package/apps/desktop/cli/main.ts +123 -0
- package/apps/desktop/cli/media-effects-service.ts +885 -0
- package/apps/desktop/cli/media-ingest-model.ts +364 -0
- package/apps/desktop/cli/media-ingest-platform.ts +227 -0
- package/apps/desktop/cli/media-ingest-program.ts +200 -0
- package/apps/desktop/cli/media-ingest.ts +30 -0
- package/apps/desktop/cli/music-analysis-service.ts +434 -0
- package/apps/desktop/cli/mutation-lock.ts +530 -0
- package/apps/desktop/cli/native-assets.d.ts +12 -0
- package/apps/desktop/cli/native-media-runtime.macos.ts +7 -0
- package/apps/desktop/cli/overlay-playback.ts +177 -0
- package/apps/desktop/cli/paths.ts +265 -0
- package/apps/desktop/cli/portable-surface.ts +242 -0
- package/apps/desktop/cli/project-camera-receipt.ts +112 -0
- package/apps/desktop/cli/project-face-camera.ts +394 -0
- package/apps/desktop/cli/project-inactivity-service.ts +552 -0
- package/apps/desktop/cli/project-media-integrity.ts +121 -0
- package/apps/desktop/cli/project-renderer.ts +1526 -0
- package/apps/desktop/cli/project-service.ts +519 -0
- package/apps/desktop/cli/project-state-transaction.ts +520 -0
- package/apps/desktop/cli/query-limits.ts +1 -0
- package/apps/desktop/cli/recording-controller.ts +1567 -0
- package/apps/desktop/cli/recording-daemon.ts +931 -0
- package/apps/desktop/cli/recording-ref.ts +56 -0
- package/apps/desktop/cli/renamed-environment.ts +6 -0
- package/apps/desktop/cli/renderer.ts +1439 -0
- package/apps/desktop/cli/run-cli-test-helper.ts +60 -0
- package/apps/desktop/cli/scene-analysis-service.ts +879 -0
- package/apps/desktop/cli/spatial-compositor-verifier.ts +213 -0
- package/apps/desktop/cli/spatial-project-service.ts +90 -0
- package/apps/desktop/cli/spatial-scene-service.ts +105 -0
- package/apps/desktop/cli/spatial-world-service.ts +39 -0
- package/apps/desktop/cli/speech-analysis-service.ts +682 -0
- package/apps/desktop/cli/studio-assemble.ts +58 -0
- package/apps/desktop/cli/studio-command.ts +60 -0
- package/apps/desktop/cli/studio-custody.ts +60 -0
- package/apps/desktop/cli/studio-encode.ts +216 -0
- package/apps/desktop/cli/studio-exr.ts +52 -0
- package/apps/desktop/cli/studio-files.ts +179 -0
- package/apps/desktop/cli/studio-output-validation.ts +162 -0
- package/apps/desktop/cli/studio-process.ts +145 -0
- package/apps/desktop/cli/studio-runtime.ts +77 -0
- package/apps/desktop/cli/studio-scaffold.ts +70 -0
- package/apps/desktop/cli/studio-service.ts +301 -0
- package/apps/desktop/cli/studio-spatial-asset.ts +248 -0
- package/apps/desktop/cli/studio-template-names.ts +3 -0
- package/apps/desktop/cli/studio-workflow.ts +19 -0
- package/apps/desktop/cli/time.ts +25 -0
- package/apps/desktop/cli/workflow-code.ts +584 -0
- package/apps/desktop/cli/workflow-runs.ts +576 -0
- package/apps/desktop/code/advanced.ts +139 -0
- package/apps/desktop/code/application-node-planner.ts +1288 -0
- package/apps/desktop/code/compiler.ts +329 -0
- package/apps/desktop/code/contracts.ts +13 -0
- package/apps/desktop/code/creative-recipes.ts +94 -0
- package/apps/desktop/code/define-workflow.ts +115 -0
- package/apps/desktop/code/editing.ts +284 -0
- package/apps/desktop/code/file-candidate-provenance.ts +420 -0
- package/apps/desktop/code/file-candidate.ts +69 -0
- package/apps/desktop/code/graph-builder.ts +10 -0
- package/apps/desktop/code/host-resource-policy.ts +55 -0
- package/apps/desktop/code/plan-contracts.ts +159 -0
- package/apps/desktop/code/planning.ts +361 -0
- package/apps/desktop/code/public.ts +134 -0
- package/apps/desktop/code/reference-projection.ts +62 -0
- package/apps/desktop/code/run-contracts.ts +466 -0
- package/apps/desktop/code/run-store.ts +2478 -0
- package/apps/desktop/code/runtime-identity.ts +328 -0
- package/apps/desktop/code/scheduler.ts +3067 -0
- package/apps/desktop/code/semantic-builder.ts +1436 -0
- package/apps/desktop/code/source-bundle.ts +1641 -0
- package/apps/desktop/code/source-typecheck.ts +211 -0
- package/apps/desktop/code/testing.ts +79 -0
- package/apps/desktop/code/worker-client.ts +1675 -0
- package/apps/desktop/code/worker-effects.ts +141 -0
- package/apps/desktop/code/worker-entry.ts +435 -0
- package/apps/desktop/code/worker-lease-guardian.ts +179 -0
- package/apps/desktop/code/worker-process-identity.ts +484 -0
- package/apps/desktop/code/worker-protocol.ts +211 -0
- package/apps/desktop/code/workflow-effects.ts +132 -0
- package/apps/desktop/contracts/analysis.ts +949 -0
- package/apps/desktop/contracts/edit.ts +576 -0
- package/apps/desktop/contracts/index.ts +9 -0
- package/apps/desktop/contracts/media-effects.ts +139 -0
- package/apps/desktop/contracts/project-render.ts +644 -0
- package/apps/desktop/contracts/project.ts +740 -0
- package/apps/desktop/contracts/recording.ts +1434 -0
- package/apps/desktop/contracts/render.ts +334 -0
- package/apps/desktop/contracts/runtime.ts +155 -0
- package/apps/desktop/contracts/spatial-compositor.ts +58 -0
- package/apps/desktop/contracts/spatial-project.ts +159 -0
- package/apps/desktop/contracts/spatial-world.ts +48 -0
- package/apps/desktop/contracts/video-effects.ts +120 -0
- package/apps/desktop/core/alignment-apply.ts +400 -0
- package/apps/desktop/core/audio-alignment.ts +466 -0
- package/apps/desktop/core/auto-zoom.ts +209 -0
- package/apps/desktop/core/canonical-json.ts +14 -0
- package/apps/desktop/core/emoji.ts +210 -0
- package/apps/desktop/core/events.ts +409 -0
- package/apps/desktop/core/face-framing.ts +533 -0
- package/apps/desktop/core/face-tracks.ts +326 -0
- package/apps/desktop/core/inactivity.ts +137 -0
- package/apps/desktop/core/index.ts +30 -0
- package/apps/desktop/core/intervals.ts +123 -0
- package/apps/desktop/core/montage.ts +236 -0
- package/apps/desktop/core/music-analysis.ts +518 -0
- package/apps/desktop/core/plan.ts +244 -0
- package/apps/desktop/core/project-auto-zoom.ts +75 -0
- package/apps/desktop/core/project-camera-spatial.ts +676 -0
- package/apps/desktop/core/project-camera.ts +403 -0
- package/apps/desktop/core/project-captions.ts +888 -0
- package/apps/desktop/core/project-inactivity.ts +125 -0
- package/apps/desktop/core/project-metadata.ts +927 -0
- package/apps/desktop/core/project-plan.ts +375 -0
- package/apps/desktop/core/project-render-plan.ts +303 -0
- package/apps/desktop/core/project-time.ts +469 -0
- package/apps/desktop/core/render-plan.ts +442 -0
- package/apps/desktop/core/scene-cache.ts +174 -0
- package/apps/desktop/core/scene-sampling.ts +448 -0
- package/apps/desktop/core/spatial-compositor.ts +22 -0
- package/apps/desktop/core/spatial-durability.ts +99 -0
- package/apps/desktop/core/spatial-project.ts +169 -0
- package/apps/desktop/core/spatial-shot-clock.ts +32 -0
- package/apps/desktop/core/speech-analysis.ts +333 -0
- package/apps/desktop/core/storage.ts +970 -0
- package/apps/desktop/core/time-map.ts +91 -0
- package/apps/desktop/core/time.ts +61 -0
- package/apps/desktop/core/video-effects.ts +660 -0
- package/apps/desktop/dist/cli/NebulaSans-Bold-26se8aek.otf +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Book-5ax05zvn.woff2 +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Book-8cenzchw.otf +0 -0
- package/apps/desktop/dist/cli/main.js +5086 -0
- package/apps/desktop/html-overlay/catalog.ts +171 -0
- package/apps/desktop/html-overlay/contracts.ts +372 -0
- package/apps/desktop/html-overlay/execution-profile.ts +77 -0
- package/apps/desktop/html-overlay/index.ts +98 -0
- package/apps/desktop/html-overlay/libraries.ts +263 -0
- package/apps/desktop/html-overlay/random.ts +49 -0
- package/apps/desktop/html-overlay/runtime.ts +813 -0
- package/apps/desktop/html-overlay/scaffolds.ts +792 -0
- package/apps/desktop/html-overlay/spark-runtime.ts +88 -0
- package/apps/desktop/html-overlay/spatial-splat-runtime.ts +60 -0
- package/apps/desktop/html-overlay/spatial.ts +720 -0
- package/apps/desktop/studio/assets/README.md +39 -0
- package/apps/desktop/studio/assets/contracts.ts +129 -0
- package/apps/desktop/studio/assets/network.ts +64 -0
- package/apps/desktop/studio/assets/poly-haven.ts +148 -0
- package/apps/desktop/studio/drivers/blender_driver.py +466 -0
- package/apps/desktop/studio/drivers/cadquery_driver.py +176 -0
- package/apps/desktop/studio/education/driver.py +308 -0
- package/apps/desktop/studio/education/lesson.py +180 -0
- package/apps/desktop/studio/education/toolkit.py +249 -0
- package/apps/desktop/workflows/chaptered-demo.ts +48 -0
- package/apps/desktop/workflows/creative-iteration.ts +107 -0
- package/apps/desktop/workflows/creative-selection.ts +92 -0
- package/apps/desktop/workflows/fragments.ts +486 -0
- package/apps/desktop/workflows/index.ts +93 -0
- package/apps/desktop/workflows/polished-screen-demo.ts +128 -0
- package/apps/desktop/workflows/scene-direction.ts +12 -0
- package/apps/desktop/workflows/social-variants.ts +75 -0
- package/apps/desktop/workflows/talking-head-cleanup.ts +53 -0
- package/dist/NebulaSans-Bold-26se8aek.otf +0 -0
- package/dist/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
- package/dist/NebulaSans-Book-5ax05zvn.woff2 +0 -0
- package/dist/NebulaSans-Book-8cenzchw.otf +0 -0
- package/dist/cli.js +479 -0
- package/dist/code/advanced.js +270 -0
- package/dist/code/index.js +2240 -0
- package/dist/generate.js +24 -0
- package/dist/host-resources.js +26 -0
- package/dist/index-42zsesc1.js +2257 -0
- package/dist/index-7308egqr.js +48 -0
- package/dist/index-8txs6fkn.js +712 -0
- package/dist/index-mcy8z0br.js +192 -0
- package/dist/index-p63wavx0.js +2029 -0
- package/dist/index-r7gdhmsp.js +424 -0
- package/dist/index-sh6xbav6.js +1219 -0
- package/dist/index-z1w83f81.js +4 -0
- package/dist/index-z7239b4h.js +2363 -0
- package/dist/index-zfeg9hmw.js +2013 -0
- package/dist/index.js +241 -0
- package/dist/operations.js +29 -0
- package/dist/skill-install-dh0ntqba.js +10 -0
- package/dist/vectorize/worker.js +142 -0
- package/dist/workflow.js +16 -0
- package/docs/README.md +38 -0
- package/docs/studio.md +215 -0
- package/examples/studio/blender/README.md +26 -0
- package/examples/studio/blender/character.py +152 -0
- package/examples/studio/blender/cloth.py +101 -0
- package/examples/studio/blender/color_chart.py +29 -0
- package/examples/studio/blender/fluid.py +78 -0
- package/examples/studio/blender/import_model.py +74 -0
- package/examples/studio/blender/product.py +53 -0
- package/examples/studio/blender/shaded_street.py +481 -0
- package/examples/studio/blender/studio_scene.py +147 -0
- package/examples/studio/cadquery/README.md +13 -0
- package/examples/studio/cadquery/bracket.py +36 -0
- package/examples/studio/cadquery/import_step.py +12 -0
- package/examples/studio/education/README.md +46 -0
- package/examples/studio/education/lesson.json +99 -0
- package/examples/studio/education/scene.py +7 -0
- package/examples/studio/hybrid-scene.ts +96 -0
- package/examples/studio/native-workflow.ts +14 -0
- package/examples/studio/vgpu/README.md +64 -0
- package/examples/studio/vgpu/heat-field.mjs +290 -0
- package/package.json +304 -0
- package/packages/scene/src/index.ts +1 -0
- package/packages/scene/src/scene.ts +215 -0
- package/schema/diagram.schema.json +334 -0
- package/skills/slopcamera/SKILL.md +45 -0
- package/skills/slopcamera/agents/openai.yaml +4 -0
- package/skills/slopcamera/references/customization.md +77 -0
- package/skills/slopcamera/references/diagrams.md +153 -0
- package/skills/slopcamera/references/directed-scenes.md +42 -0
- package/skills/slopcamera/references/directing-video.md +18 -0
- package/skills/slopcamera/references/educational-video.md +26 -0
- package/skills/slopcamera/references/gateway-media.md +134 -0
- package/skills/slopcamera/references/install.md +62 -0
- package/skills/slopcamera/references/native-studio.md +31 -0
- package/skills/slopcamera/references/reference-led-3d.md +140 -0
- package/skills/slopcamera/references/rubber-stamp-examples/poster-example-1.jpg +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/poster-example-2.jpg +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-1.png +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-2.png +0 -0
- package/skills/slopcamera/references/rubber-stamp-field-notes.md +144 -0
- package/skills/slopcamera/references/vectorization.md +29 -0
- package/skills/slopcamera/references/video-projects.md +187 -0
- package/skills/slopcamera/references/visual-communication.md +120 -0
- package/skills/slopcamera/references/workflows-sdk.md +45 -0
- package/skills/slopcamera/scripts/compose-rubber-stamp-field-note.ts +229 -0
- package/src/artifacts.ts +106 -0
- package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/PROVENANCE.md +21 -0
- package/src/assets.d.ts +9 -0
- package/src/cli.ts +601 -0
- package/src/cloud-errors.ts +26 -0
- package/src/code/advanced.ts +10 -0
- package/src/code/boundary.ts +21 -0
- package/src/code/canonical-json.ts +129 -0
- package/src/code/compiler.ts +953 -0
- package/src/code/contracts.ts +576 -0
- package/src/code/define-workflow.ts +334 -0
- package/src/code/errors.ts +41 -0
- package/src/code/graph-builder.ts +945 -0
- package/src/code/index.ts +121 -0
- package/src/code/json-snapshot.ts +899 -0
- package/src/code/json-utf8.ts +88 -0
- package/src/code/portable-builder.ts +136 -0
- package/src/code/projection.ts +378 -0
- package/src/code/public-operations.ts +450 -0
- package/src/code/runtime.ts +580 -0
- package/src/code/sha256.ts +36 -0
- package/src/config.ts +180 -0
- package/src/desktop.ts +253 -0
- package/src/fs.ts +10 -0
- package/src/generate.ts +704 -0
- package/src/host-resource-posix.ts +161 -0
- package/src/host-resources.ts +1749 -0
- package/src/icons.ts +58 -0
- package/src/index.ts +200 -0
- package/src/label-layout.ts +130 -0
- package/src/layout.ts +413 -0
- package/src/lint.ts +127 -0
- package/src/mcp/boundary.ts +354 -0
- package/src/mcp/index.ts +33 -0
- package/src/mcp/server.ts +272 -0
- package/src/mcp/tools.ts +963 -0
- package/src/mcp/types.ts +71 -0
- package/src/operations.ts +775 -0
- package/src/parse.ts +861 -0
- package/src/process-environment.ts +17 -0
- package/src/render.ts +437 -0
- package/src/skill-install.ts +49 -0
- package/src/spatial-scene/authoring.ts +27 -0
- package/src/spatial-scene/camera-track.ts +83 -0
- package/src/spatial-scene/contracts.ts +277 -0
- package/src/spatial-scene/evaluate.ts +145 -0
- package/src/spatial-scene/gltf.ts +558 -0
- package/src/spatial-scene/identity.ts +260 -0
- package/src/spatial-scene/index.ts +10 -0
- package/src/spatial-scene/inspect.ts +68 -0
- package/src/spatial-scene/math.ts +280 -0
- package/src/spatial-scene/patch.ts +131 -0
- package/src/spatial-scene/time.ts +53 -0
- package/src/studio/contracts.ts +129 -0
- package/src/studio/index.ts +2 -0
- package/src/studio/plan.ts +156 -0
- package/src/studio/shared.ts +41 -0
- package/src/theme.ts +68 -0
- package/src/tldr.ts +474 -0
- package/src/types.ts +212 -0
- package/src/vectorize/archive.ts +101 -0
- package/src/vectorize/command.ts +797 -0
- package/src/vectorize/index.ts +27 -0
- package/src/vectorize/limits.ts +61 -0
- package/src/vectorize/metrics.ts +351 -0
- package/src/vectorize/pixels.ts +323 -0
- package/src/vectorize/supervisor.ts +339 -0
- package/src/vectorize/svg.ts +188 -0
- package/src/vectorize/tool.ts +542 -0
- package/src/vectorize/types.ts +113 -0
- package/src/vectorize/vectorize.ts +634 -0
- package/src/vectorize/worker-protocol.ts +40 -0
- package/src/vectorize/worker.ts +209 -0
- package/src/version.ts +1 -0
- package/src/workflow.ts +409 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AnalysisIdSchema,
|
|
5
|
+
EditPlanIdSchema,
|
|
6
|
+
ProjectEditPlanV1Schema,
|
|
7
|
+
ProjectRenderInvocationSchema,
|
|
8
|
+
ProjectRenderOutputPathSchema,
|
|
9
|
+
ProjectRenderPlanV1Schema,
|
|
10
|
+
ProjectRenderSyncPolicySchema,
|
|
11
|
+
ProjectRenderToolchainSchema,
|
|
12
|
+
RepositoryRelativePathSchema,
|
|
13
|
+
Sha256Schema,
|
|
14
|
+
VideoProjectV1Schema,
|
|
15
|
+
VideoProjectIdSchema,
|
|
16
|
+
type ProjectEditPlanV1,
|
|
17
|
+
type ProjectRenderInvocation,
|
|
18
|
+
type ProjectRenderSyncPolicy,
|
|
19
|
+
type ProjectRenderToolchain,
|
|
20
|
+
type VideoProjectV1,
|
|
21
|
+
} from "../contracts";
|
|
22
|
+
import {
|
|
23
|
+
canonicalJsonSha256,
|
|
24
|
+
hashProjectEditPlan,
|
|
25
|
+
hashProjectStructure,
|
|
26
|
+
} from "../core";
|
|
27
|
+
import {
|
|
28
|
+
ProjectEditBasisSchema,
|
|
29
|
+
ProjectGenerationHashesSchema,
|
|
30
|
+
} from "./project-store";
|
|
31
|
+
|
|
32
|
+
export const ProjectEditCommitReceiptSchema = z.strictObject({
|
|
33
|
+
editBasis: ProjectEditBasisSchema,
|
|
34
|
+
generation: ProjectGenerationHashesSchema,
|
|
35
|
+
operation: z.enum(["batch", "cut", "speed", "trim"]),
|
|
36
|
+
planHash: Sha256Schema,
|
|
37
|
+
planId: EditPlanIdSchema,
|
|
38
|
+
projectId: VideoProjectIdSchema,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const ProjectRenderPlanArtifactSchema = z.strictObject({
|
|
42
|
+
bytes: z.number().int().safe().positive().max(256 * 1024 * 1024),
|
|
43
|
+
path: RepositoryRelativePathSchema,
|
|
44
|
+
sha256: Sha256Schema,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export const ProjectEditRevisionAspectSchema = z.enum(["16:9", "1:1", "9:16"]);
|
|
48
|
+
|
|
49
|
+
export const ProjectEditRevisionArtifactSchema = z.strictObject({
|
|
50
|
+
bytes: z.number().int().safe().positive(),
|
|
51
|
+
path: RepositoryRelativePathSchema,
|
|
52
|
+
sha256: Sha256Schema,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export function hashProjectEditRevisionOutputGeometry(input: {
|
|
56
|
+
readonly pixelHeight: number;
|
|
57
|
+
readonly pixelWidth: number;
|
|
58
|
+
readonly revisionSha256: string;
|
|
59
|
+
}): string {
|
|
60
|
+
return canonicalJsonSha256({
|
|
61
|
+
domain: "studio.project-edit-revision-output-geometry/v1",
|
|
62
|
+
pixelHeight: input.pixelHeight,
|
|
63
|
+
pixelWidth: input.pixelWidth,
|
|
64
|
+
revisionSha256: input.revisionSha256,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const ProjectEditRevisionDocumentBodySchema = z.strictObject({
|
|
69
|
+
kind: z.union([
|
|
70
|
+
z.literal("slopcamera.project-edit-revision"),
|
|
71
|
+
z.literal("studio.project-edit-revision"),
|
|
72
|
+
]),
|
|
73
|
+
project: VideoProjectV1Schema,
|
|
74
|
+
projectEditPlan: ProjectEditPlanV1Schema,
|
|
75
|
+
projectEditPlanSha256: Sha256Schema,
|
|
76
|
+
projectSha256: Sha256Schema,
|
|
77
|
+
schemaVersion: z.literal(1),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
function editRevisionDomainHash(
|
|
81
|
+
body: z.infer<typeof ProjectEditRevisionDocumentBodySchema>,
|
|
82
|
+
): string {
|
|
83
|
+
return canonicalJsonSha256({
|
|
84
|
+
domain: "studio.project-edit-revision/v1",
|
|
85
|
+
...body,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const ProjectEditRevisionDocumentSchema =
|
|
90
|
+
ProjectEditRevisionDocumentBodySchema.extend({
|
|
91
|
+
revisionSha256: Sha256Schema,
|
|
92
|
+
}).strict().superRefine((revision, context) => {
|
|
93
|
+
if (canonicalJsonSha256(revision.project) !== revision.projectSha256) {
|
|
94
|
+
context.addIssue({
|
|
95
|
+
code: "custom",
|
|
96
|
+
message: "Revision project hash does not match its frozen project.",
|
|
97
|
+
path: ["projectSha256"],
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (
|
|
101
|
+
canonicalJsonSha256(revision.projectEditPlan)
|
|
102
|
+
!== revision.projectEditPlanSha256
|
|
103
|
+
|| hashProjectEditPlan(revision.projectEditPlan)
|
|
104
|
+
!== revision.projectEditPlanSha256
|
|
105
|
+
) {
|
|
106
|
+
context.addIssue({
|
|
107
|
+
code: "custom",
|
|
108
|
+
message: "Revision edit-plan hash does not match its frozen plan.",
|
|
109
|
+
path: ["projectEditPlanSha256"],
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (
|
|
113
|
+
revision.projectEditPlan.projectId !== revision.project.projectId
|
|
114
|
+
|| revision.projectEditPlan.projectStructureSha256
|
|
115
|
+
!== hashProjectStructure(revision.project)
|
|
116
|
+
) {
|
|
117
|
+
context.addIssue({
|
|
118
|
+
code: "custom",
|
|
119
|
+
message: "Revision edit plan is not structurally bound to its frozen project.",
|
|
120
|
+
path: ["projectEditPlan"],
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const body = ProjectEditRevisionDocumentBodySchema.parse({
|
|
124
|
+
kind: revision.kind,
|
|
125
|
+
project: revision.project,
|
|
126
|
+
projectEditPlan: revision.projectEditPlan,
|
|
127
|
+
projectEditPlanSha256: revision.projectEditPlanSha256,
|
|
128
|
+
projectSha256: revision.projectSha256,
|
|
129
|
+
schemaVersion: revision.schemaVersion,
|
|
130
|
+
});
|
|
131
|
+
if (editRevisionDomainHash(body) !== revision.revisionSha256) {
|
|
132
|
+
context.addIssue({
|
|
133
|
+
code: "custom",
|
|
134
|
+
message: "Revision domain hash does not match its frozen documents.",
|
|
135
|
+
path: ["revisionSha256"],
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
export function createProjectEditRevisionDocument(
|
|
141
|
+
projectInput: VideoProjectV1,
|
|
142
|
+
planInput: ProjectEditPlanV1,
|
|
143
|
+
): z.infer<typeof ProjectEditRevisionDocumentSchema> {
|
|
144
|
+
const project = VideoProjectV1Schema.parse(projectInput);
|
|
145
|
+
const projectEditPlan = ProjectEditPlanV1Schema.parse(planInput);
|
|
146
|
+
const body = ProjectEditRevisionDocumentBodySchema.parse({
|
|
147
|
+
kind: "slopcamera.project-edit-revision",
|
|
148
|
+
project,
|
|
149
|
+
projectEditPlan,
|
|
150
|
+
projectEditPlanSha256: canonicalJsonSha256(projectEditPlan),
|
|
151
|
+
projectSha256: canonicalJsonSha256(project),
|
|
152
|
+
schemaVersion: 1,
|
|
153
|
+
});
|
|
154
|
+
return ProjectEditRevisionDocumentSchema.parse({
|
|
155
|
+
...body,
|
|
156
|
+
revisionSha256: editRevisionDomainHash(body),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export const ProjectEditRevisionReferenceSchema = z.strictObject({
|
|
161
|
+
analysisId: AnalysisIdSchema,
|
|
162
|
+
analysisSha256: Sha256Schema,
|
|
163
|
+
artifact: ProjectEditRevisionArtifactSchema,
|
|
164
|
+
aspect: ProjectEditRevisionAspectSchema,
|
|
165
|
+
baseGeneration: ProjectGenerationHashesSchema,
|
|
166
|
+
derivationSha256: Sha256Schema,
|
|
167
|
+
kind: z.union([
|
|
168
|
+
z.literal("slopcamera.project-edit-revision-reference"),
|
|
169
|
+
z.literal("studio.project-edit-revision-reference"),
|
|
170
|
+
]),
|
|
171
|
+
outputGeometrySha256: Sha256Schema,
|
|
172
|
+
pixelHeight: z.number().int().safe().positive().max(16_384),
|
|
173
|
+
pixelWidth: z.number().int().safe().positive().max(16_384),
|
|
174
|
+
planId: EditPlanIdSchema,
|
|
175
|
+
projectEditPlanSha256: Sha256Schema,
|
|
176
|
+
projectId: VideoProjectIdSchema,
|
|
177
|
+
projectSha256: Sha256Schema,
|
|
178
|
+
projectStructureSha256: Sha256Schema,
|
|
179
|
+
revisionSha256: Sha256Schema,
|
|
180
|
+
schemaVersion: z.literal(1),
|
|
181
|
+
}).superRefine((reference, context) => {
|
|
182
|
+
if (
|
|
183
|
+
reference.artifact.path
|
|
184
|
+
!== `edits/revisions/${reference.artifact.sha256}.json`
|
|
185
|
+
) {
|
|
186
|
+
context.addIssue({
|
|
187
|
+
code: "custom",
|
|
188
|
+
message: "Revision artifact path must be addressed by its physical SHA-256.",
|
|
189
|
+
path: ["artifact", "path"],
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (reference.baseGeneration.projectSha256 !== reference.projectSha256) {
|
|
193
|
+
context.addIssue({
|
|
194
|
+
code: "custom",
|
|
195
|
+
message: "Revision frozen project does not match its checked base generation.",
|
|
196
|
+
path: ["projectSha256"],
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (
|
|
200
|
+
reference.outputGeometrySha256
|
|
201
|
+
!== hashProjectEditRevisionOutputGeometry(reference)
|
|
202
|
+
) {
|
|
203
|
+
context.addIssue({
|
|
204
|
+
code: "custom",
|
|
205
|
+
message: "Revision output geometry is not bound to its immutable revision identity.",
|
|
206
|
+
path: ["outputGeometrySha256"],
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const expectedAspect = {
|
|
210
|
+
"16:9": 16 / 9,
|
|
211
|
+
"1:1": 1,
|
|
212
|
+
"9:16": 9 / 16,
|
|
213
|
+
}[reference.aspect];
|
|
214
|
+
if (
|
|
215
|
+
Math.abs(reference.pixelWidth / reference.pixelHeight - expectedAspect)
|
|
216
|
+
> 1e-12
|
|
217
|
+
) {
|
|
218
|
+
context.addIssue({
|
|
219
|
+
code: "custom",
|
|
220
|
+
message: "Revision output dimensions do not match its reviewed aspect.",
|
|
221
|
+
path: ["aspect"],
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* The render boundary depends only on the frozen project/edit documents and
|
|
228
|
+
* their output geometry. Face-analysis provenance remains available on the
|
|
229
|
+
* richer face-follow reference but is not required for a generic revision.
|
|
230
|
+
*/
|
|
231
|
+
export const RenderableProjectEditRevisionReferenceSchema = z.strictObject({
|
|
232
|
+
artifact: ProjectEditRevisionArtifactSchema,
|
|
233
|
+
baseGeneration: ProjectGenerationHashesSchema,
|
|
234
|
+
kind: z.union([
|
|
235
|
+
z.literal("slopcamera.project-edit-revision-reference"),
|
|
236
|
+
z.literal("studio.project-edit-revision-reference"),
|
|
237
|
+
]),
|
|
238
|
+
outputGeometrySha256: Sha256Schema,
|
|
239
|
+
pixelHeight: z.number().int().safe().positive().max(16_384),
|
|
240
|
+
pixelWidth: z.number().int().safe().positive().max(16_384),
|
|
241
|
+
planId: EditPlanIdSchema,
|
|
242
|
+
projectEditPlanSha256: Sha256Schema,
|
|
243
|
+
projectId: VideoProjectIdSchema,
|
|
244
|
+
projectSha256: Sha256Schema,
|
|
245
|
+
projectStructureSha256: Sha256Schema,
|
|
246
|
+
revisionSha256: Sha256Schema,
|
|
247
|
+
schemaVersion: z.literal(1),
|
|
248
|
+
}).superRefine((reference, context) => {
|
|
249
|
+
if (
|
|
250
|
+
reference.artifact.path
|
|
251
|
+
!== `edits/revisions/${reference.artifact.sha256}.json`
|
|
252
|
+
) {
|
|
253
|
+
context.addIssue({
|
|
254
|
+
code: "custom",
|
|
255
|
+
message: "Revision artifact path must be addressed by its physical SHA-256.",
|
|
256
|
+
path: ["artifact", "path"],
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
if (reference.baseGeneration.projectSha256 !== reference.projectSha256) {
|
|
260
|
+
context.addIssue({
|
|
261
|
+
code: "custom",
|
|
262
|
+
message: "Revision frozen project does not match its checked base generation.",
|
|
263
|
+
path: ["projectSha256"],
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (
|
|
267
|
+
reference.outputGeometrySha256
|
|
268
|
+
!== hashProjectEditRevisionOutputGeometry(reference)
|
|
269
|
+
) {
|
|
270
|
+
context.addIssue({
|
|
271
|
+
code: "custom",
|
|
272
|
+
message: "Revision output geometry is not bound to its immutable revision identity.",
|
|
273
|
+
path: ["outputGeometrySha256"],
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
export const ProjectEditRevisionRenderInputSchema = z.union([
|
|
279
|
+
ProjectEditRevisionReferenceSchema,
|
|
280
|
+
RenderableProjectEditRevisionReferenceSchema,
|
|
281
|
+
]);
|
|
282
|
+
|
|
283
|
+
export const ProjectRenderPlanDocumentSchema = z.strictObject({
|
|
284
|
+
kind: z.union([
|
|
285
|
+
z.literal("slopcamera.project-render-plan-document"),
|
|
286
|
+
z.literal("studio.project-render-plan-document"),
|
|
287
|
+
]),
|
|
288
|
+
outputGeometrySha256: Sha256Schema,
|
|
289
|
+
plan: ProjectRenderPlanV1Schema,
|
|
290
|
+
projectEditPlanSha256: Sha256Schema,
|
|
291
|
+
projectSha256: Sha256Schema,
|
|
292
|
+
renderPlanSha256: Sha256Schema,
|
|
293
|
+
revisionSha256: Sha256Schema,
|
|
294
|
+
schemaVersion: z.literal(1),
|
|
295
|
+
}).superRefine((document, context) => {
|
|
296
|
+
if (
|
|
297
|
+
document.plan.projectEditPlanSha256 !== document.projectEditPlanSha256
|
|
298
|
+
) {
|
|
299
|
+
context.addIssue({
|
|
300
|
+
code: "custom",
|
|
301
|
+
message: "Render plan document edit identity does not match its plan.",
|
|
302
|
+
path: ["projectEditPlanSha256"],
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (canonicalJsonSha256(document.plan) !== document.renderPlanSha256) {
|
|
306
|
+
context.addIssue({
|
|
307
|
+
code: "custom",
|
|
308
|
+
message: "Render plan document hash does not match its complete plan.",
|
|
309
|
+
path: ["renderPlanSha256"],
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
if (
|
|
313
|
+
document.outputGeometrySha256
|
|
314
|
+
!== hashProjectEditRevisionOutputGeometry({
|
|
315
|
+
pixelHeight: document.plan.output.pixelHeight,
|
|
316
|
+
pixelWidth: document.plan.output.pixelWidth,
|
|
317
|
+
revisionSha256: document.revisionSha256,
|
|
318
|
+
})
|
|
319
|
+
) {
|
|
320
|
+
context.addIssue({
|
|
321
|
+
code: "custom",
|
|
322
|
+
message: "Render plan output geometry is not bound to its immutable revision.",
|
|
323
|
+
path: ["outputGeometrySha256"],
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
export const ProjectRenderPlanReferenceSchema = z.strictObject({
|
|
329
|
+
artifact: ProjectRenderPlanArtifactSchema,
|
|
330
|
+
kind: z.union([
|
|
331
|
+
z.literal("slopcamera.project-render-plan-reference"),
|
|
332
|
+
z.literal("studio.project-render-plan-reference"),
|
|
333
|
+
]),
|
|
334
|
+
outputGeometrySha256: Sha256Schema,
|
|
335
|
+
planSha256: Sha256Schema,
|
|
336
|
+
projectEditPlanSha256: Sha256Schema,
|
|
337
|
+
projectId: VideoProjectIdSchema,
|
|
338
|
+
projectSha256: Sha256Schema,
|
|
339
|
+
renderPlanSha256: Sha256Schema,
|
|
340
|
+
revisionSha256: Sha256Schema,
|
|
341
|
+
schemaVersion: z.literal(1),
|
|
342
|
+
}).superRefine((reference, context) => {
|
|
343
|
+
if (
|
|
344
|
+
reference.artifact.path
|
|
345
|
+
!== `renders/plans/${reference.artifact.sha256}.json`
|
|
346
|
+
) {
|
|
347
|
+
context.addIssue({
|
|
348
|
+
code: "custom",
|
|
349
|
+
message: "Render plan artifact path must be addressed by its physical SHA-256.",
|
|
350
|
+
path: ["artifact", "path"],
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
export const ProjectRenderOutputReferenceSchema = z.strictObject({
|
|
356
|
+
bytes: z.number().int().safe().positive(),
|
|
357
|
+
kind: z.union([
|
|
358
|
+
z.literal("slopcamera.project-render-output-reference"),
|
|
359
|
+
z.literal("studio.project-render-output-reference"),
|
|
360
|
+
]),
|
|
361
|
+
path: ProjectRenderOutputPathSchema,
|
|
362
|
+
planArtifactSha256: Sha256Schema,
|
|
363
|
+
projectId: VideoProjectIdSchema,
|
|
364
|
+
revisionSha256: Sha256Schema,
|
|
365
|
+
schemaVersion: z.literal(1),
|
|
366
|
+
sha256: Sha256Schema,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
const ProjectRenderReceiptV2BodyBaseSchema = z.strictObject({
|
|
370
|
+
createdAt: z.string().datetime({ offset: true }),
|
|
371
|
+
inputSha256: Sha256Schema,
|
|
372
|
+
invocation: ProjectRenderInvocationSchema,
|
|
373
|
+
invocationSha256: Sha256Schema,
|
|
374
|
+
kind: z.union([
|
|
375
|
+
z.literal("slopcamera.project-render-receipt"),
|
|
376
|
+
z.literal("studio.project-render-receipt"),
|
|
377
|
+
]),
|
|
378
|
+
output: ProjectRenderOutputReferenceSchema,
|
|
379
|
+
plan: ProjectRenderPlanReferenceSchema,
|
|
380
|
+
projectId: VideoProjectIdSchema,
|
|
381
|
+
revisionSha256: Sha256Schema,
|
|
382
|
+
run: z.strictObject({
|
|
383
|
+
nodeKey: z.string()
|
|
384
|
+
.min(1)
|
|
385
|
+
.max(255)
|
|
386
|
+
.regex(/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*(?:\/[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*)*$/u),
|
|
387
|
+
nodePlanSha256: Sha256Schema,
|
|
388
|
+
runId: z.string().regex(/^run_[a-z0-9][a-z0-9_-]{5,95}$/u),
|
|
389
|
+
}),
|
|
390
|
+
schemaVersion: z.literal(2),
|
|
391
|
+
syncPolicy: ProjectRenderSyncPolicySchema,
|
|
392
|
+
toolchain: ProjectRenderToolchainSchema,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
function validateProjectRenderReceiptBody(
|
|
396
|
+
receipt: z.infer<typeof ProjectRenderReceiptV2BodyBaseSchema>,
|
|
397
|
+
context: z.RefinementCtx,
|
|
398
|
+
): void {
|
|
399
|
+
if (
|
|
400
|
+
canonicalJsonSha256(receipt.invocation) !== receipt.invocationSha256
|
|
401
|
+
|| receipt.invocation.renderPlanSha256 !== receipt.plan.renderPlanSha256
|
|
402
|
+
) {
|
|
403
|
+
context.addIssue({
|
|
404
|
+
code: "custom",
|
|
405
|
+
message: "Render receipt invocation is not bound to its exact plan.",
|
|
406
|
+
path: ["invocationSha256"],
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
if (
|
|
410
|
+
receipt.output.projectId !== receipt.projectId
|
|
411
|
+
|| receipt.plan.projectId !== receipt.projectId
|
|
412
|
+
|| receipt.output.revisionSha256 !== receipt.revisionSha256
|
|
413
|
+
|| receipt.plan.revisionSha256 !== receipt.revisionSha256
|
|
414
|
+
|| receipt.output.planArtifactSha256 !== receipt.plan.artifact.sha256
|
|
415
|
+
) {
|
|
416
|
+
context.addIssue({
|
|
417
|
+
code: "custom",
|
|
418
|
+
message: "Render receipt project, revision, plan, and output identities disagree.",
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const ProjectRenderReceiptV2BodySchema =
|
|
424
|
+
ProjectRenderReceiptV2BodyBaseSchema.superRefine(
|
|
425
|
+
validateProjectRenderReceiptBody,
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
function projectRenderReceiptDomainHash(
|
|
429
|
+
body: z.infer<typeof ProjectRenderReceiptV2BodySchema>,
|
|
430
|
+
): string {
|
|
431
|
+
return canonicalJsonSha256({
|
|
432
|
+
domain: "studio.project-render-receipt/v2",
|
|
433
|
+
...body,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export const ProjectRenderReceiptV2Schema =
|
|
438
|
+
ProjectRenderReceiptV2BodyBaseSchema.extend({
|
|
439
|
+
receiptSha256: Sha256Schema,
|
|
440
|
+
}).strict().superRefine((receipt, context) => {
|
|
441
|
+
validateProjectRenderReceiptBody(receipt, context);
|
|
442
|
+
const body = ProjectRenderReceiptV2BodySchema.parse({
|
|
443
|
+
createdAt: receipt.createdAt,
|
|
444
|
+
inputSha256: receipt.inputSha256,
|
|
445
|
+
invocation: receipt.invocation,
|
|
446
|
+
invocationSha256: receipt.invocationSha256,
|
|
447
|
+
kind: receipt.kind,
|
|
448
|
+
output: receipt.output,
|
|
449
|
+
plan: receipt.plan,
|
|
450
|
+
projectId: receipt.projectId,
|
|
451
|
+
revisionSha256: receipt.revisionSha256,
|
|
452
|
+
run: receipt.run,
|
|
453
|
+
schemaVersion: receipt.schemaVersion,
|
|
454
|
+
syncPolicy: receipt.syncPolicy,
|
|
455
|
+
toolchain: receipt.toolchain,
|
|
456
|
+
});
|
|
457
|
+
if (
|
|
458
|
+
projectRenderReceiptDomainHash(body) !== receipt.receiptSha256
|
|
459
|
+
) {
|
|
460
|
+
context.addIssue({
|
|
461
|
+
code: "custom",
|
|
462
|
+
message: "Render receipt domain hash does not match its exact execution.",
|
|
463
|
+
path: ["receiptSha256"],
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
export function createProjectRenderReceiptV2(input: {
|
|
469
|
+
readonly createdAt: string;
|
|
470
|
+
readonly inputSha256: string;
|
|
471
|
+
readonly invocation: ProjectRenderInvocation;
|
|
472
|
+
readonly output: z.infer<typeof ProjectRenderOutputReferenceSchema>;
|
|
473
|
+
readonly plan: z.infer<typeof ProjectRenderPlanReferenceSchema>;
|
|
474
|
+
readonly run: {
|
|
475
|
+
readonly nodeKey: string;
|
|
476
|
+
readonly nodePlanSha256: string;
|
|
477
|
+
readonly runId: string;
|
|
478
|
+
};
|
|
479
|
+
readonly syncPolicy: ProjectRenderSyncPolicy;
|
|
480
|
+
readonly toolchain: ProjectRenderToolchain;
|
|
481
|
+
}): z.infer<typeof ProjectRenderReceiptV2Schema> {
|
|
482
|
+
const body = ProjectRenderReceiptV2BodySchema.parse({
|
|
483
|
+
...input,
|
|
484
|
+
invocationSha256: canonicalJsonSha256(input.invocation),
|
|
485
|
+
kind: "slopcamera.project-render-receipt",
|
|
486
|
+
projectId: input.plan.projectId,
|
|
487
|
+
revisionSha256: input.plan.revisionSha256,
|
|
488
|
+
schemaVersion: 2,
|
|
489
|
+
});
|
|
490
|
+
return ProjectRenderReceiptV2Schema.parse({
|
|
491
|
+
...body,
|
|
492
|
+
receiptSha256: projectRenderReceiptDomainHash(body),
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export const ProjectRenderReceiptReferenceSchema = z.strictObject({
|
|
497
|
+
bytes: z.number().int().safe().positive().max(256 * 1024 * 1024),
|
|
498
|
+
kind: z.union([
|
|
499
|
+
z.literal("slopcamera.project-render-receipt-reference"),
|
|
500
|
+
z.literal("studio.project-render-receipt-reference"),
|
|
501
|
+
]),
|
|
502
|
+
nodePlanSha256: Sha256Schema,
|
|
503
|
+
outputSha256: Sha256Schema,
|
|
504
|
+
path: RepositoryRelativePathSchema,
|
|
505
|
+
projectId: VideoProjectIdSchema,
|
|
506
|
+
receiptSha256: Sha256Schema,
|
|
507
|
+
revisionSha256: Sha256Schema,
|
|
508
|
+
schemaVersion: z.literal(2),
|
|
509
|
+
sha256: Sha256Schema,
|
|
510
|
+
}).superRefine((reference, context) => {
|
|
511
|
+
if (
|
|
512
|
+
reference.path
|
|
513
|
+
!== `renders/receipts/${reference.nodePlanSha256}.json`
|
|
514
|
+
) {
|
|
515
|
+
context.addIssue({
|
|
516
|
+
code: "custom",
|
|
517
|
+
message: "Render receipt path must be bound to its exact node plan.",
|
|
518
|
+
path: ["path"],
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
export type ProjectEditRevisionDocument = z.infer<typeof ProjectEditRevisionDocumentSchema>;
|
|
524
|
+
export type RenderableProjectEditRevisionReference = z.infer<
|
|
525
|
+
typeof RenderableProjectEditRevisionReferenceSchema
|
|
526
|
+
>;
|
|
527
|
+
export type ProjectEditRevisionRenderInput = z.infer<
|
|
528
|
+
typeof ProjectEditRevisionRenderInputSchema
|
|
529
|
+
>;
|
|
530
|
+
export type ProjectRenderPlanDocument = z.infer<typeof ProjectRenderPlanDocumentSchema>;
|
|
531
|
+
export type ProjectRenderPlanReference = z.infer<typeof ProjectRenderPlanReferenceSchema>;
|
|
532
|
+
export type ProjectRenderOutputReference = z.infer<typeof ProjectRenderOutputReferenceSchema>;
|
|
533
|
+
export type ProjectRenderReceiptReference = z.infer<typeof ProjectRenderReceiptReferenceSchema>;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { operationBoundary, operationValidation, runStandaloneOperation, type OperationEffectFailure } from "./operation-effects";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import { ApplicationError } from "./errors";
|
|
6
|
+
import {
|
|
7
|
+
RESOURCE_KINDS,
|
|
8
|
+
type BoundedOperationSummary,
|
|
9
|
+
type OperationDefinition,
|
|
10
|
+
type OperationExecutionContext,
|
|
11
|
+
type OperationKind,
|
|
12
|
+
type OperationPolicy,
|
|
13
|
+
type OperationRequest,
|
|
14
|
+
type OperationResult,
|
|
15
|
+
} from "./operation";
|
|
16
|
+
|
|
17
|
+
export interface OperationDiscovery {
|
|
18
|
+
readonly inputSchemaId: string;
|
|
19
|
+
readonly kind: OperationKind;
|
|
20
|
+
readonly lifecycle: OperationDefinition["lifecycle"]["kind"];
|
|
21
|
+
readonly outputSchemaId: string;
|
|
22
|
+
readonly policy: OperationPolicy;
|
|
23
|
+
readonly version: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface OperationDescription extends OperationDiscovery {
|
|
27
|
+
readonly inputJsonSchema: Readonly<Record<string, unknown>>;
|
|
28
|
+
readonly outputJsonSchema: Readonly<Record<string, unknown>>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface RegisteredOperation {
|
|
32
|
+
readonly discovery: OperationDiscovery;
|
|
33
|
+
describe(): OperationDescription;
|
|
34
|
+
execute(context: OperationExecutionContext, input: unknown): Promise<OperationResult>;
|
|
35
|
+
executeEffect?(context: OperationExecutionContext, input: unknown): Effect.Effect<OperationResult, OperationEffectFailure>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function registryKey(kind: string, version: number): string {
|
|
39
|
+
return `${kind}@${String(version)}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function validatePolicy(policy: OperationPolicy): void {
|
|
43
|
+
if (!Number.isSafeInteger(policy.maxDurationMs) || policy.maxDurationMs < 1) {
|
|
44
|
+
throw new ApplicationError("invalid-data", "Operation duration limit must be a positive safe integer.");
|
|
45
|
+
}
|
|
46
|
+
for (const [name, value] of [
|
|
47
|
+
["fan-out", policy.maxFanOut],
|
|
48
|
+
["input byte", policy.maxInputBytes],
|
|
49
|
+
["output byte", policy.maxOutputBytes],
|
|
50
|
+
] as const) {
|
|
51
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
52
|
+
throw new ApplicationError("invalid-data", `Operation ${name} limit must be a nonnegative safe integer.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const knownResources = new Set<string>(RESOURCE_KINDS);
|
|
56
|
+
const seen = new Set<string>();
|
|
57
|
+
for (const claim of policy.resources) {
|
|
58
|
+
if (!knownResources.has(claim.resource)) {
|
|
59
|
+
throw new ApplicationError("invalid-data", `Unknown operation resource: ${claim.resource}`);
|
|
60
|
+
}
|
|
61
|
+
if (seen.has(claim.resource)) {
|
|
62
|
+
throw new ApplicationError("invalid-data", `Duplicate operation resource claim: ${claim.resource}`);
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isSafeInteger(claim.amount) || claim.amount < 1) {
|
|
65
|
+
throw new ApplicationError("invalid-data", `Resource ${claim.resource} must claim a positive safe integer.`);
|
|
66
|
+
}
|
|
67
|
+
seen.add(claim.resource);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function eraseDefinition<Input, Output>(
|
|
72
|
+
definition: OperationDefinition<OperationKind, Input, Output>,
|
|
73
|
+
): RegisteredOperation {
|
|
74
|
+
validatePolicy(definition.policy);
|
|
75
|
+
if (!Number.isSafeInteger(definition.version) || definition.version < 1) {
|
|
76
|
+
throw new ApplicationError("invalid-data", "Operation versions must be positive safe integers.");
|
|
77
|
+
}
|
|
78
|
+
const discovery: OperationDiscovery = Object.freeze({
|
|
79
|
+
inputSchemaId: definition.inputSchemaId,
|
|
80
|
+
kind: definition.kind,
|
|
81
|
+
lifecycle: definition.lifecycle.kind,
|
|
82
|
+
outputSchemaId: definition.outputSchemaId,
|
|
83
|
+
policy: definition.policy,
|
|
84
|
+
version: definition.version,
|
|
85
|
+
});
|
|
86
|
+
const executeEffect = (
|
|
87
|
+
context: OperationExecutionContext,
|
|
88
|
+
input: unknown,
|
|
89
|
+
): Effect.Effect<OperationResult, OperationEffectFailure> => Effect.gen(function*() {
|
|
90
|
+
const parsedInput = yield* operationValidation("input", () => definition.inputSchema.parse(input));
|
|
91
|
+
const value = definition.lifecycle.executeEffect === undefined
|
|
92
|
+
? yield* operationBoundary("execution", () => definition.lifecycle.execute(context, parsedInput))
|
|
93
|
+
: yield* definition.lifecycle.executeEffect(context, parsedInput);
|
|
94
|
+
return yield* operationValidation("output", () => {
|
|
95
|
+
const output = definition.outputSchema.parse(value);
|
|
96
|
+
const summary: BoundedOperationSummary = definition.summarize(output);
|
|
97
|
+
if (summary.kind !== definition.kind || Object.keys(summary.fields).length > 32) {
|
|
98
|
+
throw new ApplicationError("internal", `Operation ${definition.kind} returned an invalid summary.`);
|
|
99
|
+
}
|
|
100
|
+
const receiptReference = definition.receiptReference?.(output);
|
|
101
|
+
if (
|
|
102
|
+
receiptReference !== undefined
|
|
103
|
+
&& (
|
|
104
|
+
receiptReference.length < 1
|
|
105
|
+
|| receiptReference.length > 2_048
|
|
106
|
+
|| receiptReference.includes("\0")
|
|
107
|
+
)
|
|
108
|
+
) {
|
|
109
|
+
throw new ApplicationError(
|
|
110
|
+
"internal",
|
|
111
|
+
`Operation ${definition.kind} returned an invalid receipt reference.`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
kind: definition.kind,
|
|
116
|
+
output,
|
|
117
|
+
...(receiptReference === undefined ? {} : { receiptReference }),
|
|
118
|
+
summary,
|
|
119
|
+
version: definition.version,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
return Object.freeze({
|
|
125
|
+
describe: (): OperationDescription => ({
|
|
126
|
+
...discovery,
|
|
127
|
+
inputJsonSchema: {
|
|
128
|
+
...z.toJSONSchema(definition.inputSchema),
|
|
129
|
+
$id: definition.inputSchemaId,
|
|
130
|
+
},
|
|
131
|
+
outputJsonSchema: {
|
|
132
|
+
...z.toJSONSchema(definition.outputSchema),
|
|
133
|
+
$id: definition.outputSchemaId,
|
|
134
|
+
},
|
|
135
|
+
}),
|
|
136
|
+
discovery,
|
|
137
|
+
execute: async (context: OperationExecutionContext, input: unknown): Promise<OperationResult> =>
|
|
138
|
+
await runStandaloneOperation(executeEffect(context, input)),
|
|
139
|
+
executeEffect,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export class OperationRegistry {
|
|
144
|
+
readonly #operations = new Map<string, RegisteredOperation>();
|
|
145
|
+
|
|
146
|
+
register<Input, Output>(
|
|
147
|
+
definition: OperationDefinition<OperationKind, Input, Output>,
|
|
148
|
+
): void {
|
|
149
|
+
const key = registryKey(definition.kind, definition.version);
|
|
150
|
+
if (this.#operations.has(key)) {
|
|
151
|
+
throw new ApplicationError("conflict", `Duplicate operation definition: ${key}`);
|
|
152
|
+
}
|
|
153
|
+
this.#operations.set(key, eraseDefinition(definition));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
get(kind: string, version: number): RegisteredOperation {
|
|
157
|
+
const operation = this.#operations.get(registryKey(kind, version));
|
|
158
|
+
if (operation === undefined) {
|
|
159
|
+
throw new ApplicationError("unsupported-plan", `Unsupported operation: ${kind}@${String(version)}`);
|
|
160
|
+
}
|
|
161
|
+
return operation;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
describe(kind: string, version: number): OperationDescription {
|
|
165
|
+
return this.get(kind, version).describe();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
list(): readonly OperationDiscovery[] {
|
|
169
|
+
return Object.freeze([...this.#operations.values()]
|
|
170
|
+
.map(operation => operation.discovery)
|
|
171
|
+
.sort((left, right) => (
|
|
172
|
+
left.kind.localeCompare(right.kind) || left.version - right.version
|
|
173
|
+
)));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async execute(
|
|
177
|
+
context: OperationExecutionContext,
|
|
178
|
+
request: OperationRequest,
|
|
179
|
+
): Promise<OperationResult> {
|
|
180
|
+
return await this.get(request.kind, request.version).execute(context, request.input);
|
|
181
|
+
}
|
|
182
|
+
}
|