@auraindustry/aurajs 0.0.7 → 0.1.0

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 +5 -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 +4825 -1512
  17. package/src/commands/project-authoring.mjs +434 -0
  18. package/src/config.mjs +27 -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 +438 -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 +40 -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 +14 -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 +443 -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 +60 -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 +1187 -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,278 @@
1
+ import { mkdirSync, writeFileSync } from 'node:fs';
2
+ import { resolve, basename } from 'node:path';
3
+ import { explainRetroProject } from './validator/check-project.mjs';
4
+ import { RetroCompileError } from './diagnostics/emit.mjs';
5
+ import { getRetroTargetProfile } from './shared/targets.mjs';
6
+ import { relFile } from './shared/span.mjs';
7
+ import { buildRetroIr } from './ir/build-ir.mjs';
8
+ import { buildGameBoyRom } from './backend-gbc/rom.mjs';
9
+ import {
10
+ buildGameBoyAdvanceRom,
11
+ buildPlayableGameBoyAdvancePayload,
12
+ } from './backend-gba/rom.mjs';
13
+ import { compileRetroAssets } from './assets/compile.mjs';
14
+
15
+ function createPreviewSource({ targetProfile, identity, report }) {
16
+ const moduleList = report.modules.map((entry) => ` * - ${relFile(report.projectRoot, entry.filePath)}`).join('\n');
17
+ return [
18
+ '/*',
19
+ ` * Aura Retro preview source bundle`,
20
+ ` * Target: ${targetProfile.target} (${targetProfile.displayName})`,
21
+ ` * Game: ${identity.name} ${identity.version}`,
22
+ ' *',
23
+ ' * This preview lane validates the supported Aura Retro subset and emits',
24
+ ' * cartridge-oriented scaffold sources without changing the default desktop runtime.',
25
+ ' */',
26
+ '',
27
+ '#include <stdint.h>',
28
+ '',
29
+ `#define AURA_RETRO_TARGET_${targetProfile.target.toUpperCase()} 1`,
30
+ '',
31
+ 'typedef struct AuraRetroState {',
32
+ ' uint32_t frame;',
33
+ '} AuraRetroState;',
34
+ '',
35
+ 'static AuraRetroState state = {0};',
36
+ '',
37
+ 'static void aura_setup(void) {',
38
+ ' state.frame = 0;',
39
+ '}',
40
+ '',
41
+ 'static void aura_update(void) {',
42
+ ' state.frame += 1;',
43
+ '}',
44
+ '',
45
+ 'static void aura_draw(void) {',
46
+ ' (void)state.frame;',
47
+ '}',
48
+ '',
49
+ 'int main(void) {',
50
+ ' aura_setup();',
51
+ ' for (;;) {',
52
+ ' aura_update();',
53
+ ' aura_draw();',
54
+ ' }',
55
+ ' return 0;',
56
+ '}',
57
+ '',
58
+ '/* Source modules validated for this preview build:',
59
+ moduleList || ' * - <none>',
60
+ ' */',
61
+ '',
62
+ ].join('\n');
63
+ }
64
+
65
+ function createToolchainNotes({ targetProfile, report, gbaRuntime = null }) {
66
+ const outputNotes = targetProfile.family === 'gb' || targetProfile.family === 'gba'
67
+ ? [
68
+ 'This build lane emits a cartridge ROM, analysis report, IR, asset manifest, and preview C source.',
69
+ 'Use the ROM artifact for smoke checks and the preview source bundle to inspect compiler output.',
70
+ ]
71
+ : [
72
+ 'This build lane currently emits validated preview sources, manifests, and analysis artifacts.',
73
+ 'A final cartridge ROM toolchain is still a follow-up task for this target.',
74
+ ];
75
+ return [
76
+ `Aura Retro preview build for ${targetProfile.displayName}`,
77
+ '',
78
+ `Validated entry: ${relFile(report.projectRoot, report.entryFile)}`,
79
+ `Modules: ${report.moduleCount}`,
80
+ `Suggested toolchain: ${targetProfile.suggestedToolchain}`,
81
+ ...(targetProfile.family === 'gba'
82
+ ? [`Runtime mode: ${gbaRuntime?.mode || 'header-stub'}`]
83
+ : []),
84
+ '',
85
+ ...outputNotes,
86
+ '',
87
+ ].join('\n');
88
+ }
89
+
90
+ function buildRetroRom({
91
+ identity,
92
+ targetProfile,
93
+ ir,
94
+ generatedDir,
95
+ report,
96
+ assets,
97
+ logOutput,
98
+ }) {
99
+ if (targetProfile.family === 'gb') {
100
+ return {
101
+ romBytes: buildGameBoyRom({ identity, targetProfile, ir }),
102
+ runtimeMode: 'header-stub',
103
+ runtimeArtifacts: null,
104
+ };
105
+ }
106
+ if (targetProfile.family === 'gba') {
107
+ const gbaRuntime = buildPlayableGameBoyAdvancePayload({
108
+ identity,
109
+ generatedDir,
110
+ entryFile: report.entryFile,
111
+ ir,
112
+ assets: assets.compiled,
113
+ logOutput,
114
+ });
115
+ return {
116
+ romBytes: buildGameBoyAdvanceRom({
117
+ identity,
118
+ targetProfile,
119
+ ir,
120
+ payload: gbaRuntime.ok ? gbaRuntime.payload : null,
121
+ }),
122
+ runtimeMode: gbaRuntime.mode,
123
+ runtimeArtifacts: gbaRuntime.ok
124
+ ? {
125
+ runtimeSourcePath: gbaRuntime.runtimeSourcePath,
126
+ linkerScriptPath: gbaRuntime.linkerScriptPath,
127
+ objectPath: gbaRuntime.objectPath,
128
+ elfPath: gbaRuntime.elfPath,
129
+ binaryPath: gbaRuntime.binaryPath,
130
+ }
131
+ : null,
132
+ };
133
+ }
134
+ return {
135
+ romBytes: null,
136
+ runtimeMode: 'preview-only',
137
+ runtimeArtifacts: null,
138
+ };
139
+ }
140
+
141
+ export function buildRetroProject({
142
+ projectRoot,
143
+ config,
144
+ entryFile,
145
+ target,
146
+ identity,
147
+ logOutput = true,
148
+ }) {
149
+ const targetProfile = getRetroTargetProfile(target);
150
+ const report = explainRetroProject({
151
+ projectRoot,
152
+ entryFile,
153
+ target,
154
+ });
155
+ const ir = report.ok
156
+ ? buildRetroIr({
157
+ projectRoot,
158
+ entryFile,
159
+ target,
160
+ })
161
+ : null;
162
+
163
+ if (!report.ok) {
164
+ throw new RetroCompileError(
165
+ 'retro_build_blocked_by_diagnostics',
166
+ `Aura Retro build blocked for target "${target}".`,
167
+ { diagnostics: report.diagnostics, report },
168
+ );
169
+ }
170
+
171
+ const targetOutRoot = resolve(projectRoot, config.build.outDir, target);
172
+ const generatedDir = resolve(targetOutRoot, 'generated');
173
+ mkdirSync(generatedDir, { recursive: true });
174
+ const assets = compileRetroAssets({
175
+ projectRoot,
176
+ target,
177
+ emitCompiled: true,
178
+ outRoot: targetOutRoot,
179
+ });
180
+
181
+ const manifestPath = resolve(targetOutRoot, 'retro-build-manifest.json');
182
+ const analysisPath = resolve(targetOutRoot, 'retro-analysis.json');
183
+ const irPath = resolve(targetOutRoot, 'retro-ir.json');
184
+ const previewSourcePath = resolve(generatedDir, 'cartridge-preview.c');
185
+ const toolchainNotesPath = resolve(targetOutRoot, 'toolchain-notes.txt');
186
+ const retroRom = buildRetroRom({
187
+ identity,
188
+ targetProfile,
189
+ ir,
190
+ generatedDir,
191
+ report,
192
+ assets,
193
+ logOutput,
194
+ });
195
+ const romPath = retroRom.romBytes
196
+ ? resolve(targetOutRoot, `${identity.executableBaseName}${targetProfile.outputExtension}`)
197
+ : null;
198
+
199
+ const manifest = {
200
+ schemaVersion: 1,
201
+ artifactKind: romPath ? 'retro-rom-build' : 'retro-preview-build',
202
+ reasonCode: romPath ? 'retro_build_rom_ready' : 'retro_build_preview_ready',
203
+ target,
204
+ displayName: targetProfile.displayName,
205
+ architecture: targetProfile.architecture,
206
+ colorMode: targetProfile.colorMode,
207
+ projectRoot,
208
+ entryFile: report.entryFile,
209
+ moduleCount: report.moduleCount,
210
+ assetsPath: assets.outputPath,
211
+ assetSummary: assets.summary,
212
+ irPath,
213
+ romPath,
214
+ runtimeMode: retroRom.runtimeMode,
215
+ runtimeArtifacts: retroRom.runtimeArtifacts,
216
+ previewSourcePath,
217
+ analysisPath,
218
+ toolchainNotesPath,
219
+ };
220
+
221
+ writeFileSync(analysisPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
222
+ writeFileSync(irPath, `${JSON.stringify(ir, null, 2)}\n`, 'utf8');
223
+ if (romPath) {
224
+ writeFileSync(romPath, retroRom.romBytes);
225
+ }
226
+ writeFileSync(previewSourcePath, createPreviewSource({ targetProfile, identity, report }), 'utf8');
227
+ writeFileSync(toolchainNotesPath, createToolchainNotes({
228
+ targetProfile,
229
+ report,
230
+ gbaRuntime: {
231
+ mode: retroRom.runtimeMode,
232
+ },
233
+ }), 'utf8');
234
+ writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
235
+
236
+ if (logOutput) {
237
+ console.log('\n aura build: complete.');
238
+ console.log(` Game: ${identity.name}`);
239
+ console.log(` Version: ${identity.version}`);
240
+ console.log(` Output target: ${target}`);
241
+ console.log(` Retro profile: ${targetProfile.displayName}`);
242
+ console.log(` Modules: ${report.moduleCount}`);
243
+ console.log(` Assets: ${assets.summary ? `palettes=${assets.summary.paletteCount} tiles=${assets.summary.tileCount} sprites=${assets.summary.spriteCount} fonts=${assets.summary.fontCount}` : 'none'}`);
244
+ if (romPath) {
245
+ console.log(` ROM artifact: ${basename(romPath)}`);
246
+ } else {
247
+ console.log(' ROM artifact: not emitted for this target yet');
248
+ }
249
+ if (targetProfile.family === 'gba') {
250
+ console.log(` GBA runtime: ${retroRom.runtimeMode}`);
251
+ }
252
+ console.log(` Artifact mode: ${romPath ? 'retro ROM + preview source bundle' : 'retro preview source bundle'}`);
253
+ console.log('');
254
+ }
255
+
256
+ return {
257
+ projectRoot,
258
+ config,
259
+ requestedTarget: target,
260
+ platformTarget: null,
261
+ effectiveTarget: target,
262
+ targetKind: 'retro',
263
+ targetOutRoot,
264
+ executablePath: null,
265
+ launchExecutablePath: null,
266
+ bundlePath: null,
267
+ buildManifestPath: manifestPath,
268
+ assetsManifestPath: null,
269
+ assetMode: 'retro-assets',
270
+ identity,
271
+ retroAnalysisPath: analysisPath,
272
+ retroAssetsPath: assets.outputPath,
273
+ retroIrPath: irPath,
274
+ romPath,
275
+ previewSourcePath,
276
+ toolchainNotesPath,
277
+ };
278
+ }
@@ -0,0 +1,292 @@
1
+ import { explainRetroProject } from '../validator/check-project.mjs';
2
+ import { formatRetroDiagnosticReport } from '../diagnostics/emit.mjs';
3
+ import { isRetroBuildTarget } from '../shared/targets.mjs';
4
+ import { runRetroEmulator, smokeRetroEmulator } from '../emulator/runner.mjs';
5
+
6
+ class RetroCliArgumentError extends Error {
7
+ constructor(message) {
8
+ super(message);
9
+ this.name = 'RetroCliArgumentError';
10
+ }
11
+ }
12
+
13
+ function parseRetroArgs(args) {
14
+ const parsed = {
15
+ entryFile: null,
16
+ json: false,
17
+ compact: false,
18
+ target: 'gbc',
19
+ };
20
+
21
+ let positionalSeen = false;
22
+ for (let index = 0; index < args.length; index += 1) {
23
+ const token = String(args[index] || '');
24
+ if (token === '--json') {
25
+ parsed.json = true;
26
+ continue;
27
+ }
28
+ if (token === '--compact') {
29
+ parsed.compact = true;
30
+ continue;
31
+ }
32
+ if (token === '--entry') {
33
+ if ((index + 1) >= args.length) {
34
+ throw new RetroCliArgumentError('--entry requires a file path.');
35
+ }
36
+ parsed.entryFile = String(args[index + 1] || '');
37
+ index += 1;
38
+ continue;
39
+ }
40
+ if (token.startsWith('--entry=')) {
41
+ parsed.entryFile = token.slice('--entry='.length);
42
+ continue;
43
+ }
44
+ if (token === '--target') {
45
+ if ((index + 1) >= args.length) {
46
+ throw new RetroCliArgumentError('--target requires a value.');
47
+ }
48
+ parsed.target = String(args[index + 1] || '').trim().toLowerCase();
49
+ index += 1;
50
+ continue;
51
+ }
52
+ if (token.startsWith('--target=')) {
53
+ parsed.target = token.slice('--target='.length).trim().toLowerCase();
54
+ continue;
55
+ }
56
+ if (token.startsWith('--')) {
57
+ throw new RetroCliArgumentError(`Unknown retro option: ${token}`);
58
+ }
59
+ if (positionalSeen) {
60
+ throw new RetroCliArgumentError(`Unexpected argument: ${token}`);
61
+ }
62
+ parsed.entryFile = token;
63
+ positionalSeen = true;
64
+ }
65
+
66
+ if (!isRetroBuildTarget(parsed.target)) {
67
+ throw new RetroCliArgumentError(`Unsupported retro target "${parsed.target}". Supported values: gb, gbc, gba.`);
68
+ }
69
+
70
+ return parsed;
71
+ }
72
+
73
+ function parseRetroLaunchArgs(args, { allowJson = false, smoke = false } = {}) {
74
+ const parsed = {
75
+ target: null,
76
+ romPath: null,
77
+ emulator: null,
78
+ scale: null,
79
+ caseOverlay: false,
80
+ timeoutMs: 1500,
81
+ json: false,
82
+ compact: false,
83
+ headless: false,
84
+ };
85
+
86
+ for (let index = 0; index < args.length; index += 1) {
87
+ const token = String(args[index] || '');
88
+ if (token === '--target') {
89
+ if ((index + 1) >= args.length) {
90
+ throw new RetroCliArgumentError('--target requires a value.');
91
+ }
92
+ parsed.target = String(args[index + 1] || '').trim().toLowerCase();
93
+ index += 1;
94
+ continue;
95
+ }
96
+ if (token.startsWith('--target=')) {
97
+ parsed.target = token.slice('--target='.length).trim().toLowerCase();
98
+ continue;
99
+ }
100
+ if (token === '--rom') {
101
+ if ((index + 1) >= args.length) {
102
+ throw new RetroCliArgumentError('--rom requires a file path.');
103
+ }
104
+ parsed.romPath = String(args[index + 1] || '');
105
+ index += 1;
106
+ continue;
107
+ }
108
+ if (token.startsWith('--rom=')) {
109
+ parsed.romPath = token.slice('--rom='.length);
110
+ continue;
111
+ }
112
+ if (token === '--emulator') {
113
+ if ((index + 1) >= args.length) {
114
+ throw new RetroCliArgumentError('--emulator requires a path or command name.');
115
+ }
116
+ parsed.emulator = String(args[index + 1] || '');
117
+ index += 1;
118
+ continue;
119
+ }
120
+ if (token.startsWith('--emulator=')) {
121
+ parsed.emulator = token.slice('--emulator='.length);
122
+ continue;
123
+ }
124
+ if (token === '--scale') {
125
+ if ((index + 1) >= args.length) {
126
+ throw new RetroCliArgumentError('--scale requires a numeric value.');
127
+ }
128
+ parsed.scale = Number(args[index + 1]);
129
+ index += 1;
130
+ continue;
131
+ }
132
+ if (token.startsWith('--scale=')) {
133
+ parsed.scale = Number(token.slice('--scale='.length));
134
+ continue;
135
+ }
136
+ if (token === '--case') {
137
+ if (smoke) {
138
+ throw new RetroCliArgumentError('--case is only supported for `aura retro run`.');
139
+ }
140
+ parsed.caseOverlay = true;
141
+ continue;
142
+ }
143
+ if (token === '--timeout-ms') {
144
+ if ((index + 1) >= args.length) {
145
+ throw new RetroCliArgumentError('--timeout-ms requires a numeric value.');
146
+ }
147
+ parsed.timeoutMs = Number(args[index + 1]);
148
+ index += 1;
149
+ continue;
150
+ }
151
+ if (token.startsWith('--timeout-ms=')) {
152
+ parsed.timeoutMs = Number(token.slice('--timeout-ms='.length));
153
+ continue;
154
+ }
155
+ if (token === '--headless') {
156
+ parsed.headless = true;
157
+ continue;
158
+ }
159
+ if (token === '--json') {
160
+ if (!allowJson) {
161
+ throw new RetroCliArgumentError('--json is only supported for `aura retro smoke`.');
162
+ }
163
+ parsed.json = true;
164
+ continue;
165
+ }
166
+ if (token === '--compact') {
167
+ if (!allowJson) {
168
+ throw new RetroCliArgumentError('--compact is only supported for `aura retro smoke --json`.');
169
+ }
170
+ parsed.compact = true;
171
+ continue;
172
+ }
173
+ if (token.startsWith('--')) {
174
+ throw new RetroCliArgumentError(`Unknown retro option: ${token}`);
175
+ }
176
+ throw new RetroCliArgumentError(`Unexpected argument: ${token}`);
177
+ }
178
+
179
+ if (parsed.target && !isRetroBuildTarget(parsed.target)) {
180
+ throw new RetroCliArgumentError(`Unsupported retro target "${parsed.target}". Supported values: gb, gbc, gba.`);
181
+ }
182
+ if (parsed.scale != null && (!Number.isFinite(parsed.scale) || parsed.scale <= 0)) {
183
+ throw new RetroCliArgumentError('--scale must be a positive number.');
184
+ }
185
+ if (!parsed.target && !parsed.romPath) {
186
+ parsed.target = 'gbc';
187
+ }
188
+ if (parsed.caseOverlay && parsed.scale == null) {
189
+ parsed.scale = 4;
190
+ }
191
+ if (smoke && (!Number.isFinite(parsed.timeoutMs) || parsed.timeoutMs <= 0)) {
192
+ throw new RetroCliArgumentError('--timeout-ms must be a positive number.');
193
+ }
194
+ return parsed;
195
+ }
196
+
197
+ function writeRetroReport(report, parsed) {
198
+ if (parsed.json) {
199
+ const payload = parsed.compact ? JSON.stringify(report) : JSON.stringify(report, null, 2);
200
+ process.stdout.write(`${payload}\n`);
201
+ return;
202
+ }
203
+ process.stdout.write(`${formatRetroDiagnosticReport(report, report.projectRoot)}\n`);
204
+ }
205
+
206
+ export function runRetroCheckCommand(args = []) {
207
+ const parsed = parseRetroArgs(args);
208
+ const report = explainRetroProject({
209
+ entryFile: parsed.entryFile || 'src/main.js',
210
+ target: parsed.target,
211
+ });
212
+ writeRetroReport(report, parsed);
213
+ if (!report.ok) {
214
+ process.exitCode = 7;
215
+ }
216
+ }
217
+
218
+ export function runRetroExplainCommand(args = []) {
219
+ const parsed = parseRetroArgs(args);
220
+ const report = explainRetroProject({
221
+ entryFile: parsed.entryFile || 'src/main.js',
222
+ target: parsed.target,
223
+ });
224
+ writeRetroReport(report, parsed);
225
+ if (!report.ok) {
226
+ process.exitCode = 7;
227
+ }
228
+ }
229
+
230
+ export async function runRetroRunCommand(args = []) {
231
+ const parsed = parseRetroLaunchArgs(args, { allowJson: false, smoke: false });
232
+ await runRetroEmulator({
233
+ projectRoot: process.cwd(),
234
+ target: parsed.target,
235
+ romPath: parsed.romPath,
236
+ emulator: parsed.emulator,
237
+ scale: parsed.scale,
238
+ caseOverlay: parsed.caseOverlay,
239
+ headless: parsed.headless,
240
+ });
241
+ }
242
+
243
+ export async function runRetroSmokeCommand(args = []) {
244
+ const parsed = parseRetroLaunchArgs(args, { allowJson: true, smoke: true });
245
+ const result = await smokeRetroEmulator({
246
+ projectRoot: process.cwd(),
247
+ target: parsed.target,
248
+ romPath: parsed.romPath,
249
+ emulator: parsed.emulator,
250
+ timeoutMs: parsed.timeoutMs,
251
+ });
252
+ if (parsed.json) {
253
+ const payload = parsed.compact ? JSON.stringify(result) : JSON.stringify(result, null, 2);
254
+ process.stdout.write(`${payload}\n`);
255
+ return;
256
+ }
257
+ if (result.status === 'skipped') {
258
+ process.stdout.write(
259
+ `Aura Retro smoke skipped (${result.target}): no supported emulator found. Tried: ${result.checked.map((entry) => entry.command).join(', ') || '<none>'}.\n`,
260
+ );
261
+ return;
262
+ }
263
+ process.stdout.write(
264
+ `Aura Retro smoke passed (${result.target}) using ${result.emulatorId} on ${result.romPath}.\n`,
265
+ );
266
+ }
267
+
268
+ export async function runRetroCommand(args = []) {
269
+ const subcommand = String(args[0] || '').trim();
270
+ if (!subcommand) {
271
+ throw new RetroCliArgumentError('Missing retro subcommand. Usage: aura retro <check|explain|run|smoke> [options]');
272
+ }
273
+ if (subcommand === 'check') {
274
+ runRetroCheckCommand(args.slice(1));
275
+ return;
276
+ }
277
+ if (subcommand === 'explain') {
278
+ runRetroExplainCommand(args.slice(1));
279
+ return;
280
+ }
281
+ if (subcommand === 'run') {
282
+ await runRetroRunCommand(args.slice(1));
283
+ return;
284
+ }
285
+ if (subcommand === 'smoke') {
286
+ await runRetroSmokeCommand(args.slice(1));
287
+ return;
288
+ }
289
+ throw new RetroCliArgumentError(`Unknown retro subcommand "${subcommand}". Supported subcommands: check, explain, run, smoke.`);
290
+ }
291
+
292
+ export { RetroCliArgumentError };
@@ -0,0 +1,84 @@
1
+ import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
+ import { basename, dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const TEMPLATE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../../../templates/retro');
6
+
7
+ const TEMPLATE_SUMMARIES = Object.freeze({
8
+ 'topdown-adventure': 'Directional movement, room-scale exploration, HUD text, and a single hero sprite.',
9
+ 'puzzle-grid': 'Grid cursor puzzle shell with deterministic input and one-screen board state.',
10
+ 'tactics-grid': 'Turn-based tactics starter with unit selection, action points, and HUD info.',
11
+ platformer: 'Simple side-view platformer loop with jump physics and tile-ground assumptions.',
12
+ });
13
+
14
+ function projectSlugFromDestination(destination) {
15
+ return basename(resolve(destination))
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9._-]+/g, '-')
18
+ .replace(/-+/g, '-')
19
+ .replace(/^-+|-+$/g, '') || 'retro-project';
20
+ }
21
+
22
+ function replaceTokens(text, tokens) {
23
+ let output = String(text);
24
+ for (const [token, value] of Object.entries(tokens)) {
25
+ output = output.replaceAll(token, value);
26
+ }
27
+ return output;
28
+ }
29
+
30
+ function copyTemplateTree(sourceRoot, destinationRoot, tokens) {
31
+ mkdirSync(destinationRoot, { recursive: true });
32
+ for (const entry of readdirSync(sourceRoot)) {
33
+ const sourcePath = resolve(sourceRoot, entry);
34
+ const destPath = resolve(destinationRoot, entry);
35
+ const stats = statSync(sourcePath);
36
+ if (stats.isDirectory()) {
37
+ copyTemplateTree(sourcePath, destPath, tokens);
38
+ continue;
39
+ }
40
+ const ext = entry.split('.').pop() || '';
41
+ if (['js', 'json', 'md', 'txt'].includes(ext)) {
42
+ writeFileSync(destPath, replaceTokens(readFileSync(sourcePath, 'utf8'), tokens), 'utf8');
43
+ continue;
44
+ }
45
+ cpSync(sourcePath, destPath);
46
+ }
47
+ }
48
+
49
+ export function listRetroTemplates() {
50
+ return readdirSync(TEMPLATE_ROOT)
51
+ .filter((entry) => statSync(resolve(TEMPLATE_ROOT, entry)).isDirectory())
52
+ .sort()
53
+ .map((id) => ({
54
+ id,
55
+ summary: TEMPLATE_SUMMARIES[id] || 'Aura Retro starter template.',
56
+ }));
57
+ }
58
+
59
+ export function initRetroTemplate({ destination, template, force = false }) {
60
+ const templateRoot = resolve(TEMPLATE_ROOT, template);
61
+ if (!existsSync(templateRoot)) {
62
+ throw new Error(`Unknown retro template "${template}".`);
63
+ }
64
+ const destinationRoot = resolve(destination);
65
+ if (existsSync(destinationRoot) && !force) {
66
+ throw new Error(`Destination already exists: ${destinationRoot}`);
67
+ }
68
+ const slug = projectSlugFromDestination(destinationRoot);
69
+ const prettyName = slug
70
+ .split(/[-_.]+/)
71
+ .filter(Boolean)
72
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
73
+ .join(' ') || 'Retro Project';
74
+ copyTemplateTree(templateRoot, destinationRoot, {
75
+ '__AURA_RETRO_PROJECT_SLUG__': slug,
76
+ '__AURA_RETRO_PROJECT_NAME__': prettyName,
77
+ });
78
+ return {
79
+ destinationRoot,
80
+ template,
81
+ slug,
82
+ name: prettyName,
83
+ };
84
+ }