@hraness/slopcamera 3.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (441) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +60 -0
  3. package/PRIVACY.md +46 -0
  4. package/README.md +311 -0
  5. package/SECURITY.md +21 -0
  6. package/apps/desktop/README.md +966 -0
  7. package/apps/desktop/analysis/protocol.ts +223 -0
  8. package/apps/desktop/application/capability-binding.ts +594 -0
  9. package/apps/desktop/application/context.ts +97 -0
  10. package/apps/desktop/application/creative-iteration.ts +1385 -0
  11. package/apps/desktop/application/default-registry.ts +146 -0
  12. package/apps/desktop/application/directing-contract.ts +218 -0
  13. package/apps/desktop/application/directing-plan.ts +178 -0
  14. package/apps/desktop/application/errors.ts +18 -0
  15. package/apps/desktop/application/gateway-port.ts +867 -0
  16. package/apps/desktop/application/html-overlay-browser-runtime.ts +687 -0
  17. package/apps/desktop/application/html-overlay-integrity.ts +337 -0
  18. package/apps/desktop/application/html-overlay-renderer.ts +45 -0
  19. package/apps/desktop/application/index.ts +13 -0
  20. package/apps/desktop/application/operation-completion-checkpoint.ts +333 -0
  21. package/apps/desktop/application/operation-effects.ts +94 -0
  22. package/apps/desktop/application/operation.ts +224 -0
  23. package/apps/desktop/application/operations/analysis/faces.ts +244 -0
  24. package/apps/desktop/application/operations/analysis/music.ts +248 -0
  25. package/apps/desktop/application/operations/analysis/project-auto-zooms.ts +302 -0
  26. package/apps/desktop/application/operations/analysis/project-inactivity.ts +381 -0
  27. package/apps/desktop/application/operations/analysis/scenes.ts +272 -0
  28. package/apps/desktop/application/operations/analysis/shared.ts +202 -0
  29. package/apps/desktop/application/operations/derive/edit-batch.ts +967 -0
  30. package/apps/desktop/application/operations/derive/follow-faces.ts +454 -0
  31. package/apps/desktop/application/operations/edit/bind-candidate-revision.ts +91 -0
  32. package/apps/desktop/application/operations/edit/create-candidate-revision.ts +377 -0
  33. package/apps/desktop/application/operations/edit/create-revision.ts +255 -0
  34. package/apps/desktop/application/operations/edit/freeze-revision.ts +182 -0
  35. package/apps/desktop/application/operations/gateway/image.ts +41 -0
  36. package/apps/desktop/application/operations/gateway/index.ts +17 -0
  37. package/apps/desktop/application/operations/gateway/shared.ts +122 -0
  38. package/apps/desktop/application/operations/gateway/speech.ts +41 -0
  39. package/apps/desktop/application/operations/gateway/transcription.ts +42 -0
  40. package/apps/desktop/application/operations/gateway/video.ts +41 -0
  41. package/apps/desktop/application/operations/index.ts +31 -0
  42. package/apps/desktop/application/operations/iteration/create-candidate.ts +240 -0
  43. package/apps/desktop/application/operations/iteration/create-matrix.ts +117 -0
  44. package/apps/desktop/application/operations/iteration/select.ts +155 -0
  45. package/apps/desktop/application/operations/iteration/shared.ts +250 -0
  46. package/apps/desktop/application/operations/media/audio-effects.ts +376 -0
  47. package/apps/desktop/application/operations/media/binding.ts +79 -0
  48. package/apps/desktop/application/operations/media/capabilities.ts +112 -0
  49. package/apps/desktop/application/operations/media/color-grade.ts +343 -0
  50. package/apps/desktop/application/operations/media/html-overlay.ts +802 -0
  51. package/apps/desktop/application/operations/media/index.ts +8 -0
  52. package/apps/desktop/application/operations/media/ingest.ts +303 -0
  53. package/apps/desktop/application/operations/media/overlay.ts +729 -0
  54. package/apps/desktop/application/operations/media/shared.ts +845 -0
  55. package/apps/desktop/application/operations/media/transform-platform.ts +120 -0
  56. package/apps/desktop/application/operations/project/commit-edits.ts +2054 -0
  57. package/apps/desktop/application/operations/project/promote-selection.ts +495 -0
  58. package/apps/desktop/application/operations/project/snapshot.ts +95 -0
  59. package/apps/desktop/application/operations/recording/index.ts +5 -0
  60. package/apps/desktop/application/operations/recording/pause.ts +34 -0
  61. package/apps/desktop/application/operations/recording/resume.ts +34 -0
  62. package/apps/desktop/application/operations/recording/shared.ts +199 -0
  63. package/apps/desktop/application/operations/recording/start.ts +169 -0
  64. package/apps/desktop/application/operations/recording/stop.ts +34 -0
  65. package/apps/desktop/application/operations/render/bind-candidate-output.ts +324 -0
  66. package/apps/desktop/application/operations/render/materialize-selection.ts +322 -0
  67. package/apps/desktop/application/operations/render/project-caption-plan.ts +287 -0
  68. package/apps/desktop/application/operations/render/project-plan.ts +939 -0
  69. package/apps/desktop/application/operations/render/project-spatial-receipt.ts +70 -0
  70. package/apps/desktop/application/operations/render/project.ts +1922 -0
  71. package/apps/desktop/application/operations/shared.ts +67 -0
  72. package/apps/desktop/application/operations/slopcamera-portable.ts +1188 -0
  73. package/apps/desktop/application/operations/slopcamera-visuals.ts +784 -0
  74. package/apps/desktop/application/operations/spatial-project.ts +209 -0
  75. package/apps/desktop/application/operations/spatial-render.ts +415 -0
  76. package/apps/desktop/application/operations/spatial-scene.ts +97 -0
  77. package/apps/desktop/application/operations/studio.ts +143 -0
  78. package/apps/desktop/application/output-publication-lease.ts +163 -0
  79. package/apps/desktop/application/project-publication-lease.ts +233 -0
  80. package/apps/desktop/application/project-store.ts +196 -0
  81. package/apps/desktop/application/receipts.ts +533 -0
  82. package/apps/desktop/application/registry.ts +182 -0
  83. package/apps/desktop/application/spatial-assets.ts +675 -0
  84. package/apps/desktop/application/spatial-compositor-cadence.ts +23 -0
  85. package/apps/desktop/application/spatial-project-authority.ts +35 -0
  86. package/apps/desktop/application/spatial-project-lease.ts +126 -0
  87. package/apps/desktop/application/spatial-project-render-preparation.ts +225 -0
  88. package/apps/desktop/application/spatial-project-store.ts +286 -0
  89. package/apps/desktop/application/spatial-render-projection.ts +201 -0
  90. package/apps/desktop/application/spatial-render.ts +677 -0
  91. package/apps/desktop/application/spatial-spz.ts +44 -0
  92. package/apps/desktop/application/spatial-world-import.ts +135 -0
  93. package/apps/desktop/application/spatial-world-provenance.ts +46 -0
  94. package/apps/desktop/application/studio-port.ts +58 -0
  95. package/apps/desktop/application/verified-receipt-reconciliation.ts +1574 -0
  96. package/apps/desktop/capture/protocol.ts +689 -0
  97. package/apps/desktop/cli/analyzer.ts +406 -0
  98. package/apps/desktop/cli/args.ts +3181 -0
  99. package/apps/desktop/cli/asset-ingest.ts +747 -0
  100. package/apps/desktop/cli/atomic-render-effects.ts +210 -0
  101. package/apps/desktop/cli/atomic-render-platform.ts +205 -0
  102. package/apps/desktop/cli/atomic-render.ts +50 -0
  103. package/apps/desktop/cli/audio-analysis.ts +252 -0
  104. package/apps/desktop/cli/bounded-map.ts +39 -0
  105. package/apps/desktop/cli/bundle-service.ts +256 -0
  106. package/apps/desktop/cli/capabilities.ts +212 -0
  107. package/apps/desktop/cli/capture-bundle.ts +1117 -0
  108. package/apps/desktop/cli/command-host-resources.ts +251 -0
  109. package/apps/desktop/cli/commands.ts +6836 -0
  110. package/apps/desktop/cli/directing-blob.ts +291 -0
  111. package/apps/desktop/cli/directing-media.ts +517 -0
  112. package/apps/desktop/cli/directing-quote.ts +89 -0
  113. package/apps/desktop/cli/directing-service.ts +288 -0
  114. package/apps/desktop/cli/emoji-assets.ts +538 -0
  115. package/apps/desktop/cli/errors.ts +29 -0
  116. package/apps/desktop/cli/face-analysis-service.ts +940 -0
  117. package/apps/desktop/cli/filter-script.ts +76 -0
  118. package/apps/desktop/cli/gateway-application-port.ts +1142 -0
  119. package/apps/desktop/cli/gateway-credential.ts +81 -0
  120. package/apps/desktop/cli/gateway-media-artifacts.ts +723 -0
  121. package/apps/desktop/cli/gateway-media-catalog.ts +922 -0
  122. package/apps/desktop/cli/gateway-media-service.ts +3106 -0
  123. package/apps/desktop/cli/gateway-media-signature.ts +122 -0
  124. package/apps/desktop/cli/gateway-provider-options.ts +562 -0
  125. package/apps/desktop/cli/gateway-scene-provider.ts +391 -0
  126. package/apps/desktop/cli/help.ts +501 -0
  127. package/apps/desktop/cli/html-overlay-gpu.ts +97 -0
  128. package/apps/desktop/cli/html-overlay-renderer.ts +2478 -0
  129. package/apps/desktop/cli/io.ts +290 -0
  130. package/apps/desktop/cli/main.ts +123 -0
  131. package/apps/desktop/cli/media-effects-service.ts +885 -0
  132. package/apps/desktop/cli/media-ingest-model.ts +364 -0
  133. package/apps/desktop/cli/media-ingest-platform.ts +227 -0
  134. package/apps/desktop/cli/media-ingest-program.ts +200 -0
  135. package/apps/desktop/cli/media-ingest.ts +30 -0
  136. package/apps/desktop/cli/music-analysis-service.ts +434 -0
  137. package/apps/desktop/cli/mutation-lock.ts +530 -0
  138. package/apps/desktop/cli/native-assets.d.ts +12 -0
  139. package/apps/desktop/cli/native-media-runtime.macos.ts +7 -0
  140. package/apps/desktop/cli/overlay-playback.ts +177 -0
  141. package/apps/desktop/cli/paths.ts +265 -0
  142. package/apps/desktop/cli/portable-surface.ts +242 -0
  143. package/apps/desktop/cli/project-camera-receipt.ts +112 -0
  144. package/apps/desktop/cli/project-face-camera.ts +394 -0
  145. package/apps/desktop/cli/project-inactivity-service.ts +552 -0
  146. package/apps/desktop/cli/project-media-integrity.ts +121 -0
  147. package/apps/desktop/cli/project-renderer.ts +1526 -0
  148. package/apps/desktop/cli/project-service.ts +519 -0
  149. package/apps/desktop/cli/project-state-transaction.ts +520 -0
  150. package/apps/desktop/cli/query-limits.ts +1 -0
  151. package/apps/desktop/cli/recording-controller.ts +1567 -0
  152. package/apps/desktop/cli/recording-daemon.ts +931 -0
  153. package/apps/desktop/cli/recording-ref.ts +56 -0
  154. package/apps/desktop/cli/renamed-environment.ts +6 -0
  155. package/apps/desktop/cli/renderer.ts +1439 -0
  156. package/apps/desktop/cli/run-cli-test-helper.ts +60 -0
  157. package/apps/desktop/cli/scene-analysis-service.ts +879 -0
  158. package/apps/desktop/cli/spatial-compositor-verifier.ts +213 -0
  159. package/apps/desktop/cli/spatial-project-service.ts +90 -0
  160. package/apps/desktop/cli/spatial-scene-service.ts +105 -0
  161. package/apps/desktop/cli/spatial-world-service.ts +39 -0
  162. package/apps/desktop/cli/speech-analysis-service.ts +682 -0
  163. package/apps/desktop/cli/studio-assemble.ts +58 -0
  164. package/apps/desktop/cli/studio-command.ts +60 -0
  165. package/apps/desktop/cli/studio-custody.ts +60 -0
  166. package/apps/desktop/cli/studio-encode.ts +216 -0
  167. package/apps/desktop/cli/studio-exr.ts +52 -0
  168. package/apps/desktop/cli/studio-files.ts +179 -0
  169. package/apps/desktop/cli/studio-output-validation.ts +162 -0
  170. package/apps/desktop/cli/studio-process.ts +145 -0
  171. package/apps/desktop/cli/studio-runtime.ts +77 -0
  172. package/apps/desktop/cli/studio-scaffold.ts +70 -0
  173. package/apps/desktop/cli/studio-service.ts +301 -0
  174. package/apps/desktop/cli/studio-spatial-asset.ts +248 -0
  175. package/apps/desktop/cli/studio-template-names.ts +3 -0
  176. package/apps/desktop/cli/studio-workflow.ts +19 -0
  177. package/apps/desktop/cli/time.ts +25 -0
  178. package/apps/desktop/cli/workflow-code.ts +584 -0
  179. package/apps/desktop/cli/workflow-runs.ts +576 -0
  180. package/apps/desktop/code/advanced.ts +139 -0
  181. package/apps/desktop/code/application-node-planner.ts +1288 -0
  182. package/apps/desktop/code/compiler.ts +329 -0
  183. package/apps/desktop/code/contracts.ts +13 -0
  184. package/apps/desktop/code/creative-recipes.ts +94 -0
  185. package/apps/desktop/code/define-workflow.ts +115 -0
  186. package/apps/desktop/code/editing.ts +284 -0
  187. package/apps/desktop/code/file-candidate-provenance.ts +420 -0
  188. package/apps/desktop/code/file-candidate.ts +69 -0
  189. package/apps/desktop/code/graph-builder.ts +10 -0
  190. package/apps/desktop/code/host-resource-policy.ts +55 -0
  191. package/apps/desktop/code/plan-contracts.ts +159 -0
  192. package/apps/desktop/code/planning.ts +361 -0
  193. package/apps/desktop/code/public.ts +134 -0
  194. package/apps/desktop/code/reference-projection.ts +62 -0
  195. package/apps/desktop/code/run-contracts.ts +466 -0
  196. package/apps/desktop/code/run-store.ts +2478 -0
  197. package/apps/desktop/code/runtime-identity.ts +328 -0
  198. package/apps/desktop/code/scheduler.ts +3067 -0
  199. package/apps/desktop/code/semantic-builder.ts +1436 -0
  200. package/apps/desktop/code/source-bundle.ts +1641 -0
  201. package/apps/desktop/code/source-typecheck.ts +211 -0
  202. package/apps/desktop/code/testing.ts +79 -0
  203. package/apps/desktop/code/worker-client.ts +1675 -0
  204. package/apps/desktop/code/worker-effects.ts +141 -0
  205. package/apps/desktop/code/worker-entry.ts +435 -0
  206. package/apps/desktop/code/worker-lease-guardian.ts +179 -0
  207. package/apps/desktop/code/worker-process-identity.ts +484 -0
  208. package/apps/desktop/code/worker-protocol.ts +211 -0
  209. package/apps/desktop/code/workflow-effects.ts +132 -0
  210. package/apps/desktop/contracts/analysis.ts +949 -0
  211. package/apps/desktop/contracts/edit.ts +576 -0
  212. package/apps/desktop/contracts/index.ts +9 -0
  213. package/apps/desktop/contracts/media-effects.ts +139 -0
  214. package/apps/desktop/contracts/project-render.ts +644 -0
  215. package/apps/desktop/contracts/project.ts +740 -0
  216. package/apps/desktop/contracts/recording.ts +1434 -0
  217. package/apps/desktop/contracts/render.ts +334 -0
  218. package/apps/desktop/contracts/runtime.ts +155 -0
  219. package/apps/desktop/contracts/spatial-compositor.ts +58 -0
  220. package/apps/desktop/contracts/spatial-project.ts +159 -0
  221. package/apps/desktop/contracts/spatial-world.ts +48 -0
  222. package/apps/desktop/contracts/video-effects.ts +120 -0
  223. package/apps/desktop/core/alignment-apply.ts +400 -0
  224. package/apps/desktop/core/audio-alignment.ts +466 -0
  225. package/apps/desktop/core/auto-zoom.ts +209 -0
  226. package/apps/desktop/core/canonical-json.ts +14 -0
  227. package/apps/desktop/core/emoji.ts +210 -0
  228. package/apps/desktop/core/events.ts +409 -0
  229. package/apps/desktop/core/face-framing.ts +533 -0
  230. package/apps/desktop/core/face-tracks.ts +326 -0
  231. package/apps/desktop/core/inactivity.ts +137 -0
  232. package/apps/desktop/core/index.ts +30 -0
  233. package/apps/desktop/core/intervals.ts +123 -0
  234. package/apps/desktop/core/montage.ts +236 -0
  235. package/apps/desktop/core/music-analysis.ts +518 -0
  236. package/apps/desktop/core/plan.ts +244 -0
  237. package/apps/desktop/core/project-auto-zoom.ts +75 -0
  238. package/apps/desktop/core/project-camera-spatial.ts +676 -0
  239. package/apps/desktop/core/project-camera.ts +403 -0
  240. package/apps/desktop/core/project-captions.ts +888 -0
  241. package/apps/desktop/core/project-inactivity.ts +125 -0
  242. package/apps/desktop/core/project-metadata.ts +927 -0
  243. package/apps/desktop/core/project-plan.ts +375 -0
  244. package/apps/desktop/core/project-render-plan.ts +303 -0
  245. package/apps/desktop/core/project-time.ts +469 -0
  246. package/apps/desktop/core/render-plan.ts +442 -0
  247. package/apps/desktop/core/scene-cache.ts +174 -0
  248. package/apps/desktop/core/scene-sampling.ts +448 -0
  249. package/apps/desktop/core/spatial-compositor.ts +22 -0
  250. package/apps/desktop/core/spatial-durability.ts +99 -0
  251. package/apps/desktop/core/spatial-project.ts +169 -0
  252. package/apps/desktop/core/spatial-shot-clock.ts +32 -0
  253. package/apps/desktop/core/speech-analysis.ts +333 -0
  254. package/apps/desktop/core/storage.ts +970 -0
  255. package/apps/desktop/core/time-map.ts +91 -0
  256. package/apps/desktop/core/time.ts +61 -0
  257. package/apps/desktop/core/video-effects.ts +660 -0
  258. package/apps/desktop/dist/cli/NebulaSans-Bold-26se8aek.otf +0 -0
  259. package/apps/desktop/dist/cli/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  260. package/apps/desktop/dist/cli/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  261. package/apps/desktop/dist/cli/NebulaSans-Book-8cenzchw.otf +0 -0
  262. package/apps/desktop/dist/cli/main.js +5086 -0
  263. package/apps/desktop/html-overlay/catalog.ts +171 -0
  264. package/apps/desktop/html-overlay/contracts.ts +372 -0
  265. package/apps/desktop/html-overlay/execution-profile.ts +77 -0
  266. package/apps/desktop/html-overlay/index.ts +98 -0
  267. package/apps/desktop/html-overlay/libraries.ts +263 -0
  268. package/apps/desktop/html-overlay/random.ts +49 -0
  269. package/apps/desktop/html-overlay/runtime.ts +813 -0
  270. package/apps/desktop/html-overlay/scaffolds.ts +792 -0
  271. package/apps/desktop/html-overlay/spark-runtime.ts +88 -0
  272. package/apps/desktop/html-overlay/spatial-splat-runtime.ts +60 -0
  273. package/apps/desktop/html-overlay/spatial.ts +720 -0
  274. package/apps/desktop/studio/assets/README.md +39 -0
  275. package/apps/desktop/studio/assets/contracts.ts +129 -0
  276. package/apps/desktop/studio/assets/network.ts +64 -0
  277. package/apps/desktop/studio/assets/poly-haven.ts +148 -0
  278. package/apps/desktop/studio/drivers/blender_driver.py +466 -0
  279. package/apps/desktop/studio/drivers/cadquery_driver.py +176 -0
  280. package/apps/desktop/studio/education/driver.py +308 -0
  281. package/apps/desktop/studio/education/lesson.py +180 -0
  282. package/apps/desktop/studio/education/toolkit.py +249 -0
  283. package/apps/desktop/workflows/chaptered-demo.ts +48 -0
  284. package/apps/desktop/workflows/creative-iteration.ts +107 -0
  285. package/apps/desktop/workflows/creative-selection.ts +92 -0
  286. package/apps/desktop/workflows/fragments.ts +486 -0
  287. package/apps/desktop/workflows/index.ts +93 -0
  288. package/apps/desktop/workflows/polished-screen-demo.ts +128 -0
  289. package/apps/desktop/workflows/scene-direction.ts +12 -0
  290. package/apps/desktop/workflows/social-variants.ts +75 -0
  291. package/apps/desktop/workflows/talking-head-cleanup.ts +53 -0
  292. package/dist/NebulaSans-Bold-26se8aek.otf +0 -0
  293. package/dist/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  294. package/dist/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  295. package/dist/NebulaSans-Book-8cenzchw.otf +0 -0
  296. package/dist/cli.js +479 -0
  297. package/dist/code/advanced.js +270 -0
  298. package/dist/code/index.js +2240 -0
  299. package/dist/generate.js +24 -0
  300. package/dist/host-resources.js +26 -0
  301. package/dist/index-42zsesc1.js +2257 -0
  302. package/dist/index-7308egqr.js +48 -0
  303. package/dist/index-8txs6fkn.js +712 -0
  304. package/dist/index-mcy8z0br.js +192 -0
  305. package/dist/index-p63wavx0.js +2029 -0
  306. package/dist/index-r7gdhmsp.js +424 -0
  307. package/dist/index-sh6xbav6.js +1219 -0
  308. package/dist/index-z1w83f81.js +4 -0
  309. package/dist/index-z7239b4h.js +2363 -0
  310. package/dist/index-zfeg9hmw.js +2013 -0
  311. package/dist/index.js +241 -0
  312. package/dist/operations.js +29 -0
  313. package/dist/skill-install-dh0ntqba.js +10 -0
  314. package/dist/vectorize/worker.js +142 -0
  315. package/dist/workflow.js +16 -0
  316. package/docs/README.md +38 -0
  317. package/docs/studio.md +215 -0
  318. package/examples/studio/blender/README.md +26 -0
  319. package/examples/studio/blender/character.py +152 -0
  320. package/examples/studio/blender/cloth.py +101 -0
  321. package/examples/studio/blender/color_chart.py +29 -0
  322. package/examples/studio/blender/fluid.py +78 -0
  323. package/examples/studio/blender/import_model.py +74 -0
  324. package/examples/studio/blender/product.py +53 -0
  325. package/examples/studio/blender/shaded_street.py +481 -0
  326. package/examples/studio/blender/studio_scene.py +147 -0
  327. package/examples/studio/cadquery/README.md +13 -0
  328. package/examples/studio/cadquery/bracket.py +36 -0
  329. package/examples/studio/cadquery/import_step.py +12 -0
  330. package/examples/studio/education/README.md +46 -0
  331. package/examples/studio/education/lesson.json +99 -0
  332. package/examples/studio/education/scene.py +7 -0
  333. package/examples/studio/hybrid-scene.ts +96 -0
  334. package/examples/studio/native-workflow.ts +14 -0
  335. package/examples/studio/vgpu/README.md +64 -0
  336. package/examples/studio/vgpu/heat-field.mjs +290 -0
  337. package/package.json +304 -0
  338. package/packages/scene/src/index.ts +1 -0
  339. package/packages/scene/src/scene.ts +215 -0
  340. package/schema/diagram.schema.json +334 -0
  341. package/skills/slopcamera/SKILL.md +45 -0
  342. package/skills/slopcamera/agents/openai.yaml +4 -0
  343. package/skills/slopcamera/references/customization.md +77 -0
  344. package/skills/slopcamera/references/diagrams.md +153 -0
  345. package/skills/slopcamera/references/directed-scenes.md +42 -0
  346. package/skills/slopcamera/references/directing-video.md +18 -0
  347. package/skills/slopcamera/references/educational-video.md +26 -0
  348. package/skills/slopcamera/references/gateway-media.md +134 -0
  349. package/skills/slopcamera/references/install.md +62 -0
  350. package/skills/slopcamera/references/native-studio.md +31 -0
  351. package/skills/slopcamera/references/reference-led-3d.md +140 -0
  352. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-1.jpg +0 -0
  353. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-2.jpg +0 -0
  354. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-1.png +0 -0
  355. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-2.png +0 -0
  356. package/skills/slopcamera/references/rubber-stamp-field-notes.md +144 -0
  357. package/skills/slopcamera/references/vectorization.md +29 -0
  358. package/skills/slopcamera/references/video-projects.md +187 -0
  359. package/skills/slopcamera/references/visual-communication.md +120 -0
  360. package/skills/slopcamera/references/workflows-sdk.md +45 -0
  361. package/skills/slopcamera/scripts/compose-rubber-stamp-field-note.ts +229 -0
  362. package/src/artifacts.ts +106 -0
  363. package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
  364. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
  365. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
  366. package/src/assets/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
  367. package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
  368. package/src/assets/fonts/nebula-sans/PROVENANCE.md +21 -0
  369. package/src/assets.d.ts +9 -0
  370. package/src/cli.ts +601 -0
  371. package/src/cloud-errors.ts +26 -0
  372. package/src/code/advanced.ts +10 -0
  373. package/src/code/boundary.ts +21 -0
  374. package/src/code/canonical-json.ts +129 -0
  375. package/src/code/compiler.ts +953 -0
  376. package/src/code/contracts.ts +576 -0
  377. package/src/code/define-workflow.ts +334 -0
  378. package/src/code/errors.ts +41 -0
  379. package/src/code/graph-builder.ts +945 -0
  380. package/src/code/index.ts +121 -0
  381. package/src/code/json-snapshot.ts +899 -0
  382. package/src/code/json-utf8.ts +88 -0
  383. package/src/code/portable-builder.ts +136 -0
  384. package/src/code/projection.ts +378 -0
  385. package/src/code/public-operations.ts +450 -0
  386. package/src/code/runtime.ts +580 -0
  387. package/src/code/sha256.ts +36 -0
  388. package/src/config.ts +180 -0
  389. package/src/desktop.ts +253 -0
  390. package/src/fs.ts +10 -0
  391. package/src/generate.ts +704 -0
  392. package/src/host-resource-posix.ts +161 -0
  393. package/src/host-resources.ts +1749 -0
  394. package/src/icons.ts +58 -0
  395. package/src/index.ts +200 -0
  396. package/src/label-layout.ts +130 -0
  397. package/src/layout.ts +413 -0
  398. package/src/lint.ts +127 -0
  399. package/src/mcp/boundary.ts +354 -0
  400. package/src/mcp/index.ts +33 -0
  401. package/src/mcp/server.ts +272 -0
  402. package/src/mcp/tools.ts +963 -0
  403. package/src/mcp/types.ts +71 -0
  404. package/src/operations.ts +775 -0
  405. package/src/parse.ts +861 -0
  406. package/src/process-environment.ts +17 -0
  407. package/src/render.ts +437 -0
  408. package/src/skill-install.ts +49 -0
  409. package/src/spatial-scene/authoring.ts +27 -0
  410. package/src/spatial-scene/camera-track.ts +83 -0
  411. package/src/spatial-scene/contracts.ts +277 -0
  412. package/src/spatial-scene/evaluate.ts +145 -0
  413. package/src/spatial-scene/gltf.ts +558 -0
  414. package/src/spatial-scene/identity.ts +260 -0
  415. package/src/spatial-scene/index.ts +10 -0
  416. package/src/spatial-scene/inspect.ts +68 -0
  417. package/src/spatial-scene/math.ts +280 -0
  418. package/src/spatial-scene/patch.ts +131 -0
  419. package/src/spatial-scene/time.ts +53 -0
  420. package/src/studio/contracts.ts +129 -0
  421. package/src/studio/index.ts +2 -0
  422. package/src/studio/plan.ts +156 -0
  423. package/src/studio/shared.ts +41 -0
  424. package/src/theme.ts +68 -0
  425. package/src/tldr.ts +474 -0
  426. package/src/types.ts +212 -0
  427. package/src/vectorize/archive.ts +101 -0
  428. package/src/vectorize/command.ts +797 -0
  429. package/src/vectorize/index.ts +27 -0
  430. package/src/vectorize/limits.ts +61 -0
  431. package/src/vectorize/metrics.ts +351 -0
  432. package/src/vectorize/pixels.ts +323 -0
  433. package/src/vectorize/supervisor.ts +339 -0
  434. package/src/vectorize/svg.ts +188 -0
  435. package/src/vectorize/tool.ts +542 -0
  436. package/src/vectorize/types.ts +113 -0
  437. package/src/vectorize/vectorize.ts +634 -0
  438. package/src/vectorize/worker-protocol.ts +40 -0
  439. package/src/vectorize/worker.ts +209 -0
  440. package/src/version.ts +1 -0
  441. package/src/workflow.ts +409 -0
@@ -0,0 +1,594 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { constants } from "node:fs";
3
+ import {
4
+ link,
5
+ lstat,
6
+ mkdir,
7
+ open,
8
+ realpath,
9
+ unlink,
10
+ } from "node:fs/promises";
11
+ import {
12
+ basename,
13
+ isAbsolute,
14
+ join,
15
+ resolve,
16
+ sep,
17
+ } from "node:path";
18
+
19
+ import { z } from "zod";
20
+
21
+ import { canonicalJson } from "../core/canonical-json";
22
+ import type {
23
+ ApplicationCapability,
24
+ ApplicationCapabilityName,
25
+ ApplicationContext,
26
+ ApplicationProcessRunOptions,
27
+ ApplicationProcessRunResult,
28
+ ApplicationProcessRunner,
29
+ } from "./context";
30
+ import { ApplicationError } from "./errors";
31
+
32
+ const MAXIMUM_CAPABILITY_EXECUTABLE_BYTES = 512 * 1024 * 1024;
33
+ const CAPABILITY_HASH_BUFFER_BYTES = 1024 * 1024;
34
+ const CAPABILITY_PIN_DIRECTORY = "capability-pins-v1";
35
+
36
+ export const ExactCapabilityBindingSchema = z.strictObject({
37
+ bytes: z.number().int().safe().positive().max(
38
+ MAXIMUM_CAPABILITY_EXECUTABLE_BYTES,
39
+ ),
40
+ command: z.string().min(1).max(4_096).refine(
41
+ command => !command.includes("\0"),
42
+ "Capability commands cannot contain NUL bytes.",
43
+ ),
44
+ executablePath: z.string().min(1).max(4_096).refine(
45
+ path => isAbsolute(path) && !path.includes("\0"),
46
+ "Capability executable paths must be absolute and NUL-free.",
47
+ ),
48
+ executableSha256: z.string().regex(/^[a-f0-9]{64}$/u),
49
+ name: z.string().min(1).max(128),
50
+ version: z.string().min(1).max(512),
51
+ });
52
+
53
+ export const ExactCapabilityBindingsSchema = z.array(
54
+ ExactCapabilityBindingSchema,
55
+ ).max(32).superRefine((bindings, context) => {
56
+ for (let index = 0; index < bindings.length; index += 1) {
57
+ const previous = bindings[index - 1];
58
+ if (
59
+ previous !== undefined
60
+ && previous.name.localeCompare(bindings[index]!.name) >= 0
61
+ ) {
62
+ context.addIssue({
63
+ code: "custom",
64
+ message: "Exact capability bindings must have unique sorted names.",
65
+ path: [index, "name"],
66
+ });
67
+ }
68
+ }
69
+ });
70
+
71
+ export type ExactCapabilityBinding = z.infer<
72
+ typeof ExactCapabilityBindingSchema
73
+ >;
74
+
75
+ function isFileSystemError(error: unknown, code: string): boolean {
76
+ return error instanceof Error && "code" in error && error.code === code;
77
+ }
78
+
79
+ async function resolveExecutable(command: string): Promise<string> {
80
+ const requested = command.includes(sep)
81
+ ? resolve(command)
82
+ : Bun.which(command);
83
+ if (requested === null || requested === "") {
84
+ throw new ApplicationError(
85
+ "unavailable",
86
+ `Capability executable cannot be resolved: ${command}`,
87
+ );
88
+ }
89
+ try {
90
+ return await realpath(requested);
91
+ } catch (error) {
92
+ if (isFileSystemError(error, "ENOENT")) {
93
+ throw new ApplicationError(
94
+ "unavailable",
95
+ `Capability executable no longer exists: ${command}`,
96
+ );
97
+ }
98
+ throw error;
99
+ }
100
+ }
101
+
102
+ async function hashPhysicalExecutable(
103
+ executablePath: string,
104
+ label: string,
105
+ ): Promise<{ readonly bytes: number; readonly sha256: string }> {
106
+ let handle;
107
+ try {
108
+ handle = await open(
109
+ executablePath,
110
+ constants.O_RDONLY
111
+ | (constants.O_NOFOLLOW ?? 0)
112
+ | (constants.O_NONBLOCK ?? 0),
113
+ );
114
+ } catch (error) {
115
+ if (isFileSystemError(error, "ENOENT")) {
116
+ throw new ApplicationError(
117
+ "conflict",
118
+ `Capability executable disappeared before use: ${label}`,
119
+ );
120
+ }
121
+ throw error;
122
+ }
123
+ try {
124
+ const before = await handle.stat();
125
+ if (
126
+ !before.isFile()
127
+ || (before.mode & 0o111) === 0
128
+ || !Number.isSafeInteger(before.size)
129
+ || before.size < 1
130
+ || before.size > MAXIMUM_CAPABILITY_EXECUTABLE_BYTES
131
+ ) {
132
+ throw new ApplicationError(
133
+ "unsafe-path",
134
+ `Capability executable is unsafe, non-executable, or oversized: ${label}`,
135
+ );
136
+ }
137
+ const hash = createHash("sha256");
138
+ const buffer = Buffer.allocUnsafe(CAPABILITY_HASH_BUFFER_BYTES);
139
+ let offset = 0;
140
+ while (offset < before.size) {
141
+ const result = await handle.read(
142
+ buffer,
143
+ 0,
144
+ Math.min(buffer.byteLength, before.size - offset),
145
+ offset,
146
+ );
147
+ if (result.bytesRead === 0) break;
148
+ hash.update(buffer.subarray(0, result.bytesRead));
149
+ offset += result.bytesRead;
150
+ }
151
+ const after = await handle.stat();
152
+ const currentPath = await realpath(executablePath);
153
+ // Deliberately ignore ctime: creating a verified hard link changes only the
154
+ // link-count metadata on the shared inode. The open handle, inode, size,
155
+ // mode, mtime, and complete byte hash remain the executable identity.
156
+ if (
157
+ currentPath !== executablePath
158
+ || offset !== before.size
159
+ || before.dev !== after.dev
160
+ || before.ino !== after.ino
161
+ || before.size !== after.size
162
+ || before.mode !== after.mode
163
+ || before.mtimeMs !== after.mtimeMs
164
+ ) {
165
+ throw new ApplicationError(
166
+ "conflict",
167
+ `Capability executable changed while its bytes were verified: ${label}`,
168
+ );
169
+ }
170
+ return {
171
+ bytes: before.size,
172
+ sha256: hash.digest("hex"),
173
+ };
174
+ } finally {
175
+ await handle.close();
176
+ }
177
+ }
178
+
179
+ async function ensurePrivateDirectory(path: string): Promise<string> {
180
+ try {
181
+ await mkdir(path, { mode: 0o700, recursive: true });
182
+ } catch (error) {
183
+ if (!isFileSystemError(error, "EEXIST")) throw error;
184
+ }
185
+ const details = await lstat(path);
186
+ if (
187
+ details.isSymbolicLink()
188
+ || !details.isDirectory()
189
+ || (details.mode & 0o077) !== 0
190
+ ) {
191
+ throw new ApplicationError(
192
+ "unsafe-path",
193
+ `Capability pin directory must be a private physical directory: ${path}`,
194
+ );
195
+ }
196
+ return await realpath(path);
197
+ }
198
+
199
+ async function ensureCapabilityPinDirectory(
200
+ privateRoot: string,
201
+ binding: ExactCapabilityBinding,
202
+ ): Promise<{
203
+ readonly directory: string;
204
+ readonly pinPath: string;
205
+ readonly root: string;
206
+ }> {
207
+ const physicalPrivateRoot = await ensurePrivateDirectory(privateRoot);
208
+ const root = await ensurePrivateDirectory(
209
+ join(physicalPrivateRoot, CAPABILITY_PIN_DIRECTORY),
210
+ );
211
+ const directory = await ensurePrivateDirectory(
212
+ join(root, binding.executableSha256),
213
+ );
214
+ const executableName = basename(binding.executablePath);
215
+ if (
216
+ executableName === ""
217
+ || executableName === "."
218
+ || executableName === ".."
219
+ || executableName.length > 255
220
+ ) {
221
+ throw new ApplicationError(
222
+ "unsafe-path",
223
+ `Capability executable has an unsafe leaf name: ${binding.name}`,
224
+ );
225
+ }
226
+ return {
227
+ directory,
228
+ pinPath: join(directory, executableName),
229
+ root,
230
+ };
231
+ }
232
+
233
+ async function syncDirectory(path: string): Promise<void> {
234
+ const handle = await open(path, constants.O_RDONLY);
235
+ try {
236
+ await handle.sync();
237
+ } finally {
238
+ await handle.close();
239
+ }
240
+ }
241
+
242
+ async function verifyPinnedExecutable(
243
+ path: string,
244
+ binding: ExactCapabilityBinding,
245
+ ): Promise<void> {
246
+ const lexical = await lstat(path);
247
+ if (
248
+ lexical.isSymbolicLink()
249
+ || !lexical.isFile()
250
+ || (lexical.mode & 0o777) !== 0o500
251
+ ) {
252
+ throw new ApplicationError(
253
+ "unsafe-path",
254
+ `Pinned capability executable is not immutable and private: ${binding.name}`,
255
+ );
256
+ }
257
+ const identity = await hashPhysicalExecutable(
258
+ path,
259
+ `pinned ${binding.name}`,
260
+ );
261
+ if (
262
+ identity.bytes !== binding.bytes
263
+ || identity.sha256 !== binding.executableSha256
264
+ ) {
265
+ throw new ApplicationError(
266
+ "conflict",
267
+ `Pinned capability executable does not match its exact binding: ${binding.name}`,
268
+ );
269
+ }
270
+ }
271
+
272
+ async function writeAll(
273
+ handle: Awaited<ReturnType<typeof open>>,
274
+ bytes: Uint8Array,
275
+ position: number,
276
+ ): Promise<void> {
277
+ let written = 0;
278
+ while (written < bytes.byteLength) {
279
+ const result = await handle.write(
280
+ bytes,
281
+ written,
282
+ bytes.byteLength - written,
283
+ position + written,
284
+ );
285
+ if (result.bytesWritten === 0) {
286
+ throw new ApplicationError(
287
+ "internal",
288
+ "Capability pin write made no progress.",
289
+ );
290
+ }
291
+ written += result.bytesWritten;
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Copies the exact opened executable descriptor into a trusted private path.
297
+ * A rename-over of the original pathname after it is opened cannot alter the
298
+ * bytes copied or the pathname ultimately delegated for execution.
299
+ */
300
+ async function materializePinnedExecutable(
301
+ privateRoot: string,
302
+ binding: ExactCapabilityBinding,
303
+ ): Promise<string> {
304
+ const pin = await ensureCapabilityPinDirectory(privateRoot, binding);
305
+ const source = await open(
306
+ binding.executablePath,
307
+ constants.O_RDONLY
308
+ | (constants.O_NOFOLLOW ?? 0)
309
+ | (constants.O_NONBLOCK ?? 0),
310
+ );
311
+ const temporaryPath = join(
312
+ pin.root,
313
+ `.pin-${binding.executableSha256}-${randomUUID()}`,
314
+ );
315
+ let temporary:
316
+ | Awaited<ReturnType<typeof open>>
317
+ | undefined;
318
+ try {
319
+ const before = await source.stat();
320
+ if (
321
+ !before.isFile()
322
+ || (before.mode & 0o111) === 0
323
+ || before.size !== binding.bytes
324
+ ) {
325
+ throw new ApplicationError(
326
+ "conflict",
327
+ `Capability executable metadata changed before pinning: ${binding.name}`,
328
+ );
329
+ }
330
+
331
+ try {
332
+ await verifyPinnedExecutable(pin.pinPath, binding);
333
+ // The source itself must still match the binding on every launch, even
334
+ // when its already-materialized private pin can be reused.
335
+ const sourceHash = createHash("sha256");
336
+ const sourceBuffer = Buffer.allocUnsafe(
337
+ CAPABILITY_HASH_BUFFER_BYTES,
338
+ );
339
+ let sourceOffset = 0;
340
+ while (sourceOffset < before.size) {
341
+ const result = await source.read(
342
+ sourceBuffer,
343
+ 0,
344
+ Math.min(
345
+ sourceBuffer.byteLength,
346
+ before.size - sourceOffset,
347
+ ),
348
+ sourceOffset,
349
+ );
350
+ if (result.bytesRead === 0) break;
351
+ sourceHash.update(
352
+ sourceBuffer.subarray(0, result.bytesRead),
353
+ );
354
+ sourceOffset += result.bytesRead;
355
+ }
356
+ const after = await source.stat();
357
+ if (
358
+ sourceOffset !== binding.bytes
359
+ || sourceHash.digest("hex") !== binding.executableSha256
360
+ || before.dev !== after.dev
361
+ || before.ino !== after.ino
362
+ || before.size !== after.size
363
+ || before.mode !== after.mode
364
+ || before.mtimeMs !== after.mtimeMs
365
+ ) {
366
+ throw new ApplicationError(
367
+ "conflict",
368
+ `Capability executable bytes changed before subprocess launch: ${binding.name}`,
369
+ );
370
+ }
371
+ return pin.pinPath;
372
+ } catch (error) {
373
+ if (!isFileSystemError(error, "ENOENT")) throw error;
374
+ }
375
+
376
+ temporary = await open(
377
+ temporaryPath,
378
+ constants.O_CREAT
379
+ | constants.O_EXCL
380
+ | constants.O_WRONLY
381
+ | (constants.O_NOFOLLOW ?? 0),
382
+ 0o700,
383
+ );
384
+ const hash = createHash("sha256");
385
+ const buffer = Buffer.allocUnsafe(CAPABILITY_HASH_BUFFER_BYTES);
386
+ let offset = 0;
387
+ while (offset < before.size) {
388
+ const result = await source.read(
389
+ buffer,
390
+ 0,
391
+ Math.min(buffer.byteLength, before.size - offset),
392
+ offset,
393
+ );
394
+ if (result.bytesRead === 0) break;
395
+ const chunk = buffer.subarray(0, result.bytesRead);
396
+ hash.update(chunk);
397
+ await writeAll(temporary, chunk, offset);
398
+ offset += result.bytesRead;
399
+ }
400
+ const after = await source.stat();
401
+ if (
402
+ offset !== binding.bytes
403
+ || hash.digest("hex") !== binding.executableSha256
404
+ || before.dev !== after.dev
405
+ || before.ino !== after.ino
406
+ || before.size !== after.size
407
+ || before.mode !== after.mode
408
+ || before.mtimeMs !== after.mtimeMs
409
+ ) {
410
+ throw new ApplicationError(
411
+ "conflict",
412
+ `Capability executable changed while its private pin was created: ${binding.name}`,
413
+ );
414
+ }
415
+ await temporary.sync();
416
+ await temporary.chmod(0o500);
417
+ await temporary.sync();
418
+ await temporary.close();
419
+ temporary = undefined;
420
+
421
+ try {
422
+ await link(temporaryPath, pin.pinPath);
423
+ await unlink(temporaryPath);
424
+ await syncDirectory(pin.directory);
425
+ } catch (error) {
426
+ if (!isFileSystemError(error, "EEXIST")) throw error;
427
+ await unlink(temporaryPath);
428
+ }
429
+ await verifyPinnedExecutable(pin.pinPath, binding);
430
+ return pin.pinPath;
431
+ } finally {
432
+ await source.close();
433
+ if (temporary !== undefined) {
434
+ await temporary.close().catch(() => undefined);
435
+ }
436
+ await unlink(temporaryPath).catch(error => {
437
+ if (!isFileSystemError(error, "ENOENT")) throw error;
438
+ });
439
+ }
440
+ }
441
+
442
+ export async function bindExactCapability(
443
+ capability: ApplicationCapability,
444
+ ): Promise<ExactCapabilityBinding> {
445
+ if (
446
+ !capability.available
447
+ || capability.command === undefined
448
+ || capability.command === ""
449
+ ) {
450
+ throw new ApplicationError(
451
+ "unavailable",
452
+ `${capability.name} is unavailable: ${
453
+ capability.reason ?? "capability was not probed"
454
+ }`,
455
+ { capability: capability.name },
456
+ );
457
+ }
458
+ const executablePath = await resolveExecutable(capability.command);
459
+ const identity = await hashPhysicalExecutable(
460
+ executablePath,
461
+ capability.name,
462
+ );
463
+ return ExactCapabilityBindingSchema.parse({
464
+ bytes: identity.bytes,
465
+ command: capability.command,
466
+ executablePath,
467
+ executableSha256: identity.sha256,
468
+ name: capability.name,
469
+ version: capability.version ?? "unknown",
470
+ });
471
+ }
472
+
473
+ export async function bindExactCapabilities(
474
+ application: ApplicationContext,
475
+ names: readonly ApplicationCapabilityName[],
476
+ ): Promise<readonly ExactCapabilityBinding[]> {
477
+ const uniqueNames = [...new Set(names)].sort();
478
+ const bound = await Promise.all(uniqueNames.map(async name => {
479
+ const capability = await application.capability(name);
480
+ if (capability.name !== name) {
481
+ throw new ApplicationError(
482
+ "internal",
483
+ `Capability resolver returned ${capability.name} when ${name} was requested.`,
484
+ { requestedCapability: name, returnedCapability: capability.name },
485
+ );
486
+ }
487
+ return await bindExactCapability(capability);
488
+ }));
489
+ return ExactCapabilityBindingsSchema.parse(bound);
490
+ }
491
+
492
+ export async function assertExactCapabilityBindings(
493
+ application: ApplicationContext,
494
+ expected: readonly ExactCapabilityBinding[],
495
+ names: readonly ApplicationCapabilityName[],
496
+ ): Promise<void> {
497
+ const current = await bindExactCapabilities(application, names);
498
+ if (canonicalJson(expected) !== canonicalJson(current)) {
499
+ throw new ApplicationError(
500
+ "conflict",
501
+ "A capability executable, path, bytes, command, or version changed after exact node planning.",
502
+ );
503
+ }
504
+ }
505
+
506
+ /**
507
+ * Revalidates one already-bound executable directly from its physical path.
508
+ * Use this at effect boundaries that cannot delegate through
509
+ * ExactCapabilityApplicationRunner, such as a browser automation library.
510
+ */
511
+ export async function assertExactCapabilityExecutable(
512
+ expected: ExactCapabilityBinding,
513
+ ): Promise<void> {
514
+ const binding = ExactCapabilityBindingSchema.parse(expected);
515
+ const current = await hashPhysicalExecutable(
516
+ binding.executablePath,
517
+ binding.name,
518
+ );
519
+ if (
520
+ current.bytes !== binding.bytes
521
+ || current.sha256 !== binding.executableSha256
522
+ ) {
523
+ throw new ApplicationError(
524
+ "conflict",
525
+ `Capability executable bytes changed before launch: ${binding.name}`,
526
+ );
527
+ }
528
+ }
529
+
530
+ export function exactCapabilityByName(
531
+ bindings: readonly ExactCapabilityBinding[],
532
+ name: string,
533
+ ): ExactCapabilityBinding {
534
+ const binding = bindings.find(candidate => candidate.name === name);
535
+ if (binding === undefined) {
536
+ throw new ApplicationError(
537
+ "internal",
538
+ `Required exact capability was not bound: ${name}`,
539
+ );
540
+ }
541
+ return binding;
542
+ }
543
+
544
+ /**
545
+ * Revalidates the exact executable bytes immediately before each delegated
546
+ * subprocess launch. A verified private content-addressed pin, rather than
547
+ * the mutable probed pathname or PATH alias, is forwarded to the runner.
548
+ */
549
+ export class ExactCapabilityApplicationRunner
550
+ implements ApplicationProcessRunner {
551
+ readonly #bindings: readonly ExactCapabilityBinding[];
552
+ readonly #privateRoot: string;
553
+ readonly #runner: ApplicationProcessRunner;
554
+
555
+ constructor(
556
+ runner: ApplicationProcessRunner,
557
+ bindings: readonly ExactCapabilityBinding[],
558
+ privateRoot: string,
559
+ ) {
560
+ this.#runner = runner;
561
+ this.#bindings = ExactCapabilityBindingsSchema.parse(bindings);
562
+ if (!isAbsolute(privateRoot) || privateRoot.includes("\0")) {
563
+ throw new ApplicationError(
564
+ "unsafe-path",
565
+ "Capability pin root must be an absolute NUL-free path.",
566
+ );
567
+ }
568
+ this.#privateRoot = privateRoot;
569
+ }
570
+
571
+ async run(
572
+ argv: readonly [string, ...string[]],
573
+ options?: ApplicationProcessRunOptions,
574
+ ): Promise<ApplicationProcessRunResult> {
575
+ const binding = this.#bindings.find(candidate => (
576
+ argv[0] === candidate.command
577
+ || argv[0] === candidate.executablePath
578
+ ));
579
+ if (binding === undefined) {
580
+ throw new ApplicationError(
581
+ "conflict",
582
+ `Exact capability runner rejected an unbound executable: ${argv[0]}`,
583
+ );
584
+ }
585
+ const pinnedExecutable = await materializePinnedExecutable(
586
+ this.#privateRoot,
587
+ binding,
588
+ );
589
+ return await this.#runner.run(
590
+ [pinnedExecutable, ...argv.slice(1)],
591
+ options,
592
+ );
593
+ }
594
+ }
@@ -0,0 +1,97 @@
1
+ import type { HostResourceLease } from "@hraness/slopcamera/host-resources";
2
+
3
+ import type { ApplicationStudioAuthorization, ApplicationStudioPort } from "./studio-port";
4
+ import type { ApplicationGatewayPort } from "./gateway-port";
5
+ import type { HtmlOverlayRenderer } from "./html-overlay-renderer";
6
+
7
+ export interface ApplicationPaths {
8
+ readonly artifactRoot: string;
9
+ readonly desktopRoot: string;
10
+ readonly privateRoot: string;
11
+ readonly projectRoot: string;
12
+ readonly repositoryRoot: string;
13
+ }
14
+
15
+ export interface ApplicationProcessRunOptions {
16
+ readonly abortSignal?: AbortSignal;
17
+ readonly cwd?: string;
18
+ readonly env?: Readonly<Record<string, string | undefined>>;
19
+ readonly inheritedFileDescriptors?: readonly number[];
20
+ readonly maxOutputBytes?: number;
21
+ readonly stdin?: "ignore";
22
+ readonly timeoutMs?: number;
23
+ }
24
+
25
+ export interface ApplicationProcessRunResult {
26
+ readonly exitCode: number;
27
+ readonly stderr: string;
28
+ readonly stdout: string;
29
+ }
30
+
31
+ export interface ApplicationProcessRunner {
32
+ run(
33
+ argv: readonly [string, ...string[]],
34
+ options?: ApplicationProcessRunOptions,
35
+ ): Promise<ApplicationProcessRunResult>;
36
+ }
37
+
38
+ export type ApplicationCapabilityName =
39
+ | "ffmpeg"
40
+ | "ffprobe"
41
+ | "rsvg-convert"
42
+ | "whisper-cpp"
43
+ | "capture-helper"
44
+ | "face-analyzer"
45
+ | "html-browser";
46
+
47
+ export interface ApplicationCapability {
48
+ readonly available: boolean;
49
+ readonly command?: string;
50
+ readonly name: ApplicationCapabilityName;
51
+ readonly reason?: string;
52
+ readonly version?: string;
53
+ }
54
+
55
+ export interface ApplicationRecordingController {
56
+ execute(
57
+ action: "pause" | "resume" | "start" | "stop",
58
+ options?: unknown,
59
+ ): Promise<unknown>;
60
+ status(): Promise<unknown>;
61
+ }
62
+
63
+ export interface ApplicationClock {
64
+ readonly now: () => Date;
65
+ readonly timestampMilliseconds: () => number;
66
+ }
67
+
68
+ export interface ApplicationHostResourceLease extends HostResourceLease {
69
+ readonly inheritedFileDescriptors: readonly number[];
70
+ }
71
+
72
+ export interface ApplicationContext {
73
+ /** Adapter-owned current project lease; never serialized as operation input. */
74
+ readonly spatialProjectCustody?: {
75
+ readonly projectDirectory: string;
76
+ readonly projectId: string;
77
+ assertHeld(): Promise<void>;
78
+ assertLegacyTransactionSettled(): Promise<void>;
79
+ };
80
+ readonly capability: (
81
+ name: ApplicationCapabilityName,
82
+ ) => Promise<ApplicationCapability>;
83
+ readonly capabilities: (
84
+ inheritedFileDescriptors?: readonly number[],
85
+ ) => Promise<readonly ApplicationCapability[]>;
86
+ readonly clock: ApplicationClock;
87
+ readonly gatewayPort?: ApplicationGatewayPort;
88
+ readonly studioPort?: ApplicationStudioPort;
89
+ readonly studioAuthorization?: ApplicationStudioAuthorization;
90
+ readonly hostResourceLease?: ApplicationHostResourceLease;
91
+ readonly htmlOverlayRenderer?: HtmlOverlayRenderer;
92
+ /** Per-user host state shared by repository worktrees for mutation leases. */
93
+ readonly machineStateRoot?: string;
94
+ readonly paths: ApplicationPaths;
95
+ readonly recordingController?: ApplicationRecordingController;
96
+ readonly runner: ApplicationProcessRunner;
97
+ }