@aqian0/dsh-unity 0.0.0-stage → 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 (360) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/LICENSE-UNITY-COMPANION.md +122 -0
  3. package/LICENSE.md +31 -0
  4. package/NOTICE.md +90 -0
  5. package/README.md +273 -2
  6. package/cordis.patch.yml +22 -0
  7. package/docs/design.md +297 -0
  8. package/icon.svg +16 -0
  9. package/lib/frontmatter.js +392 -0
  10. package/lib/gating.js +105 -0
  11. package/lib/harness.js +16 -0
  12. package/lib/index.js +171 -0
  13. package/lib/project.js +210 -0
  14. package/lib/registry.js +268 -0
  15. package/lib/requirements.js +214 -0
  16. package/lib/skills.js +191 -0
  17. package/lib/types/frontmatter.d.ts +84 -0
  18. package/lib/types/gating.d.ts +80 -0
  19. package/lib/types/harness.d.ts +152 -0
  20. package/lib/types/index.d.ts +75 -0
  21. package/lib/types/project.d.ts +93 -0
  22. package/lib/types/registry.d.ts +96 -0
  23. package/lib/types/requirements.d.ts +67 -0
  24. package/lib/types/skills.d.ts +54 -0
  25. package/lib/types/watch.d.ts +34 -0
  26. package/lib/watch.js +84 -0
  27. package/locale/en.json +6 -0
  28. package/locale/zh.json +6 -0
  29. package/package.json +70 -4
  30. package/skills/2d-pixel-perfect/SKILL.md +208 -0
  31. package/skills/2d-pixel-perfect/references/api-reference.md +81 -0
  32. package/skills/2d-pixel-perfect/references/camera-setup-builtin.cs +40 -0
  33. package/skills/2d-pixel-perfect/references/camera-setup-urp.cs +49 -0
  34. package/skills/2d-pixel-perfect/references/pipeline-detection.cs +50 -0
  35. package/skills/2d-pixel-perfect/references/sprite-settings.cs +37 -0
  36. package/skills/asset-transformer-toolkit/SECURITY.md +15 -0
  37. package/skills/asset-transformer-toolkit/SKILL.md +39 -0
  38. package/skills/asset-transformer-toolkit/references/create-importer.md +121 -0
  39. package/skills/asset-transformer-toolkit/references/lods.md +61 -0
  40. package/skills/asset-transformer-toolkit/references/rule-api.md +154 -0
  41. package/skills/asset-transformer-toolkit/references/ruleblock-api.md +37 -0
  42. package/skills/asset-transformer-toolkit/references/ruleset-api.md +138 -0
  43. package/skills/asset-transformer-toolkit/references/rulesets-and-actions.md +227 -0
  44. package/skills/audio-setup-mixers/SECURITY.md +16 -0
  45. package/skills/audio-setup-mixers/SKILL.md +127 -0
  46. package/skills/audio-setup-mixers/references/api.md +162 -0
  47. package/skills/build-gtk/SECURITY.md +16 -0
  48. package/skills/build-gtk/SKILL.md +200 -0
  49. package/skills/build-gtk/references/api-reference.md +33 -0
  50. package/skills/build-gtk/references/graph-api-gaps.md +96 -0
  51. package/skills/build-gtk/references/runtime-and-visualization.md +191 -0
  52. package/skills/build-gtk/references/state-machine-api.md +270 -0
  53. package/skills/build-gtk/references/where-the-docs-stop.md +49 -0
  54. package/skills/build-live-game/SKILL.md +159 -0
  55. package/skills/build-live-game/references/achievements.md +757 -0
  56. package/skills/build-live-game/references/apis.md +271 -0
  57. package/skills/build-live-game/references/authentication.md +431 -0
  58. package/skills/build-live-game/references/battlepass.md +904 -0
  59. package/skills/build-live-game/references/blueprints-and-samples.md +75 -0
  60. package/skills/build-live-game/references/cloud-code-cloudbehaviours.md +1111 -0
  61. package/skills/build-live-game/references/cloud-code-modules.md +1276 -0
  62. package/skills/build-live-game/references/cloud-code.md +58 -0
  63. package/skills/build-live-game/references/cloud-save.md +464 -0
  64. package/skills/build-live-game/references/deployment.md +231 -0
  65. package/skills/build-live-game/references/orientation.md +30 -0
  66. package/skills/build-live-game/references/player-account.md +821 -0
  67. package/skills/build-live-game/references/remote-config.md +96 -0
  68. package/skills/build-live-game/references/services-overview.md +76 -0
  69. package/skills/build-live-game/references/tooling.md +375 -0
  70. package/skills/build-live-game/references/ugs-cli.md +86 -0
  71. package/skills/craft-game-floors/SECURITY.md +23 -0
  72. package/skills/craft-game-floors/SKILL.md +134 -0
  73. package/skills/craft-game-floors/references/art-direction.md +85 -0
  74. package/skills/craft-game-floors/references/camera-rigs.md +51 -0
  75. package/skills/craft-game-floors/references/character-motion.md +35 -0
  76. package/skills/craft-game-floors/references/game-audio.md +47 -0
  77. package/skills/craft-game-floors/references/game-feel.md +68 -0
  78. package/skills/craft-game-floors/references/game-shell.md +45 -0
  79. package/skills/craft-game-floors/references/live-floor.md +35 -0
  80. package/skills/craft-game-floors/references/placeholder-assets.md +35 -0
  81. package/skills/craft-game-floors/references/scene-lighting.md +52 -0
  82. package/skills/craft-game-floors/references/toon-shading.md +34 -0
  83. package/skills/craft-game-floors/references/vfx.md +40 -0
  84. package/skills/craft-game-floors/references/visual-scorecard.md +43 -0
  85. package/skills/create-2d-physics/SECURITY.md +16 -0
  86. package/skills/create-2d-physics/SKILL.md +128 -0
  87. package/skills/create-2d-physics/references/2d-physics-core.md +155 -0
  88. package/skills/create-2d-physics/references/legacy-2d-physics.md +45 -0
  89. package/skills/create-tile-palette-or-rule-tiles/SKILL.md +95 -0
  90. package/skills/create-tile-palette-or-rule-tiles/references/hexagonalruletile.md +71 -0
  91. package/skills/create-tile-palette-or-rule-tiles/references/palette-create.md +38 -0
  92. package/skills/create-tile-palette-or-rule-tiles/references/ruletile-createempty.md +37 -0
  93. package/skills/create-tile-palette-or-rule-tiles/references/ruletile-createfromsegment.md +219 -0
  94. package/skills/create-tile-palette-or-rule-tiles/references/ruletile.md +95 -0
  95. package/skills/create-tile-palette-or-rule-tiles/scripts/CreatePaletteTemplate.cs +148 -0
  96. package/skills/create-tile-palette-or-rule-tiles/scripts/ManualWorkflowExample.cs +63 -0
  97. package/skills/create-tile-palette-or-rule-tiles/scripts/RuleTileGenerator.cs +61 -0
  98. package/skills/create-tile-palette-or-rule-tiles/scripts/TilemapRuleTileCreateFromSegment.cs +225 -0
  99. package/skills/fix-3d-physics-collisions/SECURITY.md +17 -0
  100. package/skills/fix-3d-physics-collisions/SKILL.md +139 -0
  101. package/skills/fix-3d-physics-collisions/references/collision-checklist.md +80 -0
  102. package/skills/fix-3d-physics-collisions/references/collision-debugger.md +18 -0
  103. package/skills/fix-3d-physics-collisions/references/console-errors-table.md +9 -0
  104. package/skills/fix-3d-physics-collisions/references/kinematic-trigger-facts.md +18 -0
  105. package/skills/fix-3d-physics-collisions/references/other-symptoms.md +29 -0
  106. package/skills/fix-3d-physics-collisions/references/raycast-checklist.md +8 -0
  107. package/skills/fix-3d-physics-collisions/references/topic-map.md +42 -0
  108. package/skills/fix-3d-physics-collisions/references/trigger-checklist.md +9 -0
  109. package/skills/fix-3d-physics-collisions/scripts/CollisionDebugger.cs +561 -0
  110. package/skills/generate-editor-search-query/SECURITY.md +17 -0
  111. package/skills/generate-editor-search-query/SKILL.md +117 -0
  112. package/skills/generate-editor-search-query/references/open-search-window.md +70 -0
  113. package/skills/generate-editor-search-query/references/query-patterns.md +124 -0
  114. package/skills/implement-in-app-purchases/SKILL.md +82 -0
  115. package/skills/implement-in-app-purchases/references/api-details.md +41 -0
  116. package/skills/implement-in-app-purchases/references/api-notes.md +105 -0
  117. package/skills/implement-in-app-purchases/references/codeless-catalog.md +197 -0
  118. package/skills/implement-in-app-purchases/references/convert-adapty.md +270 -0
  119. package/skills/implement-in-app-purchases/references/convert-essentialkit.md +239 -0
  120. package/skills/implement-in-app-purchases/references/convert-revenuecat.md +277 -0
  121. package/skills/implement-in-app-purchases/references/convert-unipay.md +145 -0
  122. package/skills/implement-in-app-purchases/references/migration-v4-to-v5.md +46 -0
  123. package/skills/implement-in-app-purchases/references/path-add-iap-to-new-project.md +197 -0
  124. package/skills/implement-in-app-purchases/references/path-convert-native-google-billing.md +302 -0
  125. package/skills/implement-in-app-purchases/references/path-convert-native-storekit.md +357 -0
  126. package/skills/implement-in-app-purchases/references/path-implement-iap-d2c.md +253 -0
  127. package/skills/implement-in-app-purchases/references/platform-notes.md +55 -0
  128. package/skills/implement-in-app-purchases/references/pre-check.md +207 -0
  129. package/skills/implement-in-app-purchases/references/topic-map.md +46 -0
  130. package/skills/initialize-ai-navigation/SKILL.md +109 -0
  131. package/skills/initialize-ai-navigation/references/navigation-system.md +793 -0
  132. package/skills/initialize-ai-navigation/references/topic-map.md +66 -0
  133. package/skills/levelplay-unity-integration/SKILL.md +122 -0
  134. package/skills/levelplay-unity-integration/references/adding-more-ad-formats.md +15 -0
  135. package/skills/levelplay-unity-integration/references/banner-api.md +927 -0
  136. package/skills/levelplay-unity-integration/references/best-practices.md +604 -0
  137. package/skills/levelplay-unity-integration/references/dependency-resolution.md +94 -0
  138. package/skills/levelplay-unity-integration/references/examples.md +10 -0
  139. package/skills/levelplay-unity-integration/references/ilrd-api.md +337 -0
  140. package/skills/levelplay-unity-integration/references/initialization-api.md +851 -0
  141. package/skills/levelplay-unity-integration/references/interstitial-api.md +907 -0
  142. package/skills/levelplay-unity-integration/references/ios-setup.md +463 -0
  143. package/skills/levelplay-unity-integration/references/migration-sdk-9.md +666 -0
  144. package/skills/levelplay-unity-integration/references/privacy-settings.md +593 -0
  145. package/skills/levelplay-unity-integration/references/production-release-checklist.md +22 -0
  146. package/skills/levelplay-unity-integration/references/rewarded-api.md +918 -0
  147. package/skills/levelplay-unity-integration/references/step-0-new-or-migration.md +8 -0
  148. package/skills/levelplay-unity-integration/references/step-1-verify-environment.md +4 -0
  149. package/skills/levelplay-unity-integration/references/step-10-testing.md +15 -0
  150. package/skills/levelplay-unity-integration/references/step-2-business-goals.md +12 -0
  151. package/skills/levelplay-unity-integration/references/step-3-install-sdk.md +55 -0
  152. package/skills/levelplay-unity-integration/references/step-4-native-dependencies.md +22 -0
  153. package/skills/levelplay-unity-integration/references/step-5-app-key-and-ad-units.md +18 -0
  154. package/skills/levelplay-unity-integration/references/step-6-5-privacy-and-regulation.md +51 -0
  155. package/skills/levelplay-unity-integration/references/step-6-admob-keys.md +16 -0
  156. package/skills/levelplay-unity-integration/references/step-7-initialize.md +50 -0
  157. package/skills/levelplay-unity-integration/references/step-8-ad-unit-strategy.md +16 -0
  158. package/skills/levelplay-unity-integration/references/step-9-implement-ad-units.md +66 -0
  159. package/skills/levelplay-unity-integration/references/testing-and-validation.md +222 -0
  160. package/skills/levelplay-unity-integration/references/troubleshooting.md +99 -0
  161. package/skills/localize-unity-project/SKILL.md +159 -0
  162. package/skills/localize-unity-project/references/api-notes.md +15 -0
  163. package/skills/localize-unity-project/references/cjk-fonts.md +83 -0
  164. package/skills/localize-unity-project/references/docs-map.md +42 -0
  165. package/skills/localize-unity-project/references/documentation-lookup.md +33 -0
  166. package/skills/localize-unity-project/references/locale-switching.md +17 -0
  167. package/skills/localize-unity-project/references/table-completeness-check.md +47 -0
  168. package/skills/localize-unity-project/references/translating-existing-project.md +47 -0
  169. package/skills/localize-unity-project/references/translation-strategy.md +41 -0
  170. package/skills/localize-unity-project/references/troubleshooting.md +12 -0
  171. package/skills/localize-unity-project/scripts/L10nBatchProcessor.cs +191 -0
  172. package/skills/localize-unity-project/scripts/LocalizedFontAsset.cs +18 -0
  173. package/skills/manage-sprite-atlas/SKILL.md +202 -0
  174. package/skills/manage-sprite-atlas/references/addressables-delivery.md +58 -0
  175. package/skills/manage-sprite-atlas/references/advanced-manual-authoring.md +19 -0
  176. package/skills/manage-sprite-atlas/references/api.md +382 -0
  177. package/skills/manage-sprite-atlas/references/best-practices.md +183 -0
  178. package/skills/manage-sprite-atlas/references/common-errors.md +123 -0
  179. package/skills/manage-sprite-atlas/references/complete-workflow.md +61 -0
  180. package/skills/manage-sprite-atlas/references/custom-packing.md +147 -0
  181. package/skills/manage-sprite-atlas/references/delivery-mechanism.md +30 -0
  182. package/skills/manage-sprite-atlas/references/key-requirements.md +21 -0
  183. package/skills/manage-sprite-atlas/references/manual-authoring.md +39 -0
  184. package/skills/manage-sprite-atlas/references/namespaces.md +15 -0
  185. package/skills/manage-sprite-atlas/references/v2-architecture.md +21 -0
  186. package/skills/manage-sprite-atlas/resources/authoringvsruntime.cs +176 -0
  187. package/skills/manage-sprite-atlas/resources/buildaddressablespostprocess.cs +59 -0
  188. package/skills/manage-sprite-atlas/resources/cacheloadedatlases.cs +145 -0
  189. package/skills/manage-sprite-atlas/resources/cleanupbatchoperations.cs +119 -0
  190. package/skills/manage-sprite-atlas/resources/createandconfiguremasteratlas.cs +57 -0
  191. package/skills/manage-sprite-atlas/resources/custompackersetup.cs +88 -0
  192. package/skills/manage-sprite-atlas/resources/deprecatedmethods.cs +142 -0
  193. package/skills/manage-sprite-atlas/resources/dontmodifywithoutsaving.cs +120 -0
  194. package/skills/manage-sprite-atlas/resources/dontpackinruntimebuilds.cs +190 -0
  195. package/skills/manage-sprite-atlas/resources/dontscriptspriteatlasineditor.cs +114 -0
  196. package/skills/manage-sprite-atlas/resources/editorconfiguration.cs +95 -0
  197. package/skills/manage-sprite-atlas/resources/enablespritepacking.cs +172 -0
  198. package/skills/manage-sprite-atlas/resources/gridspritepacker.cs +50 -0
  199. package/skills/manage-sprite-atlas/resources/handlelatebinding.cs +147 -0
  200. package/skills/manage-sprite-atlas/resources/handlenullcases.cs +141 -0
  201. package/skills/manage-sprite-atlas/resources/migratev1tov2.cs +335 -0
  202. package/skills/manage-sprite-atlas/resources/multipagepacker.cs +80 -0
  203. package/skills/manage-sprite-atlas/resources/optimizetexturesettings.cs +191 -0
  204. package/skills/manage-sprite-atlas/resources/packerdebugging.cs +158 -0
  205. package/skills/manage-sprite-atlas/resources/packtransform.cs +51 -0
  206. package/skills/manage-sprite-atlas/resources/platformnames.cs +127 -0
  207. package/skills/manage-sprite-atlas/resources/queryspritesefficiently.cs +222 -0
  208. package/skills/manage-sprite-atlas/resources/registercallbacks.cs +152 -0
  209. package/skills/manage-sprite-atlas/resources/runtimeatlasloader.cs +15 -0
  210. package/skills/manage-sprite-atlas/resources/runtimespriteaccess.cs +19 -0
  211. package/skills/manage-sprite-atlas/resources/savespriteatlasasset.cs +107 -0
  212. package/skills/manage-sprite-atlas/resources/scriptablepacker.cs +81 -0
  213. package/skills/manage-sprite-atlas/resources/setincludeinbuild.cs +164 -0
  214. package/skills/manage-sprite-atlas/resources/sizeoptimizedpacker.cs +88 -0
  215. package/skills/manage-sprite-atlas/resources/spriteatlaslatebinding.cs +123 -0
  216. package/skills/manage-sprite-atlas/resources/spriteatlasprebuildgenerator.cs +219 -0
  217. package/skills/manage-sprite-atlas/resources/spritedata.cs +35 -0
  218. package/skills/manage-sprite-atlas/resources/spritepack.cs +39 -0
  219. package/skills/manage-sprite-atlas/resources/texturedata.cs +15 -0
  220. package/skills/manage-sprite-atlas/resources/updatebuildscripts.cs +357 -0
  221. package/skills/manage-sprite-atlas/resources/updatesettingsconfiguration.cs +135 -0
  222. package/skills/manage-sprite-atlas/resources/usevariantswisely.cs +179 -0
  223. package/skills/manage-sprite-atlas/resources/variantatlas.cs +39 -0
  224. package/skills/migrate-birp-to-urp/SECURITY.md +16 -0
  225. package/skills/migrate-birp-to-urp/SKILL.md +167 -0
  226. package/skills/migrate-birp-to-urp/references/capturing-the-editor.md +66 -0
  227. package/skills/migrate-birp-to-urp/references/complex-shader-situations.md +272 -0
  228. package/skills/migrate-birp-to-urp/references/conversion-and-rendering-triage.md +113 -0
  229. package/skills/migrate-birp-to-urp/references/custom-shader-triage.md +123 -0
  230. package/skills/migrate-birp-to-urp/references/implementation-patterns.md +529 -0
  231. package/skills/migrate-birp-to-urp/references/migration-workflow.md +265 -0
  232. package/skills/migrate-birp-to-urp/references/parity-validation-and-troubleshooting.md +114 -0
  233. package/skills/migrate-birp-to-urp/references/preflight-and-urp-setup.md +195 -0
  234. package/skills/migrate-birp-to-urp/references/quality-settings-map.md +69 -0
  235. package/skills/new-unity-project/SECURITY.md +26 -0
  236. package/skills/new-unity-project/SKILL.md +171 -0
  237. package/skills/new-unity-project/references/checklist.md +18 -0
  238. package/skills/new-unity-project/references/common-mistakes.md +15 -0
  239. package/skills/new-unity-project/references/skill-setup.md +66 -0
  240. package/skills/new-unity-project/references/step-1-concept.md +13 -0
  241. package/skills/new-unity-project/references/step-2-platforms-and-create.md +31 -0
  242. package/skills/new-unity-project/references/step-3-join-and-reconcile.md +16 -0
  243. package/skills/new-unity-project/references/step-4-source-control.md +9 -0
  244. package/skills/new-unity-project/references/step-5-packages.md +18 -0
  245. package/skills/new-unity-project/references/step-6-identity-and-floors.md +20 -0
  246. package/skills/new-unity-project/references/step-7-visual-baseline.md +75 -0
  247. package/skills/new-unity-project/references/step-8-first-commit.md +21 -0
  248. package/skills/new-unity-project/references/step-9-handoff.md +23 -0
  249. package/skills/optimize-audio/SECURITY.md +16 -0
  250. package/skills/optimize-audio/SKILL.md +120 -0
  251. package/skills/optimize-audio/references/diagnostics.md +42 -0
  252. package/skills/optimize-audio/references/troubleshooting.md +41 -0
  253. package/skills/optimize-audio/resources/audio-import-api.md +149 -0
  254. package/skills/optimize-audio/resources/platform-settings.md +48 -0
  255. package/skills/optimize-text-mesh-pro/SKILL.md +181 -0
  256. package/skills/optimize-text-mesh-pro/references/dynamic-atlas-and-profiling.md +28 -0
  257. package/skills/optimize-text-mesh-pro/references/topic-map.md +36 -0
  258. package/skills/optimize-web/SECURITY.md +16 -0
  259. package/skills/optimize-web/SKILL.md +157 -0
  260. package/skills/optimize-web/references/editor-csharp.md +120 -0
  261. package/skills/optimize-web/references/topic-map.md +49 -0
  262. package/skills/optimize-web/references/troubleshooting.md +45 -0
  263. package/skills/optimize-web/references/understand-request.md +19 -0
  264. package/skills/optimize-web/references/web-assets-quality.md +59 -0
  265. package/skills/optimize-web/references/web-player-settings.md +39 -0
  266. package/skills/optimize-web/references/web-profiling-memory.md +71 -0
  267. package/skills/optimize-web/scripts/WebOptimizer.cs +46 -0
  268. package/skills/optimize-web/scripts/toktx-examples.sh +11 -0
  269. package/skills/setup-multiplayer-services/SKILL.md +36 -0
  270. package/skills/setup-multiplayer-services/references/dgs-entrypoint.md +79 -0
  271. package/skills/setup-multiplayer-services/references/entrypoints.md +213 -0
  272. package/skills/setup-multiplayer-services/references/examples.md +33 -0
  273. package/skills/setup-multiplayer-services/references/implementation-fit.md +30 -0
  274. package/skills/setup-multiplayer-services/references/underlying-services.md +11 -0
  275. package/skills/setup-multiplayer-services/references/workflows-prerequisites.md +17 -0
  276. package/skills/setup-vivox-voice-chat/SECURITY.md +16 -0
  277. package/skills/setup-vivox-voice-chat/SKILL.md +166 -0
  278. package/skills/setup-vivox-voice-chat/references/api-reference-lookup.md +28 -0
  279. package/skills/setup-vivox-voice-chat/references/docs-topic-map.md +13 -0
  280. package/skills/setup-vivox-voice-chat/references/events-and-participants.md +79 -0
  281. package/skills/setup-vivox-voice-chat/references/init-and-login.md +92 -0
  282. package/skills/setup-vivox-voice-chat/references/text-chat.md +93 -0
  283. package/skills/setup-vivox-voice-chat/references/troubleshooting.md +47 -0
  284. package/skills/setup-vivox-voice-chat/references/voice-channels.md +92 -0
  285. package/skills/shader-graph-create-custom-node/SKILL.md +25 -0
  286. package/skills/shader-graph-create-custom-node/resources/all_hints.hlsl +182 -0
  287. package/skills/sprite-editor/SECURITY.md +16 -0
  288. package/skills/sprite-editor/SKILL.md +66 -0
  289. package/skills/sprite-editor/references/api_reference.md +151 -0
  290. package/skills/sprite-editor/references/background.md +112 -0
  291. package/skills/sprite-editor/references/templates.md +72 -0
  292. package/skills/sprite-editor/scripts/AutomaticSliceTexture.cs +40 -0
  293. package/skills/sprite-editor/scripts/GenerateNewSpriteRects.cs +200 -0
  294. package/skills/sprite-editor/scripts/GetTextureSourceImageSize.cs +32 -0
  295. package/skills/sprite-editor/scripts/GetTextureToSlice.cs +55 -0
  296. package/skills/sprite-editor/scripts/GridSliceTexture.cs +40 -0
  297. package/skills/sprite-editor/scripts/IsometricSliceTexture.cs +141 -0
  298. package/skills/sprite-editor/scripts/README.md +134 -0
  299. package/skills/sprite-editor/scripts/SetPivotExample.cs +58 -0
  300. package/skills/sprite-editor/scripts/SpriteToPng.cs +88 -0
  301. package/skills/sprite-segment-3x3grid/SKILL.md +177 -0
  302. package/skills/sprite-segment-3x3grid/references/topic-map.md +37 -0
  303. package/skills/sprite-segment-3x3grid/scripts/SpriteGridAnalysis.cs +119 -0
  304. package/skills/ui/SKILL.md +142 -0
  305. package/skills/ui-imgui/SKILL.md +180 -0
  306. package/skills/ui-imgui/references/gui-elements.md +156 -0
  307. package/skills/ui-imgui/references/templates.md +141 -0
  308. package/skills/ui-ugui/SKILL.md +217 -0
  309. package/skills/ui-ugui/references/layout-and-anchors.md +61 -0
  310. package/skills/ui-ugui/references/scrollview-setup.md +29 -0
  311. package/skills/ui-uitk/SKILL.md +229 -0
  312. package/skills/ui-uitk/references/common-issues.md +74 -0
  313. package/skills/ui-uitk/references/custom-elements.md +241 -0
  314. package/skills/ui-uitk/references/painter2d.md +282 -0
  315. package/skills/ui-uitk/references/pointermanipulator-guide.md +94 -0
  316. package/skills/ui-uitk/references/svg-icons.md +136 -0
  317. package/skills/ui-uitk/references/ui-runtime-binding.md +234 -0
  318. package/skills/ui-uitk/references/uss-guide.md +138 -0
  319. package/skills/unity-cli/CHANGELOG.md +524 -0
  320. package/skills/unity-cli/SECURITY.md +68 -0
  321. package/skills/unity-cli/SKILL.md +160 -0
  322. package/skills/unity-cli/references/auth-license-cloud.md +318 -0
  323. package/skills/unity-cli/references/bootstrap-project.md +177 -0
  324. package/skills/unity-cli/references/build-run-test.md +555 -0
  325. package/skills/unity-cli/references/catalog-plugins.md +86 -0
  326. package/skills/unity-cli/references/ci-recipes.md +76 -0
  327. package/skills/unity-cli/references/cloud-automation.md +819 -0
  328. package/skills/unity-cli/references/cloud-workflows.md +19 -0
  329. package/skills/unity-cli/references/collaboration.md +533 -0
  330. package/skills/unity-cli/references/config-hub.md +239 -0
  331. package/skills/unity-cli/references/diagnostics-maintenance.md +718 -0
  332. package/skills/unity-cli/references/docs-workflow.md +179 -0
  333. package/skills/unity-cli/references/editor-targeting.md +29 -0
  334. package/skills/unity-cli/references/editors-install.md +490 -0
  335. package/skills/unity-cli/references/environment-variables.md +42 -0
  336. package/skills/unity-cli/references/exit-codes.md +47 -0
  337. package/skills/unity-cli/references/global-flags.md +32 -0
  338. package/skills/unity-cli/references/integration-advanced.md +1130 -0
  339. package/skills/unity-cli/references/notes.md +20 -0
  340. package/skills/unity-cli/references/notifications.md +39 -0
  341. package/skills/unity-cli/references/playmode-verification-loop.md +279 -0
  342. package/skills/unity-cli/references/projects-templates.md +997 -0
  343. package/skills/unity-cli/references/scene-editing-preflight.md +25 -0
  344. package/skills/unity-cli/references/setup-and-help.md +54 -0
  345. package/skills/unity-cli/references/version-control.md +612 -0
  346. package/skills/unity-package-management/SKILL.md +169 -0
  347. package/skills/unity-package-management/references/discovering-packages.md +66 -0
  348. package/skills/unity-package-management/references/headless-run.md +31 -0
  349. package/skills/unity-package-management/references/installer-script.md +92 -0
  350. package/skills/unity-package-management/references/select-packages.md +126 -0
  351. package/skills/unity-pipeline/SECURITY.md +17 -0
  352. package/skills/unity-pipeline/SKILL.md +205 -0
  353. package/skills/unity-pipeline/references/csharp-eval.md +23 -0
  354. package/skills/unity-pipeline/references/multiplayer-play-mode.md +103 -0
  355. package/skills/urp-postprocessing/SECURITY.md +16 -0
  356. package/skills/urp-postprocessing/SKILL.md +188 -0
  357. package/skills/urp-postprocessing/references/code-templates.md +150 -0
  358. package/skills/urp-postprocessing/references/effect-reference.md +86 -0
  359. package/skills/validate-urp-render-graph-renderer-feature/SKILL.md +92 -0
  360. package/skills/validate-urp-render-graph-renderer-feature/references/validation-checklist.md +179 -0
package/lib/project.js ADDED
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Unity project detection.
3
+ *
4
+ * A session's working directory may sit anywhere inside a Unity project, so the
5
+ * plugin walks up to the nearest ancestor that carries
6
+ * `ProjectSettings/ProjectVersion.txt` — the marker Unity itself writes and the
7
+ * same file that names the editor version. From there it reads the facts that
8
+ * decide whether a skill applies: the editor version, the UPM packages in
9
+ * `Packages/manifest.json`, the inferred render pipeline, whether an Editor holds
10
+ * the project lock, and whether the `unity` CLI is on `PATH`.
11
+ *
12
+ * Everything here is read-only and best-effort. A partially readable project is
13
+ * reported with the fields it does have; a directory that is not a Unity project
14
+ * reports `undefined` rather than throwing.
15
+ *
16
+ * @module dsh-unity/lib/project
17
+ */
18
+ import { readFile, readdir, stat } from 'node:fs/promises';
19
+ import { dirname, join, resolve } from 'node:path';
20
+ /** Relative path of the file that identifies a Unity project root. */
21
+ export const PROJECT_MARKER = join('ProjectSettings', 'ProjectVersion.txt');
22
+ /** Render-pipeline package ids, in the order that decides the answer. */
23
+ const PIPELINE_PACKAGES = [
24
+ ['com.unity.render-pipelines.high-definition', 'hdrp'],
25
+ ['com.unity.render-pipelines.universal', 'urp'],
26
+ ];
27
+ /** Project-relative skill roots that a project may use to override a skill. */
28
+ const PROJECT_SKILL_ROOTS = [join('.dsh', 'skills'), join('.agents', 'skills')];
29
+ /** How many ancestor directories detection walks before giving up. */
30
+ const DEFAULT_MAX_DEPTH = 8;
31
+ /**
32
+ * Find the nearest ancestor containing the Unity project marker.
33
+ *
34
+ * @param cwd - directory to start from.
35
+ * @param options - injectable filesystem and walk depth.
36
+ * @returns the absolute project root, or `undefined` when there is none.
37
+ */
38
+ export async function findProjectRoot(cwd, options = {}) {
39
+ const statFile = options.stat ?? stat;
40
+ const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
41
+ let current = resolve(cwd);
42
+ for (let depth = 0; depth <= maxDepth; depth += 1) {
43
+ try {
44
+ const info = await statFile(join(current, PROJECT_MARKER));
45
+ if (info.isFile())
46
+ return current;
47
+ }
48
+ catch {
49
+ // Not a project at this level; keep walking up.
50
+ }
51
+ const parent = dirname(current);
52
+ if (parent === current)
53
+ return undefined;
54
+ current = parent;
55
+ }
56
+ return undefined;
57
+ }
58
+ /**
59
+ * Read the editor version from `ProjectVersion.txt`.
60
+ *
61
+ * @param text - file contents.
62
+ * @returns the version such as `6000.3.14f1`, or `undefined` when absent.
63
+ */
64
+ export function parseProjectVersion(text) {
65
+ const match = /^\s*m_EditorVersion:\s*(\S+)\s*$/m.exec(text);
66
+ return match?.[1];
67
+ }
68
+ /**
69
+ * Read installed UPM packages from a manifest.
70
+ *
71
+ * @param text - `Packages/manifest.json` contents.
72
+ * @returns package id to version, or `undefined` when the manifest is not a mapping.
73
+ */
74
+ export function parsePackages(text) {
75
+ try {
76
+ const manifest = JSON.parse(text);
77
+ const dependencies = manifest?.dependencies;
78
+ if (typeof dependencies !== 'object' || dependencies === null || Array.isArray(dependencies))
79
+ return undefined;
80
+ const packages = new Map();
81
+ for (const [name, version] of Object.entries(dependencies)) {
82
+ if (typeof version === 'string')
83
+ packages.set(name, version.trim());
84
+ }
85
+ return packages;
86
+ }
87
+ catch {
88
+ return undefined;
89
+ }
90
+ }
91
+ /**
92
+ * Infer the render pipeline from installed packages.
93
+ *
94
+ * @param packages - installed packages, or `undefined` when unknown.
95
+ * @returns the pipeline name, or `undefined` when the package list is unknown.
96
+ */
97
+ export function inferRenderPipeline(packages) {
98
+ if (packages === undefined)
99
+ return undefined;
100
+ for (const [id, pipeline] of PIPELINE_PACKAGES) {
101
+ if (packages.has(id))
102
+ return pipeline;
103
+ }
104
+ return 'builtin';
105
+ }
106
+ /**
107
+ * Detect the Unity project that contains a directory.
108
+ *
109
+ * @param cwd - session working directory.
110
+ * @param options - injectable collaborators and walk depth.
111
+ * @returns project facts, or `undefined` outside a project.
112
+ */
113
+ export async function detectProject(cwd, options = {}) {
114
+ if (typeof cwd !== 'string' || cwd === '')
115
+ return undefined;
116
+ const statFile = options.stat ?? stat;
117
+ const readText = options.readFile ?? ((path) => readFile(path, 'utf8'));
118
+ const root = await findProjectRoot(cwd, { ...options, stat: statFile });
119
+ if (root === undefined)
120
+ return undefined;
121
+ let editorVersion;
122
+ try {
123
+ editorVersion = parseProjectVersion(await readText(join(root, PROJECT_MARKER)));
124
+ }
125
+ catch {
126
+ editorVersion = undefined;
127
+ }
128
+ let packages;
129
+ try {
130
+ packages = parsePackages(await readText(join(root, 'Packages', 'manifest.json')));
131
+ }
132
+ catch {
133
+ packages = undefined;
134
+ }
135
+ let editorOpen = false;
136
+ try {
137
+ editorOpen = (await statFile(join(root, 'Temp', 'UnityLockfile'))).isFile();
138
+ }
139
+ catch {
140
+ editorOpen = false;
141
+ }
142
+ let cliAvailable = false;
143
+ if (typeof options.resolveExecutable === 'function') {
144
+ try {
145
+ cliAvailable = (await options.resolveExecutable('unity')) !== undefined;
146
+ }
147
+ catch {
148
+ cliAvailable = false;
149
+ }
150
+ }
151
+ return {
152
+ root,
153
+ ...(editorVersion === undefined ? {} : { editorVersion }),
154
+ ...(packages === undefined ? {} : { packages }),
155
+ renderPipeline: inferRenderPipeline(packages),
156
+ editorOpen,
157
+ cliAvailable,
158
+ };
159
+ }
160
+ /**
161
+ * Skill names a project provides itself, which this plugin must not shadow.
162
+ *
163
+ * @param root - project root.
164
+ * @param options - injectable filesystem.
165
+ * @returns skill names found under the project skill roots.
166
+ */
167
+ export async function readProjectSkillNames(root, options = {}) {
168
+ const listDir = options.readdir ?? readdir;
169
+ const statFile = options.stat ?? stat;
170
+ const names = new Set();
171
+ for (const relative of PROJECT_SKILL_ROOTS) {
172
+ let entries;
173
+ try {
174
+ entries = await listDir(join(root, relative), { withFileTypes: true });
175
+ }
176
+ catch {
177
+ continue;
178
+ }
179
+ for (const entry of entries) {
180
+ if (!entry.isDirectory() && !entry.isSymbolicLink())
181
+ continue;
182
+ try {
183
+ const info = await statFile(join(root, relative, entry.name, 'SKILL.md'));
184
+ if (info.isFile())
185
+ names.add(entry.name);
186
+ }
187
+ catch {
188
+ // A directory without SKILL.md is not a skill override.
189
+ }
190
+ }
191
+ }
192
+ return names;
193
+ }
194
+ /**
195
+ * A short, stable identity for a fact set, used to notice project changes.
196
+ *
197
+ * @param facts - detected facts.
198
+ * @returns a cache and comparison key.
199
+ */
200
+ export function factsKey(facts) {
201
+ if (facts === undefined)
202
+ return 'none';
203
+ const packages = facts.packages === undefined
204
+ ? '?'
205
+ : [...facts.packages.entries()]
206
+ .sort(([left], [right]) => left.localeCompare(right))
207
+ .map(([id, version]) => `${id}@${version}`)
208
+ .join(',');
209
+ return [facts.root, facts.editorVersion ?? '?', facts.renderPipeline ?? '?', facts.editorOpen ? 'open' : 'closed', packages].join('|');
210
+ }
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Per-agent skill provider registry.
3
+ *
4
+ * A bundle row lands in the harness's global scope layer, while an agent preset
5
+ * mounts its own skill provider in the agent's layer — and the nearest layer wins
6
+ * a duplicate name outright, regardless of rank. Registering from a bundle row
7
+ * alone therefore loses to whatever the preset already sees, and cannot vary by
8
+ * project. Registering through `agent.ctx` instead places this provider in that
9
+ * agent's layer: it wins the names it owns, and its catalog can depend on the
10
+ * project the agent is actually working in.
11
+ *
12
+ * This module keeps that bookkeeping: one shared reader and parse cache, one fact
13
+ * cache per working directory, and one registration per live agent. It also
14
+ * implements the provider itself, which re-reads the project facts whenever the
15
+ * harness asks for the catalog, so a changed editor version or package list
16
+ * invalidates the catalog instead of waiting for a restart.
17
+ *
18
+ * @module dsh-unity/lib/registry
19
+ */
20
+ import { detectProject, factsKey, readProjectSkillNames } from './project.js';
21
+ import { gateCatalog, renderContext } from './gating.js';
22
+ import { createUnitySkillReader } from './skills.js';
23
+ /** How long detected project facts stay fresh before they are read again. */
24
+ export const FACTS_TTL_MS = 2000;
25
+ /** Prompt order for the contributed Unity context: after policies, before harness source. */
26
+ const CONTEXT_ORDER = 180;
27
+ /**
28
+ * Create the registry that owns every per-agent registration.
29
+ *
30
+ * @param options - registry settings and injectable collaborators.
31
+ * @returns the registry.
32
+ */
33
+ export function createAgentRegistry(options) {
34
+ const { ctx, settings } = options;
35
+ const skillReader = options.reader ??
36
+ createUnitySkillReader({
37
+ skillDir: settings.skillDir,
38
+ providerName: settings.providerName,
39
+ source: settings.source,
40
+ rank: settings.rank,
41
+ exclude: settings.exclude,
42
+ parseCache: settings.parseCache,
43
+ logger: ctx.logger,
44
+ });
45
+ const detectProjectFacts = options.detect ?? ((cwd) => detectProject(cwd, resolveDetectOptions(ctx)));
46
+ const readOverrides = options.readProjectSkills ?? ((root) => readProjectSkillNames(root));
47
+ const factsByCwd = new Map();
48
+ const overridesByRoot = new Map();
49
+ const states = new Map();
50
+ async function factsFor(cwd) {
51
+ if (typeof cwd !== 'string' || cwd === '')
52
+ return undefined;
53
+ const cached = factsByCwd.get(cwd);
54
+ const now = Date.now();
55
+ if (cached !== undefined && now - cached.at < FACTS_TTL_MS)
56
+ return cached.facts;
57
+ let facts;
58
+ try {
59
+ facts = await detectProjectFacts(cwd);
60
+ }
61
+ catch (error) {
62
+ ctx.logger.warn(`unity skills: project detection failed for ${cwd}: ${String(error)}`);
63
+ facts = undefined;
64
+ }
65
+ factsByCwd.set(cwd, { facts, at: now });
66
+ return facts;
67
+ }
68
+ async function overridesFor(facts) {
69
+ if (facts === undefined || !settings.respectProjectRoots)
70
+ return new Set();
71
+ const now = Date.now();
72
+ const cached = overridesByRoot.get(facts.root);
73
+ if (cached !== undefined && now - cached.at < FACTS_TTL_MS)
74
+ return cached.names;
75
+ let names;
76
+ try {
77
+ names = await readOverrides(facts.root);
78
+ }
79
+ catch {
80
+ names = new Set();
81
+ }
82
+ overridesByRoot.set(facts.root, { names, at: now });
83
+ return names;
84
+ }
85
+ /** Compute the gated catalog for one working directory. */
86
+ async function view(cwd, lookup) {
87
+ const facts = await factsFor(cwd);
88
+ const projectSkills = await overridesFor(facts);
89
+ const candidates = await skillReader.list(lookup);
90
+ const gated = gateCatalog(candidates, facts, settings, projectSkills);
91
+ return { ...gated, facts, key: factsKey(facts) };
92
+ }
93
+ /** The provider one agent sees. */
94
+ class UnitySkillProvider {
95
+ name;
96
+ resolveView;
97
+ constructor(providerName, resolveView) {
98
+ this.name = providerName;
99
+ this.resolveView = resolveView;
100
+ }
101
+ async list(lookup = {}) {
102
+ const result = await this.resolveView(lookup);
103
+ return result.candidates;
104
+ }
105
+ get(candidate, lookup = {}) {
106
+ return skillReader.load(candidate, lookup);
107
+ }
108
+ }
109
+ function cwdOf(agent) {
110
+ const session = agent?.session;
111
+ let directory;
112
+ try {
113
+ directory = serviceOf(ctx, 'workingDirectory')?.get(session);
114
+ }
115
+ catch {
116
+ directory = undefined;
117
+ }
118
+ return directory ?? session?.header?.cwd ?? session?.cwd;
119
+ }
120
+ async function add(agent) {
121
+ const id = agent?.session?.id ?? agent?.id;
122
+ if (id === undefined || states.has(id))
123
+ return 'skipped';
124
+ const agentSkills = serviceOf(agent?.ctx, 'skills');
125
+ if (agentSkills === undefined)
126
+ return 'unavailable';
127
+ const cwd = cwdOf(agent);
128
+ const state = {
129
+ id,
130
+ agent: agent,
131
+ control: undefined,
132
+ facts: undefined,
133
+ hidden: [],
134
+ lastKey: 'unset',
135
+ disposers: [],
136
+ };
137
+ states.set(id, state);
138
+ const provider = new UnitySkillProvider(settings.providerName, async (lookup) => {
139
+ const current = cwdOf(agent) ?? cwd;
140
+ const result = await view(current, lookup);
141
+ state.facts = result.facts;
142
+ state.hidden = result.hidden;
143
+ if (result.key !== state.lastKey) {
144
+ state.lastKey = result.key;
145
+ // Facts moved (editor version, packages, project root): refresh the cached
146
+ // catalog so the next snapshot reflects the new gating.
147
+ const control = state.control;
148
+ if (control !== undefined)
149
+ queueMicrotask(() => control.invalidate());
150
+ }
151
+ return result;
152
+ });
153
+ state.disposers.push(agentSkills.registerProvider((control) => {
154
+ state.control = control;
155
+ return provider;
156
+ }));
157
+ const agentPrompt = serviceOf(agent?.ctx, 'systemPrompt');
158
+ if (settings.injectContext && agentPrompt !== undefined) {
159
+ state.disposers.push(agentPrompt.context({
160
+ name: 'unity:project',
161
+ order: CONTEXT_ORDER,
162
+ text: () => renderContext(state.facts, state.hidden) ?? '',
163
+ }));
164
+ }
165
+ // Prime the facts so the first prompt assembly already carries the context.
166
+ await factsFor(cwd);
167
+ return 'registered';
168
+ }
169
+ function remove(agent) {
170
+ const id = typeof agent?.session?.id === 'string' ? agent.session.id : typeof agent?.id === 'string' ? agent.id : undefined;
171
+ if (id === undefined)
172
+ return;
173
+ const state = states.get(id);
174
+ if (state === undefined)
175
+ return;
176
+ states.delete(id);
177
+ for (const dispose of state.disposers.splice(0)) {
178
+ try {
179
+ dispose();
180
+ }
181
+ catch (error) {
182
+ ctx.logger.warn(`unity skills: registration cleanup failed: ${String(error)}`);
183
+ }
184
+ }
185
+ }
186
+ return {
187
+ reader: skillReader,
188
+ size: () => states.size,
189
+ add,
190
+ remove,
191
+ factsFor,
192
+ projectSkillsFor: overridesFor,
193
+ invalidateAll() {
194
+ for (const state of states.values())
195
+ state.control?.invalidate();
196
+ },
197
+ disposeAll() {
198
+ for (const state of [...states.values()])
199
+ remove(state.agent);
200
+ states.clear();
201
+ factsByCwd.clear();
202
+ overridesByRoot.clear();
203
+ },
204
+ };
205
+ }
206
+ /**
207
+ * Resolve an optional service from a context without requiring an injection.
208
+ *
209
+ * @param context - the context to read from, possibly an agent scope.
210
+ * @param name - service name.
211
+ * @returns the service, or `undefined` when unavailable.
212
+ */
213
+ export function serviceOf(context, name) {
214
+ if (context === undefined)
215
+ return undefined;
216
+ try {
217
+ return context.get(name);
218
+ }
219
+ catch {
220
+ return undefined;
221
+ }
222
+ }
223
+ /** Options passed to the real project detector. */
224
+ export function resolveDetectOptions(ctx) {
225
+ const subprocess = serviceOf(ctx, 'subprocess');
226
+ return {
227
+ maxDepth: 8,
228
+ ...(subprocess === undefined
229
+ ? {}
230
+ : {
231
+ resolveExecutable: async (command) => {
232
+ try {
233
+ return await subprocess.resolveExecutable(command);
234
+ }
235
+ catch {
236
+ return undefined;
237
+ }
238
+ },
239
+ }),
240
+ };
241
+ }
242
+ /**
243
+ * Build a single provider that resolves project facts from each lookup's `cwd`.
244
+ *
245
+ * Used as the fallback when a plugin context cannot reach `agent.ctx.skills`: the
246
+ * catalog still follows each lookup's working directory, but it registers in the
247
+ * global layer, where the nearest layer (the agent preset) wins a duplicate name.
248
+ * Context contribution stays agent-scoped, so a deployment on this path gets
249
+ * gating without the runtime-context line.
250
+ *
251
+ * @param options - settings and the registry whose caches are reused.
252
+ * @returns the provider to register globally.
253
+ */
254
+ export function createGlobalProvider(options) {
255
+ const { settings, registry } = options;
256
+ return {
257
+ name: settings.providerName,
258
+ async list(lookup = {}) {
259
+ const candidates = await registry.reader.list(lookup);
260
+ const facts = await registry.factsFor(lookup.cwd);
261
+ const projectSkills = await registry.projectSkillsFor(facts);
262
+ return gateCatalog(candidates, facts, settings, projectSkills).candidates;
263
+ },
264
+ get(candidate, lookup = {}) {
265
+ return registry.reader.load(candidate, lookup);
266
+ },
267
+ };
268
+ }
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Unity version and UPM package requirement arithmetic.
3
+ *
4
+ * Skill frontmatter can state what the skill needs: `required_editor_version`
5
+ * (a range such as `>=6000.6`) and `required_packages` (a map of package id to
6
+ * range). The harness has no equivalent mechanism, so this module turns those
7
+ * declarations into a decision the plugin can act on: is the skill applicable to
8
+ * the project this agent is working in?
9
+ *
10
+ * Parsing is deliberately tolerant. A Unity editor version like `6000.3.14f1`
11
+ * becomes `[6000, 3, 14]` — the `f1` build suffix is information about the build
12
+ * channel, not ordering — while a package version keeps its prerelease tag.
13
+ * Anything unparseable is "unknown", and the caller treats unknown as *do not
14
+ * hide*: a declaration nobody can evaluate must not silently remove a skill.
15
+ *
16
+ * @module dsh-unity/lib/requirements
17
+ */
18
+ /** Range operators this reader understands, longest match first. */
19
+ const OPERATORS = ['>=', '<=', '>', '<', '=', '^', '~'];
20
+ /**
21
+ * Parse a version string into comparable numeric segments.
22
+ *
23
+ * @param value - raw version such as `6000.3.14f1`, `17.5.0`, `1.2`.
24
+ * @returns the parsed version, or `undefined` when it is not a version.
25
+ */
26
+ export function parseVersion(value) {
27
+ if (typeof value !== 'string')
28
+ return undefined;
29
+ const text = value.trim();
30
+ if (text === '')
31
+ return undefined;
32
+ // Unity editor versions carry a build channel suffix: 6000.3.14f1, 2022.3.10b5.
33
+ const match = /^v?(\d+(?:\.\d+)*)(?:[-+]([0-9A-Za-z.-]+))?$/.exec(text.replace(/[fabp]\d+$/, ''));
34
+ if (match === null)
35
+ return undefined;
36
+ const segments = (match[1] ?? '').split('.').map((part) => Number(part));
37
+ if (segments.some((segment) => !Number.isInteger(segment) || segment < 0))
38
+ return undefined;
39
+ return { segments, prerelease: match[2] };
40
+ }
41
+ /** Compare two parsed versions, padding the shorter one with zeros. */
42
+ export function compareVersions(left, right) {
43
+ const length = Math.max(left.segments.length, right.segments.length);
44
+ for (let index = 0; index < length; index += 1) {
45
+ const a = left.segments[index] ?? 0;
46
+ const b = right.segments[index] ?? 0;
47
+ if (a !== b)
48
+ return a < b ? -1 : 1;
49
+ }
50
+ if (left.prerelease === right.prerelease)
51
+ return 0;
52
+ if (left.prerelease === undefined)
53
+ return 1;
54
+ if (right.prerelease === undefined)
55
+ return -1;
56
+ return left.prerelease < right.prerelease ? -1 : 1;
57
+ }
58
+ /** Resolve one comparator such as `>=6000.6` against a version. */
59
+ function satisfiesToken(token, version) {
60
+ const operator = OPERATORS.find((candidate) => token.startsWith(candidate)) ?? '';
61
+ const body = (operator === '' ? token : token.slice(operator.length)).trim();
62
+ if (body === '' || body === '*' || body === 'x')
63
+ return true;
64
+ const wanted = parseVersion(body);
65
+ if (wanted === undefined)
66
+ return undefined;
67
+ // A bare `6000.6` means "this release line", i.e. >=6000.6 <6000.7; a full
68
+ // three-part version is an exact release.
69
+ if (operator === '' || operator === '=') {
70
+ if (wanted.segments.length < 3)
71
+ return isWithinLine(version, wanted);
72
+ return compareVersions(version, wanted) === 0;
73
+ }
74
+ switch (operator) {
75
+ case '>=':
76
+ return compareVersions(version, wanted) >= 0;
77
+ case '>':
78
+ return compareVersions(version, wanted) > 0;
79
+ case '<=':
80
+ return compareVersions(version, wanted) <= 0;
81
+ case '<':
82
+ return compareVersions(version, wanted) < 0;
83
+ case '^':
84
+ return compareVersions(version, wanted) >= 0 && compareVersions(version, caretUpperBound(wanted)) < 0;
85
+ case '~':
86
+ return compareVersions(version, wanted) >= 0 && compareVersions(version, tildeUpperBound(wanted)) < 0;
87
+ default:
88
+ return undefined;
89
+ }
90
+ }
91
+ /** Whether a version sits inside the release line the wanted prefix names. */
92
+ function isWithinLine(version, wanted) {
93
+ for (let index = 0; index < wanted.segments.length; index += 1) {
94
+ if ((version.segments[index] ?? 0) !== wanted.segments[index])
95
+ return false;
96
+ }
97
+ return true;
98
+ }
99
+ /** `^1.2.3` allows `<2.0.0`; `^0.2.3` allows `<0.3.0`. */
100
+ function caretUpperBound(wanted) {
101
+ const major = wanted.segments[0] ?? 0;
102
+ const minor = wanted.segments[1] ?? 0;
103
+ return (major > 0 ? parseVersion(`${major + 1}.0.0`) : parseVersion(`0.${minor + 1}.0`));
104
+ }
105
+ /** `~1.2.3` allows `<1.3.0`. */
106
+ function tildeUpperBound(wanted) {
107
+ const major = wanted.segments[0] ?? 0;
108
+ const minor = wanted.segments[1] ?? 0;
109
+ return parseVersion(`${major}.${minor + 1}.0`);
110
+ }
111
+ /**
112
+ * Check a range against a version.
113
+ *
114
+ * @param rawRange - range text, for example `>=6000.6`.
115
+ * @param rawVersion - version text, for example `6000.3.14f1`.
116
+ * @returns `undefined` when either side cannot be parsed, so the caller can treat
117
+ * the answer as unknown instead of hiding a skill.
118
+ */
119
+ export function satisfiesRange(rawRange, rawVersion) {
120
+ if (typeof rawRange !== 'string' || rawRange.trim() === '')
121
+ return true;
122
+ if (rawVersion === undefined || rawVersion === null)
123
+ return undefined;
124
+ const version = parseVersion(rawVersion);
125
+ if (version === undefined)
126
+ return undefined;
127
+ // Comparators may be comma- or space-separated, and the operator may be
128
+ // separated from its version (`>= 6000.6`), so normalise before splitting.
129
+ const normalized = rawRange.replace(/(>=|<=|>|<|=|\^|~)\s+/g, '$1');
130
+ const tokens = normalized.split(/[,\s]+/).filter((token) => token !== '');
131
+ if (tokens.length === 0)
132
+ return true;
133
+ let unknown = false;
134
+ for (const token of tokens) {
135
+ const verdict = satisfiesToken(token, version);
136
+ if (verdict === undefined)
137
+ unknown = true;
138
+ else if (verdict === false)
139
+ return false;
140
+ }
141
+ return unknown ? undefined : true;
142
+ }
143
+ /**
144
+ * Read the requirement declarations out of parsed skill frontmatter.
145
+ *
146
+ * @param data - parsed SKILL.md frontmatter.
147
+ * @returns the declared editor range and package ranges.
148
+ */
149
+ export function readRequirements(data) {
150
+ const rawEditor = data.required_editor_version;
151
+ const editor = typeof rawEditor === 'string' ? rawEditor : typeof rawEditor === 'number' ? String(rawEditor) : undefined;
152
+ const packages = [];
153
+ const declared = data.required_packages;
154
+ if (typeof declared === 'object' && declared !== null && !Array.isArray(declared)) {
155
+ for (const [name, range] of Object.entries(declared)) {
156
+ if (typeof range === 'string' || typeof range === 'number')
157
+ packages.push({ name, range: String(range) });
158
+ else if (range === null || range === '')
159
+ packages.push({ name, range: '' });
160
+ }
161
+ }
162
+ return { ...(editor === undefined ? {} : { editor }), packages };
163
+ }
164
+ /**
165
+ * Evaluate requirements against project facts.
166
+ *
167
+ * @param requirements - declarations from {@link readRequirements}.
168
+ * @param facts - detected project facts; `undefined` means no project was detected.
169
+ * @returns the decision; `applicable` stays true when the answer is only unknown.
170
+ */
171
+ export function evaluateRequirements(requirements, facts) {
172
+ const reasons = [];
173
+ let unknown = false;
174
+ if (requirements.editor !== undefined) {
175
+ if (facts?.editorVersion === undefined) {
176
+ unknown = true;
177
+ reasons.push(`cannot check Unity ${requirements.editor}: editor version unknown`);
178
+ }
179
+ else {
180
+ const verdict = satisfiesRange(requirements.editor, facts.editorVersion);
181
+ if (verdict === false) {
182
+ return { applicable: false, unknown, reasons: [`needs Unity ${requirements.editor} (project ${facts.editorVersion})`] };
183
+ }
184
+ if (verdict === undefined) {
185
+ unknown = true;
186
+ reasons.push(`cannot check Unity ${requirements.editor} against ${facts.editorVersion}`);
187
+ }
188
+ }
189
+ }
190
+ for (const requirement of requirements.packages) {
191
+ if (facts?.packages === undefined) {
192
+ unknown = true;
193
+ reasons.push(`cannot check ${requirement.name}: installed packages unknown`);
194
+ continue;
195
+ }
196
+ const installed = facts.packages.get(requirement.name);
197
+ if (installed === undefined) {
198
+ return {
199
+ applicable: false,
200
+ unknown,
201
+ reasons: [`missing package ${requirement.name}${requirement.range === '' ? '' : ` ${requirement.range}`}`],
202
+ };
203
+ }
204
+ const verdict = satisfiesRange(requirement.range, installed);
205
+ if (verdict === false) {
206
+ return { applicable: false, unknown, reasons: [`needs ${requirement.name} ${requirement.range} (project ${installed})`] };
207
+ }
208
+ if (verdict === undefined) {
209
+ unknown = true;
210
+ reasons.push(`cannot check ${requirement.name} ${requirement.range} against ${installed}`);
211
+ }
212
+ }
213
+ return { applicable: true, unknown, reasons };
214
+ }