@holoscript/core 7.0.0 → 8.0.1

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 (350) hide show
  1. package/README.md +4 -4
  2. package/bin/holoscript.cjs +3 -0
  3. package/dist/GLTFPipeline-N6B6PJ6G.cjs +38 -0
  4. package/dist/GLTFPipeline-P3WMNYCN.js +17 -0
  5. package/dist/HoloScriptPlusParser-7FBIFUFC.js +693 -0
  6. package/dist/HoloScriptPlusParser-A2W7OCN2.cjs +698 -0
  7. package/dist/HoloScriptPlusParser-F2Z56FJR.js +10 -0
  8. package/dist/HoloScriptPlusParser-WKHRIH6T.cjs +27 -0
  9. package/dist/HoloScriptRuntime-CBYJX3LZ.js +10 -0
  10. package/dist/HoloScriptRuntime-VJ374RER.cjs +19 -0
  11. package/dist/USDZExporter-3FWJ25JI.cjs +1037 -0
  12. package/dist/USDZExporter-D2HQLQYK.js +1035 -0
  13. package/dist/agents/index.cjs +19 -0
  14. package/dist/agents/index.d.ts +100 -0
  15. package/dist/agents/index.js +17 -0
  16. package/dist/chunk-2BSMSUCE.js +1941 -0
  17. package/dist/chunk-2IWC4FP7.cjs +1189 -0
  18. package/dist/chunk-2M2DPHKB.js +762 -0
  19. package/dist/chunk-2X7NGX3M.js +2426 -0
  20. package/dist/chunk-2YSNA2F2.cjs +1274 -0
  21. package/dist/chunk-3FOKASKO.cjs +348 -0
  22. package/dist/chunk-3WZEJHUQ.cjs +116 -0
  23. package/dist/chunk-4C57PR42.js +468 -0
  24. package/dist/chunk-4GU5GCIY.js +1384 -0
  25. package/dist/chunk-4N4SXXWF.js +769 -0
  26. package/dist/chunk-4PDEPEQW.cjs +41 -0
  27. package/dist/chunk-4R6SBXDB.js +45 -0
  28. package/dist/chunk-4SDKXQ4C.js +811 -0
  29. package/dist/chunk-4V2E7U7Q.cjs +2015 -0
  30. package/dist/chunk-5FSKKMR7.cjs +2092 -0
  31. package/dist/chunk-5GLCTO44.js +161 -0
  32. package/dist/chunk-5H2G27PK.cjs +627 -0
  33. package/dist/chunk-5JEU52DW.js +382 -0
  34. package/dist/chunk-5NWINHR5.cjs +689 -0
  35. package/dist/chunk-5S7RKFGR.cjs +446 -0
  36. package/dist/chunk-5WUNN6ZN.cjs +428 -0
  37. package/dist/chunk-6CTRH7HT.cjs +1985 -0
  38. package/dist/chunk-6EX3I5P4.cjs +130 -0
  39. package/dist/chunk-6Q7RC2MK.cjs +1418 -0
  40. package/dist/chunk-7H33U5SM.cjs +413 -0
  41. package/dist/chunk-7M3PNU2M.cjs +672 -0
  42. package/dist/chunk-7T25IEZ2.js +449 -0
  43. package/dist/chunk-7V4JI5TB.cjs +6947 -0
  44. package/dist/chunk-A6KINLZJ.js +236 -0
  45. package/dist/chunk-ADADVMXY.js +404 -0
  46. package/dist/chunk-AIA52I7T.cjs +543 -0
  47. package/dist/chunk-ALC6K7GL.cjs +4402 -0
  48. package/dist/chunk-ANXZFVY2.js +113 -0
  49. package/dist/chunk-AOVGZ25K.cjs +56583 -0
  50. package/dist/chunk-AVJHHUC5.cjs +718 -0
  51. package/dist/chunk-BGY3SDG3.js +4396 -0
  52. package/dist/chunk-BOVPWH4H.js +3857 -0
  53. package/dist/chunk-BRQJKJGT.cjs +20 -0
  54. package/dist/chunk-C37BHB7N.cjs +636 -0
  55. package/dist/chunk-CBJY23VL.js +126 -0
  56. package/dist/chunk-CCATWPXM.js +778 -0
  57. package/dist/chunk-CIWWXYHZ.cjs +50 -0
  58. package/dist/chunk-CMT5NMMS.js +669 -0
  59. package/dist/chunk-CR4FMIWL.cjs +1049 -0
  60. package/dist/chunk-CR7XRXRN.cjs +639 -0
  61. package/dist/chunk-CSD27UNQ.js +2176 -0
  62. package/dist/chunk-D3STJ56J.js +714 -0
  63. package/dist/chunk-DAJXW4KX.js +725 -0
  64. package/dist/chunk-DHO2YRIM.js +756 -0
  65. package/dist/chunk-DTGBOSEM.cjs +319 -0
  66. package/dist/chunk-E6XXE66V.js +2252 -0
  67. package/dist/chunk-E7JP3BS3.cjs +61 -0
  68. package/dist/chunk-EKBKLK7P.js +1169 -0
  69. package/dist/chunk-EKYL4PE3.cjs +404 -0
  70. package/dist/chunk-EXKSFGSX.cjs +274 -0
  71. package/dist/chunk-EXUP2BUM.cjs +1173 -0
  72. package/dist/chunk-FDSGHPAK.js +130 -0
  73. package/dist/chunk-FEWUHQNM.cjs +144 -0
  74. package/dist/chunk-FFAOS5HQ.js +70 -0
  75. package/dist/chunk-FGGJQRLZ.js +270 -0
  76. package/dist/chunk-FHP6LXJS.js +415 -0
  77. package/dist/chunk-FJPADH77.cjs +666 -0
  78. package/dist/chunk-FL33V6U7.js +421 -0
  79. package/dist/chunk-FYSPZT4V.cjs +169 -0
  80. package/dist/chunk-GIOYPNTH.js +5575 -0
  81. package/dist/chunk-GJNCFRJU.cjs +125 -0
  82. package/dist/chunk-GMP623FG.cjs +1508 -0
  83. package/dist/chunk-GQHQOPXZ.cjs +5580 -0
  84. package/dist/chunk-GTU2Z2WW.cjs +262 -0
  85. package/dist/chunk-GYZE55MO.js +2007 -0
  86. package/dist/chunk-GZG4KA4E.js +529 -0
  87. package/dist/chunk-H652NHX5.js +600 -0
  88. package/dist/chunk-HCCQLAA4.cjs +74 -0
  89. package/dist/chunk-HKEXJUWS.cjs +4007 -0
  90. package/dist/chunk-HNDK4IQU.cjs +5737 -0
  91. package/dist/chunk-HR2OSYVQ.js +56165 -0
  92. package/dist/chunk-HYNTS5CP.js +422 -0
  93. package/dist/chunk-I6XZ5DZF.cjs +488 -0
  94. package/dist/chunk-ILRBGFVD.cjs +72 -0
  95. package/dist/chunk-IUDGEUDO.cjs +1409 -0
  96. package/dist/chunk-IUTY5WQ2.cjs +424 -0
  97. package/dist/chunk-IVY74O6C.js +247 -0
  98. package/dist/chunk-IWC5DM2M.cjs +611 -0
  99. package/dist/chunk-J32ZJZJH.js +554 -0
  100. package/dist/chunk-J52VSAQ7.js +6884 -0
  101. package/dist/chunk-J6M4FPK5.js +421 -0
  102. package/dist/chunk-J7XZV333.js +844 -0
  103. package/dist/chunk-JBNDTXXV.cjs +2433 -0
  104. package/dist/chunk-JC5YBPSF.cjs +984 -0
  105. package/dist/chunk-JD7CIZ33.js +1949 -0
  106. package/dist/chunk-JIBL5LRK.js +4287 -0
  107. package/dist/chunk-JIYN45TV.cjs +2525 -0
  108. package/dist/chunk-K574J76X.cjs +457 -0
  109. package/dist/chunk-KHDZJE5D.cjs +2196 -0
  110. package/dist/chunk-KKFZ3B6J.cjs +557 -0
  111. package/dist/chunk-KKP7JKN4.cjs +6002 -0
  112. package/dist/chunk-KPJL34Y7.cjs +186 -0
  113. package/dist/chunk-KQCN6AKJ.cjs +3042 -0
  114. package/dist/chunk-L5LKKENW.cjs +424 -0
  115. package/dist/chunk-LHAXPADA.js +882 -0
  116. package/dist/chunk-LM2VU56C.cjs +37 -0
  117. package/dist/chunk-M56JSP4A.js +400 -0
  118. package/dist/chunk-MBOOR7X4.js +18 -0
  119. package/dist/chunk-MQWAT42R.cjs +4310 -0
  120. package/dist/chunk-MXFUTKCO.js +56 -0
  121. package/dist/chunk-MYY4PMWX.cjs +264 -0
  122. package/dist/chunk-N75IH2HY.js +258 -0
  123. package/dist/chunk-NCWCUZNS.cjs +72 -0
  124. package/dist/chunk-NG77ATEW.cjs +778 -0
  125. package/dist/chunk-NW5G5FBQ.js +215 -0
  126. package/dist/chunk-OBIYPYYS.cjs +1993 -0
  127. package/dist/chunk-OH2FAIVU.js +608 -0
  128. package/dist/chunk-OIQYIIO3.cjs +473 -0
  129. package/dist/chunk-OL46QLBJ.js +61 -0
  130. package/dist/chunk-OMXII44L.js +5386 -0
  131. package/dist/chunk-OSYNRVOV.cjs +243 -0
  132. package/dist/chunk-PGANYCAG.cjs +220 -0
  133. package/dist/chunk-PHENW4MQ.js +65 -0
  134. package/dist/chunk-PY37LNDP.js +686 -0
  135. package/dist/chunk-Q56TT7IL.js +483 -0
  136. package/dist/chunk-QD32ADK6.js +1046 -0
  137. package/dist/chunk-QPOQ7VPI.js +1491 -0
  138. package/dist/chunk-QPSKHBJP.js +5963 -0
  139. package/dist/chunk-QXH7QDSZ.js +1989 -0
  140. package/dist/chunk-R24NNAEG.js +1399 -0
  141. package/dist/chunk-R75BSDH7.cjs +50 -0
  142. package/dist/chunk-RARB3MBR.js +207 -0
  143. package/dist/chunk-ROHLEP2W.cjs +847 -0
  144. package/dist/chunk-S3MDHNKB.cjs +490 -0
  145. package/dist/chunk-S6YWHCKV.cjs +410 -0
  146. package/dist/chunk-SIEXCILW.js +229 -0
  147. package/dist/chunk-SLU6UPJI.cjs +410 -0
  148. package/dist/chunk-SMIWS6DE.cjs +212 -0
  149. package/dist/chunk-T5J7ZKP3.cjs +4885 -0
  150. package/dist/chunk-TDCNJHWO.js +341 -0
  151. package/dist/chunk-TG7O4WBC.js +406 -0
  152. package/dist/chunk-THCK6ECW.js +2085 -0
  153. package/dist/chunk-TJHVSBP2.js +439 -0
  154. package/dist/chunk-TVHSPJ4N.cjs +606 -0
  155. package/dist/chunk-TWUXUCEW.cjs +781 -0
  156. package/dist/chunk-U44IKGG7.cjs +5390 -0
  157. package/dist/chunk-UFZZ7TSN.cjs +886 -0
  158. package/dist/chunk-UJXISJBN.js +487 -0
  159. package/dist/chunk-UOIGFQXC.cjs +9750 -0
  160. package/dist/chunk-URG2SJLK.js +2521 -0
  161. package/dist/chunk-UWJHCOH2.js +623 -0
  162. package/dist/chunk-V6MKC2FZ.js +979 -0
  163. package/dist/chunk-VJ3L7CHT.cjs +169 -0
  164. package/dist/chunk-VMLKSV26.js +1216 -0
  165. package/dist/chunk-VVKVQZI6.js +55 -0
  166. package/dist/chunk-W6RW64BB.cjs +1219 -0
  167. package/dist/chunk-WKX5AMOY.js +309 -0
  168. package/dist/chunk-WNNE3PO3.js +34 -0
  169. package/dist/chunk-WRKUDAZJ.js +3038 -0
  170. package/dist/chunk-WRLUBRKS.cjs +1943 -0
  171. package/dist/chunk-WRNEH5MO.js +3169 -0
  172. package/dist/chunk-WRWEX5ZF.js +658 -0
  173. package/dist/chunk-X3GJPRVK.cjs +3246 -0
  174. package/dist/chunk-X3UVCWNL.cjs +2257 -0
  175. package/dist/chunk-XB274MW5.cjs +814 -0
  176. package/dist/chunk-XHIV6326.cjs +793 -0
  177. package/dist/chunk-XIVIE43A.cjs +729 -0
  178. package/dist/chunk-XJAN7CZG.cjs +432 -0
  179. package/dist/chunk-XKTPFXGA.js +164 -0
  180. package/dist/chunk-XL6INWKT.js +121 -0
  181. package/dist/chunk-XSFNHP2E.js +632 -0
  182. package/dist/chunk-XT6JY5W5.js +9684 -0
  183. package/dist/chunk-XUILI4KB.cjs +430 -0
  184. package/dist/chunk-YF2I3MV3.js +46 -0
  185. package/dist/chunk-YIMN575O.js +4847 -0
  186. package/dist/chunk-YIVFJNYV.js +176 -0
  187. package/dist/chunk-YKGPCZEE.cjs +237 -0
  188. package/dist/chunk-YN2YWTXW.js +5731 -0
  189. package/dist/chunk-YN6V7R3L.cjs +327 -0
  190. package/dist/chunk-YQELFNJV.js +39 -0
  191. package/dist/chunk-YVD3CSO3.js +1183 -0
  192. package/dist/chunk-YVOAF4ML.js +623 -0
  193. package/dist/chunk-YWOBW2PV.cjs +759 -0
  194. package/dist/chunk-YYXH45E2.js +426 -0
  195. package/dist/chunk-ZDSYWBIE.cjs +69 -0
  196. package/dist/chunk-ZU7NIRT6.js +325 -0
  197. package/dist/chunk-ZZ7RO2UQ.js +1243 -0
  198. package/dist/cli/holoscript-runner.cjs +2255 -0
  199. package/dist/cli/holoscript-runner.js +2230 -0
  200. package/dist/codebase/index.cjs +336 -0
  201. package/dist/codebase/index.js +331 -0
  202. package/dist/compiler/agent-inference.cjs +31 -0
  203. package/dist/compiler/agent-inference.js +8 -0
  204. package/dist/compiler/android-xr.cjs +24 -0
  205. package/dist/compiler/android-xr.js +14 -0
  206. package/dist/compiler/android.cjs +24 -0
  207. package/dist/compiler/android.js +14 -0
  208. package/dist/compiler/ar.cjs +23 -0
  209. package/dist/compiler/ar.js +11 -0
  210. package/dist/compiler/babylon.cjs +21 -0
  211. package/dist/compiler/babylon.js +15 -0
  212. package/dist/compiler/business-quest.cjs +43 -0
  213. package/dist/compiler/business-quest.js +4 -0
  214. package/dist/compiler/coco.cjs +27 -0
  215. package/dist/compiler/coco.js +4 -0
  216. package/dist/compiler/context.cjs +25 -0
  217. package/dist/compiler/context.d.ts +28 -0
  218. package/dist/compiler/context.js +8 -0
  219. package/dist/compiler/domain-block-utils.cjs +609 -0
  220. package/dist/compiler/domain-block-utils.js +11 -0
  221. package/dist/compiler/dtdl.cjs +27 -0
  222. package/dist/compiler/dtdl.js +11 -0
  223. package/dist/compiler/gltf-pipeline.cjs +39 -0
  224. package/dist/compiler/gltf-pipeline.js +4 -0
  225. package/dist/compiler/godot.cjs +18 -0
  226. package/dist/compiler/godot.js +12 -0
  227. package/dist/compiler/incremental.cjs +34 -0
  228. package/dist/compiler/incremental.js +9 -0
  229. package/dist/compiler/index.cjs +5408 -0
  230. package/dist/compiler/index.d.ts +334 -21
  231. package/dist/compiler/index.js +5069 -0
  232. package/dist/compiler/ios.cjs +23 -0
  233. package/dist/compiler/ios.js +13 -0
  234. package/dist/compiler/llm-provider-capabilities.cjs +25 -0
  235. package/dist/compiler/llm-provider-capabilities.d.ts +43 -0
  236. package/dist/compiler/llm-provider-capabilities.js +8 -0
  237. package/dist/compiler/multi-layer.cjs +24 -0
  238. package/dist/compiler/multi-layer.js +15 -0
  239. package/dist/compiler/nodetoy.cjs +23 -0
  240. package/dist/compiler/nodetoy.d.ts +69 -0
  241. package/dist/compiler/nodetoy.js +4 -0
  242. package/dist/compiler/openxr.cjs +19 -0
  243. package/dist/compiler/openxr.js +13 -0
  244. package/dist/compiler/playcanvas.cjs +19 -0
  245. package/dist/compiler/playcanvas.js +13 -0
  246. package/dist/compiler/r3f.cjs +39 -0
  247. package/dist/compiler/r3f.d.ts +22 -0
  248. package/dist/compiler/r3f.js +17 -0
  249. package/dist/compiler/remotion.cjs +23 -0
  250. package/dist/compiler/remotion.js +4 -0
  251. package/dist/compiler/reproducibility.cjs +39 -0
  252. package/dist/compiler/reproducibility.js +4 -0
  253. package/dist/compiler/sdf.cjs +24 -0
  254. package/dist/compiler/sdf.js +12 -0
  255. package/dist/compiler/semantic-scene.cjs +31 -0
  256. package/dist/compiler/semantic-scene.js +4 -0
  257. package/dist/compiler/state.cjs +21 -0
  258. package/dist/compiler/state.js +11 -0
  259. package/dist/compiler/trait-composition.cjs +30 -0
  260. package/dist/compiler/trait-composition.js +9 -0
  261. package/dist/compiler/unity.cjs +19 -0
  262. package/dist/compiler/unity.js +13 -0
  263. package/dist/compiler/unreal.cjs +23 -0
  264. package/dist/compiler/unreal.js +13 -0
  265. package/dist/compiler/urdf.cjs +52 -0
  266. package/dist/compiler/urdf.js +12 -0
  267. package/dist/compiler/usd-physics.cjs +26 -0
  268. package/dist/compiler/usd-physics.js +9 -0
  269. package/dist/compiler/visionos.cjs +19 -0
  270. package/dist/compiler/visionos.js +13 -0
  271. package/dist/compiler/vrchat.cjs +22 -0
  272. package/dist/compiler/vrchat.js +12 -0
  273. package/dist/compiler/vrr.cjs +24 -0
  274. package/dist/compiler/vrr.js +12 -0
  275. package/dist/compiler/wasm.cjs +36 -0
  276. package/dist/compiler/wasm.js +12 -0
  277. package/dist/compiler/webgpu.cjs +18 -0
  278. package/dist/compiler/webgpu.js +12 -0
  279. package/dist/coordinators/index.cjs +1266 -0
  280. package/dist/coordinators/index.d.ts +72 -1
  281. package/dist/coordinators/index.js +1259 -0
  282. package/dist/debugger.cjs +24 -0
  283. package/dist/debugger.js +11 -0
  284. package/dist/dist-ACXG6IH5.cjs +3113 -0
  285. package/dist/dist-VD4L6V7Q.js +3076 -0
  286. package/dist/entries/interop.cjs +64 -0
  287. package/dist/entries/interop.js +7 -0
  288. package/dist/entries/scripting.cjs +55 -0
  289. package/dist/entries/scripting.js +10 -0
  290. package/dist/hololand/index.cjs +146 -0
  291. package/dist/hololand/index.d.ts +70 -0
  292. package/dist/hololand/index.js +5 -0
  293. package/dist/index.cjs +44660 -0
  294. package/dist/index.d.ts +978 -21
  295. package/dist/index.js +41422 -0
  296. package/dist/math/tropical-spmv.cjs +45 -0
  297. package/dist/math/tropical-spmv.js +4 -0
  298. package/dist/math/vec3.cjs +57 -0
  299. package/dist/math/vec3.js +4 -0
  300. package/dist/ml-dsa-FSKBTE3W.cjs +1265 -0
  301. package/dist/ml-dsa-Z7JDKW4L.js +1265 -0
  302. package/dist/paper-0c-spike/index.cjs +150 -0
  303. package/dist/paper-0c-spike/index.js +141 -0
  304. package/dist/parser.cjs +61 -0
  305. package/dist/parser.d.ts +11 -0
  306. package/dist/parser.js +12 -0
  307. package/dist/playwright-3AT3AKTV.cjs +98673 -0
  308. package/dist/playwright-VZPDVUEQ.js +98660 -0
  309. package/dist/reconstruction/index.cjs +153 -0
  310. package/dist/reconstruction/index.d.ts +29 -2
  311. package/dist/reconstruction/index.js +8 -0
  312. package/dist/runtime.cjs +316 -0
  313. package/dist/runtime.d.ts +61 -0
  314. package/dist/runtime.js +31 -0
  315. package/dist/self-improvement/index.cjs +563 -0
  316. package/dist/self-improvement/index.js +545 -0
  317. package/dist/src-4ROC227P.cjs +2094 -0
  318. package/dist/src-HCCCSYP7.js +2073 -0
  319. package/dist/storage/index.cjs +38 -0
  320. package/dist/storage/index.js +5 -0
  321. package/dist/testing.cjs +25 -0
  322. package/dist/testing.d.ts +70 -0
  323. package/dist/testing.js +4 -0
  324. package/dist/traitDocs/traitDocs.cjs +33 -0
  325. package/dist/traitDocs/traitDocs.js +7 -0
  326. package/dist/traits/botanical-lotus.cjs +177 -0
  327. package/dist/traits/botanical-lotus.d.ts +502 -0
  328. package/dist/traits/botanical-lotus.js +7 -0
  329. package/dist/traits/engines/index.cjs +520 -0
  330. package/dist/traits/engines/index.js +380 -0
  331. package/dist/traits/index.cjs +24548 -0
  332. package/dist/traits/index.d.ts +171 -35
  333. package/dist/traits/index.js +21638 -0
  334. package/dist/traits/simulation-solver-factory.cjs +13 -0
  335. package/dist/traits/simulation-solver-factory.d.ts +23 -0
  336. package/dist/traits/simulation-solver-factory.js +4 -0
  337. package/dist/traits/webcam-gaze.cjs +35 -0
  338. package/dist/traits/webcam-gaze.d.ts +17 -0
  339. package/dist/traits/webcam-gaze.js +4 -0
  340. package/dist/type-checker.cjs +19 -0
  341. package/dist/type-checker.js +6 -0
  342. package/dist/world/index.cjs +947 -0
  343. package/dist/world/index.d.ts +147 -0
  344. package/dist/world/index.js +939 -0
  345. package/dist/world-model/index.cjs +1446 -0
  346. package/dist/world-model/index.d.ts +119 -0
  347. package/dist/world-model/index.js +1414 -0
  348. package/dist/wot/index.cjs +29 -0
  349. package/dist/wot/index.js +4 -0
  350. package/package.json +93 -49
@@ -0,0 +1,1243 @@
1
+ import { init_safeJsonParse, readJson } from './chunk-VVKVQZI6.js';
2
+ import path from 'path';
3
+
4
+ var DEFAULT_STDLIB_POLICY = {
5
+ allowedPaths: ["compositions", "data", "src", "packages"],
6
+ maxFileBytes: 2 * 1024 * 1024,
7
+ allowShell: false,
8
+ allowedShellCommands: [],
9
+ maxShellOutputBytes: 100 * 1024,
10
+ shellTimeoutMs: 6e4,
11
+ allowNetwork: false,
12
+ allowedHosts: [],
13
+ rootDir: ".",
14
+ allowMediaDecode: false,
15
+ allowDepthInference: false,
16
+ allowGpuCompute: false,
17
+ allowDeviceProbe: false,
18
+ allowedDeviceScopes: [],
19
+ deviceProbeTimeoutMs: 1e4,
20
+ allowDeviceRead: false,
21
+ allowDevicePair: false,
22
+ allowDeviceCommand: false,
23
+ allowHaptic: false,
24
+ allowXrSession: false,
25
+ allowSensorRead: false,
26
+ maxGifFrames: 500,
27
+ maxVideoDurationSec: 300,
28
+ maxMediaResolution: 4096
29
+ };
30
+ function resolveRepoRelativePath(targetPath, rootDir) {
31
+ const normalized = targetPath.replace(/\\/g, "/").replace(/^\.\//, "").trim();
32
+ if (!normalized) return { ok: false, error: "Path is required" };
33
+ const abs = path.resolve(rootDir, normalized);
34
+ const rel = path.relative(rootDir, abs).replace(/\\/g, "/");
35
+ if (!rel || rel.startsWith("..") || path.isAbsolute(rel)) {
36
+ return { ok: false, error: "Path escapes repository root" };
37
+ }
38
+ return { ok: true, rel, abs };
39
+ }
40
+ function isPathAllowed(relPath, allowedRoots) {
41
+ const normalized = relPath.replace(/\\/g, "/");
42
+ return allowedRoots.some((root) => normalized === root || normalized.startsWith(`${root}/`));
43
+ }
44
+ function parseHostFromUrl(url) {
45
+ try {
46
+ return new URL(url).hostname.toLowerCase();
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+ function truncateText(value, max) {
52
+ const str = typeof value === "string" ? value : String(value ?? "");
53
+ if (!Number.isFinite(max) || max <= 0 || str.length <= max) return str;
54
+ return `${str.slice(0, max)}
55
+ ...[truncated ${str.length - max} chars]`;
56
+ }
57
+ function toStringArray(value) {
58
+ if (!Array.isArray(value)) return [];
59
+ return value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean);
60
+ }
61
+ function resolveInto(params, defaultPrefix) {
62
+ return typeof params.into === "string" && params.into.trim().length > 0 ? params.into.trim() : defaultPrefix;
63
+ }
64
+ function createStdlibActions(options) {
65
+ const { policy, hostCapabilities: caps, debug } = options;
66
+ const log = debug ? (msg) => console.log(` [stdlib] ${msg}`) : () => {
67
+ };
68
+ return {
69
+ // ── File System ──────────────────────────────────────────────────────
70
+ fs_read: async (params, bb) => {
71
+ const prefix = resolveInto(params, "fs_read");
72
+ const filePath = typeof params.path === "string" ? params.path : "";
73
+ const resolved = resolveRepoRelativePath(filePath, policy.rootDir);
74
+ if (!resolved.ok) {
75
+ bb[`${prefix}_error`] = resolved.error;
76
+ return false;
77
+ }
78
+ if (!isPathAllowed(resolved.rel, policy.allowedPaths)) {
79
+ bb[`${prefix}_error`] = `path "${resolved.rel}" is outside allowed roots`;
80
+ return false;
81
+ }
82
+ if (!caps?.fileSystem) {
83
+ bb[`${prefix}_error`] = "fileSystem capability not available";
84
+ return false;
85
+ }
86
+ const exists = caps.fileSystem.exists ? await Promise.resolve(caps.fileSystem.exists(resolved.rel)) : true;
87
+ if (!exists) {
88
+ bb[`${prefix}_error`] = `file not found: ${resolved.rel}`;
89
+ bb[`${prefix}_exists`] = false;
90
+ return false;
91
+ }
92
+ const content = await Promise.resolve(caps.fileSystem.readFile(resolved.rel));
93
+ if (Buffer.byteLength(content, "utf-8") > policy.maxFileBytes) {
94
+ bb[`${prefix}_error`] = `file exceeds max size (${policy.maxFileBytes} bytes)`;
95
+ return false;
96
+ }
97
+ bb[`${prefix}_content`] = content;
98
+ bb[`${prefix}_exists`] = true;
99
+ log(`fs_read: ${resolved.rel} (${Buffer.byteLength(content, "utf-8")} bytes)`);
100
+ return true;
101
+ },
102
+ fs_write: async (params, bb) => {
103
+ const prefix = resolveInto(params, "fs_write");
104
+ const filePath = typeof params.path === "string" ? params.path : "";
105
+ const content = typeof params.content === "string" ? params.content : null;
106
+ const append = params.append === true;
107
+ if (content === null) {
108
+ bb[`${prefix}_error`] = "content is required";
109
+ return false;
110
+ }
111
+ if (Buffer.byteLength(content, "utf-8") > policy.maxFileBytes) {
112
+ bb[`${prefix}_error`] = `content exceeds max size (${policy.maxFileBytes} bytes)`;
113
+ return false;
114
+ }
115
+ const resolved = resolveRepoRelativePath(filePath, policy.rootDir);
116
+ if (!resolved.ok) {
117
+ bb[`${prefix}_error`] = resolved.error;
118
+ return false;
119
+ }
120
+ if (!isPathAllowed(resolved.rel, policy.allowedPaths)) {
121
+ bb[`${prefix}_error`] = `path "${resolved.rel}" is outside allowed roots`;
122
+ return false;
123
+ }
124
+ if (!caps?.fileSystem) {
125
+ bb[`${prefix}_error`] = "fileSystem capability not available";
126
+ return false;
127
+ }
128
+ let finalContent = content;
129
+ if (append && caps.fileSystem.exists) {
130
+ const exists = await Promise.resolve(caps.fileSystem.exists(resolved.rel));
131
+ if (exists) {
132
+ const current = await Promise.resolve(caps.fileSystem.readFile(resolved.rel));
133
+ finalContent = `${current}${content}`;
134
+ }
135
+ }
136
+ await Promise.resolve(caps.fileSystem.writeFile(resolved.rel, finalContent));
137
+ bb[`${prefix}_path`] = resolved.rel;
138
+ bb[`${prefix}_bytes`] = Buffer.byteLength(content, "utf-8");
139
+ log(`fs_write: ${resolved.rel} (${bb[`${prefix}_bytes`]} bytes, append=${append})`);
140
+ return true;
141
+ },
142
+ fs_exists: async (params, bb) => {
143
+ const prefix = resolveInto(params, "fs_exists");
144
+ const filePath = typeof params.path === "string" ? params.path : "";
145
+ const resolved = resolveRepoRelativePath(filePath, policy.rootDir);
146
+ if (!resolved.ok) {
147
+ bb[`${prefix}_error`] = resolved.error;
148
+ return false;
149
+ }
150
+ if (!caps?.fileSystem?.exists) {
151
+ bb[`${prefix}_error`] = "fileSystem.exists capability not available";
152
+ return false;
153
+ }
154
+ const exists = await Promise.resolve(caps.fileSystem.exists(resolved.rel));
155
+ bb[`${prefix}_exists`] = exists;
156
+ log(`fs_exists: ${resolved.rel} \u2192 ${exists}`);
157
+ return true;
158
+ },
159
+ fs_delete: async (params, bb) => {
160
+ const prefix = resolveInto(params, "fs_delete");
161
+ const filePath = typeof params.path === "string" ? params.path : "";
162
+ const resolved = resolveRepoRelativePath(filePath, policy.rootDir);
163
+ if (!resolved.ok) {
164
+ bb[`${prefix}_error`] = resolved.error;
165
+ return false;
166
+ }
167
+ if (!isPathAllowed(resolved.rel, policy.allowedPaths)) {
168
+ bb[`${prefix}_error`] = `path "${resolved.rel}" is outside allowed roots`;
169
+ return false;
170
+ }
171
+ if (!caps?.fileSystem?.deleteFile) {
172
+ bb[`${prefix}_error`] = "fileSystem.deleteFile capability not available";
173
+ return false;
174
+ }
175
+ await Promise.resolve(caps.fileSystem.deleteFile(resolved.rel));
176
+ log(`fs_delete: ${resolved.rel}`);
177
+ return true;
178
+ },
179
+ // ── Process Execution ─────────────────────────────────────────────────
180
+ process_exec: async (params, bb) => {
181
+ const prefix = resolveInto(params, "process_exec");
182
+ if (!policy.allowShell) {
183
+ bb[`${prefix}_error`] = `${prefix} is disabled by policy`;
184
+ return false;
185
+ }
186
+ const command = typeof params.cmd === "string" ? params.cmd.trim() : "";
187
+ const args = toStringArray(params.args);
188
+ if (!command) {
189
+ bb[`${prefix}_error`] = "cmd is required";
190
+ return false;
191
+ }
192
+ if (policy.allowedShellCommands.length > 0) {
193
+ const executable = command.split(/\s+/)[0].toLowerCase();
194
+ const allowed = policy.allowedShellCommands.some((c) => c.toLowerCase() === executable);
195
+ if (!allowed) {
196
+ bb[`${prefix}_error`] = `command "${executable}" is not allowlisted`;
197
+ return false;
198
+ }
199
+ }
200
+ if (!caps?.process?.exec) {
201
+ bb[`${prefix}_error`] = "process.exec capability not available";
202
+ return false;
203
+ }
204
+ const timeoutMs = typeof params.timeout === "number" && Number.isFinite(params.timeout) ? Math.max(1e3, Math.min(policy.shellTimeoutMs, Math.floor(params.timeout))) : policy.shellTimeoutMs;
205
+ const cwd = typeof params.cwd === "string" ? params.cwd : policy.rootDir;
206
+ const result = await Promise.resolve(caps.process.exec(command, args, { cwd, timeoutMs }));
207
+ bb[`${prefix}_code`] = result.code ?? -1;
208
+ bb[`${prefix}_stdout`] = truncateText(result.stdout, policy.maxShellOutputBytes);
209
+ bb[`${prefix}_stderr`] = truncateText(result.stderr, policy.maxShellOutputBytes);
210
+ log(`process_exec: ${command} ${args.join(" ")} \u2192 code ${result.code}`);
211
+ return result.code === 0;
212
+ },
213
+ // ── Network ───────────────────────────────────────────────────────────
214
+ // ── Media Decode ──────────────────────────────────────────────────────
215
+ media_decode: async (params, bb) => {
216
+ const prefix = resolveInto(params, "media_decode");
217
+ if (!policy.allowMediaDecode) {
218
+ bb[`${prefix}_error`] = "media_decode is disabled by policy (allowMediaDecode=false)";
219
+ return false;
220
+ }
221
+ if (!caps?.media?.decodeFrames) {
222
+ bb[`${prefix}_error`] = "media.decodeFrames capability not available";
223
+ return false;
224
+ }
225
+ const source = params.source;
226
+ if (typeof source !== "string" && !(source instanceof ArrayBuffer)) {
227
+ bb[`${prefix}_error`] = "source (URL string or ArrayBuffer) is required";
228
+ return false;
229
+ }
230
+ const maxFrames = typeof params.maxFrames === "number" ? Math.min(params.maxFrames, policy.maxGifFrames ?? 500) : policy.maxGifFrames ?? 500;
231
+ const mediaType = params.type === "video" ? "video" : "gif";
232
+ try {
233
+ const frames = await caps.media.decodeFrames(source, {
234
+ maxFrames,
235
+ type: mediaType
236
+ });
237
+ bb[`${prefix}_frames`] = frames;
238
+ bb[`${prefix}_count`] = frames.length;
239
+ log(`media_decode: decoded ${frames.length} frames (type=${mediaType})`);
240
+ return true;
241
+ } catch (error) {
242
+ bb[`${prefix}_error`] = error.message;
243
+ return false;
244
+ }
245
+ },
246
+ // ── Depth Inference ───────────────────────────────────────────────────
247
+ depth_inference: async (params, bb) => {
248
+ const prefix = resolveInto(params, "depth_inference");
249
+ if (!policy.allowDepthInference) {
250
+ bb[`${prefix}_error`] = "depth_inference is disabled by policy (allowDepthInference=false)";
251
+ return false;
252
+ }
253
+ if (!caps?.depthInference?.estimateDepth) {
254
+ bb[`${prefix}_error`] = "depthInference.estimateDepth capability not available";
255
+ return false;
256
+ }
257
+ const source = params.source;
258
+ if (typeof source !== "string" && !(source instanceof ArrayBuffer)) {
259
+ bb[`${prefix}_error`] = "source (image URL string or ArrayBuffer) is required";
260
+ return false;
261
+ }
262
+ const maxRes = policy.maxMediaResolution ?? 4096;
263
+ const width = typeof params.width === "number" ? Math.min(params.width, maxRes) : void 0;
264
+ const height = typeof params.height === "number" ? Math.min(params.height, maxRes) : void 0;
265
+ const modelId = typeof params.modelId === "string" ? params.modelId : void 0;
266
+ try {
267
+ const depthMap = await caps.depthInference.estimateDepth(source, {
268
+ width,
269
+ height,
270
+ modelId
271
+ });
272
+ bb[`${prefix}_data`] = depthMap.data;
273
+ bb[`${prefix}_width`] = depthMap.width;
274
+ bb[`${prefix}_height`] = depthMap.height;
275
+ bb[`${prefix}_backend`] = depthMap.backend;
276
+ bb[`${prefix}_inferenceMs`] = depthMap.inferenceMs;
277
+ log(
278
+ `depth_inference: ${depthMap.width}\xD7${depthMap.height} via ${depthMap.backend} (${depthMap.inferenceMs}ms)`
279
+ );
280
+ return true;
281
+ } catch (error) {
282
+ bb[`${prefix}_error`] = error.message;
283
+ return false;
284
+ }
285
+ },
286
+ // ── GPU Compute ───────────────────────────────────────────────────────
287
+ gpu_compute: async (params, bb) => {
288
+ const prefix = resolveInto(params, "gpu_compute");
289
+ if (!policy.allowGpuCompute) {
290
+ bb[`${prefix}_error`] = "gpu_compute is disabled by policy (allowGpuCompute=false)";
291
+ return false;
292
+ }
293
+ if (!caps?.gpuCompute?.dispatch) {
294
+ bb[`${prefix}_error`] = "gpuCompute.dispatch capability not available";
295
+ return false;
296
+ }
297
+ const shader = typeof params.shader === "string" ? params.shader.trim() : "";
298
+ if (!shader) {
299
+ bb[`${prefix}_error`] = "shader (WGSL source) is required";
300
+ return false;
301
+ }
302
+ const inputs = {};
303
+ if (typeof params.inputs === "object" && params.inputs !== null) {
304
+ for (const [k, v] of Object.entries(params.inputs)) {
305
+ if (v instanceof ArrayBuffer) inputs[k] = v;
306
+ }
307
+ }
308
+ const rawWg = params.workgroups;
309
+ const workgroups = Array.isArray(rawWg) ? [rawWg[0], rawWg[1], rawWg[2]] : [1];
310
+ try {
311
+ const result = await caps.gpuCompute.dispatch(shader, inputs, workgroups);
312
+ bb[`${prefix}_outputs`] = result.outputs;
313
+ bb[`${prefix}_dispatchMs`] = result.dispatchMs;
314
+ log(`gpu_compute: dispatch completed in ${result.dispatchMs}ms`);
315
+ return true;
316
+ } catch (error) {
317
+ bb[`${prefix}_error`] = error.message;
318
+ return false;
319
+ }
320
+ },
321
+ // ── Target Device Probe ───────────────────────────────────────────────
322
+ device_probe: async (params, bb) => {
323
+ const prefix = resolveInto(params, "device_probe");
324
+ if (!policy.allowDeviceProbe) {
325
+ bb[`${prefix}_error`] = "device_probe is disabled by policy (allowDeviceProbe=false)";
326
+ return false;
327
+ }
328
+ const scope = typeof params.scope === "string" ? params.scope.trim() : "";
329
+ if (!scope) {
330
+ bb[`${prefix}_error`] = "scope is required";
331
+ return false;
332
+ }
333
+ const allowedScopes = policy.allowedDeviceScopes ?? [];
334
+ if (!allowedScopes.includes(scope)) {
335
+ bb[`${prefix}_error`] = `device scope "${scope}" is not allowlisted`;
336
+ bb[`${prefix}_denial_receipt`] = {
337
+ scope,
338
+ reason: "scope_not_allowlisted",
339
+ policy: "allowedDeviceScopes",
340
+ deniedAt: (/* @__PURE__ */ new Date()).toISOString()
341
+ };
342
+ return false;
343
+ }
344
+ const scopeGateMap = {
345
+ allowDeviceRead: policy.allowDeviceRead,
346
+ allowDevicePair: policy.allowDevicePair,
347
+ allowDeviceCommand: policy.allowDeviceCommand,
348
+ allowHaptic: policy.allowHaptic,
349
+ allowXrSession: policy.allowXrSession,
350
+ allowSensorRead: policy.allowSensorRead
351
+ };
352
+ if (scope in scopeGateMap && scopeGateMap[scope] === false) {
353
+ bb[`${prefix}_error`] = `device scope "${scope}" is denied by policy (${scope}=false)`;
354
+ bb[`${prefix}_denial_receipt`] = {
355
+ scope,
356
+ reason: "scope_gate_denied",
357
+ policy: scope,
358
+ deniedAt: (/* @__PURE__ */ new Date()).toISOString()
359
+ };
360
+ return false;
361
+ }
362
+ if (!caps?.deviceProbe?.probe || !caps.deviceProbe.available) {
363
+ bb[`${prefix}_error`] = "deviceProbe capability not available";
364
+ return false;
365
+ }
366
+ const timeoutPolicyMs = policy.deviceProbeTimeoutMs ?? 1e4;
367
+ const timeoutMs = typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs) ? Math.max(250, Math.min(timeoutPolicyMs, Math.floor(params.timeoutMs))) : timeoutPolicyMs;
368
+ try {
369
+ const result = await caps.deviceProbe.probe({
370
+ scope,
371
+ targetId: typeof params.targetId === "string" ? params.targetId : void 0,
372
+ targetKind: typeof params.targetKind === "string" ? params.targetKind : void 0,
373
+ timeoutMs,
374
+ metadata: typeof params.metadata === "object" && params.metadata !== null ? params.metadata : void 0
375
+ });
376
+ bb[`${prefix}_ok`] = result.ok;
377
+ bb[`${prefix}_status`] = result.status;
378
+ bb[`${prefix}_deviceId`] = result.deviceId;
379
+ bb[`${prefix}_targetKind`] = result.targetKind;
380
+ bb[`${prefix}_detail`] = result.detail;
381
+ bb[`${prefix}_metrics`] = result.metrics;
382
+ bb[`${prefix}_receipt`] = result.receipt;
383
+ log(`device_probe: ${scope} \u2192 ${result.status}`);
384
+ return result.ok;
385
+ } catch (error) {
386
+ bb[`${prefix}_error`] = error.message;
387
+ return false;
388
+ }
389
+ },
390
+ net_fetch: async (params, bb) => {
391
+ const prefix = resolveInto(params, "net_fetch");
392
+ const url = typeof params.url === "string" ? params.url.trim() : "";
393
+ if (!url) {
394
+ bb[`${prefix}_error`] = "url is required";
395
+ return false;
396
+ }
397
+ if (!policy.allowNetwork) {
398
+ bb[`${prefix}_error`] = "network access is disabled by policy";
399
+ return false;
400
+ }
401
+ const hostName = parseHostFromUrl(url);
402
+ if (!hostName) {
403
+ bb[`${prefix}_error`] = "invalid url";
404
+ return false;
405
+ }
406
+ if (policy.allowedHosts.length > 0) {
407
+ const allowed = policy.allowedHosts.includes(hostName) || policy.allowedHosts.some((h) => hostName.endsWith(`.${h}`));
408
+ if (!allowed) {
409
+ bb[`${prefix}_error`] = `host "${hostName}" is not allowlisted`;
410
+ return false;
411
+ }
412
+ }
413
+ if (caps?.network?.fetch) {
414
+ try {
415
+ const response = await Promise.resolve(
416
+ caps.network.fetch(url, {
417
+ method: typeof params.method === "string" ? params.method : "GET",
418
+ headers: typeof params.headers === "object" && params.headers ? params.headers : void 0,
419
+ body: typeof params.body === "string" ? params.body : void 0
420
+ })
421
+ );
422
+ bb[`${prefix}_status`] = response.status;
423
+ bb[`${prefix}_body`] = truncateText(response.text ?? "", policy.maxShellOutputBytes);
424
+ bb[`${prefix}_ok`] = response.ok;
425
+ log(`net_fetch: ${url} \u2192 ${response.status}`);
426
+ return response.ok;
427
+ } catch (error) {
428
+ bb[`${prefix}_error`] = error.message;
429
+ return false;
430
+ }
431
+ }
432
+ try {
433
+ const response = await globalThis.fetch(url, {
434
+ method: typeof params.method === "string" ? params.method : "GET",
435
+ headers: typeof params.headers === "object" && params.headers ? params.headers : void 0
436
+ });
437
+ const text = await response.text();
438
+ bb[`${prefix}_status`] = response.status;
439
+ bb[`${prefix}_body`] = truncateText(text, policy.maxShellOutputBytes);
440
+ bb[`${prefix}_ok`] = response.ok;
441
+ log(`net_fetch: ${url} \u2192 ${response.status}`);
442
+ return response.ok;
443
+ } catch (error) {
444
+ bb[`${prefix}_error`] = error.message;
445
+ return false;
446
+ }
447
+ }
448
+ };
449
+ }
450
+ function registerStdlib(runtime, options) {
451
+ const actions = createStdlibActions(options);
452
+ for (const [name, handler] of Object.entries(actions)) {
453
+ runtime.registerAction(name, handler);
454
+ }
455
+ }
456
+
457
+ // src/stdlib/PermissionScopePolicy.ts
458
+ function normalizePermissionScopeName(scope) {
459
+ return scope.trim().toLowerCase();
460
+ }
461
+ function isValidPermissionScopeName(scope) {
462
+ if (typeof scope !== "string") return false;
463
+ const normalized = normalizePermissionScopeName(scope);
464
+ return normalized.length > 0 && !/[\u0000-\u001f\s]/.test(normalized);
465
+ }
466
+ function normalizedScopeNames(scopes) {
467
+ return new Set(
468
+ scopes.map((scope) => normalizePermissionScopeName(scope.scope)).filter((scope) => scope.length > 0)
469
+ );
470
+ }
471
+ function invalidScopeNames(scopes) {
472
+ return scopes.map((scope) => scope.scope).filter((scope) => !isValidPermissionScopeName(scope));
473
+ }
474
+ function invalidNeverScopeNames(neverScopes) {
475
+ return neverScopes.filter((scope) => !isValidPermissionScopeName(scope));
476
+ }
477
+ function forbiddenScopeReason(scope, neverScopes) {
478
+ const normalized = normalizePermissionScopeName(scope);
479
+ const explicitNever = neverScopes.map(normalizePermissionScopeName);
480
+ if (explicitNever.includes(normalized)) return "is listed in neverScopes";
481
+ if (normalized === "*" || normalized.includes("*")) return "uses a wildcard";
482
+ if (/\b(admin|billing|owner|delete|full_access|write_all|manage_all)\b/.test(normalized)) {
483
+ return "requests broad administrative authority";
484
+ }
485
+ return void 0;
486
+ }
487
+ function evaluateStdlibPermissionScopePolicy(scope, neverScopes = []) {
488
+ const normalizedScope = normalizePermissionScopeName(scope);
489
+ const reason = isValidPermissionScopeName(scope) ? forbiddenScopeReason(scope, neverScopes) : "is empty or contains whitespace/control characters";
490
+ return {
491
+ scope,
492
+ normalizedScope,
493
+ allowed: !reason,
494
+ ...reason ? { reason } : {}
495
+ };
496
+ }
497
+ function findMissingRequiredPermissionScopes(requiredScopes, candidateScopes) {
498
+ const candidateNames = normalizedScopeNames(candidateScopes);
499
+ return requiredScopes.filter((scope) => scope.required === true).map((scope) => scope.scope).filter((scope) => !candidateNames.has(normalizePermissionScopeName(scope)));
500
+ }
501
+ function findExtraPermissionScopes(grantedScopes, minimumRequiredScopes) {
502
+ const minimumNames = normalizedScopeNames(minimumRequiredScopes);
503
+ return grantedScopes.map((scope) => scope.scope).filter((scope) => !minimumNames.has(normalizePermissionScopeName(scope)));
504
+ }
505
+ function buildStdlibPermissionScopeDiff(input) {
506
+ const requested = input.requestedScopes ?? [];
507
+ const minimum = input.minimumRequiredScopes ?? [];
508
+ const granted = input.grantedScopes ?? [];
509
+ const neverScopes = input.neverScopes ?? [];
510
+ const invalidRequestedScopes = invalidScopeNames(requested);
511
+ const invalidMinimumRequiredScopes = invalidScopeNames(minimum);
512
+ const invalidGrantedScopes = invalidScopeNames(granted);
513
+ const invalidNeverScopes = invalidNeverScopeNames(neverScopes);
514
+ const missingRequestedRequiredScopes = findMissingRequiredPermissionScopes(minimum, requested);
515
+ const missingGrantedRequiredScopes = findMissingRequiredPermissionScopes(minimum, granted);
516
+ const extraGrantedScopes = findExtraPermissionScopes(granted, minimum);
517
+ const forbiddenRequestedScopes = requested.map((scope) => evaluateStdlibPermissionScopePolicy(scope.scope, neverScopes)).filter((scope) => !scope.allowed);
518
+ const forbiddenGrantedScopes = granted.map((scope) => evaluateStdlibPermissionScopePolicy(scope.scope, neverScopes)).filter((scope) => !scope.allowed);
519
+ const policyInputValid = invalidRequestedScopes.length === 0 && invalidMinimumRequiredScopes.length === 0 && invalidGrantedScopes.length === 0 && invalidNeverScopes.length === 0;
520
+ return {
521
+ requestedScopes: requested.map((scope) => scope.scope),
522
+ minimumRequiredScopes: minimum.map((scope) => scope.scope),
523
+ grantedScopes: granted.map((scope) => scope.scope),
524
+ invalidRequestedScopes,
525
+ invalidMinimumRequiredScopes,
526
+ invalidGrantedScopes,
527
+ invalidNeverScopes,
528
+ missingRequestedRequiredScopes,
529
+ missingGrantedRequiredScopes,
530
+ extraGrantedScopes,
531
+ forbiddenRequestedScopes,
532
+ forbiddenGrantedScopes,
533
+ minimumScopeSatisfied: policyInputValid && missingRequestedRequiredScopes.length === 0 && missingGrantedRequiredScopes.length === 0 && forbiddenRequestedScopes.length === 0 && forbiddenGrantedScopes.length === 0,
534
+ excessScopesAbsent: extraGrantedScopes.length === 0,
535
+ policyInputValid
536
+ };
537
+ }
538
+ function redactStdlibPermissionPreview(value) {
539
+ const original = value ?? "";
540
+ let preview = original;
541
+ let absolutePathRedacted = false;
542
+ let credentialMaterialRedacted = false;
543
+ preview = preview.replace(
544
+ /(^|[\s"'`=])(?:[A-Za-z]:[\\/]|\/(?!\/)[^\s"'`]+)/g,
545
+ (match, prefix) => {
546
+ absolutePathRedacted = true;
547
+ return `${prefix}<absolute-path-redacted>`;
548
+ }
549
+ );
550
+ preview = preview.replace(
551
+ /\b(access_token|refresh_token|id_token|client_secret|authorization|cookie|code)=([^&\s]+)/gi,
552
+ (_match, key, secret) => {
553
+ if (secret === "<redacted>") return `${key}=<redacted>`;
554
+ credentialMaterialRedacted = true;
555
+ return `${key}=<redacted>`;
556
+ }
557
+ );
558
+ preview = preview.replace(
559
+ /\bBearer\s+([A-Za-z0-9._~+/=-]+|<redacted>)/gi,
560
+ (_match, secret) => {
561
+ if (secret === "<redacted>") return "Bearer <redacted>";
562
+ credentialMaterialRedacted = true;
563
+ return "Bearer <redacted>";
564
+ }
565
+ );
566
+ return {
567
+ preview,
568
+ redacted: preview !== original,
569
+ absolutePathRedacted,
570
+ credentialMaterialRedacted
571
+ };
572
+ }
573
+ function stdlibPermissionPreviewHasPublicLeak(value) {
574
+ const redaction = redactStdlibPermissionPreview(value);
575
+ return redaction.absolutePathRedacted || redaction.credentialMaterialRedacted;
576
+ }
577
+
578
+ // src/traits/TestTrait.ts
579
+ init_safeJsonParse();
580
+ var CompositionTestRunner = class {
581
+ constructor(initialState, computedDefs = [], config = {}) {
582
+ this.initialState = { ...initialState };
583
+ this.computedDefs = computedDefs;
584
+ this.config = {
585
+ bail: config.bail ?? false,
586
+ debug: config.debug ?? false,
587
+ timeout: config.timeout ?? 5e3
588
+ };
589
+ }
590
+ /**
591
+ * Extract and run all @test blocks from .hsplus source
592
+ */
593
+ runTestsFromSource(source) {
594
+ const tests = this.extractTestBlocks(source);
595
+ if (this.config.debug) {
596
+ console.debug(`[composition_test] Found ${tests.length} @test blocks`);
597
+ }
598
+ return this.runAll(tests);
599
+ }
600
+ /**
601
+ * Run all test blocks
602
+ */
603
+ runAll(tests) {
604
+ const results = [];
605
+ for (const test of tests) {
606
+ if (test.skip) {
607
+ results.push({
608
+ name: test.name,
609
+ status: "skipped",
610
+ durationMs: 0,
611
+ assertions: test.assertions.length,
612
+ passedAssertions: 0
613
+ });
614
+ continue;
615
+ }
616
+ const result = this.runSingle(test);
617
+ results.push(result);
618
+ if (this.config.bail && result.status === "failed") {
619
+ break;
620
+ }
621
+ }
622
+ return results;
623
+ }
624
+ /**
625
+ * Run a single test block:
626
+ * 1. Clone initial state
627
+ * 2. Apply setup assignments
628
+ * 3. Evaluate computed values
629
+ * 4. Check assertions
630
+ */
631
+ runSingle(test) {
632
+ const start = Date.now();
633
+ let passedAssertions = 0;
634
+ try {
635
+ const state = { ...this.initialState };
636
+ for (const { variable, expression } of test.setupAssignments) {
637
+ const value = this.evaluateValue(expression, state);
638
+ state[variable] = value;
639
+ }
640
+ const computed = this.evaluateComputedValues(state);
641
+ const fullState = { ...state, ...computed };
642
+ if (this.config.debug) {
643
+ console.debug(`[composition_test] "${test.name}" state:`, fullState);
644
+ }
645
+ for (const assertion of test.assertions) {
646
+ const passed = this.evaluateAssertion(assertion.expression, fullState);
647
+ if (passed) {
648
+ passedAssertions++;
649
+ } else {
650
+ return {
651
+ name: test.name,
652
+ status: "failed",
653
+ durationMs: Date.now() - start,
654
+ error: `Assertion failed: ${assertion.expression}`,
655
+ assertions: test.assertions.length,
656
+ passedAssertions
657
+ };
658
+ }
659
+ }
660
+ return {
661
+ name: test.name,
662
+ status: "passed",
663
+ durationMs: Date.now() - start,
664
+ assertions: test.assertions.length,
665
+ passedAssertions
666
+ };
667
+ } catch (error) {
668
+ return {
669
+ name: test.name,
670
+ status: "failed",
671
+ durationMs: Date.now() - start,
672
+ error: error instanceof Error ? error.message : String(error),
673
+ assertions: test.assertions.length,
674
+ passedAssertions
675
+ };
676
+ }
677
+ }
678
+ // ─── Extraction ──────────────────────────────────────────────────────────────
679
+ /**
680
+ * Extract @test { name: "...", setup: { ... }, assert: { ... } } blocks
681
+ */
682
+ extractTestBlocks(source) {
683
+ const blocks = [];
684
+ const regex = /@test\s*\{/g;
685
+ let match;
686
+ while ((match = regex.exec(source)) !== null) {
687
+ const startIdx = match.index + match[0].length;
688
+ let depth = 1;
689
+ let endIdx = startIdx;
690
+ while (depth > 0 && endIdx < source.length) {
691
+ if (source[endIdx] === "{") depth++;
692
+ if (source[endIdx] === "}") depth--;
693
+ endIdx++;
694
+ }
695
+ const body = source.substring(startIdx, endIdx - 1).trim();
696
+ const block = this.parseTestBody(body);
697
+ if (block) blocks.push(block);
698
+ }
699
+ return blocks;
700
+ }
701
+ /**
702
+ * Parse the body of a @test block into structured data
703
+ */
704
+ parseTestBody(body) {
705
+ const nameMatch = body.match(/name:\s*"([^"]+)"/);
706
+ if (!nameMatch) return null;
707
+ const name = nameMatch[1];
708
+ const skipMatch = body.match(/skip:\s*(true|false)/);
709
+ const skip = skipMatch?.[1] === "true";
710
+ const setupAssignments = [];
711
+ const setupMatch = body.match(/setup:\s*\{([^}]+)\}/);
712
+ if (setupMatch) {
713
+ const setupBody = setupMatch[1].trim();
714
+ const assignRegex = /\$([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)/g;
715
+ let assignMatch;
716
+ while ((assignMatch = assignRegex.exec(setupBody)) !== null) {
717
+ setupAssignments.push({
718
+ variable: assignMatch[1],
719
+ expression: assignMatch[2].trim().replace(/[,;]\s*$/, "")
720
+ });
721
+ }
722
+ }
723
+ const assertions = [];
724
+ const assertRegex = /assert:\s*\{([^}]+)\}/g;
725
+ let assertMatch;
726
+ while ((assertMatch = assertRegex.exec(body)) !== null) {
727
+ const assertBody = assertMatch[1].trim();
728
+ const lines = assertBody.split(/[;\n]/).map((l) => l.trim()).filter(Boolean);
729
+ for (const line of lines) {
730
+ assertions.push({ expression: line });
731
+ }
732
+ }
733
+ return { name, setupAssignments, assertions, skip };
734
+ }
735
+ // ─── Evaluation ──────────────────────────────────────────────────────────────
736
+ /**
737
+ * Evaluate a single value expression, resolving $vars from state
738
+ */
739
+ evaluateValue(expr, state) {
740
+ const trimmed = expr.trim();
741
+ if (trimmed === "true") return true;
742
+ if (trimmed === "false") return false;
743
+ if (trimmed === "null") return null;
744
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) return Number(trimmed);
745
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
746
+ return trimmed.slice(1, -1);
747
+ }
748
+ if (trimmed.startsWith("$")) {
749
+ const varName = trimmed.slice(1);
750
+ return state[varName];
751
+ }
752
+ try {
753
+ const transformed = trimmed.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, varName) => varName);
754
+ const keys = Object.keys(state);
755
+ const values = Object.values(state);
756
+ const fn = new Function(
757
+ ...keys,
758
+ "Math",
759
+ "String",
760
+ "Number",
761
+ "Boolean",
762
+ "Date",
763
+ "JSON",
764
+ `"use strict"; return (${transformed})`
765
+ );
766
+ return fn(...values, Math, String, Number, Boolean, Date, JSON);
767
+ } catch {
768
+ return trimmed;
769
+ }
770
+ }
771
+ /**
772
+ * Evaluate an assertion expression against state.
773
+ * Supports: $var == value, $var != value, $var > value, etc.
774
+ */
775
+ evaluateAssertion(expr, state) {
776
+ const trimmed = expr.trim();
777
+ const transformed = trimmed.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, varName) => varName);
778
+ try {
779
+ const keys = Object.keys(state);
780
+ const values = Object.values(state);
781
+ const fn = new Function(
782
+ ...keys,
783
+ "Math",
784
+ "String",
785
+ "Number",
786
+ "Boolean",
787
+ "Date",
788
+ "JSON",
789
+ `"use strict"; return !!(${transformed})`
790
+ );
791
+ return fn(...values, Math, String, Number, Boolean, Date, JSON);
792
+ } catch {
793
+ return false;
794
+ }
795
+ }
796
+ /**
797
+ * Evaluate computed values from their definitions
798
+ */
799
+ evaluateComputedValues(state) {
800
+ const result = {};
801
+ for (const def of this.computedDefs) {
802
+ try {
803
+ const transformed = def.expression.replace(
804
+ /\$([a-zA-Z_][a-zA-Z0-9_]*)/g,
805
+ (_, varName) => varName
806
+ );
807
+ const keys = Object.keys(state);
808
+ const values = Object.values(state);
809
+ const fn = new Function(
810
+ ...keys,
811
+ "Math",
812
+ "String",
813
+ "Number",
814
+ "Boolean",
815
+ "Date",
816
+ "JSON",
817
+ `"use strict"; return (${transformed})`
818
+ );
819
+ result[def.name] = fn(...values, Math, String, Number, Boolean, Date, JSON);
820
+ } catch {
821
+ result[def.name] = void 0;
822
+ }
823
+ }
824
+ return result;
825
+ }
826
+ // ─── Static helpers ──────────────────────────────────────────────────────────
827
+ /**
828
+ * Extract state block from .hsplus source.
829
+ * Handles nested objects { ... } and arrays [ ... ].
830
+ */
831
+ static extractStateFromSource(source) {
832
+ const result = {};
833
+ const stateMatch = source.match(/\bstate\s*\{/);
834
+ if (stateMatch) {
835
+ const startIdx = stateMatch.index + stateMatch[0].length;
836
+ const body = extractBracedBody(source, startIdx);
837
+ Object.assign(result, parseNestedBlock(body));
838
+ }
839
+ const inlineRegex = /^\s*state\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*\w+\s*=\s*(.+)$/gm;
840
+ let inlineMatch;
841
+ while ((inlineMatch = inlineRegex.exec(source)) !== null) {
842
+ const key = inlineMatch[1];
843
+ if (!(key in result)) {
844
+ result[key] = parseStateValue(inlineMatch[2].trim());
845
+ }
846
+ }
847
+ return result;
848
+ }
849
+ /**
850
+ * Extract computed definitions from .hsplus source
851
+ */
852
+ static extractComputedFromSource(source) {
853
+ const defs = [];
854
+ const computedMatch = source.match(/\bcomputed\s*\{/);
855
+ if (!computedMatch) return defs;
856
+ const startIdx = computedMatch.index + computedMatch[0].length;
857
+ let depth = 1;
858
+ let endIdx = startIdx;
859
+ while (depth > 0 && endIdx < source.length) {
860
+ if (source[endIdx] === "{") depth++;
861
+ if (source[endIdx] === "}") depth--;
862
+ endIdx++;
863
+ }
864
+ const body = source.substring(startIdx, endIdx - 1);
865
+ const lines = body.split("\n");
866
+ for (const line of lines) {
867
+ const trimmed = line.trim();
868
+ if (!trimmed || trimmed.startsWith("//")) continue;
869
+ const kvMatch = trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+?)\s*$/);
870
+ if (kvMatch) {
871
+ defs.push({ name: kvMatch[1], expression: kvMatch[2] });
872
+ }
873
+ }
874
+ return defs;
875
+ }
876
+ };
877
+ function extractBracedBody(source, startIdx) {
878
+ let depth = 1;
879
+ let i = startIdx;
880
+ while (depth > 0 && i < source.length) {
881
+ if (source[i] === "{") depth++;
882
+ if (source[i] === "}") depth--;
883
+ i++;
884
+ }
885
+ return source.substring(startIdx, i - 1);
886
+ }
887
+ function parseNestedBlock(body) {
888
+ const result = {};
889
+ let i = 0;
890
+ while (i < body.length) {
891
+ while (i < body.length && /\s/.test(body[i])) i++;
892
+ if (i >= body.length) break;
893
+ if (body[i] === "/" && body[i + 1] === "/") {
894
+ while (i < body.length && body[i] !== "\n") i++;
895
+ continue;
896
+ }
897
+ const keyMatch = body.slice(i).match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*/);
898
+ if (!keyMatch) {
899
+ i++;
900
+ continue;
901
+ }
902
+ const key = keyMatch[1];
903
+ i += keyMatch[0].length;
904
+ while (i < body.length && /\s/.test(body[i])) i++;
905
+ if (body[i] === "{") {
906
+ i++;
907
+ const nestedBody = extractBracedBody(body, i);
908
+ i += nestedBody.length + 1;
909
+ result[key] = parseNestedBlock(nestedBody);
910
+ } else if (body[i] === "[") {
911
+ const arrStart = i;
912
+ let depth = 1;
913
+ i++;
914
+ while (depth > 0 && i < body.length) {
915
+ if (body[i] === "[") depth++;
916
+ if (body[i] === "]") depth--;
917
+ i++;
918
+ }
919
+ const arrStr = body.substring(arrStart, i).trim();
920
+ try {
921
+ result[key] = readJson(arrStr);
922
+ } catch {
923
+ result[key] = arrStr;
924
+ }
925
+ } else {
926
+ const valMatch = body.slice(i).match(/^(.+?)(?:\n|$)/);
927
+ if (valMatch) {
928
+ const raw = valMatch[1].trim().replace(/,\s*$/, "");
929
+ result[key] = parseStateValue(raw);
930
+ i += valMatch[0].length;
931
+ } else {
932
+ i++;
933
+ }
934
+ }
935
+ }
936
+ return result;
937
+ }
938
+ function parseStateValue(raw) {
939
+ const v = raw.trim().replace(/,\s*$/, "");
940
+ if (v === "true") return true;
941
+ if (v === "false") return false;
942
+ if (v === "null") return null;
943
+ if (/^-?\d+(\.\d+)?$/.test(v)) return Number(v);
944
+ if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
945
+ return v.slice(1, -1);
946
+ }
947
+ return v;
948
+ }
949
+ var TEST_TRAIT = {
950
+ name: "test",
951
+ category: "testing",
952
+ description: "Native composition testing with $stateVar syntax",
953
+ compileTargets: ["node", "python", "ros2", "headless"],
954
+ requiresRenderer: false,
955
+ parameters: [
956
+ { name: "name", type: "string", required: true, description: "Test name" },
957
+ { name: "setup", type: "object", required: false, description: "State setup assignments" },
958
+ { name: "assert", type: "object", required: true, description: "Assertion expressions" },
959
+ {
960
+ name: "skip",
961
+ type: "boolean",
962
+ required: false,
963
+ default: false,
964
+ description: "Skip this test"
965
+ }
966
+ ]
967
+ };
968
+ var testHandler = {
969
+ name: "test",
970
+ defaultConfig: { bail: false, debug: false, timeout: 5e3 },
971
+ onAttach(node, config, ctx) {
972
+ const instance = new CompositionTestRunner({}, [], config);
973
+ node.__test_instance = instance;
974
+ ctx.emit?.("test:attached", { node, config });
975
+ },
976
+ onDetach(node, _config, ctx) {
977
+ delete node.__test_instance;
978
+ ctx.emit?.("test:detached", { node });
979
+ },
980
+ onUpdate() {
981
+ },
982
+ onEvent(node, _config, ctx, event) {
983
+ const instance = node.__test_instance;
984
+ if (!instance) return;
985
+ const eventType = typeof event === "string" ? event : event.type;
986
+ if (eventType === "test:run" && event.source) {
987
+ const results = instance.runTestsFromSource(event.source);
988
+ ctx.emit?.("test:results", { results });
989
+ }
990
+ }
991
+ };
992
+
993
+ // src/deploy/license-checker.ts
994
+ var RESTRICTIVENESS = {
995
+ free: 0,
996
+ cc_by: 1,
997
+ cc_by_sa: 2,
998
+ cc_by_nc: 3,
999
+ commercial: 4,
1000
+ exclusive: 5
1001
+ };
1002
+ function checkLicenseCompatibility(compositionLicense, importedLicenses) {
1003
+ const errors = [];
1004
+ const warnings = [];
1005
+ let forcedLicense;
1006
+ if (importedLicenses.length === 0) {
1007
+ return { compatible: true, errors: [], warnings: [] };
1008
+ }
1009
+ for (const imp of importedLicenses) {
1010
+ if (imp.license === "exclusive") {
1011
+ errors.push(
1012
+ `Cannot import "${imp.path}" \u2014 license is "exclusive" (view-only, no import allowed)`
1013
+ );
1014
+ continue;
1015
+ }
1016
+ if (imp.license === "commercial") {
1017
+ warnings.push(
1018
+ `Import "${imp.path}" has "commercial" license \u2014 ensure purchase is verified before publishing`
1019
+ );
1020
+ continue;
1021
+ }
1022
+ if (imp.license === "cc_by_sa") {
1023
+ const compositionLevel = RESTRICTIVENESS[compositionLicense];
1024
+ const requiredLevel = RESTRICTIVENESS.cc_by_sa;
1025
+ if (compositionLevel < requiredLevel) {
1026
+ if (!forcedLicense || RESTRICTIVENESS[forcedLicense] < requiredLevel) {
1027
+ forcedLicense = "cc_by_sa";
1028
+ }
1029
+ warnings.push(
1030
+ `Import "${imp.path}" is "cc_by_sa" \u2014 your composition license forced to "cc_by_sa" (share-alike)`
1031
+ );
1032
+ }
1033
+ }
1034
+ if (imp.license === "cc_by_nc") {
1035
+ if (compositionLicense === "free" || compositionLicense === "cc_by") {
1036
+ if (!forcedLicense || RESTRICTIVENESS[forcedLicense] < RESTRICTIVENESS.cc_by_nc) {
1037
+ forcedLicense = "cc_by_nc";
1038
+ }
1039
+ warnings.push(
1040
+ `Import "${imp.path}" is "cc_by_nc" \u2014 your composition license forced to "cc_by_nc" (non-commercial)`
1041
+ );
1042
+ }
1043
+ }
1044
+ if (imp.license === "cc_by") {
1045
+ if (compositionLicense === "free") {
1046
+ if (!forcedLicense || RESTRICTIVENESS[forcedLicense] < RESTRICTIVENESS.cc_by) {
1047
+ forcedLicense = "cc_by";
1048
+ }
1049
+ warnings.push(
1050
+ `Import "${imp.path}" is "cc_by" \u2014 your composition license forced to at least "cc_by" (attribution required)`
1051
+ );
1052
+ }
1053
+ }
1054
+ }
1055
+ const hasShareAlike = importedLicenses.some((i) => i.license === "cc_by_sa");
1056
+ const hasNonCommercial = importedLicenses.some((i) => i.license === "cc_by_nc");
1057
+ if (hasShareAlike && hasNonCommercial) {
1058
+ errors.push(
1059
+ 'License conflict: cannot mix "cc_by_sa" (share-alike) and "cc_by_nc" (non-commercial) imports \u2014 cc_by_sa requires derivatives use the same license, but cc_by_nc requires non-commercial use'
1060
+ );
1061
+ }
1062
+ return {
1063
+ compatible: errors.length === 0,
1064
+ errors,
1065
+ warnings,
1066
+ forcedLicense
1067
+ };
1068
+ }
1069
+
1070
+ // src/deploy/protocol-types.ts
1071
+ var PROTOCOL_CONSTANTS = {
1072
+ /** Platform fee in basis points (2.5%) */
1073
+ PLATFORM_FEE_BPS: 250,
1074
+ /** Import royalty per level in basis points (5% per level) */
1075
+ IMPORT_ROYALTY_BPS: 500,
1076
+ /** Maximum import depth for revenue distribution */
1077
+ MAX_IMPORT_DEPTH: 3,
1078
+ /** Default referral reward in basis points (2%) */
1079
+ DEFAULT_REFERRAL_BPS: 200,
1080
+ /** Basis points denominator */
1081
+ BPS_DENOMINATOR: 1e4,
1082
+ /** Zora mint fee per edition (in wei) */
1083
+ ZORA_MINT_FEE_WEI: 777000000000000n,
1084
+ // 0.000777 ETH
1085
+ /** Chain configuration */
1086
+ CHAIN: {
1087
+ id: 8453,
1088
+ name: "base",
1089
+ testnet: {
1090
+ id: 84532,
1091
+ name: "base-sepolia"
1092
+ }
1093
+ },
1094
+ /** Protocol registry base URL */
1095
+ REGISTRY_BASE_URL: "https://holoscript.net",
1096
+ /** Zora 1155 factory address (same on all chains) */
1097
+ ZORA_1155_FACTORY: "0x777777C338d93e2C7adf08D102d45CA7CC4Ed021",
1098
+ /** Environment variable names */
1099
+ ENV: {
1100
+ WALLET_KEY: "HOLOSCRIPT_WALLET_KEY",
1101
+ COLLECTION_ADDRESS: "HOLOSCRIPT_COLLECTION_ADDRESS",
1102
+ SERVER_URL: "HOLOSCRIPT_SERVER_URL"
1103
+ }
1104
+ };
1105
+
1106
+ // src/deploy/revenue-splitter.ts
1107
+ function calculateRevenueDistribution(collectPrice, creator, importChain, options = {}) {
1108
+ const {
1109
+ platformFeeBps = PROTOCOL_CONSTANTS.PLATFORM_FEE_BPS,
1110
+ importRoyaltyBps = PROTOCOL_CONSTANTS.IMPORT_ROYALTY_BPS,
1111
+ maxImportDepth = PROTOCOL_CONSTANTS.MAX_IMPORT_DEPTH,
1112
+ referralBps = PROTOCOL_CONSTANTS.DEFAULT_REFERRAL_BPS,
1113
+ referrer,
1114
+ platformAddress = "platform"
1115
+ } = options;
1116
+ const flows = [];
1117
+ if (collectPrice === 0n) {
1118
+ return { totalPrice: 0n, flows: [] };
1119
+ }
1120
+ const bpsDenom = BigInt(PROTOCOL_CONSTANTS.BPS_DENOMINATOR);
1121
+ let remaining = collectPrice;
1122
+ const platformFee = collectPrice * BigInt(platformFeeBps) / bpsDenom;
1123
+ if (platformFee > 0n) {
1124
+ flows.push({
1125
+ recipient: platformAddress,
1126
+ amount: platformFee,
1127
+ reason: "platform",
1128
+ bps: platformFeeBps
1129
+ });
1130
+ remaining -= platformFee;
1131
+ }
1132
+ if (referrer) {
1133
+ const referralAmount = collectPrice * BigInt(referralBps) / bpsDenom;
1134
+ if (referralAmount > 0n) {
1135
+ flows.push({
1136
+ recipient: referrer,
1137
+ amount: referralAmount,
1138
+ reason: "referral",
1139
+ bps: referralBps
1140
+ });
1141
+ remaining -= referralAmount;
1142
+ }
1143
+ }
1144
+ const flattenedByDepth = flattenImportsByDepth(importChain, maxImportDepth);
1145
+ for (const [depth, nodes] of flattenedByDepth.entries()) {
1146
+ if (nodes.length === 0) continue;
1147
+ const levelRoyalty = collectPrice * BigInt(importRoyaltyBps) / bpsDenom;
1148
+ const perImportRoyalty = levelRoyalty / BigInt(nodes.length);
1149
+ const dust = levelRoyalty - perImportRoyalty * BigInt(nodes.length);
1150
+ for (let i = 0; i < nodes.length; i++) {
1151
+ const amount = i === 0 ? perImportRoyalty + dust : perImportRoyalty;
1152
+ if (amount > 0n) {
1153
+ flows.push({
1154
+ recipient: nodes[i].author,
1155
+ amount,
1156
+ reason: "import_royalty",
1157
+ depth,
1158
+ bps: Math.floor(importRoyaltyBps / nodes.length)
1159
+ });
1160
+ remaining -= amount;
1161
+ }
1162
+ }
1163
+ }
1164
+ if (remaining > 0n) {
1165
+ const creatorBps = PROTOCOL_CONSTANTS.BPS_DENOMINATOR - platformFeeBps - (referrer ? referralBps : 0) - importRoyaltyBps * flattenedByDepth.size;
1166
+ flows.push({
1167
+ recipient: creator,
1168
+ amount: remaining,
1169
+ reason: "creator",
1170
+ bps: Math.max(creatorBps, 0)
1171
+ });
1172
+ }
1173
+ return { totalPrice: collectPrice, flows };
1174
+ }
1175
+ function flattenImportsByDepth(chain, maxDepth) {
1176
+ const byDepth = /* @__PURE__ */ new Map();
1177
+ const seen = /* @__PURE__ */ new Set();
1178
+ function walk(nodes, depth) {
1179
+ if (depth > maxDepth) return;
1180
+ for (const node of nodes) {
1181
+ if (seen.has(node.contentHash)) continue;
1182
+ seen.add(node.contentHash);
1183
+ const list = byDepth.get(depth) ?? [];
1184
+ list.push(node);
1185
+ byDepth.set(depth, list);
1186
+ if (node.children.length > 0) {
1187
+ walk(node.children, depth + 1);
1188
+ }
1189
+ }
1190
+ }
1191
+ walk(chain, 1);
1192
+ return byDepth;
1193
+ }
1194
+ async function resolveImportChain(imports, resolver, maxDepth = PROTOCOL_CONSTANTS.MAX_IMPORT_DEPTH) {
1195
+ const seen = /* @__PURE__ */ new Set();
1196
+ async function resolve(importList, depth) {
1197
+ if (depth > maxDepth) return [];
1198
+ const nodes = [];
1199
+ for (const imp of importList) {
1200
+ const hash = imp.hash;
1201
+ if (!hash || seen.has(hash)) continue;
1202
+ seen.add(hash);
1203
+ const record = await resolver(hash);
1204
+ const author = record?.author ?? imp.author ?? "unknown";
1205
+ const children = record && depth < maxDepth ? await resolve(
1206
+ record.importHashes.map((h) => ({ hash: h, path: "", author: "" })),
1207
+ depth + 1
1208
+ ) : [];
1209
+ nodes.push({
1210
+ contentHash: hash,
1211
+ author,
1212
+ depth,
1213
+ children
1214
+ });
1215
+ }
1216
+ return nodes;
1217
+ }
1218
+ return resolve(imports, 1);
1219
+ }
1220
+ function formatRevenueDistribution(dist) {
1221
+ if (dist.totalPrice === 0n) return ["Free collect \u2014 no revenue distribution"];
1222
+ return dist.flows.map((flow) => {
1223
+ const pct = (Number(flow.amount) / Number(dist.totalPrice) * 100).toFixed(1);
1224
+ const depthLabel = flow.depth ? `, depth ${flow.depth}` : "";
1225
+ return `${pct}% \u2192 ${flow.recipient} (${flow.reason}${depthLabel})`;
1226
+ });
1227
+ }
1228
+ function ethToWei(eth) {
1229
+ const parts = eth.split(".");
1230
+ const whole = parts[0] || "0";
1231
+ const fraction = (parts[1] || "").padEnd(18, "0").slice(0, 18);
1232
+ return BigInt(whole) * 10n ** 18n + BigInt(fraction);
1233
+ }
1234
+ function weiToEth(wei) {
1235
+ const str = wei.toString().padStart(19, "0");
1236
+ const whole = str.slice(0, str.length - 18) || "0";
1237
+ const fraction = str.slice(str.length - 18).replace(/0+$/, "") || "0";
1238
+ return `${whole}.${fraction}`;
1239
+ }
1240
+
1241
+ export { CompositionTestRunner, DEFAULT_STDLIB_POLICY, PROTOCOL_CONSTANTS, TEST_TRAIT, buildStdlibPermissionScopeDiff, calculateRevenueDistribution, checkLicenseCompatibility, createStdlibActions, ethToWei, evaluateStdlibPermissionScopePolicy, findExtraPermissionScopes, findMissingRequiredPermissionScopes, formatRevenueDistribution, isPathAllowed, isValidPermissionScopeName, normalizePermissionScopeName, parseHostFromUrl, redactStdlibPermissionPreview, registerStdlib, resolveImportChain, resolveRepoRelativePath, stdlibPermissionPreviewHasPublicLeak, testHandler, toStringArray, truncateText, weiToEth };
1242
+ //# sourceMappingURL=chunk-ZZ7RO2UQ.js.map
1243
+ //# sourceMappingURL=chunk-ZZ7RO2UQ.js.map