@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,354 @@
1
+ import { open, mkdir, realpath, stat } from "node:fs/promises"
2
+ import {
3
+ basename,
4
+ dirname,
5
+ isAbsolute,
6
+ join,
7
+ relative,
8
+ resolve,
9
+ win32,
10
+ } from "node:path"
11
+
12
+ export const mcpSourceByteLimit = 1024 * 1024
13
+
14
+ export class WorkspaceBoundaryError extends Error {
15
+ readonly code:
16
+ | "INVALID_PATH"
17
+ | "PATH_OUTSIDE_ROOT"
18
+ | "SOURCE_NOT_FOUND"
19
+ | "SOURCE_NOT_FILE"
20
+ | "SOURCE_TOO_LARGE"
21
+ | "SOURCE_ENCODING"
22
+ | "OUTPUT_NOT_DIRECTORY"
23
+ | "FILESYSTEM_ERROR"
24
+
25
+ constructor(
26
+ code: WorkspaceBoundaryError["code"],
27
+ message: string,
28
+ ) {
29
+ super(message)
30
+ this.name = "WorkspaceBoundaryError"
31
+ this.code = code
32
+ }
33
+ }
34
+
35
+ interface NormalizedRelativePath {
36
+ readonly native: string
37
+ readonly portable: string
38
+ }
39
+
40
+ export interface WorkspaceSource {
41
+ readonly absolutePath: string
42
+ readonly relativePath: string
43
+ readonly text: string
44
+ }
45
+
46
+ export interface WorkspaceDirectory {
47
+ readonly absolutePath: string
48
+ readonly relativePath: string
49
+ }
50
+
51
+ export interface WorkspaceFile {
52
+ readonly absolutePath: string
53
+ readonly relativePath: string
54
+ }
55
+
56
+ function filesystemCode(error: unknown): string | undefined {
57
+ if (
58
+ typeof error === "object" &&
59
+ error !== null &&
60
+ "code" in error &&
61
+ typeof error.code === "string"
62
+ ) {
63
+ return error.code
64
+ }
65
+ return undefined
66
+ }
67
+
68
+ function normalizeRelativePath(
69
+ value: string,
70
+ options: { readonly allowRoot: boolean },
71
+ ): NormalizedRelativePath {
72
+ if (value.length === 0 || value.includes("\0")) {
73
+ throw new WorkspaceBoundaryError("INVALID_PATH", "Path must be a non-empty root-relative path.")
74
+ }
75
+ if (
76
+ isAbsolute(value) ||
77
+ win32.isAbsolute(value) ||
78
+ /^[A-Za-z]:/.test(value)
79
+ ) {
80
+ throw new WorkspaceBoundaryError("INVALID_PATH", "Absolute paths are not allowed.")
81
+ }
82
+ const segments = value
83
+ .split(/[\\/]/)
84
+ .filter((segment) => segment !== "" && segment !== ".")
85
+ if (segments.includes("..")) {
86
+ throw new WorkspaceBoundaryError("INVALID_PATH", "Parent-directory traversal is not allowed.")
87
+ }
88
+ if (segments.length === 0) {
89
+ if (!options.allowRoot) {
90
+ throw new WorkspaceBoundaryError("INVALID_PATH", "Path must identify a file below the root.")
91
+ }
92
+ return { native: ".", portable: "." }
93
+ }
94
+ return {
95
+ native: segments.join("/"),
96
+ portable: segments.join("/"),
97
+ }
98
+ }
99
+
100
+ function isConfined(rootDirectory: string, target: string): boolean {
101
+ const fromRoot = relative(rootDirectory, target)
102
+ return fromRoot === "" || (!fromRoot.startsWith("..") && !isAbsolute(fromRoot))
103
+ }
104
+
105
+ async function readUtf8WithCap(filePath: string): Promise<string> {
106
+ let handle
107
+ try {
108
+ handle = await open(filePath, "r")
109
+ const metadata = await handle.stat()
110
+ if (!metadata.isFile()) {
111
+ throw new WorkspaceBoundaryError(
112
+ "SOURCE_NOT_FILE",
113
+ "Diagram source must be a regular file.",
114
+ )
115
+ }
116
+ if (metadata.size > mcpSourceByteLimit) {
117
+ throw new WorkspaceBoundaryError(
118
+ "SOURCE_TOO_LARGE",
119
+ `Diagram source exceeds the ${mcpSourceByteLimit}-byte limit.`,
120
+ )
121
+ }
122
+
123
+ const buffer = Buffer.allocUnsafe(mcpSourceByteLimit + 1)
124
+ let bytesRead = 0
125
+ while (bytesRead <= mcpSourceByteLimit) {
126
+ const next = await handle.read(
127
+ buffer,
128
+ bytesRead,
129
+ mcpSourceByteLimit + 1 - bytesRead,
130
+ null,
131
+ )
132
+ if (next.bytesRead === 0) break
133
+ bytesRead += next.bytesRead
134
+ }
135
+ if (bytesRead > mcpSourceByteLimit) {
136
+ throw new WorkspaceBoundaryError(
137
+ "SOURCE_TOO_LARGE",
138
+ `Diagram source exceeds the ${mcpSourceByteLimit}-byte limit.`,
139
+ )
140
+ }
141
+ try {
142
+ return new TextDecoder("utf-8", { fatal: true }).decode(
143
+ buffer.subarray(0, bytesRead),
144
+ )
145
+ } catch {
146
+ throw new WorkspaceBoundaryError(
147
+ "SOURCE_ENCODING",
148
+ "Diagram source must contain valid UTF-8.",
149
+ )
150
+ }
151
+ } catch (error) {
152
+ if (error instanceof WorkspaceBoundaryError) throw error
153
+ const code = filesystemCode(error)
154
+ if (code === "ENOENT") {
155
+ throw new WorkspaceBoundaryError("SOURCE_NOT_FOUND", "Diagram source does not exist.")
156
+ }
157
+ throw new WorkspaceBoundaryError("FILESYSTEM_ERROR", "Diagram source could not be read.")
158
+ } finally {
159
+ await handle?.close()
160
+ }
161
+ }
162
+
163
+ export class WorkspaceBoundary {
164
+ readonly rootDirectory: string
165
+
166
+ private constructor(rootDirectory: string) {
167
+ this.rootDirectory = rootDirectory
168
+ }
169
+
170
+ static async create(rootDirectory: string): Promise<WorkspaceBoundary> {
171
+ let resolvedRoot: string
172
+ try {
173
+ resolvedRoot = await realpath(resolve(rootDirectory))
174
+ if (!(await stat(resolvedRoot)).isDirectory()) {
175
+ throw new WorkspaceBoundaryError(
176
+ "OUTPUT_NOT_DIRECTORY",
177
+ "MCP root must be a directory.",
178
+ )
179
+ }
180
+ } catch (error) {
181
+ if (error instanceof WorkspaceBoundaryError) throw error
182
+ throw new WorkspaceBoundaryError(
183
+ "FILESYSTEM_ERROR",
184
+ "MCP root could not be opened.",
185
+ )
186
+ }
187
+ return new WorkspaceBoundary(resolvedRoot)
188
+ }
189
+
190
+ private assertConfined(target: string): void {
191
+ if (!isConfined(this.rootDirectory, target)) {
192
+ throw new WorkspaceBoundaryError(
193
+ "PATH_OUTSIDE_ROOT",
194
+ "Path resolves outside the MCP root.",
195
+ )
196
+ }
197
+ }
198
+
199
+ toRelativePath(absolutePath: string): string {
200
+ this.assertConfined(absolutePath)
201
+ const fromRoot = relative(this.rootDirectory, absolutePath)
202
+ return fromRoot === "" ? "." : fromRoot.split("\\").join("/")
203
+ }
204
+
205
+ async readSource(value: string): Promise<WorkspaceSource> {
206
+ const normalized = normalizeRelativePath(value, { allowRoot: false })
207
+ const lexicalPath = resolve(this.rootDirectory, normalized.native)
208
+ this.assertConfined(lexicalPath)
209
+
210
+ let canonicalPath: string
211
+ try {
212
+ canonicalPath = await realpath(lexicalPath)
213
+ } catch (error) {
214
+ if (filesystemCode(error) === "ENOENT") {
215
+ throw new WorkspaceBoundaryError(
216
+ "SOURCE_NOT_FOUND",
217
+ "Diagram source does not exist.",
218
+ )
219
+ }
220
+ throw new WorkspaceBoundaryError(
221
+ "FILESYSTEM_ERROR",
222
+ "Diagram source could not be resolved.",
223
+ )
224
+ }
225
+ this.assertConfined(canonicalPath)
226
+ return {
227
+ absolutePath: canonicalPath,
228
+ relativePath: this.toRelativePath(canonicalPath),
229
+ text: await readUtf8WithCap(canonicalPath),
230
+ }
231
+ }
232
+
233
+ async resolveInputFile(
234
+ value: string,
235
+ maximumBytes: number,
236
+ ): Promise<WorkspaceFile> {
237
+ const normalized = normalizeRelativePath(value, { allowRoot: false })
238
+ const lexicalPath = resolve(this.rootDirectory, normalized.native)
239
+ this.assertConfined(lexicalPath)
240
+ let canonicalPath: string
241
+ try {
242
+ canonicalPath = await realpath(lexicalPath)
243
+ this.assertConfined(canonicalPath)
244
+ const metadata = await stat(canonicalPath)
245
+ if (!metadata.isFile()) {
246
+ throw new WorkspaceBoundaryError(
247
+ "SOURCE_NOT_FILE",
248
+ "Input must be a regular file.",
249
+ )
250
+ }
251
+ if (
252
+ !Number.isSafeInteger(maximumBytes) ||
253
+ maximumBytes < 1 ||
254
+ metadata.size > maximumBytes
255
+ ) {
256
+ throw new WorkspaceBoundaryError(
257
+ "SOURCE_TOO_LARGE",
258
+ `Input exceeds the ${maximumBytes}-byte limit.`,
259
+ )
260
+ }
261
+ } catch (error) {
262
+ if (error instanceof WorkspaceBoundaryError) throw error
263
+ if (filesystemCode(error) === "ENOENT") {
264
+ throw new WorkspaceBoundaryError(
265
+ "SOURCE_NOT_FOUND",
266
+ "Input does not exist.",
267
+ )
268
+ }
269
+ throw new WorkspaceBoundaryError(
270
+ "FILESYSTEM_ERROR",
271
+ "Input could not be resolved.",
272
+ )
273
+ }
274
+ return {
275
+ absolutePath: canonicalPath,
276
+ relativePath: this.toRelativePath(canonicalPath),
277
+ }
278
+ }
279
+
280
+ async prepareOutputFile(value: string): Promise<WorkspaceFile> {
281
+ const normalized = normalizeRelativePath(value, { allowRoot: false })
282
+ const fileName = basename(normalized.native)
283
+ if (fileName === "." || fileName === ".." || fileName.length === 0) {
284
+ throw new WorkspaceBoundaryError(
285
+ "INVALID_PATH",
286
+ "Output path must identify a file below the root.",
287
+ )
288
+ }
289
+ const directory = await this.prepareOutputDirectory(
290
+ dirname(normalized.native),
291
+ )
292
+ const absolutePath = join(directory.absolutePath, fileName)
293
+ this.assertConfined(absolutePath)
294
+ return {
295
+ absolutePath,
296
+ relativePath: this.toRelativePath(absolutePath),
297
+ }
298
+ }
299
+
300
+ async prepareOutputDirectory(value: string): Promise<WorkspaceDirectory> {
301
+ const normalized = normalizeRelativePath(value, { allowRoot: true })
302
+ const lexicalPath = resolve(this.rootDirectory, normalized.native)
303
+ this.assertConfined(lexicalPath)
304
+
305
+ // Resolve the nearest existing ancestor before mkdir so a symlink in the
306
+ // requested path cannot redirect writes outside the server root.
307
+ let ancestor = lexicalPath
308
+ for (;;) {
309
+ try {
310
+ const canonicalAncestor = await realpath(ancestor)
311
+ this.assertConfined(canonicalAncestor)
312
+ break
313
+ } catch (error) {
314
+ if (error instanceof WorkspaceBoundaryError) throw error
315
+ if (filesystemCode(error) !== "ENOENT") {
316
+ throw new WorkspaceBoundaryError(
317
+ "FILESYSTEM_ERROR",
318
+ "Output directory could not be resolved.",
319
+ )
320
+ }
321
+ const parent = dirname(ancestor)
322
+ if (parent === ancestor) {
323
+ throw new WorkspaceBoundaryError(
324
+ "PATH_OUTSIDE_ROOT",
325
+ "Output directory resolves outside the MCP root.",
326
+ )
327
+ }
328
+ ancestor = parent
329
+ }
330
+ }
331
+
332
+ try {
333
+ await mkdir(lexicalPath, { recursive: true })
334
+ const canonicalPath = await realpath(lexicalPath)
335
+ this.assertConfined(canonicalPath)
336
+ if (!(await stat(canonicalPath)).isDirectory()) {
337
+ throw new WorkspaceBoundaryError(
338
+ "OUTPUT_NOT_DIRECTORY",
339
+ "Output path must be a directory.",
340
+ )
341
+ }
342
+ return {
343
+ absolutePath: canonicalPath,
344
+ relativePath: this.toRelativePath(canonicalPath),
345
+ }
346
+ } catch (error) {
347
+ if (error instanceof WorkspaceBoundaryError) throw error
348
+ throw new WorkspaceBoundaryError(
349
+ "FILESYSTEM_ERROR",
350
+ "Output directory could not be created.",
351
+ )
352
+ }
353
+ }
354
+ }
@@ -0,0 +1,33 @@
1
+ export {
2
+ slopcameraMcpProtocolVersion,
3
+ slopcameraMcpServerName,
4
+ runMcpServer,
5
+ } from "./server.js"
6
+ export {
7
+ slopcameraMcpTools,
8
+ SlopcameraMcpToolRuntime,
9
+ mcpMaximumEdges,
10
+ mcpMaximumRenderedPixels,
11
+ mcpMaximumReturnedFindings,
12
+ mcpMaximumScale,
13
+ mcpMaximumShapes,
14
+ } from "./tools.js"
15
+ export {
16
+ mcpSourceByteLimit,
17
+ WorkspaceBoundary,
18
+ WorkspaceBoundaryError,
19
+ type WorkspaceDirectory,
20
+ type WorkspaceFile,
21
+ type WorkspaceSource,
22
+ } from "./boundary.js"
23
+ export type {
24
+ JsonRpcFailure,
25
+ JsonRpcId,
26
+ JsonRpcResponseId,
27
+ JsonRpcResponse,
28
+ JsonRpcSuccess,
29
+ McpServerOptions,
30
+ McpTextContent,
31
+ McpToolDefinition,
32
+ McpToolResult,
33
+ } from "./types.js"
@@ -0,0 +1,272 @@
1
+ import {
2
+ slopcameraMcpTools,
3
+ SlopcameraMcpToolRuntime,
4
+ } from "./tools.js"
5
+ import type {
6
+ JsonRpcId,
7
+ JsonRpcResponse,
8
+ JsonRpcResponseId,
9
+ McpServerOptions,
10
+ } from "./types.js"
11
+ import { SLOPCAMERA_VERSION } from "../version.js"
12
+
13
+ export const slopcameraMcpProtocolVersion = "2025-11-25"
14
+ export const slopcameraMcpServerName = "hraness-slopcamera"
15
+
16
+ const maximumMessageBytes = 1024 * 1024
17
+
18
+ interface RequestRecord {
19
+ readonly jsonrpc: "2.0"
20
+ readonly id?: JsonRpcId
21
+ readonly method: string
22
+ readonly params?: unknown
23
+ }
24
+
25
+ type LifecycleState = "new" | "initializing" | "ready"
26
+
27
+ function isRecord(value: unknown): value is Record<string, unknown> {
28
+ return typeof value === "object" && value !== null && !Array.isArray(value)
29
+ }
30
+
31
+ function isJsonRpcId(value: unknown): value is JsonRpcId {
32
+ return (
33
+ typeof value === "string" ||
34
+ (typeof value === "number" && Number.isSafeInteger(value))
35
+ )
36
+ }
37
+
38
+ function isInitializeParams(value: unknown): value is Readonly<{
39
+ protocolVersion: string
40
+ capabilities: Readonly<Record<string, unknown>>
41
+ clientInfo: Readonly<{ name: string; version: string }>
42
+ }> {
43
+ return (
44
+ isRecord(value) &&
45
+ typeof value.protocolVersion === "string" &&
46
+ isRecord(value.capabilities) &&
47
+ isRecord(value.clientInfo) &&
48
+ typeof value.clientInfo.name === "string" &&
49
+ typeof value.clientInfo.version === "string"
50
+ )
51
+ }
52
+
53
+ function parseRequest(value: unknown): RequestRecord {
54
+ if (
55
+ !isRecord(value) ||
56
+ value.jsonrpc !== "2.0" ||
57
+ typeof value.method !== "string" ||
58
+ value.method.length === 0 ||
59
+ ("id" in value && !isJsonRpcId(value.id))
60
+ ) {
61
+ throw new Error("invalid request")
62
+ }
63
+ return {
64
+ jsonrpc: "2.0",
65
+ ...("id" in value ? { id: value.id as JsonRpcId } : {}),
66
+ method: value.method,
67
+ ...("params" in value ? { params: value.params } : {}),
68
+ }
69
+ }
70
+
71
+ function success(id: JsonRpcId, result: unknown): JsonRpcResponse {
72
+ return { jsonrpc: "2.0", id, result }
73
+ }
74
+
75
+ function failure(
76
+ id: JsonRpcResponseId,
77
+ code: number,
78
+ message: string,
79
+ ): JsonRpcResponse {
80
+ return { jsonrpc: "2.0", id, error: { code, message } }
81
+ }
82
+
83
+ function parseToolCall(
84
+ params: unknown,
85
+ ): { readonly name: string; readonly argumentsValue: unknown } {
86
+ if (
87
+ !isRecord(params) ||
88
+ typeof params.name !== "string" ||
89
+ (params.arguments !== undefined && !isRecord(params.arguments))
90
+ ) {
91
+ throw new Error("invalid params")
92
+ }
93
+ const unknownKeys = Object.keys(params).filter(
94
+ (key) => key !== "name" && key !== "arguments",
95
+ )
96
+ if (unknownKeys.length > 0) throw new Error("invalid params")
97
+ return {
98
+ name: params.name,
99
+ argumentsValue: params.arguments ?? {},
100
+ }
101
+ }
102
+
103
+ class SlopcameraMcpSession {
104
+ readonly runtime: SlopcameraMcpToolRuntime
105
+ readonly serverVersion: string
106
+ state: LifecycleState = "new"
107
+
108
+ constructor(runtime: SlopcameraMcpToolRuntime, serverVersion: string) {
109
+ this.runtime = runtime
110
+ this.serverVersion = serverVersion
111
+ }
112
+
113
+ async handle(value: unknown): Promise<JsonRpcResponse | null> {
114
+ let request: RequestRecord
115
+ try {
116
+ request = parseRequest(value)
117
+ } catch {
118
+ return failure(null, -32600, "Invalid Request")
119
+ }
120
+
121
+ const notification = request.id === undefined
122
+ if (request.method === "notifications/initialized") {
123
+ if (!notification) {
124
+ return failure(request.id!, -32600, "Invalid Request")
125
+ }
126
+ if (this.state === "initializing") this.state = "ready"
127
+ return null
128
+ }
129
+ if (notification) return null
130
+ const id = request.id!
131
+
132
+ if (request.method === "initialize") {
133
+ if (this.state !== "new" || !isInitializeParams(request.params)) {
134
+ return failure(id, -32602, "Invalid initialize parameters")
135
+ }
136
+ this.state = "initializing"
137
+ return success(id, {
138
+ protocolVersion: slopcameraMcpProtocolVersion,
139
+ capabilities: {
140
+ tools: { listChanged: false },
141
+ },
142
+ serverInfo: {
143
+ name: slopcameraMcpServerName,
144
+ version: this.serverVersion,
145
+ },
146
+ instructions:
147
+ "Use check_diagram/render_diagram or search_slopcamera followed by execute_slopcamera with an exact registry code and typed JSON. Local paths are root-relative; source code is never accepted or evaluated.",
148
+ })
149
+ }
150
+
151
+ if (this.state !== "ready") {
152
+ return failure(id, -32002, "Server is not initialized")
153
+ }
154
+ if (request.method === "ping") return success(id, {})
155
+ if (request.method === "tools/list") {
156
+ if (
157
+ request.params !== undefined &&
158
+ (!isRecord(request.params) || Object.keys(request.params).length > 0)
159
+ ) {
160
+ return failure(id, -32602, "Invalid tools/list parameters")
161
+ }
162
+ return success(id, { tools: slopcameraMcpTools })
163
+ }
164
+ if (request.method === "tools/call") {
165
+ try {
166
+ const toolCall = parseToolCall(request.params)
167
+ if (!slopcameraMcpTools.some((tool) => tool.name === toolCall.name)) {
168
+ return failure(id, -32602, "Unknown tool")
169
+ }
170
+ return success(
171
+ id,
172
+ await this.runtime.call(toolCall.name, toolCall.argumentsValue),
173
+ )
174
+ } catch {
175
+ return failure(id, -32602, "Invalid tools/call parameters")
176
+ }
177
+ }
178
+ return failure(id, -32601, "Method not found")
179
+ }
180
+ }
181
+
182
+ async function defaultWriteLine(line: string): Promise<void> {
183
+ await new Promise<void>((resolve, reject) => {
184
+ process.stdout.write(`${line}\n`, (error) => {
185
+ if (error === null || error === undefined) resolve()
186
+ else reject(error)
187
+ })
188
+ })
189
+ }
190
+
191
+ function defaultInput(): AsyncIterable<Uint8Array> {
192
+ return process.stdin
193
+ }
194
+
195
+ async function emitResponse(
196
+ writeLine: (line: string) => void | Promise<void>,
197
+ response: JsonRpcResponse,
198
+ ): Promise<void> {
199
+ await writeLine(JSON.stringify(response))
200
+ }
201
+
202
+ async function processLine(
203
+ line: Uint8Array,
204
+ session: SlopcameraMcpSession,
205
+ writeLine: (line: string) => void | Promise<void>,
206
+ ): Promise<void> {
207
+ if (line.byteLength === 0) return
208
+ let value: unknown
209
+ try {
210
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(line)
211
+ if (text.trim() === "") return
212
+ value = JSON.parse(text)
213
+ } catch {
214
+ await emitResponse(writeLine, failure(null, -32700, "Parse error"))
215
+ return
216
+ }
217
+ if (Array.isArray(value)) {
218
+ await emitResponse(writeLine, failure(null, -32600, "Invalid Request"))
219
+ return
220
+ }
221
+ const response = await session.handle(value)
222
+ if (response !== null) await emitResponse(writeLine, response)
223
+ }
224
+
225
+ /**
226
+ * Run one newline-delimited JSON-RPC MCP session. Protocol output is the only
227
+ * stdout surface; callers that need logs must write them to stderr.
228
+ */
229
+ export async function runMcpServer(
230
+ options: McpServerOptions = {},
231
+ ): Promise<void> {
232
+ const runtime = await SlopcameraMcpToolRuntime.create(
233
+ options.rootDirectory ?? process.cwd(),
234
+ options.generateDependencies,
235
+ )
236
+ const session = new SlopcameraMcpSession(
237
+ runtime,
238
+ options.serverVersion ?? SLOPCAMERA_VERSION,
239
+ )
240
+ const writeLine = options.writeLine ?? defaultWriteLine
241
+ let buffered = Buffer.alloc(0)
242
+
243
+ for await (const chunk of options.input ?? defaultInput()) {
244
+ const bytes =
245
+ typeof chunk === "string" ? Buffer.from(chunk, "utf8") : Buffer.from(chunk)
246
+ buffered = Buffer.concat([buffered, bytes])
247
+ if (buffered.byteLength > maximumMessageBytes && !buffered.includes(0x0a)) {
248
+ buffered = Buffer.alloc(0)
249
+ await emitResponse(writeLine, failure(null, -32700, "Parse error"))
250
+ continue
251
+ }
252
+ for (;;) {
253
+ const newline = buffered.indexOf(0x0a)
254
+ if (newline === -1) break
255
+ let line = buffered.subarray(0, newline)
256
+ buffered = buffered.subarray(newline + 1)
257
+ if (line.at(-1) === 0x0d) line = line.subarray(0, -1)
258
+ if (line.byteLength > maximumMessageBytes) {
259
+ await emitResponse(writeLine, failure(null, -32700, "Parse error"))
260
+ } else {
261
+ await processLine(line, session, writeLine)
262
+ }
263
+ }
264
+ }
265
+ if (buffered.byteLength > 0) {
266
+ if (buffered.byteLength > maximumMessageBytes) {
267
+ await emitResponse(writeLine, failure(null, -32700, "Parse error"))
268
+ } else {
269
+ await processLine(buffered, session, writeLine)
270
+ }
271
+ }
272
+ }