@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
package/src/cli.ts
ADDED
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { writeFile } from "node:fs/promises"
|
|
4
|
+
import { resolve } from "node:path"
|
|
5
|
+
import { createInterface } from "node:readline/promises"
|
|
6
|
+
import {
|
|
7
|
+
artifactSummary,
|
|
8
|
+
checkDiagramFile,
|
|
9
|
+
desktopStatus,
|
|
10
|
+
getLatestDesktopRelease,
|
|
11
|
+
installDesktop,
|
|
12
|
+
openInDesktop,
|
|
13
|
+
renderDiagramFile,
|
|
14
|
+
runMcpServer,
|
|
15
|
+
selectDesktopAsset,
|
|
16
|
+
vectorizeImage,
|
|
17
|
+
} from "./index.js"
|
|
18
|
+
import {
|
|
19
|
+
generateSlopcameraImageFile,
|
|
20
|
+
slopcameraGatewayCredentialStatus,
|
|
21
|
+
slopcameraImageModels,
|
|
22
|
+
type SlopcameraImageModel,
|
|
23
|
+
} from "./generate.js"
|
|
24
|
+
import {
|
|
25
|
+
executeSlopcameraOperation,
|
|
26
|
+
slopcameraOperationCodes,
|
|
27
|
+
isSlopcameraOperationCode,
|
|
28
|
+
searchSlopcameraOperations,
|
|
29
|
+
withSlopcameraOperationHostAdmission,
|
|
30
|
+
} from "./operations.js"
|
|
31
|
+
import type { HostResourceCoordinator } from "./host-resources.js"
|
|
32
|
+
import { installSkill, type SkillScope, type SkillTarget } from "./skill-install.js"
|
|
33
|
+
import { pathExists } from "./fs.js"
|
|
34
|
+
import { SLOPCAMERA_VERSION } from "./version.js"
|
|
35
|
+
|
|
36
|
+
export const slopcameraCliVersion = SLOPCAMERA_VERSION
|
|
37
|
+
|
|
38
|
+
const help = `slopcamera ${slopcameraCliVersion}
|
|
39
|
+
|
|
40
|
+
Turn source material into deterministic diagrams, images, and canvas assets.
|
|
41
|
+
|
|
42
|
+
Usage:
|
|
43
|
+
slopcamera diagram init [file]
|
|
44
|
+
slopcamera diagram check <file> [--config <file>] [--strict]
|
|
45
|
+
slopcamera diagram render <file> [--out-dir <directory>] [--config <file>] [--scale <number>]
|
|
46
|
+
slopcamera image vectorize <image> --output <file.svg> [--json] [--duotone <#rgb,#rgb>]
|
|
47
|
+
slopcamera image generate <prompt> --output <file.png|jpg|webp> [--model <provider/model>] [--json]
|
|
48
|
+
slopcamera code search [query] [--limit <number>]
|
|
49
|
+
slopcamera code execute <operation> --input <JSON>
|
|
50
|
+
slopcamera mcp --root <workspace>
|
|
51
|
+
slopcamera canvas open <file.tldr|file.tldraw>
|
|
52
|
+
slopcamera canvas status
|
|
53
|
+
slopcamera canvas url
|
|
54
|
+
slopcamera canvas install [--yes] [--download-only]
|
|
55
|
+
slopcamera doctor
|
|
56
|
+
slopcamera skill path
|
|
57
|
+
slopcamera skill install [--target codex|claude|agents] [--scope user|project] [--force]
|
|
58
|
+
|
|
59
|
+
Render writes the same five replaceable artifacts on every run:
|
|
60
|
+
<name>.tldr
|
|
61
|
+
<name>.light.svg
|
|
62
|
+
<name>.dark.svg
|
|
63
|
+
<name>.light.png
|
|
64
|
+
<name>.dark.png
|
|
65
|
+
|
|
66
|
+
The .tldr file is editable tldraw interchange. It imports into tldraw Offline,
|
|
67
|
+
which can save the newer app-owned .tldraw bundle. Rendering does not require
|
|
68
|
+
tldraw Offline or the tldraw SDK.
|
|
69
|
+
|
|
70
|
+
Vectorize adaptively traces a raster with a checksum-pinned VTracer binary.
|
|
71
|
+
It enforces bounded input, decode, time, path, and output budgets and emits a
|
|
72
|
+
safe path-only SVG (plus an internal vector alpha mask when fidelity requires).
|
|
73
|
+
It is fully local. No source path or bytes are sent to a network endpoint.
|
|
74
|
+
|
|
75
|
+
Generate sends one bounded, non-retried request directly to Vercel AI Gateway.
|
|
76
|
+
Set AI_GATEWAY_API_KEY, or run through \`vercel env run -- …\` so
|
|
77
|
+
VERCEL_OIDC_TOKEN is available. Slopcamera never stores or prints the token.
|
|
78
|
+
PNG, JPEG, and WebP responses are signature-checked and published atomically.
|
|
79
|
+
|
|
80
|
+
Code mode searches and executes a fixed semantic registry. Execute accepts
|
|
81
|
+
typed JSON for one exact owned operation code; it never evaluates source text.
|
|
82
|
+
|
|
83
|
+
MCP preserves root-relative check_diagram/render_diagram and adds closed
|
|
84
|
+
search_slopcamera/execute_slopcamera registry tools. It uses built-in assets, never
|
|
85
|
+
executes workspace config or caller code, and writes protocol messages only to
|
|
86
|
+
stdout.
|
|
87
|
+
`
|
|
88
|
+
|
|
89
|
+
interface ParsedArguments {
|
|
90
|
+
readonly positionals: readonly string[]
|
|
91
|
+
readonly options: Readonly<Record<string, string>>
|
|
92
|
+
readonly flags: ReadonlySet<string>
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function parseArguments(args: readonly string[], valueOptions: ReadonlySet<string>): ParsedArguments {
|
|
96
|
+
const positionals: string[] = []
|
|
97
|
+
const options: Record<string, string> = {}
|
|
98
|
+
const flags = new Set<string>()
|
|
99
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
100
|
+
const argument = args[index]
|
|
101
|
+
if (argument === undefined) continue
|
|
102
|
+
if (!argument.startsWith("--")) {
|
|
103
|
+
positionals.push(argument)
|
|
104
|
+
continue
|
|
105
|
+
}
|
|
106
|
+
const name = argument.slice(2)
|
|
107
|
+
if (!valueOptions.has(name)) {
|
|
108
|
+
flags.add(name)
|
|
109
|
+
continue
|
|
110
|
+
}
|
|
111
|
+
const value = args[index + 1]
|
|
112
|
+
if (value === undefined || value.startsWith("--")) {
|
|
113
|
+
throw new Error(`--${name} requires a value`)
|
|
114
|
+
}
|
|
115
|
+
options[name] = value
|
|
116
|
+
index += 1
|
|
117
|
+
}
|
|
118
|
+
return { positionals, options, flags }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function requiredPositional(parsed: ParsedArguments, index: number, label: string): string {
|
|
122
|
+
const value = parsed.positionals[index]
|
|
123
|
+
if (value === undefined) throw new Error(`Missing ${label}`)
|
|
124
|
+
return value
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function requiredOption(parsed: ParsedArguments, name: string): string {
|
|
128
|
+
const value = parsed.options[name]
|
|
129
|
+
if (value === undefined) throw new Error(`--${name} is required`)
|
|
130
|
+
return value
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function parsePositiveInteger(value: string | undefined, name: string): number | undefined {
|
|
134
|
+
if (value === undefined) return undefined
|
|
135
|
+
const parsed = Number(value)
|
|
136
|
+
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
137
|
+
throw new Error(`--${name} must be a positive integer`)
|
|
138
|
+
}
|
|
139
|
+
return parsed
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function parseDuotone(value: string | undefined): readonly [string, string] | undefined {
|
|
143
|
+
if (value === undefined) return undefined
|
|
144
|
+
const colors = value.split(",").map((color) => color.trim())
|
|
145
|
+
if (
|
|
146
|
+
colors.length !== 2 ||
|
|
147
|
+
colors.some((color) => !/^#[a-f0-9]{3}(?:[a-f0-9]{3})?$/iu.test(color))
|
|
148
|
+
) {
|
|
149
|
+
throw new Error("--duotone must contain two #rgb or #rrggbb colors separated by a comma")
|
|
150
|
+
}
|
|
151
|
+
return [colors[0]!, colors[1]!]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function printFindings(findings: Awaited<ReturnType<typeof checkDiagramFile>>["findings"]): void {
|
|
155
|
+
if (findings.length === 0) {
|
|
156
|
+
console.log("No diagram lint findings.")
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
console.warn(`${findings.length} diagram lint finding${findings.length === 1 ? "" : "s"}:`)
|
|
160
|
+
for (const finding of findings) {
|
|
161
|
+
console.warn(` [${finding.code}] ${finding.message}`)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const starter = {
|
|
166
|
+
$schema: "https://raw.githubusercontent.com/hraness/slopcamera/main/schema/diagram.schema.json",
|
|
167
|
+
version: 1,
|
|
168
|
+
name: "example-flow",
|
|
169
|
+
canvas: { width: 960, height: 540, padding: 64 },
|
|
170
|
+
layout: { type: "stack", direction: "horizontal", gap: 160, align: "center" },
|
|
171
|
+
shapes: [
|
|
172
|
+
{
|
|
173
|
+
id: "source",
|
|
174
|
+
type: "rect",
|
|
175
|
+
width: 240,
|
|
176
|
+
height: 160,
|
|
177
|
+
label: "Source",
|
|
178
|
+
icon: "document",
|
|
179
|
+
tone: "blue",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
id: "result",
|
|
183
|
+
type: "rect",
|
|
184
|
+
width: 240,
|
|
185
|
+
height: 160,
|
|
186
|
+
label: "Result",
|
|
187
|
+
icon: "check",
|
|
188
|
+
tone: "green",
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
edges: [{ id: "source-result", from: "source", to: "result" }],
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function confirmInstall(): Promise<boolean> {
|
|
195
|
+
if (!process.stdin.isTTY) {
|
|
196
|
+
throw new Error("Pass --yes to download the 100–230 MB official tldraw Offline installer")
|
|
197
|
+
}
|
|
198
|
+
const prompt = createInterface({ input: process.stdin, output: process.stdout })
|
|
199
|
+
try {
|
|
200
|
+
const answer = await prompt.question(
|
|
201
|
+
"Download, verify, and launch the official tldraw Offline installer? [y/N] ",
|
|
202
|
+
)
|
|
203
|
+
return answer.trim().toLowerCase() === "y" || answer.trim().toLowerCase() === "yes"
|
|
204
|
+
} finally {
|
|
205
|
+
prompt.close()
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface SlopcameraCliDependencies {
|
|
210
|
+
readonly generate?: typeof generateSlopcameraImageFile
|
|
211
|
+
readonly hostResourceCoordinator?: HostResourceCoordinator
|
|
212
|
+
readonly log?: (value: string) => void
|
|
213
|
+
readonly vectorize?: typeof vectorizeImage
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function hostAdmissionOptions(
|
|
217
|
+
dependencies: SlopcameraCliDependencies,
|
|
218
|
+
): { readonly hostResourceCoordinator?: HostResourceCoordinator } {
|
|
219
|
+
return dependencies.hostResourceCoordinator === undefined
|
|
220
|
+
? {}
|
|
221
|
+
: { hostResourceCoordinator: dependencies.hostResourceCoordinator }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function canonicalArguments(args: readonly string[]): readonly string[] {
|
|
225
|
+
const [surface, subcommand, ...rest] = args
|
|
226
|
+
if (surface === "diagram") {
|
|
227
|
+
if (subcommand === "init" || subcommand === "check" || subcommand === "render") {
|
|
228
|
+
return [subcommand, ...rest]
|
|
229
|
+
}
|
|
230
|
+
throw new Error("Use slopcamera diagram init, check, or render")
|
|
231
|
+
}
|
|
232
|
+
if (surface === "image") {
|
|
233
|
+
if (subcommand === "vectorize" || subcommand === "generate") {
|
|
234
|
+
return [subcommand, ...rest]
|
|
235
|
+
}
|
|
236
|
+
throw new Error("Use slopcamera image vectorize or generate")
|
|
237
|
+
}
|
|
238
|
+
if (surface === "canvas") {
|
|
239
|
+
if (subcommand === "open") return ["open", ...rest]
|
|
240
|
+
if (subcommand === "status" || subcommand === "url" || subcommand === "install") {
|
|
241
|
+
return ["desktop", subcommand, ...rest]
|
|
242
|
+
}
|
|
243
|
+
throw new Error("Use slopcamera canvas open, status, url, or install")
|
|
244
|
+
}
|
|
245
|
+
if (
|
|
246
|
+
surface === "init" ||
|
|
247
|
+
surface === "check" ||
|
|
248
|
+
surface === "render" ||
|
|
249
|
+
surface === "vectorize" ||
|
|
250
|
+
surface === "generate" ||
|
|
251
|
+
surface === "open" ||
|
|
252
|
+
surface === "desktop"
|
|
253
|
+
) {
|
|
254
|
+
throw new Error(`The flat \`${surface}\` command moved to a namespaced Slopcamera surface.\n\n${help}`)
|
|
255
|
+
}
|
|
256
|
+
return args
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export async function main(
|
|
260
|
+
args: readonly string[],
|
|
261
|
+
dependencies: SlopcameraCliDependencies = {},
|
|
262
|
+
): Promise<void> {
|
|
263
|
+
const [command, ...rest] = canonicalArguments(args)
|
|
264
|
+
if (command === undefined || command === "help" || command === "--help" || command === "-h") {
|
|
265
|
+
console.log(help)
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
if (command === "version" || command === "--version" || command === "-v") {
|
|
269
|
+
console.log(slopcameraCliVersion)
|
|
270
|
+
return
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (command === "init") {
|
|
274
|
+
const parsed = parseArguments(rest, new Set())
|
|
275
|
+
const filePath = resolve(parsed.positionals[0] ?? "diagram.diagram.json")
|
|
276
|
+
if (await pathExists(filePath)) throw new Error(`Refusing to overwrite existing file: ${filePath}`)
|
|
277
|
+
await writeFile(filePath, `${JSON.stringify(starter, null, 2)}\n`)
|
|
278
|
+
console.log(`Created ${filePath}`)
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (command === "check") {
|
|
283
|
+
const parsed = parseArguments(rest, new Set(["config"]))
|
|
284
|
+
const result = await withSlopcameraOperationHostAdmission(
|
|
285
|
+
"slopcamera.diagram.check",
|
|
286
|
+
async () => await checkDiagramFile({
|
|
287
|
+
filePath: requiredPositional(parsed, 0, "diagram file"),
|
|
288
|
+
...(parsed.options.config === undefined
|
|
289
|
+
? {}
|
|
290
|
+
: { configPath: parsed.options.config }),
|
|
291
|
+
}),
|
|
292
|
+
hostAdmissionOptions(dependencies),
|
|
293
|
+
)
|
|
294
|
+
console.log(`Valid diagram${result.configPath === null ? "" : ` with ${result.configPath}`}.`)
|
|
295
|
+
printFindings(result.findings)
|
|
296
|
+
if (parsed.flags.has("strict") && result.findings.length > 0) process.exitCode = 2
|
|
297
|
+
return
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (command === "render") {
|
|
301
|
+
const parsed = parseArguments(rest, new Set(["out-dir", "config", "scale"]))
|
|
302
|
+
const scale =
|
|
303
|
+
parsed.options.scale === undefined ? undefined : Number.parseFloat(parsed.options.scale)
|
|
304
|
+
const result = await withSlopcameraOperationHostAdmission(
|
|
305
|
+
"slopcamera.diagram.render",
|
|
306
|
+
async () => await renderDiagramFile({
|
|
307
|
+
filePath: requiredPositional(parsed, 0, "diagram file"),
|
|
308
|
+
...(parsed.options["out-dir"] === undefined
|
|
309
|
+
? {}
|
|
310
|
+
: { outDirectory: parsed.options["out-dir"] }),
|
|
311
|
+
...(parsed.options.config === undefined
|
|
312
|
+
? {}
|
|
313
|
+
: { configPath: parsed.options.config }),
|
|
314
|
+
...(scale === undefined ? {} : { scale }),
|
|
315
|
+
}),
|
|
316
|
+
hostAdmissionOptions(dependencies),
|
|
317
|
+
)
|
|
318
|
+
console.log(artifactSummary(result.artifacts))
|
|
319
|
+
printFindings(result.findings)
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (command === "vectorize") {
|
|
324
|
+
const parsed = parseArguments(
|
|
325
|
+
rest,
|
|
326
|
+
new Set(["output", "duotone", "alpha-cutoff", "timeout-ms"]),
|
|
327
|
+
)
|
|
328
|
+
const unknownFlags = [...parsed.flags].filter((flag) => flag !== "json")
|
|
329
|
+
if (unknownFlags.length > 0) {
|
|
330
|
+
throw new Error(`Unknown vectorize option: --${unknownFlags[0]}`)
|
|
331
|
+
}
|
|
332
|
+
if (parsed.positionals.length > 1) {
|
|
333
|
+
throw new Error("slopcamera image vectorize accepts exactly one raster input")
|
|
334
|
+
}
|
|
335
|
+
const output = requiredOption(parsed, "output")
|
|
336
|
+
if (!output.toLowerCase().endsWith(".svg")) {
|
|
337
|
+
throw new Error("--output must end in .svg")
|
|
338
|
+
}
|
|
339
|
+
const alphaCutoff = parsePositiveInteger(parsed.options["alpha-cutoff"], "alpha-cutoff")
|
|
340
|
+
const timeoutMs = parsePositiveInteger(parsed.options["timeout-ms"], "timeout-ms")
|
|
341
|
+
const duotone = parseDuotone(parsed.options.duotone)
|
|
342
|
+
const result = await withSlopcameraOperationHostAdmission(
|
|
343
|
+
"slopcamera.image.vectorize",
|
|
344
|
+
async (lease) => await (dependencies.vectorize ?? vectorizeImage)(
|
|
345
|
+
requiredPositional(parsed, 0, "raster image"),
|
|
346
|
+
{
|
|
347
|
+
...(alphaCutoff === undefined ? {} : { alphaCutoff }),
|
|
348
|
+
...(duotone === undefined ? {} : { duotone }),
|
|
349
|
+
...(timeoutMs === undefined
|
|
350
|
+
? {}
|
|
351
|
+
: { limits: { maxDurationMs: timeoutMs } }),
|
|
352
|
+
inheritedFileDescriptors: [lease.inheritedFileDescriptor],
|
|
353
|
+
outputPath: output,
|
|
354
|
+
},
|
|
355
|
+
),
|
|
356
|
+
hostAdmissionOptions(dependencies),
|
|
357
|
+
)
|
|
358
|
+
if (parsed.flags.has("json")) {
|
|
359
|
+
;(dependencies.log ?? console.log)(
|
|
360
|
+
JSON.stringify({ ...result.receipt, outputPath: result.outputPath }, null, 2),
|
|
361
|
+
)
|
|
362
|
+
} else {
|
|
363
|
+
;(dependencies.log ?? console.log)(
|
|
364
|
+
`Vectorized ${result.receipt.width}×${result.receipt.height} with `
|
|
365
|
+
+ `${result.receipt.profile}/${result.receipt.representation}: ${result.outputPath}`,
|
|
366
|
+
)
|
|
367
|
+
}
|
|
368
|
+
return
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (command === "generate") {
|
|
372
|
+
const parsed = parseArguments(
|
|
373
|
+
rest,
|
|
374
|
+
new Set(["model", "output"]),
|
|
375
|
+
)
|
|
376
|
+
const unknownFlags = [...parsed.flags].filter((flag) => flag !== "json")
|
|
377
|
+
if (unknownFlags.length > 0) {
|
|
378
|
+
throw new Error(`Unknown generate option: --${unknownFlags[0]}`)
|
|
379
|
+
}
|
|
380
|
+
if (parsed.positionals.length !== 1) {
|
|
381
|
+
throw new Error("slopcamera image generate accepts exactly one prompt")
|
|
382
|
+
}
|
|
383
|
+
const model = parsed.options.model ?? slopcameraImageModels[1]
|
|
384
|
+
if (
|
|
385
|
+
model.length > 256 ||
|
|
386
|
+
!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(model)
|
|
387
|
+
) {
|
|
388
|
+
throw new Error(
|
|
389
|
+
"--model must be a bounded Vercel AI Gateway provider/model id",
|
|
390
|
+
)
|
|
391
|
+
}
|
|
392
|
+
const result = await withSlopcameraOperationHostAdmission(
|
|
393
|
+
"slopcamera.image.generate",
|
|
394
|
+
async () => await (dependencies.generate ?? generateSlopcameraImageFile)({
|
|
395
|
+
model: model as SlopcameraImageModel,
|
|
396
|
+
prompt: requiredPositional(parsed, 0, "prompt"),
|
|
397
|
+
outputPath: requiredOption(parsed, "output"),
|
|
398
|
+
}),
|
|
399
|
+
hostAdmissionOptions(dependencies),
|
|
400
|
+
)
|
|
401
|
+
if (parsed.flags.has("json")) {
|
|
402
|
+
;(dependencies.log ?? console.log)(JSON.stringify(result, null, 2))
|
|
403
|
+
} else {
|
|
404
|
+
;(dependencies.log ?? console.log)(
|
|
405
|
+
`Generated ${result.mediaType} with ${result.model}: ${result.outputPath} (${result.bytes} bytes, request ${result.requestId})`,
|
|
406
|
+
)
|
|
407
|
+
}
|
|
408
|
+
return
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (command === "code") {
|
|
412
|
+
const [subcommand, ...subcommandArgs] = rest
|
|
413
|
+
if (subcommand === "search") {
|
|
414
|
+
const parsed = parseArguments(subcommandArgs, new Set(["limit"]))
|
|
415
|
+
if (parsed.flags.size > 0 || parsed.positionals.length > 1) {
|
|
416
|
+
throw new Error(
|
|
417
|
+
"Use slopcamera code search [query] [--limit <number>]",
|
|
418
|
+
)
|
|
419
|
+
}
|
|
420
|
+
const limit =
|
|
421
|
+
parsePositiveInteger(parsed.options.limit, "limit") ??
|
|
422
|
+
slopcameraOperationCodes.length
|
|
423
|
+
const operations = searchSlopcameraOperations(
|
|
424
|
+
parsed.positionals[0] ?? "",
|
|
425
|
+
limit,
|
|
426
|
+
)
|
|
427
|
+
console.log(JSON.stringify({ operations }, null, 2))
|
|
428
|
+
return
|
|
429
|
+
}
|
|
430
|
+
if (subcommand === "execute") {
|
|
431
|
+
const parsed = parseArguments(subcommandArgs, new Set(["input"]))
|
|
432
|
+
if (
|
|
433
|
+
parsed.flags.size > 0 ||
|
|
434
|
+
parsed.positionals.length !== 1
|
|
435
|
+
) {
|
|
436
|
+
throw new Error(
|
|
437
|
+
"Use slopcamera code execute <operation> --input <JSON>",
|
|
438
|
+
)
|
|
439
|
+
}
|
|
440
|
+
const requestedOperation = parsed.positionals[0]!
|
|
441
|
+
const operation = isSlopcameraOperationCode(requestedOperation)
|
|
442
|
+
? requestedOperation
|
|
443
|
+
: undefined
|
|
444
|
+
if (operation === undefined) {
|
|
445
|
+
throw new Error(`Unknown Slopcamera operation code: ${requestedOperation}`)
|
|
446
|
+
}
|
|
447
|
+
const inputText = requiredOption(parsed, "input")
|
|
448
|
+
if (Buffer.byteLength(inputText, "utf8") > 64 * 1024) {
|
|
449
|
+
throw new Error("--input JSON must be no more than 65536 UTF-8 bytes")
|
|
450
|
+
}
|
|
451
|
+
let input: unknown
|
|
452
|
+
try {
|
|
453
|
+
input = JSON.parse(inputText)
|
|
454
|
+
} catch {
|
|
455
|
+
throw new Error("--input must be valid JSON")
|
|
456
|
+
}
|
|
457
|
+
const result = await executeSlopcameraOperation(operation, input, {
|
|
458
|
+
...hostAdmissionOptions(dependencies),
|
|
459
|
+
})
|
|
460
|
+
;(dependencies.log ?? console.log)(
|
|
461
|
+
JSON.stringify({ operation, result }, null, 2),
|
|
462
|
+
)
|
|
463
|
+
return
|
|
464
|
+
}
|
|
465
|
+
throw new Error(
|
|
466
|
+
"Use slopcamera code search [query] or slopcamera code execute <operation> --input <JSON>",
|
|
467
|
+
)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (command === "mcp") {
|
|
471
|
+
const parsed = parseArguments(rest, new Set(["root"]))
|
|
472
|
+
if (parsed.positionals.length > 0 || parsed.flags.size > 0) {
|
|
473
|
+
throw new Error("slopcamera mcp accepts only --root <workspace>")
|
|
474
|
+
}
|
|
475
|
+
await runMcpServer({
|
|
476
|
+
rootDirectory: requiredOption(parsed, "root"),
|
|
477
|
+
serverVersion: slopcameraCliVersion,
|
|
478
|
+
})
|
|
479
|
+
return
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (command === "open") {
|
|
483
|
+
const parsed = parseArguments(rest, new Set())
|
|
484
|
+
await openInDesktop(requiredPositional(parsed, 0, "tldraw file"))
|
|
485
|
+
console.log("Opened in tldraw Offline.")
|
|
486
|
+
return
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (command === "doctor") {
|
|
490
|
+
const status = await desktopStatus()
|
|
491
|
+
console.log(`slopcamera ${slopcameraCliVersion}`)
|
|
492
|
+
console.log(`Bun ${process.versions.bun ?? "not detected"}`)
|
|
493
|
+
console.log("Headless diagram SVG/PNG/tldraw renderer ready")
|
|
494
|
+
console.log(
|
|
495
|
+
process.platform === "win32"
|
|
496
|
+
? "Local raster-to-SVG vectorizer unavailable on Windows (fails closed with tool_platform)"
|
|
497
|
+
: "Local raster-to-SVG vectorizer ready without authentication (VTracer downloads on first use)",
|
|
498
|
+
)
|
|
499
|
+
console.log("Root-relative MCP check/render server ready (trusted local workspace)")
|
|
500
|
+
const gateway = slopcameraGatewayCredentialStatus()
|
|
501
|
+
console.log(
|
|
502
|
+
gateway.available
|
|
503
|
+
? `Vercel AI Gateway ready via ${gateway.source}`
|
|
504
|
+
: "Vercel AI Gateway requires AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN",
|
|
505
|
+
)
|
|
506
|
+
console.log(
|
|
507
|
+
status.installedPath === null
|
|
508
|
+
? "tldraw Offline not installed (optional)"
|
|
509
|
+
: `tldraw Offline: ${status.installedPath}`,
|
|
510
|
+
)
|
|
511
|
+
console.log(
|
|
512
|
+
status.server === null
|
|
513
|
+
? "tldraw Offline agent server not running (optional)"
|
|
514
|
+
: `tldraw Offline agent server: localhost:${status.server.port}`,
|
|
515
|
+
)
|
|
516
|
+
return
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (command === "desktop") {
|
|
520
|
+
const [subcommand, ...subcommandArgs] = rest
|
|
521
|
+
if (subcommand === "status") {
|
|
522
|
+
const status = await desktopStatus()
|
|
523
|
+
console.log(JSON.stringify(status, null, 2))
|
|
524
|
+
return
|
|
525
|
+
}
|
|
526
|
+
if (subcommand === "url") {
|
|
527
|
+
const release = await getLatestDesktopRelease()
|
|
528
|
+
const asset = selectDesktopAsset(release)
|
|
529
|
+
console.log(
|
|
530
|
+
JSON.stringify(
|
|
531
|
+
{
|
|
532
|
+
release: release.tag_name,
|
|
533
|
+
releaseUrl: release.html_url,
|
|
534
|
+
asset: asset.name,
|
|
535
|
+
url: asset.browser_download_url,
|
|
536
|
+
bytes: asset.size,
|
|
537
|
+
sha256: asset.digest,
|
|
538
|
+
},
|
|
539
|
+
null,
|
|
540
|
+
2,
|
|
541
|
+
),
|
|
542
|
+
)
|
|
543
|
+
return
|
|
544
|
+
}
|
|
545
|
+
if (subcommand === "install") {
|
|
546
|
+
const parsed = parseArguments(subcommandArgs, new Set())
|
|
547
|
+
if (!parsed.flags.has("yes") && !(await confirmInstall())) {
|
|
548
|
+
console.log("Cancelled.")
|
|
549
|
+
return
|
|
550
|
+
}
|
|
551
|
+
const result = await installDesktop({ downloadOnly: parsed.flags.has("download-only") })
|
|
552
|
+
console.log(
|
|
553
|
+
`${parsed.flags.has("download-only") ? "Downloaded" : "Prepared"} tldraw Offline ${result.release}: ${result.filePath}`,
|
|
554
|
+
)
|
|
555
|
+
return
|
|
556
|
+
}
|
|
557
|
+
throw new Error("Use slopcamera canvas status, url, or install")
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (command === "skill") {
|
|
561
|
+
const [subcommand, ...subcommandArgs] = rest
|
|
562
|
+
if (subcommand === "path") {
|
|
563
|
+
const { bundledSkillPath } = await import("./skill-install.js")
|
|
564
|
+
console.log(bundledSkillPath())
|
|
565
|
+
return
|
|
566
|
+
}
|
|
567
|
+
if (subcommand === "install") {
|
|
568
|
+
const parsed = parseArguments(subcommandArgs, new Set(["target", "scope", "project"]))
|
|
569
|
+
const target = (parsed.options.target ?? "codex") as SkillTarget
|
|
570
|
+
const scope = (parsed.options.scope ?? "user") as SkillScope
|
|
571
|
+
if (!["codex", "claude", "agents"].includes(target)) {
|
|
572
|
+
throw new Error("--target must be codex, claude, or agents")
|
|
573
|
+
}
|
|
574
|
+
if (!["user", "project"].includes(scope)) {
|
|
575
|
+
throw new Error("--scope must be user or project")
|
|
576
|
+
}
|
|
577
|
+
const destination = await installSkill({
|
|
578
|
+
target,
|
|
579
|
+
scope,
|
|
580
|
+
...(parsed.options.project === undefined
|
|
581
|
+
? {}
|
|
582
|
+
: { projectDirectory: parsed.options.project }),
|
|
583
|
+
force: parsed.flags.has("force"),
|
|
584
|
+
})
|
|
585
|
+
console.log(`Installed slopcamera skill at ${destination}`)
|
|
586
|
+
return
|
|
587
|
+
}
|
|
588
|
+
throw new Error("Use slopcamera skill path or install")
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
throw new Error(`Unknown command: ${command}\n\n${help}`)
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
if (import.meta.main) {
|
|
595
|
+
try {
|
|
596
|
+
await main(process.argv.slice(2))
|
|
597
|
+
} catch (error) {
|
|
598
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
599
|
+
process.exitCode = 1
|
|
600
|
+
}
|
|
601
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type SlopcameraCloudErrorCode =
|
|
2
|
+
| "AUTHENTICATION_REQUIRED"
|
|
3
|
+
| "GENERATION_FAILED"
|
|
4
|
+
| "GENERATION_INVALID_RESPONSE"
|
|
5
|
+
| "INVALID_ARGUMENT"
|
|
6
|
+
| "OUTPUT_WRITE_FAILED"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A stable, redacted failure from the direct Gateway boundary.
|
|
10
|
+
*
|
|
11
|
+
* `cause` is retained for local diagnostics but is deliberately not included
|
|
12
|
+
* in the public message or CLI output.
|
|
13
|
+
*/
|
|
14
|
+
export class SlopcameraCloudError extends Error {
|
|
15
|
+
readonly code: SlopcameraCloudErrorCode
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
code: SlopcameraCloudErrorCode,
|
|
19
|
+
message: string,
|
|
20
|
+
options?: ErrorOptions,
|
|
21
|
+
) {
|
|
22
|
+
super(`[${code}] ${message}`, options)
|
|
23
|
+
this.name = "SlopcameraCloudError"
|
|
24
|
+
this.code = code
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./canonical-json.js"
|
|
2
|
+
export * from "./compiler.js"
|
|
3
|
+
export * from "./contracts.js"
|
|
4
|
+
export * from "./define-workflow.js"
|
|
5
|
+
export * from "./errors.js"
|
|
6
|
+
export * from "./graph-builder.js"
|
|
7
|
+
export * from "./portable-builder.js"
|
|
8
|
+
export * from "./projection.js"
|
|
9
|
+
export * from "./public-operations.js"
|
|
10
|
+
export * from "./runtime.js"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { z } from "zod"
|
|
2
|
+
|
|
3
|
+
import { SlopcameraCodeError } from "./errors.js"
|
|
4
|
+
|
|
5
|
+
export function parseCodeBoundary<Output>(
|
|
6
|
+
schema: z.ZodType<Output>,
|
|
7
|
+
input: unknown,
|
|
8
|
+
name: string,
|
|
9
|
+
): Output {
|
|
10
|
+
const result = schema.safeParse(input)
|
|
11
|
+
if (!result.success) {
|
|
12
|
+
throw new SlopcameraCodeError("invalid-data", `Invalid ${name}.`, {
|
|
13
|
+
issues: result.error.issues.map(issue => ({
|
|
14
|
+
code: issue.code,
|
|
15
|
+
message: issue.message,
|
|
16
|
+
path: issue.path.map(String),
|
|
17
|
+
})),
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
return result.data
|
|
21
|
+
}
|