@auraindustry/aurajs 0.0.7 → 0.1.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 (334) hide show
  1. package/README.md +98 -2
  2. package/benchmarks/perf-thresholds.json +54 -0
  3. package/package.json +4 -7
  4. package/src/asset-pack.mjs +8 -1
  5. package/src/authored-project.mjs +1449 -0
  6. package/src/authored-runtime.mjs +2016 -0
  7. package/src/authoring/avatar-animation-graph.mjs +648 -0
  8. package/src/bin-integrity.mjs +272 -0
  9. package/src/build-contract/assets.mjs +130 -0
  10. package/src/build-contract/capabilities.mjs +116 -0
  11. package/src/build-contract/constants.mjs +6 -0
  12. package/src/build-contract/helpers.mjs +44 -0
  13. package/src/build-contract/web-templates.mjs +5993 -0
  14. package/src/build-contract.mjs +27 -2910
  15. package/src/bundler.mjs +188 -55
  16. package/src/cli.mjs +4840 -1512
  17. package/src/commands/project-authoring.mjs +454 -0
  18. package/src/config.mjs +44 -0
  19. package/src/conformance/cases/app-and-ui-runtime-cases.mjs +3309 -0
  20. package/src/conformance/cases/core-runtime-cases.mjs +1431 -0
  21. package/src/conformance/cases/index.mjs +11 -0
  22. package/src/conformance/cases/scene3d-and-media-cases.mjs +2094 -0
  23. package/src/conformance/cases/systems-and-gameplay-cases.mjs +1776 -0
  24. package/src/conformance/shared.mjs +27 -0
  25. package/src/conformance-runner.mjs +25 -13
  26. package/src/conformance.mjs +619 -4020
  27. package/src/cutscene.mjs +362 -5
  28. package/src/dev-cli-action.mjs +249 -0
  29. package/src/dev-cli-inspect.mjs +92 -0
  30. package/src/dev-cli-state.mjs +80 -0
  31. package/src/external-asset-cache.mjs +587 -0
  32. package/src/external-asset-policy.mjs +217 -0
  33. package/src/external-package-surface.mjs +206 -0
  34. package/src/game-action-runtime.mjs +869 -0
  35. package/src/game-state-runtime.mjs +206 -6
  36. package/src/headless-action.mjs +186 -0
  37. package/src/headless-test/runtime-animation.mjs +1173 -0
  38. package/src/headless-test/runtime-coordinator.mjs +1514 -0
  39. package/src/headless-test/runtime-primitives.mjs +320 -0
  40. package/src/headless-test/runtime-world.mjs +2253 -0
  41. package/src/headless-test.mjs +392 -4298
  42. package/src/host-binary.mjs +342 -14
  43. package/src/icon-discovery.mjs +64 -0
  44. package/src/make-catalog.mjs +109 -0
  45. package/src/make.mjs +197 -0
  46. package/src/package-integrity.mjs +586 -0
  47. package/src/perf-benchmark.mjs +353 -0
  48. package/src/postinstall.mjs +5 -5
  49. package/src/prefabs/index.mjs +34 -0
  50. package/src/prefabs/scene-serialization.mjs +184 -0
  51. package/src/project-importer.mjs +620 -0
  52. package/src/project-registry.mjs +24 -0
  53. package/src/publish-command.mjs +195 -0
  54. package/src/publish-env-example.mjs +83 -0
  55. package/src/publish-validation.mjs +708 -0
  56. package/src/retro/assets/compile.mjs +232 -0
  57. package/src/retro/backend-gba/authoring.mjs +1029 -0
  58. package/src/retro/backend-gba/rom.mjs +363 -0
  59. package/src/retro/backend-gbc/rom.mjs +85 -0
  60. package/src/retro/build.mjs +278 -0
  61. package/src/retro/cli/commands.mjs +292 -0
  62. package/src/retro/cli/templates.mjs +84 -0
  63. package/src/retro/diagnostics/catalog.mjs +110 -0
  64. package/src/retro/diagnostics/emit.mjs +72 -0
  65. package/src/retro/emulator/case-overlay.mjs +64 -0
  66. package/src/retro/emulator/discovery.mjs +158 -0
  67. package/src/retro/emulator/macos-case-overlay.swift +220 -0
  68. package/src/retro/emulator/profiles.mjs +146 -0
  69. package/src/retro/emulator/runner.mjs +289 -0
  70. package/src/retro/frontend/load-project.mjs +98 -0
  71. package/src/retro/index.mjs +30 -0
  72. package/src/retro/ir/build-ir.mjs +108 -0
  73. package/src/retro/runtime-gba/contract.mjs +151 -0
  74. package/src/retro/runtime-gbc/contract.mjs +117 -0
  75. package/src/retro/shared/span.mjs +26 -0
  76. package/src/retro/shared/targets.mjs +64 -0
  77. package/src/retro/validator/check-project.mjs +114 -0
  78. package/src/runtime-hotspot-audit.mjs +707 -0
  79. package/src/scaffold/config.mjs +1000 -0
  80. package/src/scaffold/fs.mjs +56 -0
  81. package/src/scaffold/layout.mjs +318 -0
  82. package/src/scaffold/project-docs.mjs +439 -0
  83. package/src/scaffold.mjs +93 -596
  84. package/src/scene-composition/index.mjs +326 -0
  85. package/src/scene-composition/runtime.mjs +751 -0
  86. package/src/self-hosted-assets.mjs +604 -0
  87. package/src/session-client.mjs +750 -0
  88. package/src/session-native-launcher.mjs +74 -0
  89. package/src/session-protocol.mjs +75 -0
  90. package/src/session-runtime.mjs +321 -0
  91. package/src/session-server.mjs +360 -0
  92. package/src/shader-kits/index.mjs +773 -0
  93. package/src/starter-content-registry.mjs +292 -0
  94. package/src/state-artifacts.mjs +662 -24
  95. package/src/state-dev-reload.mjs +99 -2
  96. package/src/terminal-ui.mjs +245 -0
  97. package/src/web-conformance.mjs +219 -0
  98. package/templates/create/2d/config/gameplay/shooter.config.js +26 -0
  99. package/templates/create/2d/content/gameplay/waves.json +26 -0
  100. package/templates/create/2d/content/registries/.gitkeep +1 -0
  101. package/templates/create/2d/docs/design/.gitkeep +1 -0
  102. package/templates/create/2d/docs/design/loop.md +5 -0
  103. package/templates/create/2d/prefabs/enemies.prefab.js +90 -0
  104. package/templates/create/2d/prefabs/enemy-basic.prefab.js +18 -0
  105. package/templates/create/2d/prefabs/player.prefab.js +36 -0
  106. package/templates/create/2d/prefabs/projectiles.prefab.js +35 -0
  107. package/templates/create/2d/scenes/boot.scene.js +12 -0
  108. package/templates/create/2d/scenes/gameplay.scene.js +230 -0
  109. package/templates/create/2d/scenes/menu.scene.js +9 -0
  110. package/templates/create/2d/src/main.js +6 -185
  111. package/templates/create/2d/src/runtime/app.js +49 -0
  112. package/templates/create/2d/src/runtime/capabilities.js +35 -0
  113. package/templates/create/2d/ui/hud.screen.js +40 -0
  114. package/templates/create/2d/ui/pause.screen.js +149 -0
  115. package/templates/create/2d/ui/settings.screen.js +347 -0
  116. package/templates/create/2d/ui/title.screen.js +13 -0
  117. package/templates/create/2d-adventure/aura.config.json +28 -0
  118. package/templates/create/2d-adventure/config/gameplay/adventure.config.js +14 -0
  119. package/templates/create/2d-adventure/content/gameplay/world.js +46 -0
  120. package/templates/create/2d-adventure/content/registries/.gitkeep +1 -0
  121. package/templates/create/2d-adventure/docs/design/loop.md +5 -0
  122. package/templates/create/2d-adventure/prefabs/player.prefab.js +54 -0
  123. package/templates/create/2d-adventure/prefabs/relic.prefab.js +38 -0
  124. package/templates/create/2d-adventure/prefabs/world.prefab.js +125 -0
  125. package/templates/create/2d-adventure/scenes/gameplay.scene.js +256 -0
  126. package/templates/create/2d-adventure/src/runtime/capabilities.js +34 -0
  127. package/templates/create/2d-adventure/ui/hud.screen.js +60 -0
  128. package/templates/create/2d-survivor/config/gameplay/survivor.config.js +33 -0
  129. package/templates/create/2d-survivor/content/gameplay/spawn-zones.json +29 -0
  130. package/templates/create/2d-survivor/content/registries/.gitkeep +1 -0
  131. package/templates/create/2d-survivor/docs/design/.gitkeep +1 -0
  132. package/templates/create/2d-survivor/docs/design/loop.md +5 -0
  133. package/templates/create/2d-survivor/prefabs/enemies.prefab.js +178 -0
  134. package/templates/create/2d-survivor/prefabs/enemy-swarm.prefab.js +18 -0
  135. package/templates/create/2d-survivor/prefabs/player.prefab.js +42 -0
  136. package/templates/create/2d-survivor/prefabs/projectiles.prefab.js +56 -0
  137. package/templates/create/2d-survivor/scenes/boot.scene.js +12 -0
  138. package/templates/create/2d-survivor/scenes/gameplay.scene.js +314 -0
  139. package/templates/create/2d-survivor/scenes/menu.scene.js +9 -0
  140. package/templates/create/2d-survivor/src/main.js +5 -332
  141. package/templates/create/2d-survivor/src/runtime/app.js +49 -0
  142. package/templates/create/2d-survivor/src/runtime/capabilities.js +35 -0
  143. package/templates/create/2d-survivor/ui/hud.screen.js +45 -0
  144. package/templates/create/2d-survivor/ui/title.screen.js +13 -0
  145. package/templates/create/3d/assets/models/starter-avatar.gltf +184 -0
  146. package/templates/create/3d/config/gameplay/.gitkeep +1 -0
  147. package/templates/create/3d/content/gameplay/checkpoints.json +33 -0
  148. package/templates/create/3d/content/gameplay/course.js +40 -0
  149. package/templates/create/3d/content/registries/.gitkeep +1 -0
  150. package/templates/create/3d/docs/design/.gitkeep +1 -0
  151. package/templates/create/3d/docs/design/loop.md +5 -0
  152. package/templates/create/3d/prefabs/checkpoint.prefab.js +15 -0
  153. package/templates/create/3d/prefabs/player.prefab.js +204 -0
  154. package/templates/create/3d/prefabs/world.prefab.js +112 -0
  155. package/templates/create/3d/scenes/boot.scene.js +12 -0
  156. package/templates/create/3d/scenes/checkpoint.scene.js +9 -0
  157. package/templates/create/3d/scenes/gameplay.scene.js +292 -0
  158. package/templates/create/3d/src/main.js +6 -295
  159. package/templates/create/3d/src/runtime/app.js +49 -0
  160. package/templates/create/3d/src/runtime/capabilities.js +53 -0
  161. package/templates/create/3d/src/runtime/materials.js +34 -0
  162. package/templates/create/3d/src/runtime/state.js +39 -0
  163. package/templates/create/3d/ui/hud.screen.js +75 -0
  164. package/templates/create/3d/ui/pause.screen.js +166 -0
  165. package/templates/create/3d/ui/settings.screen.js +387 -0
  166. package/templates/create/3d-adventure/assets/models/starter-avatar.gltf +184 -0
  167. package/templates/create/3d-adventure/aura.config.json +28 -0
  168. package/templates/create/3d-adventure/config/gameplay/adventure.config.js +9 -0
  169. package/templates/create/3d-adventure/content/gameplay/course.js +62 -0
  170. package/templates/create/3d-adventure/content/registries/.gitkeep +1 -0
  171. package/templates/create/3d-adventure/docs/design/loop.md +5 -0
  172. package/templates/create/3d-adventure/prefabs/player.prefab.js +168 -0
  173. package/templates/create/3d-adventure/prefabs/relic.prefab.js +35 -0
  174. package/templates/create/3d-adventure/prefabs/world.prefab.js +119 -0
  175. package/templates/create/3d-adventure/scenes/gameplay.scene.js +358 -0
  176. package/templates/create/3d-adventure/src/runtime/capabilities.js +56 -0
  177. package/templates/create/3d-adventure/src/runtime/materials.js +39 -0
  178. package/templates/create/3d-adventure/src/runtime/state.js +31 -0
  179. package/templates/create/3d-adventure/ui/hud.screen.js +70 -0
  180. package/templates/create/3d-adventure/ui/pause.screen.js +437 -0
  181. package/templates/create/3d-collectathon/assets/models/starter-avatar.gltf +184 -0
  182. package/templates/create/3d-collectathon/config/gameplay/.gitkeep +1 -0
  183. package/templates/create/3d-collectathon/content/gameplay/collectibles.json +26 -0
  184. package/templates/create/3d-collectathon/content/gameplay/course.js +46 -0
  185. package/templates/create/3d-collectathon/content/registries/.gitkeep +1 -0
  186. package/templates/create/3d-collectathon/docs/design/.gitkeep +1 -0
  187. package/templates/create/3d-collectathon/docs/design/loop.md +5 -0
  188. package/templates/create/3d-collectathon/prefabs/collectible.prefab.js +15 -0
  189. package/templates/create/3d-collectathon/prefabs/player.prefab.js +207 -0
  190. package/templates/create/3d-collectathon/prefabs/world.prefab.js +112 -0
  191. package/templates/create/3d-collectathon/scenes/boot.scene.js +12 -0
  192. package/templates/create/3d-collectathon/scenes/checkpoint.scene.js +9 -0
  193. package/templates/create/3d-collectathon/scenes/gameplay.scene.js +200 -0
  194. package/templates/create/3d-collectathon/src/main.js +5 -355
  195. package/templates/create/3d-collectathon/src/runtime/app.js +49 -0
  196. package/templates/create/3d-collectathon/src/runtime/capabilities.js +53 -0
  197. package/templates/create/3d-collectathon/src/runtime/materials.js +34 -0
  198. package/templates/create/3d-collectathon/src/runtime/state.js +27 -0
  199. package/templates/create/3d-collectathon/ui/hud.screen.js +66 -0
  200. package/templates/create/3d-collectathon/ui/pause.screen.js +13 -0
  201. package/templates/create/blank/config/gameplay/.gitkeep +1 -0
  202. package/templates/create/blank/content/gameplay/.gitkeep +1 -0
  203. package/templates/create/blank/content/registries/.gitkeep +1 -0
  204. package/templates/create/blank/docs/design/.gitkeep +1 -0
  205. package/templates/create/blank/docs/design/loop.md +5 -0
  206. package/templates/create/blank/prefabs/.gitkeep +1 -0
  207. package/templates/create/blank/scenes/.gitkeep +1 -0
  208. package/templates/create/blank/src/runtime/.gitkeep +1 -0
  209. package/templates/create/blank/ui/.gitkeep +1 -0
  210. package/templates/create/deckbuilder-2d/assets/audio/.gitkeep +1 -0
  211. package/templates/create/deckbuilder-2d/assets/fonts/.gitkeep +1 -0
  212. package/templates/create/deckbuilder-2d/assets/sprites/.gitkeep +1 -0
  213. package/templates/create/deckbuilder-2d/assets/starter/README.md +11 -0
  214. package/templates/create/deckbuilder-2d/assets/ui/.gitkeep +1 -0
  215. package/templates/create/deckbuilder-2d/aura.config.json +28 -0
  216. package/templates/create/deckbuilder-2d/config/gameplay/deckbuilder.config.js +26 -0
  217. package/templates/create/deckbuilder-2d/content/cards/guard.card.js +19 -0
  218. package/templates/create/deckbuilder-2d/content/cards/spark.card.js +20 -0
  219. package/templates/create/deckbuilder-2d/content/cards/starter.deck.js +69 -0
  220. package/templates/create/deckbuilder-2d/content/cards/strike.card.js +19 -0
  221. package/templates/create/deckbuilder-2d/content/cards/survey.card.js +20 -0
  222. package/templates/create/deckbuilder-2d/content/encounters/training-battle.encounter.js +14 -0
  223. package/templates/create/deckbuilder-2d/content/encounters/training-battle.js +65 -0
  224. package/templates/create/deckbuilder-2d/content/enemies/training-automaton.enemy.js +48 -0
  225. package/templates/create/deckbuilder-2d/content/gameplay/.gitkeep +1 -0
  226. package/templates/create/deckbuilder-2d/content/registries/cards.registry.js +26 -0
  227. package/templates/create/deckbuilder-2d/content/registries/encounters.registry.js +20 -0
  228. package/templates/create/deckbuilder-2d/content/registries/enemies.registry.js +20 -0
  229. package/templates/create/deckbuilder-2d/content/registries/relics.registry.js +20 -0
  230. package/templates/create/deckbuilder-2d/content/relics/ember-charm.relic.js +18 -0
  231. package/templates/create/deckbuilder-2d/docs/design/loop.md +12 -0
  232. package/templates/create/deckbuilder-2d/prefabs/.gitkeep +1 -0
  233. package/templates/create/deckbuilder-2d/scenes/boot.scene.js +84 -0
  234. package/templates/create/deckbuilder-2d/scenes/gameplay.scene.js +641 -0
  235. package/templates/create/deckbuilder-2d/src/components/.gitkeep +1 -0
  236. package/templates/create/deckbuilder-2d/src/main.js +17 -0
  237. package/templates/create/deckbuilder-2d/src/runtime/capabilities.js +22 -0
  238. package/templates/create/deckbuilder-2d/src/shared/.gitkeep +1 -0
  239. package/templates/create/deckbuilder-2d/src/systems/.gitkeep +1 -0
  240. package/templates/create/deckbuilder-2d/tests/smoke/.gitkeep +1 -0
  241. package/templates/create/deckbuilder-2d/ui/hud.screen.js +80 -0
  242. package/templates/create/deckbuilder-2d/ui/pause.screen.js +146 -0
  243. package/templates/create/deckbuilder-2d/ui/settings.screen.js +342 -0
  244. package/templates/create/local-multiplayer/aura.config.json +41 -0
  245. package/templates/create/local-multiplayer/config/gameplay/local-multiplayer.config.js +26 -0
  246. package/templates/create/local-multiplayer/content/gameplay/room-layout.js +13 -0
  247. package/templates/create/local-multiplayer/content/registries/.gitkeep +1 -0
  248. package/templates/create/local-multiplayer/docs/design/loop.md +16 -0
  249. package/templates/create/local-multiplayer/prefabs/player.prefab.js +99 -0
  250. package/templates/create/local-multiplayer/scenes/boot.scene.js +12 -0
  251. package/templates/create/local-multiplayer/scenes/gameplay.scene.js +472 -0
  252. package/templates/create/local-multiplayer/src/main.js +17 -0
  253. package/templates/create/local-multiplayer/src/runtime/capabilities.js +28 -0
  254. package/templates/create/local-multiplayer/ui/hud.screen.js +65 -0
  255. package/templates/create/shared/src/runtime/project-inspector.js +105 -0
  256. package/templates/create/shared/src/runtime/scene-flow.js +290 -0
  257. package/templates/create/shared/src/runtime/screen-shell.js +222 -0
  258. package/templates/create/shared/src/runtime/ui-forms.js +209 -0
  259. package/templates/create/shared/src/runtime/ui-settings.js +237 -0
  260. package/templates/create/shared/src/runtime/ui-theme.js +352 -0
  261. package/templates/create/shared/src/starter-utils/adventure-objectives.js +102 -0
  262. package/templates/create/shared/src/starter-utils/animation-2d.js +337 -0
  263. package/templates/create/shared/src/starter-utils/avatar-3d.js +404 -0
  264. package/templates/create/shared/src/starter-utils/combat-feedback-2d.js +320 -0
  265. package/templates/create/shared/src/starter-utils/core.js +39 -3
  266. package/templates/create/shared/src/starter-utils/index.js +8 -2
  267. package/templates/create/shared/src/starter-utils/platformer-3d.js +34 -3
  268. package/templates/create/shared/src/starter-utils/triggers.js +662 -0
  269. package/templates/create/shared/src/starter-utils/tween-2d.js +615 -0
  270. package/templates/create/video-cutscene/assets/video/.gitkeep +0 -0
  271. package/templates/create/video-cutscene/aura.config.json +28 -0
  272. package/templates/create/video-cutscene/config/gameplay/.gitkeep +0 -0
  273. package/templates/create/video-cutscene/content/gameplay/.gitkeep +0 -0
  274. package/templates/create/video-cutscene/content/registries/.gitkeep +0 -0
  275. package/templates/create/video-cutscene/docs/design/loop.md +22 -0
  276. package/templates/create/video-cutscene/prefabs/.gitkeep +0 -0
  277. package/templates/create/video-cutscene/scenes/boot.scene.js +11 -0
  278. package/templates/create/video-cutscene/scenes/cutscene.scene.js +113 -0
  279. package/templates/create/video-cutscene/scenes/gameplay.scene.js +50 -0
  280. package/templates/create/video-cutscene/src/main.js +17 -0
  281. package/templates/create/video-cutscene/src/runtime/app.js +52 -0
  282. package/templates/create/video-cutscene/src/runtime/capabilities.js +35 -0
  283. package/templates/create/video-cutscene/src/runtime/state.js +13 -0
  284. package/templates/create/video-cutscene/ui/.gitkeep +0 -0
  285. package/templates/create-bin/play.js +1192 -0
  286. package/templates/make/README.md +46 -0
  287. package/templates/make/catalog.json +51 -0
  288. package/templates/make/component/files/{{MAKE_NAME}}.component.js +20 -0
  289. package/templates/make/component/manifest.json +9 -0
  290. package/templates/make/data/files/{{MAKE_NAME}}.json +14 -0
  291. package/templates/make/data/manifest.json +9 -0
  292. package/templates/make/material/files/{{MAKE_NAME}}.material.json +17 -0
  293. package/templates/make/material/manifest.json +9 -0
  294. package/templates/make/prefab/files/{{MAKE_NAME}}.prefab.js +20 -0
  295. package/templates/make/prefab/manifest.json +9 -0
  296. package/templates/make/scene/files/{{MAKE_NAME}}.scene.js +31 -0
  297. package/templates/make/scene/manifest.json +9 -0
  298. package/templates/make/shader/files/{{MAKE_NAME}}.shader.js +23 -0
  299. package/templates/make/shader/manifest.json +9 -0
  300. package/templates/make/system/files/{{MAKE_NAME}}.system.js +15 -0
  301. package/templates/make/system/manifest.json +9 -0
  302. package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.js +16 -0
  303. package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.json +23 -0
  304. package/templates/make/ui-screen/manifest.json +10 -0
  305. package/templates/make-starters/deckbuilder-2d/card/files/{{MAKE_NAME}}.card.js +22 -0
  306. package/templates/make-starters/deckbuilder-2d/card/manifest.json +9 -0
  307. package/templates/make-starters/deckbuilder-2d/catalog.json +34 -0
  308. package/templates/make-starters/deckbuilder-2d/encounter/files/{{MAKE_NAME}}.encounter.js +18 -0
  309. package/templates/make-starters/deckbuilder-2d/encounter/manifest.json +9 -0
  310. package/templates/make-starters/deckbuilder-2d/enemy/files/{{MAKE_NAME}}.enemy.js +28 -0
  311. package/templates/make-starters/deckbuilder-2d/enemy/manifest.json +9 -0
  312. package/templates/make-starters/deckbuilder-2d/relic/files/{{MAKE_NAME}}.relic.js +23 -0
  313. package/templates/make-starters/deckbuilder-2d/relic/manifest.json +9 -0
  314. package/templates/retro/platformer/README.md +10 -0
  315. package/templates/retro/platformer/assets/retro/assets.json +91 -0
  316. package/templates/retro/platformer/aura.config.json +7 -0
  317. package/templates/retro/platformer/package.json +5 -0
  318. package/templates/retro/platformer/src/main.js +40 -0
  319. package/templates/retro/puzzle-grid/README.md +10 -0
  320. package/templates/retro/puzzle-grid/assets/retro/assets.json +90 -0
  321. package/templates/retro/puzzle-grid/aura.config.json +7 -0
  322. package/templates/retro/puzzle-grid/package.json +5 -0
  323. package/templates/retro/puzzle-grid/src/main.js +29 -0
  324. package/templates/retro/tactics-grid/README.md +10 -0
  325. package/templates/retro/tactics-grid/assets/retro/assets.json +90 -0
  326. package/templates/retro/tactics-grid/aura.config.json +7 -0
  327. package/templates/retro/tactics-grid/package.json +5 -0
  328. package/templates/retro/tactics-grid/src/main.js +35 -0
  329. package/templates/retro/topdown-adventure/README.md +10 -0
  330. package/templates/retro/topdown-adventure/assets/retro/assets.json +95 -0
  331. package/templates/retro/topdown-adventure/aura.config.json +7 -0
  332. package/templates/retro/topdown-adventure/package.json +5 -0
  333. package/templates/retro/topdown-adventure/src/main.js +29 -0
  334. package/templates/skills/aurajs/SKILL.md +61 -5
@@ -0,0 +1,604 @@
1
+ import { createHash } from 'node:crypto';
2
+ import {
3
+ copyFileSync,
4
+ existsSync,
5
+ mkdirSync,
6
+ readFileSync,
7
+ statSync,
8
+ writeFileSync,
9
+ } from 'node:fs';
10
+ import { basename, dirname, join, resolve } from 'node:path';
11
+
12
+ export const SELF_HOSTED_RELEASE_SCHEMA = 'aurajs.external-assets-release.v1';
13
+ export const SELF_HOSTED_ASSETS_SCHEMA = 'aurajs.external-assets-manifest.v1';
14
+ export const SELF_HOSTED_PLAN_SCHEMA = 'aurajs.external-assets-plan.v1';
15
+ export const SELF_HOSTED_CONFIG_SCHEMA = 'aurajs.external-assets-config.v1';
16
+
17
+ export class SelfHostedAssetsError extends Error {
18
+ constructor(reasonCode, message, details = {}) {
19
+ super(message);
20
+ this.name = 'SelfHostedAssetsError';
21
+ this.reasonCode = typeof reasonCode === 'string' && reasonCode
22
+ ? reasonCode
23
+ : 'external_assets_failed';
24
+ this.details = details && typeof details === 'object' ? details : {};
25
+ }
26
+ }
27
+
28
+ function currentPlatformTarget() {
29
+ if (process.platform === 'win32') return 'windows';
30
+ if (process.platform === 'darwin') return 'mac';
31
+ return 'linux';
32
+ }
33
+
34
+ function readJsonFile(path, label) {
35
+ if (!existsSync(path)) {
36
+ throw new SelfHostedAssetsError(
37
+ 'external_assets_file_missing',
38
+ `${label} not found: ${path}`,
39
+ { path, label },
40
+ );
41
+ }
42
+ try {
43
+ return JSON.parse(readFileSync(path, 'utf8'));
44
+ } catch (error) {
45
+ throw new SelfHostedAssetsError(
46
+ 'external_assets_json_parse_failed',
47
+ `Unable to parse ${label} at ${path}: ${error instanceof Error ? error.message : String(error)}`,
48
+ { path, label },
49
+ );
50
+ }
51
+ }
52
+
53
+ function normalizeSlug(value, label) {
54
+ const normalized = String(value || '').trim().toLowerCase()
55
+ .replace(/[^a-z0-9._-]+/g, '-')
56
+ .replace(/-+/g, '-')
57
+ .replace(/^-+|-+$/g, '');
58
+ if (!normalized) {
59
+ throw new SelfHostedAssetsError(
60
+ 'external_assets_invalid_input',
61
+ `${label} must resolve to a non-empty slug.`,
62
+ { label, value },
63
+ );
64
+ }
65
+ return normalized;
66
+ }
67
+
68
+ function normalizeRelease(value, fallback = '0.1.0') {
69
+ const normalized = String(value || fallback).trim();
70
+ if (!normalized) {
71
+ throw new SelfHostedAssetsError(
72
+ 'external_assets_invalid_input',
73
+ 'release must be a non-empty string.',
74
+ { value },
75
+ );
76
+ }
77
+ return normalized;
78
+ }
79
+
80
+ function normalizeChannel(value) {
81
+ const normalized = String(value || 'latest').trim();
82
+ if (!normalized) {
83
+ throw new SelfHostedAssetsError(
84
+ 'external_assets_invalid_input',
85
+ 'channel must be a non-empty string.',
86
+ { value },
87
+ );
88
+ }
89
+ return normalized;
90
+ }
91
+
92
+ function normalizePublicBaseUrl(value) {
93
+ const normalized = String(value || '').trim().replace(/\/+$/g, '');
94
+ if (!normalized) {
95
+ throw new SelfHostedAssetsError(
96
+ 'external_assets_public_base_url_missing',
97
+ 'external-assets generate requires --public-base-url <url>.',
98
+ );
99
+ }
100
+ let url;
101
+ try {
102
+ url = new URL(normalized);
103
+ } catch (error) {
104
+ throw new SelfHostedAssetsError(
105
+ 'external_assets_public_base_url_invalid',
106
+ `Invalid --public-base-url: ${error instanceof Error ? error.message : String(error)}`,
107
+ { value: normalized },
108
+ );
109
+ }
110
+ if (url.protocol !== 'https:') {
111
+ throw new SelfHostedAssetsError(
112
+ 'external_assets_public_base_url_invalid',
113
+ '--public-base-url must use https:// for the self-hosted public lane.',
114
+ { value: normalized },
115
+ );
116
+ }
117
+ return normalized;
118
+ }
119
+
120
+ function resolveBuildDir(projectRoot, buildDir) {
121
+ if (buildDir) return resolve(projectRoot, buildDir);
122
+ return resolve(projectRoot, 'build', currentPlatformTarget());
123
+ }
124
+
125
+ function sha256File(path) {
126
+ const hash = createHash('sha256');
127
+ hash.update(readFileSync(path));
128
+ return hash.digest('hex');
129
+ }
130
+
131
+ function toPosix(pathLike) {
132
+ return String(pathLike || '').replace(/\\/g, '/');
133
+ }
134
+
135
+ function writeJson(path, value) {
136
+ mkdirSync(dirname(path), { recursive: true });
137
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
138
+ }
139
+
140
+ function ensureBuildManifest(buildManifestPath) {
141
+ const manifest = readJsonFile(buildManifestPath, 'AuraJS build manifest');
142
+ if (manifest?.schema !== 'aurajs.build-manifest.v1') {
143
+ throw new SelfHostedAssetsError(
144
+ 'external_assets_build_manifest_unsupported',
145
+ `Expected aurajs.build-manifest.v1 at ${buildManifestPath}. Run "aura build" for a native target first.`,
146
+ { buildManifestPath },
147
+ );
148
+ }
149
+ return manifest;
150
+ }
151
+
152
+ function ensureAssetsManifest(assetsManifestPath) {
153
+ const manifest = readJsonFile(assetsManifestPath, 'AuraJS assets manifest');
154
+ if (manifest?.schema !== 'aurajs.asset-manifest.v1') {
155
+ throw new SelfHostedAssetsError(
156
+ 'external_assets_assets_manifest_unsupported',
157
+ `Expected aurajs.asset-manifest.v1 at ${assetsManifestPath}.`,
158
+ { assetsManifestPath },
159
+ );
160
+ }
161
+ return manifest;
162
+ }
163
+
164
+ function copyBlobIntoStage({ sourcePath, payloadRoot, sha256 }) {
165
+ const blobKey = `blobs/sha256/${sha256.slice(0, 2)}/${sha256}`;
166
+ const destPath = resolve(payloadRoot, ...blobKey.split('/'));
167
+ if (!existsSync(destPath)) {
168
+ mkdirSync(dirname(destPath), { recursive: true });
169
+ copyFileSync(sourcePath, destPath);
170
+ }
171
+ return { blobKey, destPath };
172
+ }
173
+
174
+ function createUploadRecord({ kind, sourcePath, key, url, sizeBytes, sha256 = null }) {
175
+ return {
176
+ kind,
177
+ sourcePath,
178
+ key,
179
+ url,
180
+ sizeBytes,
181
+ sha256,
182
+ };
183
+ }
184
+
185
+ function parseLongOptions(args) {
186
+ const options = { _: [] };
187
+ for (let index = 0; index < args.length; index += 1) {
188
+ const token = String(args[index] || '');
189
+ if (!token.startsWith('--')) {
190
+ options._.push(token);
191
+ continue;
192
+ }
193
+ if (token === '--json') {
194
+ options.json = true;
195
+ continue;
196
+ }
197
+ if (token.includes('=')) {
198
+ const [rawKey, ...rest] = token.slice(2).split('=');
199
+ options[rawKey] = rest.join('=');
200
+ continue;
201
+ }
202
+ const key = token.slice(2);
203
+ const value = String(args[index + 1] || '').trim();
204
+ if (!value) {
205
+ throw new SelfHostedAssetsError(
206
+ 'external_assets_invalid_args',
207
+ `${token} requires a value.`,
208
+ );
209
+ }
210
+ options[key] = value;
211
+ index += 1;
212
+ }
213
+ return options;
214
+ }
215
+
216
+ function printJson(value) {
217
+ console.log(JSON.stringify(value, null, 2));
218
+ }
219
+
220
+ function printHelp() {
221
+ console.log(`
222
+ aura external-assets generate --public-base-url <url> [options]
223
+
224
+ Generate provider-neutral self-hosted asset metadata for a built AuraJS game.
225
+
226
+ Generate options:
227
+ --public-base-url <url> Public HTTPS base URL where manifests + blobs will live
228
+ --build-dir <path> Build output directory (default: build/<current-platform>)
229
+ --project <slug> Project slug (default: build-manifest identity.executableBaseName)
230
+ --release <version> Release version (default: build-manifest identity.version)
231
+ --channel <name> Release channel (default: latest)
232
+ --stage-dir <path> Override local staging directory
233
+ --config-path <path> Override generated aura.external-assets.json path
234
+ --json Emit machine-readable command output
235
+ `.trimStart());
236
+ }
237
+
238
+ function printGenerateSummary(plan) {
239
+ console.log('\n aura external-assets: staged self-hosted asset metadata.');
240
+ console.log(` Project: ${plan.project}`);
241
+ console.log(` Release: ${plan.release}`);
242
+ console.log(` Channel: ${plan.channel}`);
243
+ console.log(` Build dir: ${plan.buildDir}`);
244
+ console.log(` Stage dir: ${plan.stageDir}`);
245
+ console.log(` Public base URL: ${plan.publicBaseUrl}`);
246
+ console.log(` Provider: ${plan.provider}`);
247
+ console.log(` Unique blobs: ${plan.uniqueBlobCount}`);
248
+ console.log(` Blob bytes: ${plan.totalBlobBytes}`);
249
+ console.log(` Upload records: ${plan.uploads.length}`);
250
+ console.log(` Plan: ${plan.publishPlanPath}`);
251
+ console.log(` Config: ${plan.configPath}`);
252
+ console.log('');
253
+ console.log(' Staged manifests:');
254
+ console.log(` build: ${plan.manifests.buildManifestPath}`);
255
+ console.log(` assets: ${plan.manifests.assetsManifestPath}`);
256
+ console.log(` release: ${plan.manifests.releaseManifestPath}`);
257
+ console.log('');
258
+ }
259
+
260
+ export function stageSelfHostedAssets(options = {}) {
261
+ const projectRoot = resolve(options.projectRoot || process.cwd());
262
+ const buildDir = resolveBuildDir(projectRoot, options.buildDir);
263
+ const buildManifestPath = resolve(buildDir, 'build-manifest.json');
264
+ const buildManifest = ensureBuildManifest(buildManifestPath);
265
+ const assetsManifestPath = resolve(buildDir, buildManifest.assetsManifest);
266
+ const assetsManifest = ensureAssetsManifest(assetsManifestPath);
267
+ const publicBaseUrl = normalizePublicBaseUrl(options.publicBaseUrl);
268
+
269
+ const project = normalizeSlug(
270
+ options.project
271
+ || buildManifest?.identity?.executableBaseName
272
+ || basename(projectRoot),
273
+ 'project',
274
+ );
275
+ const release = normalizeRelease(
276
+ options.release || buildManifest?.identity?.version || '0.1.0',
277
+ );
278
+ const channel = normalizeChannel(options.channel);
279
+ const stageNamespace = options.stageNamespace || 'external-assets';
280
+ const stageDir = resolve(options.stageDir || join(projectRoot, '.aura', stageNamespace, project, release));
281
+ const payloadRoot = resolve(stageDir, 'payload');
282
+ const releasePrefix = `releases/${project}/${release}`;
283
+ const releaseRoot = resolve(payloadRoot, ...releasePrefix.split('/'));
284
+ const createdAt = new Date().toISOString();
285
+ const provider = String(options.provider || 'self-hosted').trim() || 'self-hosted';
286
+ const schemas = {
287
+ release: options.schemas?.release || SELF_HOSTED_RELEASE_SCHEMA,
288
+ assets: options.schemas?.assets || SELF_HOSTED_ASSETS_SCHEMA,
289
+ plan: options.schemas?.plan || SELF_HOSTED_PLAN_SCHEMA,
290
+ config: options.schemas?.config || SELF_HOSTED_CONFIG_SCHEMA,
291
+ };
292
+ const storage = {
293
+ publicBaseUrl,
294
+ releasePrefix,
295
+ blobPrefix: 'blobs/sha256',
296
+ ...(options.storageExtra && typeof options.storageExtra === 'object' ? options.storageExtra : {}),
297
+ };
298
+
299
+ const blobUploads = [];
300
+ const uniqueBlobs = new Map();
301
+ const createBlobDescriptor = (sourcePath) => {
302
+ const stats = statSync(sourcePath);
303
+ const sha256 = sha256File(sourcePath);
304
+ const cached = uniqueBlobs.get(sha256);
305
+ if (cached) {
306
+ return cached;
307
+ }
308
+ const copied = copyBlobIntoStage({ sourcePath, payloadRoot, sha256 });
309
+ const descriptor = {
310
+ sha256,
311
+ sizeBytes: stats.size,
312
+ blobKey: copied.blobKey,
313
+ blobUrl: `${publicBaseUrl}/${copied.blobKey}`,
314
+ stagedPath: copied.destPath,
315
+ sourcePath,
316
+ };
317
+ uniqueBlobs.set(sha256, descriptor);
318
+ blobUploads.push(createUploadRecord({
319
+ kind: 'blob',
320
+ sourcePath: copied.destPath,
321
+ key: copied.blobKey,
322
+ url: descriptor.blobUrl,
323
+ sizeBytes: descriptor.sizeBytes,
324
+ sha256,
325
+ }));
326
+ return descriptor;
327
+ };
328
+
329
+ let publicAssetsManifest;
330
+ if (assetsManifest.mode === 'embed') {
331
+ const packFile = assetsManifest?.pack?.file;
332
+ if (!packFile) {
333
+ throw new SelfHostedAssetsError(
334
+ 'external_assets_pack_missing',
335
+ `Embedded assets manifest at ${assetsManifestPath} is missing pack.file`,
336
+ { assetsManifestPath },
337
+ );
338
+ }
339
+ const packSourcePath = resolve(buildDir, packFile);
340
+ const packBlob = createBlobDescriptor(packSourcePath);
341
+ publicAssetsManifest = {
342
+ schema: schemas.assets,
343
+ createdAt,
344
+ provider,
345
+ project,
346
+ release,
347
+ channel,
348
+ sourceSchema: assetsManifest.schema,
349
+ sourceManifestHash: assetsManifest.manifestHash || null,
350
+ assetMode: assetsManifest.mode,
351
+ runtimeResolver: assetsManifest.runtimeResolver || buildManifest.runtimeResolver || null,
352
+ storage,
353
+ pack: {
354
+ ...assetsManifest.pack,
355
+ sha256: packBlob.sha256,
356
+ blobKey: packBlob.blobKey,
357
+ blobUrl: packBlob.blobUrl,
358
+ },
359
+ entries: Array.isArray(assetsManifest.entries)
360
+ ? assetsManifest.entries.map((entry) => ({
361
+ ...entry,
362
+ packBlobKey: packBlob.blobKey,
363
+ packBlobUrl: packBlob.blobUrl,
364
+ }))
365
+ : [],
366
+ };
367
+ } else if (assetsManifest.mode === 'sibling') {
368
+ publicAssetsManifest = {
369
+ schema: schemas.assets,
370
+ createdAt,
371
+ provider,
372
+ project,
373
+ release,
374
+ channel,
375
+ sourceSchema: assetsManifest.schema,
376
+ sourceManifestHash: assetsManifest.manifestHash || null,
377
+ assetMode: assetsManifest.mode,
378
+ runtimeResolver: assetsManifest.runtimeResolver || buildManifest.runtimeResolver || null,
379
+ storage,
380
+ entries: Array.isArray(assetsManifest.entries)
381
+ ? assetsManifest.entries.map((entry) => {
382
+ const sourceFile = entry.file || `assets/${entry.path}`;
383
+ const sourcePath = resolve(buildDir, sourceFile);
384
+ const blob = createBlobDescriptor(sourcePath);
385
+ return {
386
+ path: entry.path,
387
+ kind: entry.kind,
388
+ sizeBytes: entry.sizeBytes,
389
+ sha1: entry.sha1 || null,
390
+ sha256: blob.sha256,
391
+ sourceFile: toPosix(sourceFile),
392
+ blobKey: blob.blobKey,
393
+ blobUrl: blob.blobUrl,
394
+ };
395
+ })
396
+ : [],
397
+ };
398
+ } else {
399
+ throw new SelfHostedAssetsError(
400
+ 'external_assets_asset_mode_unsupported',
401
+ `Unsupported asset mode "${assetsManifest.mode}". Expected "embed" or "sibling".`,
402
+ { mode: assetsManifest.mode },
403
+ );
404
+ }
405
+
406
+ const publicAssetsManifestPath = resolve(releaseRoot, 'assets-manifest.json');
407
+ writeJson(publicAssetsManifestPath, publicAssetsManifest);
408
+
409
+ const releaseManifestUrl = `${publicBaseUrl}/${releasePrefix}/release.json`;
410
+ const assetsManifestUrl = `${publicBaseUrl}/${releasePrefix}/assets-manifest.json`;
411
+ const publicBuildManifest = {
412
+ ...buildManifest,
413
+ distribution: {
414
+ mode: options.distributionMode || 'npm+self-hosted-assets',
415
+ provider,
416
+ project,
417
+ release,
418
+ channel,
419
+ releaseManifestUrl,
420
+ assetsManifestUrl,
421
+ ...(options.buildManifestDistributionExtra && typeof options.buildManifestDistributionExtra === 'object'
422
+ ? options.buildManifestDistributionExtra
423
+ : {}),
424
+ },
425
+ };
426
+ const publicBuildManifestPath = resolve(releaseRoot, 'build-manifest.json');
427
+ writeJson(publicBuildManifestPath, publicBuildManifest);
428
+
429
+ const releaseManifest = {
430
+ schema: schemas.release,
431
+ createdAt,
432
+ mode: options.planMode || 'stage-only-self-hosted',
433
+ provider,
434
+ project,
435
+ release,
436
+ channel,
437
+ buildDir,
438
+ storage,
439
+ manifests: {
440
+ build: {
441
+ key: `${releasePrefix}/build-manifest.json`,
442
+ url: `${publicBaseUrl}/${releasePrefix}/build-manifest.json`,
443
+ },
444
+ assets: {
445
+ key: `${releasePrefix}/assets-manifest.json`,
446
+ url: assetsManifestUrl,
447
+ },
448
+ },
449
+ blobSummary: {
450
+ uniqueBlobCount: uniqueBlobs.size,
451
+ totalBlobBytes: [...uniqueBlobs.values()].reduce((sum, entry) => sum + entry.sizeBytes, 0),
452
+ assetMode: assetsManifest.mode,
453
+ },
454
+ notes: Array.isArray(options.releaseNotes) ? options.releaseNotes : [],
455
+ };
456
+ const releaseManifestPath = resolve(releaseRoot, 'release.json');
457
+ writeJson(releaseManifestPath, releaseManifest);
458
+
459
+ const manifestUploads = [
460
+ createUploadRecord({
461
+ kind: 'manifest',
462
+ sourcePath: publicBuildManifestPath,
463
+ key: `${releasePrefix}/build-manifest.json`,
464
+ url: `${publicBaseUrl}/${releasePrefix}/build-manifest.json`,
465
+ sizeBytes: statSync(publicBuildManifestPath).size,
466
+ }),
467
+ createUploadRecord({
468
+ kind: 'manifest',
469
+ sourcePath: publicAssetsManifestPath,
470
+ key: `${releasePrefix}/assets-manifest.json`,
471
+ url: assetsManifestUrl,
472
+ sizeBytes: statSync(publicAssetsManifestPath).size,
473
+ }),
474
+ createUploadRecord({
475
+ kind: 'manifest',
476
+ sourcePath: releaseManifestPath,
477
+ key: `${releasePrefix}/release.json`,
478
+ url: releaseManifestUrl,
479
+ sizeBytes: statSync(releaseManifestPath).size,
480
+ }),
481
+ ];
482
+
483
+ const configPath = resolve(options.configPath || join(projectRoot, options.configFilename || 'aura.external-assets.json'));
484
+ const config = {
485
+ schema: schemas.config,
486
+ mode: options.configMode || 'self-hosted',
487
+ project,
488
+ release,
489
+ channel,
490
+ provider,
491
+ releaseManifestUrl,
492
+ assetsManifestUrl,
493
+ generatedAt: createdAt,
494
+ ...(options.configExtra && typeof options.configExtra === 'object' ? options.configExtra : {}),
495
+ };
496
+ writeJson(configPath, config);
497
+
498
+ const publishPlan = {
499
+ schema: schemas.plan,
500
+ createdAt,
501
+ provider,
502
+ mode: options.planMode || 'stage-only-self-hosted',
503
+ project,
504
+ release,
505
+ channel,
506
+ projectRoot,
507
+ buildDir,
508
+ stageDir,
509
+ configPath,
510
+ summary: {
511
+ assetMode: assetsManifest.mode,
512
+ uniqueBlobCount: uniqueBlobs.size,
513
+ manifestCount: manifestUploads.length,
514
+ totalUploadBytes: [...blobUploads, ...manifestUploads].reduce((sum, entry) => sum + entry.sizeBytes, 0),
515
+ },
516
+ uploads: [...manifestUploads, ...blobUploads],
517
+ nextSteps: Array.isArray(options.planNextSteps) && options.planNextSteps.length > 0
518
+ ? options.planNextSteps
519
+ : [
520
+ 'Verify the staged release metadata under the stageDir.',
521
+ 'Upload manifests to releases/<project>/<release>/ at the public base URL origin.',
522
+ 'Upload all referenced blob keys under blobs/sha256/<prefix>/<sha256>.',
523
+ 'Publish the slim npm package only after the generated aura.external-assets.json is present.',
524
+ ],
525
+ ...(options.planExtra && typeof options.planExtra === 'object' ? options.planExtra : {}),
526
+ };
527
+ const publishPlanPath = resolve(stageDir, 'publish-plan.json');
528
+ writeJson(publishPlanPath, publishPlan);
529
+
530
+ return {
531
+ publishPlanPath,
532
+ stageDir,
533
+ buildDir,
534
+ project,
535
+ release,
536
+ channel,
537
+ publicBaseUrl,
538
+ provider,
539
+ uniqueBlobCount: uniqueBlobs.size,
540
+ totalBlobBytes: releaseManifest.blobSummary.totalBlobBytes,
541
+ uploads: publishPlan.uploads,
542
+ manifests: {
543
+ buildManifestPath: publicBuildManifestPath,
544
+ assetsManifestPath: publicAssetsManifestPath,
545
+ releaseManifestPath,
546
+ },
547
+ configPath,
548
+ };
549
+ }
550
+
551
+ function runGenerate(options) {
552
+ const plan = stageSelfHostedAssets({
553
+ projectRoot: process.cwd(),
554
+ buildDir: options['build-dir'] || null,
555
+ project: options.project || null,
556
+ release: options.release || null,
557
+ channel: options.channel || null,
558
+ stageDir: options['stage-dir'] || null,
559
+ publicBaseUrl: options['public-base-url'] || null,
560
+ configPath: options['config-path'] || null,
561
+ });
562
+
563
+ if (options.json) {
564
+ printJson({
565
+ ok: true,
566
+ reasonCode: 'external_assets_generate_staged',
567
+ publishPlanPath: plan.publishPlanPath,
568
+ stageDir: plan.stageDir,
569
+ project: plan.project,
570
+ release: plan.release,
571
+ channel: plan.channel,
572
+ publicBaseUrl: plan.publicBaseUrl,
573
+ provider: plan.provider,
574
+ uniqueBlobCount: plan.uniqueBlobCount,
575
+ totalBlobBytes: plan.totalBlobBytes,
576
+ uploadCount: plan.uploads.length,
577
+ manifests: plan.manifests,
578
+ configPath: plan.configPath,
579
+ });
580
+ return;
581
+ }
582
+
583
+ printGenerateSummary(plan);
584
+ }
585
+
586
+ export async function runExternalAssetsCommand(args = []) {
587
+ const [firstArg, ...restArgs] = args;
588
+ if (!firstArg || firstArg === 'generate') {
589
+ runGenerate(parseLongOptions(firstArg ? restArgs : args));
590
+ return;
591
+ }
592
+ if (firstArg === '--help' || firstArg === '-h' || firstArg === 'help') {
593
+ printHelp();
594
+ return;
595
+ }
596
+ if (firstArg.startsWith('--')) {
597
+ runGenerate(parseLongOptions(args));
598
+ return;
599
+ }
600
+ throw new SelfHostedAssetsError(
601
+ 'external_assets_invalid_args',
602
+ `Unknown external-assets subcommand "${firstArg}". Supported subcommands: generate.`,
603
+ );
604
+ }