@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.
- package/CHANGELOG.md +53 -0
- package/LICENSE-UNITY-COMPANION.md +122 -0
- package/LICENSE.md +31 -0
- package/NOTICE.md +90 -0
- package/README.md +273 -2
- package/cordis.patch.yml +22 -0
- package/docs/design.md +297 -0
- package/icon.svg +16 -0
- package/lib/frontmatter.js +392 -0
- package/lib/gating.js +105 -0
- package/lib/harness.js +16 -0
- package/lib/index.js +171 -0
- package/lib/project.js +210 -0
- package/lib/registry.js +268 -0
- package/lib/requirements.js +214 -0
- package/lib/skills.js +191 -0
- package/lib/types/frontmatter.d.ts +84 -0
- package/lib/types/gating.d.ts +80 -0
- package/lib/types/harness.d.ts +152 -0
- package/lib/types/index.d.ts +75 -0
- package/lib/types/project.d.ts +93 -0
- package/lib/types/registry.d.ts +96 -0
- package/lib/types/requirements.d.ts +67 -0
- package/lib/types/skills.d.ts +54 -0
- package/lib/types/watch.d.ts +34 -0
- package/lib/watch.js +84 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +70 -4
- package/skills/2d-pixel-perfect/SKILL.md +208 -0
- package/skills/2d-pixel-perfect/references/api-reference.md +81 -0
- package/skills/2d-pixel-perfect/references/camera-setup-builtin.cs +40 -0
- package/skills/2d-pixel-perfect/references/camera-setup-urp.cs +49 -0
- package/skills/2d-pixel-perfect/references/pipeline-detection.cs +50 -0
- package/skills/2d-pixel-perfect/references/sprite-settings.cs +37 -0
- package/skills/asset-transformer-toolkit/SECURITY.md +15 -0
- package/skills/asset-transformer-toolkit/SKILL.md +39 -0
- package/skills/asset-transformer-toolkit/references/create-importer.md +121 -0
- package/skills/asset-transformer-toolkit/references/lods.md +61 -0
- package/skills/asset-transformer-toolkit/references/rule-api.md +154 -0
- package/skills/asset-transformer-toolkit/references/ruleblock-api.md +37 -0
- package/skills/asset-transformer-toolkit/references/ruleset-api.md +138 -0
- package/skills/asset-transformer-toolkit/references/rulesets-and-actions.md +227 -0
- package/skills/audio-setup-mixers/SECURITY.md +16 -0
- package/skills/audio-setup-mixers/SKILL.md +127 -0
- package/skills/audio-setup-mixers/references/api.md +162 -0
- package/skills/build-gtk/SECURITY.md +16 -0
- package/skills/build-gtk/SKILL.md +200 -0
- package/skills/build-gtk/references/api-reference.md +33 -0
- package/skills/build-gtk/references/graph-api-gaps.md +96 -0
- package/skills/build-gtk/references/runtime-and-visualization.md +191 -0
- package/skills/build-gtk/references/state-machine-api.md +270 -0
- package/skills/build-gtk/references/where-the-docs-stop.md +49 -0
- package/skills/build-live-game/SKILL.md +159 -0
- package/skills/build-live-game/references/achievements.md +757 -0
- package/skills/build-live-game/references/apis.md +271 -0
- package/skills/build-live-game/references/authentication.md +431 -0
- package/skills/build-live-game/references/battlepass.md +904 -0
- package/skills/build-live-game/references/blueprints-and-samples.md +75 -0
- package/skills/build-live-game/references/cloud-code-cloudbehaviours.md +1111 -0
- package/skills/build-live-game/references/cloud-code-modules.md +1276 -0
- package/skills/build-live-game/references/cloud-code.md +58 -0
- package/skills/build-live-game/references/cloud-save.md +464 -0
- package/skills/build-live-game/references/deployment.md +231 -0
- package/skills/build-live-game/references/orientation.md +30 -0
- package/skills/build-live-game/references/player-account.md +821 -0
- package/skills/build-live-game/references/remote-config.md +96 -0
- package/skills/build-live-game/references/services-overview.md +76 -0
- package/skills/build-live-game/references/tooling.md +375 -0
- package/skills/build-live-game/references/ugs-cli.md +86 -0
- package/skills/craft-game-floors/SECURITY.md +23 -0
- package/skills/craft-game-floors/SKILL.md +134 -0
- package/skills/craft-game-floors/references/art-direction.md +85 -0
- package/skills/craft-game-floors/references/camera-rigs.md +51 -0
- package/skills/craft-game-floors/references/character-motion.md +35 -0
- package/skills/craft-game-floors/references/game-audio.md +47 -0
- package/skills/craft-game-floors/references/game-feel.md +68 -0
- package/skills/craft-game-floors/references/game-shell.md +45 -0
- package/skills/craft-game-floors/references/live-floor.md +35 -0
- package/skills/craft-game-floors/references/placeholder-assets.md +35 -0
- package/skills/craft-game-floors/references/scene-lighting.md +52 -0
- package/skills/craft-game-floors/references/toon-shading.md +34 -0
- package/skills/craft-game-floors/references/vfx.md +40 -0
- package/skills/craft-game-floors/references/visual-scorecard.md +43 -0
- package/skills/create-2d-physics/SECURITY.md +16 -0
- package/skills/create-2d-physics/SKILL.md +128 -0
- package/skills/create-2d-physics/references/2d-physics-core.md +155 -0
- package/skills/create-2d-physics/references/legacy-2d-physics.md +45 -0
- package/skills/create-tile-palette-or-rule-tiles/SKILL.md +95 -0
- package/skills/create-tile-palette-or-rule-tiles/references/hexagonalruletile.md +71 -0
- package/skills/create-tile-palette-or-rule-tiles/references/palette-create.md +38 -0
- package/skills/create-tile-palette-or-rule-tiles/references/ruletile-createempty.md +37 -0
- package/skills/create-tile-palette-or-rule-tiles/references/ruletile-createfromsegment.md +219 -0
- package/skills/create-tile-palette-or-rule-tiles/references/ruletile.md +95 -0
- package/skills/create-tile-palette-or-rule-tiles/scripts/CreatePaletteTemplate.cs +148 -0
- package/skills/create-tile-palette-or-rule-tiles/scripts/ManualWorkflowExample.cs +63 -0
- package/skills/create-tile-palette-or-rule-tiles/scripts/RuleTileGenerator.cs +61 -0
- package/skills/create-tile-palette-or-rule-tiles/scripts/TilemapRuleTileCreateFromSegment.cs +225 -0
- package/skills/fix-3d-physics-collisions/SECURITY.md +17 -0
- package/skills/fix-3d-physics-collisions/SKILL.md +139 -0
- package/skills/fix-3d-physics-collisions/references/collision-checklist.md +80 -0
- package/skills/fix-3d-physics-collisions/references/collision-debugger.md +18 -0
- package/skills/fix-3d-physics-collisions/references/console-errors-table.md +9 -0
- package/skills/fix-3d-physics-collisions/references/kinematic-trigger-facts.md +18 -0
- package/skills/fix-3d-physics-collisions/references/other-symptoms.md +29 -0
- package/skills/fix-3d-physics-collisions/references/raycast-checklist.md +8 -0
- package/skills/fix-3d-physics-collisions/references/topic-map.md +42 -0
- package/skills/fix-3d-physics-collisions/references/trigger-checklist.md +9 -0
- package/skills/fix-3d-physics-collisions/scripts/CollisionDebugger.cs +561 -0
- package/skills/generate-editor-search-query/SECURITY.md +17 -0
- package/skills/generate-editor-search-query/SKILL.md +117 -0
- package/skills/generate-editor-search-query/references/open-search-window.md +70 -0
- package/skills/generate-editor-search-query/references/query-patterns.md +124 -0
- package/skills/implement-in-app-purchases/SKILL.md +82 -0
- package/skills/implement-in-app-purchases/references/api-details.md +41 -0
- package/skills/implement-in-app-purchases/references/api-notes.md +105 -0
- package/skills/implement-in-app-purchases/references/codeless-catalog.md +197 -0
- package/skills/implement-in-app-purchases/references/convert-adapty.md +270 -0
- package/skills/implement-in-app-purchases/references/convert-essentialkit.md +239 -0
- package/skills/implement-in-app-purchases/references/convert-revenuecat.md +277 -0
- package/skills/implement-in-app-purchases/references/convert-unipay.md +145 -0
- package/skills/implement-in-app-purchases/references/migration-v4-to-v5.md +46 -0
- package/skills/implement-in-app-purchases/references/path-add-iap-to-new-project.md +197 -0
- package/skills/implement-in-app-purchases/references/path-convert-native-google-billing.md +302 -0
- package/skills/implement-in-app-purchases/references/path-convert-native-storekit.md +357 -0
- package/skills/implement-in-app-purchases/references/path-implement-iap-d2c.md +253 -0
- package/skills/implement-in-app-purchases/references/platform-notes.md +55 -0
- package/skills/implement-in-app-purchases/references/pre-check.md +207 -0
- package/skills/implement-in-app-purchases/references/topic-map.md +46 -0
- package/skills/initialize-ai-navigation/SKILL.md +109 -0
- package/skills/initialize-ai-navigation/references/navigation-system.md +793 -0
- package/skills/initialize-ai-navigation/references/topic-map.md +66 -0
- package/skills/levelplay-unity-integration/SKILL.md +122 -0
- package/skills/levelplay-unity-integration/references/adding-more-ad-formats.md +15 -0
- package/skills/levelplay-unity-integration/references/banner-api.md +927 -0
- package/skills/levelplay-unity-integration/references/best-practices.md +604 -0
- package/skills/levelplay-unity-integration/references/dependency-resolution.md +94 -0
- package/skills/levelplay-unity-integration/references/examples.md +10 -0
- package/skills/levelplay-unity-integration/references/ilrd-api.md +337 -0
- package/skills/levelplay-unity-integration/references/initialization-api.md +851 -0
- package/skills/levelplay-unity-integration/references/interstitial-api.md +907 -0
- package/skills/levelplay-unity-integration/references/ios-setup.md +463 -0
- package/skills/levelplay-unity-integration/references/migration-sdk-9.md +666 -0
- package/skills/levelplay-unity-integration/references/privacy-settings.md +593 -0
- package/skills/levelplay-unity-integration/references/production-release-checklist.md +22 -0
- package/skills/levelplay-unity-integration/references/rewarded-api.md +918 -0
- package/skills/levelplay-unity-integration/references/step-0-new-or-migration.md +8 -0
- package/skills/levelplay-unity-integration/references/step-1-verify-environment.md +4 -0
- package/skills/levelplay-unity-integration/references/step-10-testing.md +15 -0
- package/skills/levelplay-unity-integration/references/step-2-business-goals.md +12 -0
- package/skills/levelplay-unity-integration/references/step-3-install-sdk.md +55 -0
- package/skills/levelplay-unity-integration/references/step-4-native-dependencies.md +22 -0
- package/skills/levelplay-unity-integration/references/step-5-app-key-and-ad-units.md +18 -0
- package/skills/levelplay-unity-integration/references/step-6-5-privacy-and-regulation.md +51 -0
- package/skills/levelplay-unity-integration/references/step-6-admob-keys.md +16 -0
- package/skills/levelplay-unity-integration/references/step-7-initialize.md +50 -0
- package/skills/levelplay-unity-integration/references/step-8-ad-unit-strategy.md +16 -0
- package/skills/levelplay-unity-integration/references/step-9-implement-ad-units.md +66 -0
- package/skills/levelplay-unity-integration/references/testing-and-validation.md +222 -0
- package/skills/levelplay-unity-integration/references/troubleshooting.md +99 -0
- package/skills/localize-unity-project/SKILL.md +159 -0
- package/skills/localize-unity-project/references/api-notes.md +15 -0
- package/skills/localize-unity-project/references/cjk-fonts.md +83 -0
- package/skills/localize-unity-project/references/docs-map.md +42 -0
- package/skills/localize-unity-project/references/documentation-lookup.md +33 -0
- package/skills/localize-unity-project/references/locale-switching.md +17 -0
- package/skills/localize-unity-project/references/table-completeness-check.md +47 -0
- package/skills/localize-unity-project/references/translating-existing-project.md +47 -0
- package/skills/localize-unity-project/references/translation-strategy.md +41 -0
- package/skills/localize-unity-project/references/troubleshooting.md +12 -0
- package/skills/localize-unity-project/scripts/L10nBatchProcessor.cs +191 -0
- package/skills/localize-unity-project/scripts/LocalizedFontAsset.cs +18 -0
- package/skills/manage-sprite-atlas/SKILL.md +202 -0
- package/skills/manage-sprite-atlas/references/addressables-delivery.md +58 -0
- package/skills/manage-sprite-atlas/references/advanced-manual-authoring.md +19 -0
- package/skills/manage-sprite-atlas/references/api.md +382 -0
- package/skills/manage-sprite-atlas/references/best-practices.md +183 -0
- package/skills/manage-sprite-atlas/references/common-errors.md +123 -0
- package/skills/manage-sprite-atlas/references/complete-workflow.md +61 -0
- package/skills/manage-sprite-atlas/references/custom-packing.md +147 -0
- package/skills/manage-sprite-atlas/references/delivery-mechanism.md +30 -0
- package/skills/manage-sprite-atlas/references/key-requirements.md +21 -0
- package/skills/manage-sprite-atlas/references/manual-authoring.md +39 -0
- package/skills/manage-sprite-atlas/references/namespaces.md +15 -0
- package/skills/manage-sprite-atlas/references/v2-architecture.md +21 -0
- package/skills/manage-sprite-atlas/resources/authoringvsruntime.cs +176 -0
- package/skills/manage-sprite-atlas/resources/buildaddressablespostprocess.cs +59 -0
- package/skills/manage-sprite-atlas/resources/cacheloadedatlases.cs +145 -0
- package/skills/manage-sprite-atlas/resources/cleanupbatchoperations.cs +119 -0
- package/skills/manage-sprite-atlas/resources/createandconfiguremasteratlas.cs +57 -0
- package/skills/manage-sprite-atlas/resources/custompackersetup.cs +88 -0
- package/skills/manage-sprite-atlas/resources/deprecatedmethods.cs +142 -0
- package/skills/manage-sprite-atlas/resources/dontmodifywithoutsaving.cs +120 -0
- package/skills/manage-sprite-atlas/resources/dontpackinruntimebuilds.cs +190 -0
- package/skills/manage-sprite-atlas/resources/dontscriptspriteatlasineditor.cs +114 -0
- package/skills/manage-sprite-atlas/resources/editorconfiguration.cs +95 -0
- package/skills/manage-sprite-atlas/resources/enablespritepacking.cs +172 -0
- package/skills/manage-sprite-atlas/resources/gridspritepacker.cs +50 -0
- package/skills/manage-sprite-atlas/resources/handlelatebinding.cs +147 -0
- package/skills/manage-sprite-atlas/resources/handlenullcases.cs +141 -0
- package/skills/manage-sprite-atlas/resources/migratev1tov2.cs +335 -0
- package/skills/manage-sprite-atlas/resources/multipagepacker.cs +80 -0
- package/skills/manage-sprite-atlas/resources/optimizetexturesettings.cs +191 -0
- package/skills/manage-sprite-atlas/resources/packerdebugging.cs +158 -0
- package/skills/manage-sprite-atlas/resources/packtransform.cs +51 -0
- package/skills/manage-sprite-atlas/resources/platformnames.cs +127 -0
- package/skills/manage-sprite-atlas/resources/queryspritesefficiently.cs +222 -0
- package/skills/manage-sprite-atlas/resources/registercallbacks.cs +152 -0
- package/skills/manage-sprite-atlas/resources/runtimeatlasloader.cs +15 -0
- package/skills/manage-sprite-atlas/resources/runtimespriteaccess.cs +19 -0
- package/skills/manage-sprite-atlas/resources/savespriteatlasasset.cs +107 -0
- package/skills/manage-sprite-atlas/resources/scriptablepacker.cs +81 -0
- package/skills/manage-sprite-atlas/resources/setincludeinbuild.cs +164 -0
- package/skills/manage-sprite-atlas/resources/sizeoptimizedpacker.cs +88 -0
- package/skills/manage-sprite-atlas/resources/spriteatlaslatebinding.cs +123 -0
- package/skills/manage-sprite-atlas/resources/spriteatlasprebuildgenerator.cs +219 -0
- package/skills/manage-sprite-atlas/resources/spritedata.cs +35 -0
- package/skills/manage-sprite-atlas/resources/spritepack.cs +39 -0
- package/skills/manage-sprite-atlas/resources/texturedata.cs +15 -0
- package/skills/manage-sprite-atlas/resources/updatebuildscripts.cs +357 -0
- package/skills/manage-sprite-atlas/resources/updatesettingsconfiguration.cs +135 -0
- package/skills/manage-sprite-atlas/resources/usevariantswisely.cs +179 -0
- package/skills/manage-sprite-atlas/resources/variantatlas.cs +39 -0
- package/skills/migrate-birp-to-urp/SECURITY.md +16 -0
- package/skills/migrate-birp-to-urp/SKILL.md +167 -0
- package/skills/migrate-birp-to-urp/references/capturing-the-editor.md +66 -0
- package/skills/migrate-birp-to-urp/references/complex-shader-situations.md +272 -0
- package/skills/migrate-birp-to-urp/references/conversion-and-rendering-triage.md +113 -0
- package/skills/migrate-birp-to-urp/references/custom-shader-triage.md +123 -0
- package/skills/migrate-birp-to-urp/references/implementation-patterns.md +529 -0
- package/skills/migrate-birp-to-urp/references/migration-workflow.md +265 -0
- package/skills/migrate-birp-to-urp/references/parity-validation-and-troubleshooting.md +114 -0
- package/skills/migrate-birp-to-urp/references/preflight-and-urp-setup.md +195 -0
- package/skills/migrate-birp-to-urp/references/quality-settings-map.md +69 -0
- package/skills/new-unity-project/SECURITY.md +26 -0
- package/skills/new-unity-project/SKILL.md +171 -0
- package/skills/new-unity-project/references/checklist.md +18 -0
- package/skills/new-unity-project/references/common-mistakes.md +15 -0
- package/skills/new-unity-project/references/skill-setup.md +66 -0
- package/skills/new-unity-project/references/step-1-concept.md +13 -0
- package/skills/new-unity-project/references/step-2-platforms-and-create.md +31 -0
- package/skills/new-unity-project/references/step-3-join-and-reconcile.md +16 -0
- package/skills/new-unity-project/references/step-4-source-control.md +9 -0
- package/skills/new-unity-project/references/step-5-packages.md +18 -0
- package/skills/new-unity-project/references/step-6-identity-and-floors.md +20 -0
- package/skills/new-unity-project/references/step-7-visual-baseline.md +75 -0
- package/skills/new-unity-project/references/step-8-first-commit.md +21 -0
- package/skills/new-unity-project/references/step-9-handoff.md +23 -0
- package/skills/optimize-audio/SECURITY.md +16 -0
- package/skills/optimize-audio/SKILL.md +120 -0
- package/skills/optimize-audio/references/diagnostics.md +42 -0
- package/skills/optimize-audio/references/troubleshooting.md +41 -0
- package/skills/optimize-audio/resources/audio-import-api.md +149 -0
- package/skills/optimize-audio/resources/platform-settings.md +48 -0
- package/skills/optimize-text-mesh-pro/SKILL.md +181 -0
- package/skills/optimize-text-mesh-pro/references/dynamic-atlas-and-profiling.md +28 -0
- package/skills/optimize-text-mesh-pro/references/topic-map.md +36 -0
- package/skills/optimize-web/SECURITY.md +16 -0
- package/skills/optimize-web/SKILL.md +157 -0
- package/skills/optimize-web/references/editor-csharp.md +120 -0
- package/skills/optimize-web/references/topic-map.md +49 -0
- package/skills/optimize-web/references/troubleshooting.md +45 -0
- package/skills/optimize-web/references/understand-request.md +19 -0
- package/skills/optimize-web/references/web-assets-quality.md +59 -0
- package/skills/optimize-web/references/web-player-settings.md +39 -0
- package/skills/optimize-web/references/web-profiling-memory.md +71 -0
- package/skills/optimize-web/scripts/WebOptimizer.cs +46 -0
- package/skills/optimize-web/scripts/toktx-examples.sh +11 -0
- package/skills/setup-multiplayer-services/SKILL.md +36 -0
- package/skills/setup-multiplayer-services/references/dgs-entrypoint.md +79 -0
- package/skills/setup-multiplayer-services/references/entrypoints.md +213 -0
- package/skills/setup-multiplayer-services/references/examples.md +33 -0
- package/skills/setup-multiplayer-services/references/implementation-fit.md +30 -0
- package/skills/setup-multiplayer-services/references/underlying-services.md +11 -0
- package/skills/setup-multiplayer-services/references/workflows-prerequisites.md +17 -0
- package/skills/setup-vivox-voice-chat/SECURITY.md +16 -0
- package/skills/setup-vivox-voice-chat/SKILL.md +166 -0
- package/skills/setup-vivox-voice-chat/references/api-reference-lookup.md +28 -0
- package/skills/setup-vivox-voice-chat/references/docs-topic-map.md +13 -0
- package/skills/setup-vivox-voice-chat/references/events-and-participants.md +79 -0
- package/skills/setup-vivox-voice-chat/references/init-and-login.md +92 -0
- package/skills/setup-vivox-voice-chat/references/text-chat.md +93 -0
- package/skills/setup-vivox-voice-chat/references/troubleshooting.md +47 -0
- package/skills/setup-vivox-voice-chat/references/voice-channels.md +92 -0
- package/skills/shader-graph-create-custom-node/SKILL.md +25 -0
- package/skills/shader-graph-create-custom-node/resources/all_hints.hlsl +182 -0
- package/skills/sprite-editor/SECURITY.md +16 -0
- package/skills/sprite-editor/SKILL.md +66 -0
- package/skills/sprite-editor/references/api_reference.md +151 -0
- package/skills/sprite-editor/references/background.md +112 -0
- package/skills/sprite-editor/references/templates.md +72 -0
- package/skills/sprite-editor/scripts/AutomaticSliceTexture.cs +40 -0
- package/skills/sprite-editor/scripts/GenerateNewSpriteRects.cs +200 -0
- package/skills/sprite-editor/scripts/GetTextureSourceImageSize.cs +32 -0
- package/skills/sprite-editor/scripts/GetTextureToSlice.cs +55 -0
- package/skills/sprite-editor/scripts/GridSliceTexture.cs +40 -0
- package/skills/sprite-editor/scripts/IsometricSliceTexture.cs +141 -0
- package/skills/sprite-editor/scripts/README.md +134 -0
- package/skills/sprite-editor/scripts/SetPivotExample.cs +58 -0
- package/skills/sprite-editor/scripts/SpriteToPng.cs +88 -0
- package/skills/sprite-segment-3x3grid/SKILL.md +177 -0
- package/skills/sprite-segment-3x3grid/references/topic-map.md +37 -0
- package/skills/sprite-segment-3x3grid/scripts/SpriteGridAnalysis.cs +119 -0
- package/skills/ui/SKILL.md +142 -0
- package/skills/ui-imgui/SKILL.md +180 -0
- package/skills/ui-imgui/references/gui-elements.md +156 -0
- package/skills/ui-imgui/references/templates.md +141 -0
- package/skills/ui-ugui/SKILL.md +217 -0
- package/skills/ui-ugui/references/layout-and-anchors.md +61 -0
- package/skills/ui-ugui/references/scrollview-setup.md +29 -0
- package/skills/ui-uitk/SKILL.md +229 -0
- package/skills/ui-uitk/references/common-issues.md +74 -0
- package/skills/ui-uitk/references/custom-elements.md +241 -0
- package/skills/ui-uitk/references/painter2d.md +282 -0
- package/skills/ui-uitk/references/pointermanipulator-guide.md +94 -0
- package/skills/ui-uitk/references/svg-icons.md +136 -0
- package/skills/ui-uitk/references/ui-runtime-binding.md +234 -0
- package/skills/ui-uitk/references/uss-guide.md +138 -0
- package/skills/unity-cli/CHANGELOG.md +524 -0
- package/skills/unity-cli/SECURITY.md +68 -0
- package/skills/unity-cli/SKILL.md +160 -0
- package/skills/unity-cli/references/auth-license-cloud.md +318 -0
- package/skills/unity-cli/references/bootstrap-project.md +177 -0
- package/skills/unity-cli/references/build-run-test.md +555 -0
- package/skills/unity-cli/references/catalog-plugins.md +86 -0
- package/skills/unity-cli/references/ci-recipes.md +76 -0
- package/skills/unity-cli/references/cloud-automation.md +819 -0
- package/skills/unity-cli/references/cloud-workflows.md +19 -0
- package/skills/unity-cli/references/collaboration.md +533 -0
- package/skills/unity-cli/references/config-hub.md +239 -0
- package/skills/unity-cli/references/diagnostics-maintenance.md +718 -0
- package/skills/unity-cli/references/docs-workflow.md +179 -0
- package/skills/unity-cli/references/editor-targeting.md +29 -0
- package/skills/unity-cli/references/editors-install.md +490 -0
- package/skills/unity-cli/references/environment-variables.md +42 -0
- package/skills/unity-cli/references/exit-codes.md +47 -0
- package/skills/unity-cli/references/global-flags.md +32 -0
- package/skills/unity-cli/references/integration-advanced.md +1130 -0
- package/skills/unity-cli/references/notes.md +20 -0
- package/skills/unity-cli/references/notifications.md +39 -0
- package/skills/unity-cli/references/playmode-verification-loop.md +279 -0
- package/skills/unity-cli/references/projects-templates.md +997 -0
- package/skills/unity-cli/references/scene-editing-preflight.md +25 -0
- package/skills/unity-cli/references/setup-and-help.md +54 -0
- package/skills/unity-cli/references/version-control.md +612 -0
- package/skills/unity-package-management/SKILL.md +169 -0
- package/skills/unity-package-management/references/discovering-packages.md +66 -0
- package/skills/unity-package-management/references/headless-run.md +31 -0
- package/skills/unity-package-management/references/installer-script.md +92 -0
- package/skills/unity-package-management/references/select-packages.md +126 -0
- package/skills/unity-pipeline/SECURITY.md +17 -0
- package/skills/unity-pipeline/SKILL.md +205 -0
- package/skills/unity-pipeline/references/csharp-eval.md +23 -0
- package/skills/unity-pipeline/references/multiplayer-play-mode.md +103 -0
- package/skills/urp-postprocessing/SECURITY.md +16 -0
- package/skills/urp-postprocessing/SKILL.md +188 -0
- package/skills/urp-postprocessing/references/code-templates.md +150 -0
- package/skills/urp-postprocessing/references/effect-reference.md +86 -0
- package/skills/validate-urp-render-graph-renderer-feature/SKILL.md +92 -0
- package/skills/validate-urp-render-graph-renderer-feature/references/validation-checklist.md +179 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML frontmatter reader for SKILL.md files.
|
|
3
|
+
*
|
|
4
|
+
* The skill documents use a small, well-understood subset of YAML, so the plugin
|
|
5
|
+
* carries its own reader instead of a parser dependency: the package must install
|
|
6
|
+
* with no build-time or run-time third-party code. Supported syntax:
|
|
7
|
+
*
|
|
8
|
+
* - top-level `key: value` mappings, including nested block mappings
|
|
9
|
+
* (`required_packages`, `metadata`);
|
|
10
|
+
* - block sequences (`allowed-tools` followed by `- item` lines);
|
|
11
|
+
* - flow sequences (`modes: [agent, ask]`);
|
|
12
|
+
* - plain, single-quoted, and double-quoted scalars;
|
|
13
|
+
* - literal (`|`, `|-`, `|+`) and folded (`>`, `>-`, `>+`) block scalars;
|
|
14
|
+
* - full-line comments and inline ` #` comments on plain scalars.
|
|
15
|
+
*
|
|
16
|
+
* Scalars resolve through the YAML 1.2 core schema, matching what a full parser
|
|
17
|
+
* would produce for these documents. The invocation policy uses the registry's
|
|
18
|
+
* strict boolean grammar. A value this reader cannot represent is reported as a
|
|
19
|
+
* syntax error so the caller can skip the skill instead of advertising a wrong
|
|
20
|
+
* description.
|
|
21
|
+
*
|
|
22
|
+
* @module dsh-unity/lib/frontmatter
|
|
23
|
+
*/
|
|
24
|
+
/** Kebab-case grammar shared by the harness skill registry. */
|
|
25
|
+
export const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
26
|
+
const FENCE = '---';
|
|
27
|
+
const BLOCK_HEADER = /^([|>])([+-]?)(\d?)$/;
|
|
28
|
+
/**
|
|
29
|
+
* Split a Markdown document into its YAML frontmatter block and body.
|
|
30
|
+
*
|
|
31
|
+
* @param raw - complete file text.
|
|
32
|
+
* @returns the frontmatter source and body, or `undefined` without a fence.
|
|
33
|
+
*/
|
|
34
|
+
export function splitFrontmatter(raw) {
|
|
35
|
+
const text = raw.replace(/^\uFEFF/, '').replace(/\r\n?/g, '\n');
|
|
36
|
+
const lines = text.split('\n');
|
|
37
|
+
if (lines[0]?.trimEnd() !== FENCE)
|
|
38
|
+
return undefined;
|
|
39
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
40
|
+
if (lines[index]?.trimEnd() === FENCE) {
|
|
41
|
+
return { yaml: lines.slice(1, index).join('\n'), body: lines.slice(index + 1).join('\n') };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parse a SKILL.md document into frontmatter fields and body.
|
|
48
|
+
*
|
|
49
|
+
* @param raw - complete file text.
|
|
50
|
+
* @returns parsed frontmatter and the trimmed body, or `undefined` without a fence.
|
|
51
|
+
* @throws {SyntaxError} when the frontmatter is not the supported YAML subset.
|
|
52
|
+
*/
|
|
53
|
+
export function parseSkillMarkdown(raw) {
|
|
54
|
+
const split = splitFrontmatter(raw);
|
|
55
|
+
if (split === undefined)
|
|
56
|
+
return undefined;
|
|
57
|
+
const data = parseYamlSubset(split.yaml);
|
|
58
|
+
if (data === null || typeof data !== 'object' || Array.isArray(data)) {
|
|
59
|
+
throw new SyntaxError('frontmatter is not a mapping');
|
|
60
|
+
}
|
|
61
|
+
return { data: data, body: split.body.trim() };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Parse the supported YAML subset into a plain value.
|
|
65
|
+
*
|
|
66
|
+
* @param source - YAML text without the surrounding fences.
|
|
67
|
+
* @returns a mapping, sequence, scalar, or `null` for a `key:` without a value.
|
|
68
|
+
* @throws {SyntaxError} on indentation this subset cannot represent.
|
|
69
|
+
*/
|
|
70
|
+
export function parseYamlSubset(source) {
|
|
71
|
+
const lines = source.replace(/\r\n?/g, '\n').split('\n');
|
|
72
|
+
const cursor = { index: 0 };
|
|
73
|
+
skipInert(lines, cursor);
|
|
74
|
+
if (cursor.index >= lines.length)
|
|
75
|
+
return {};
|
|
76
|
+
const value = parseBlock(lines, cursor, indentationOf(lines[cursor.index] ?? ''));
|
|
77
|
+
skipInert(lines, cursor);
|
|
78
|
+
if (cursor.index < lines.length) {
|
|
79
|
+
throw new SyntaxError(`unexpected content on line ${cursor.index + 1}`);
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Read a frontmatter boolean with the registry's strict grammar.
|
|
85
|
+
*
|
|
86
|
+
* @param data - parsed frontmatter.
|
|
87
|
+
* @param key - exact frontmatter key.
|
|
88
|
+
* @returns the value, or `undefined` when the key is absent.
|
|
89
|
+
* @throws {TypeError} when the key is present but is not a boolean spelling.
|
|
90
|
+
*/
|
|
91
|
+
export function frontmatterBoolean(data, key) {
|
|
92
|
+
if (!Object.hasOwn(data, key))
|
|
93
|
+
return undefined;
|
|
94
|
+
const value = data[key];
|
|
95
|
+
if (typeof value === 'boolean')
|
|
96
|
+
return value;
|
|
97
|
+
if (value === 1 || value === '1')
|
|
98
|
+
return true;
|
|
99
|
+
if (value === 0 || value === '0')
|
|
100
|
+
return false;
|
|
101
|
+
if (typeof value === 'string') {
|
|
102
|
+
switch (value.toLowerCase()) {
|
|
103
|
+
case 'true':
|
|
104
|
+
case 'yes':
|
|
105
|
+
case 'on':
|
|
106
|
+
return true;
|
|
107
|
+
case 'false':
|
|
108
|
+
case 'no':
|
|
109
|
+
case 'off':
|
|
110
|
+
return false;
|
|
111
|
+
default:
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
throw new TypeError(`frontmatter field "${key}" must be a boolean`);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Resolve the invocation policy from frontmatter.
|
|
119
|
+
*
|
|
120
|
+
* @param data - parsed frontmatter.
|
|
121
|
+
* @returns the policy; absent keys keep both surfaces permitted.
|
|
122
|
+
* @throws {Error} when a legacy camelCase key is present.
|
|
123
|
+
*/
|
|
124
|
+
export function parseInvocation(data) {
|
|
125
|
+
const legacy = [
|
|
126
|
+
['disableModelInvocation', 'disable-model-invocation'],
|
|
127
|
+
['modelInvocable', 'disable-model-invocation'],
|
|
128
|
+
['userInvocable', 'user-invocable'],
|
|
129
|
+
];
|
|
130
|
+
for (const [alias, canonical] of legacy) {
|
|
131
|
+
if (Object.hasOwn(data, alias)) {
|
|
132
|
+
throw new Error(`frontmatter field "${alias}" is unsupported; use "${canonical}"`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
modelInvocable: frontmatterBoolean(data, 'disable-model-invocation') !== true,
|
|
137
|
+
userInvocable: frontmatterBoolean(data, 'user-invocable') !== false,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/** Advance the cursor past blank lines and full-line comments. */
|
|
141
|
+
function skipInert(lines, cursor) {
|
|
142
|
+
while (cursor.index < lines.length) {
|
|
143
|
+
const line = lines[cursor.index] ?? '';
|
|
144
|
+
if (line.trim() === '' || line.trimStart().startsWith('#')) {
|
|
145
|
+
cursor.index += 1;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** Count leading spaces of a line. */
|
|
152
|
+
function indentationOf(line) {
|
|
153
|
+
const match = /^ */.exec(line);
|
|
154
|
+
return match === null ? 0 : match[0].length;
|
|
155
|
+
}
|
|
156
|
+
/** Parse one block (mapping or sequence) whose lines start at `indent`. */
|
|
157
|
+
function parseBlock(lines, cursor, indent) {
|
|
158
|
+
const first = lines[cursor.index] ?? '';
|
|
159
|
+
if (/^\s*-(?:\s|$)/.test(first))
|
|
160
|
+
return parseSequence(lines, cursor, indent);
|
|
161
|
+
return parseMapping(lines, cursor, indent);
|
|
162
|
+
}
|
|
163
|
+
/** Parse consecutive `key: value` lines at one indentation. */
|
|
164
|
+
function parseMapping(lines, cursor, indent) {
|
|
165
|
+
const result = {};
|
|
166
|
+
while (true) {
|
|
167
|
+
skipInert(lines, cursor);
|
|
168
|
+
if (cursor.index >= lines.length)
|
|
169
|
+
break;
|
|
170
|
+
const line = lines[cursor.index] ?? '';
|
|
171
|
+
const current = indentationOf(line);
|
|
172
|
+
if (current < indent)
|
|
173
|
+
break;
|
|
174
|
+
if (current > indent)
|
|
175
|
+
throw new SyntaxError(`unexpected indentation on line ${cursor.index + 1}`);
|
|
176
|
+
const entry = /^([^:#][^:]*?):(?:[ \t]+(.*)|[ \t]*)$/.exec(line.slice(indent));
|
|
177
|
+
if (entry === null)
|
|
178
|
+
throw new SyntaxError(`expected "key: value" on line ${cursor.index + 1}`);
|
|
179
|
+
const key = entry[1]?.trim() ?? '';
|
|
180
|
+
const rest = (entry[2] ?? '').trimEnd();
|
|
181
|
+
cursor.index += 1;
|
|
182
|
+
result[key] = parseValue(lines, cursor, indent, rest);
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
/** Parse consecutive `- item` lines at one indentation. */
|
|
187
|
+
function parseSequence(lines, cursor, indent) {
|
|
188
|
+
const result = [];
|
|
189
|
+
while (true) {
|
|
190
|
+
skipInert(lines, cursor);
|
|
191
|
+
if (cursor.index >= lines.length)
|
|
192
|
+
break;
|
|
193
|
+
const line = lines[cursor.index] ?? '';
|
|
194
|
+
const current = indentationOf(line);
|
|
195
|
+
if (current < indent)
|
|
196
|
+
break;
|
|
197
|
+
if (current > indent)
|
|
198
|
+
throw new SyntaxError(`unexpected indentation on line ${cursor.index + 1}`);
|
|
199
|
+
const item = /^-(?:\s+(.*)|\s*)$/.exec(line.slice(indent).trimEnd());
|
|
200
|
+
if (item === null)
|
|
201
|
+
break;
|
|
202
|
+
const rest = (item[1] ?? '').trim();
|
|
203
|
+
cursor.index += 1;
|
|
204
|
+
if (rest === '') {
|
|
205
|
+
skipInert(lines, cursor);
|
|
206
|
+
const nested = lines[cursor.index];
|
|
207
|
+
const nestedIndent = nested === undefined ? indent : indentationOf(nested);
|
|
208
|
+
result.push(nestedIndent > indent ? parseBlock(lines, cursor, nestedIndent) : null);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
result.push(parseValue(lines, cursor, indent, rest));
|
|
212
|
+
}
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
/** Resolve the value that follows `key:` or `- `. */
|
|
216
|
+
function parseValue(lines, cursor, indent, rest) {
|
|
217
|
+
if (rest.startsWith('#'))
|
|
218
|
+
return parseNestedOrNull(lines, cursor, indent);
|
|
219
|
+
const block = BLOCK_HEADER.exec(rest);
|
|
220
|
+
if (block !== null)
|
|
221
|
+
return parseBlockScalar(lines, cursor, indent, block[1], block[2]);
|
|
222
|
+
if (rest !== '') {
|
|
223
|
+
const plain = stripComment(rest);
|
|
224
|
+
return plain === '' ? parseNestedOrNull(lines, cursor, indent) : parseScalar(plain);
|
|
225
|
+
}
|
|
226
|
+
return parseNestedOrNull(lines, cursor, indent);
|
|
227
|
+
}
|
|
228
|
+
/** Read a nested block after `key:` when no inline value was present. */
|
|
229
|
+
function parseNestedOrNull(lines, cursor, indent) {
|
|
230
|
+
skipInert(lines, cursor);
|
|
231
|
+
const next = lines[cursor.index];
|
|
232
|
+
if (next === undefined)
|
|
233
|
+
return null;
|
|
234
|
+
const nestedIndent = indentationOf(next);
|
|
235
|
+
if (nestedIndent <= indent)
|
|
236
|
+
return null;
|
|
237
|
+
return parseBlock(lines, cursor, nestedIndent);
|
|
238
|
+
}
|
|
239
|
+
/** Collect an indented block scalar and apply its folding and chomping. */
|
|
240
|
+
function parseBlockScalar(lines, cursor, indent, style, chomping) {
|
|
241
|
+
const collected = [];
|
|
242
|
+
let blockIndent;
|
|
243
|
+
while (cursor.index < lines.length) {
|
|
244
|
+
const line = lines[cursor.index] ?? '';
|
|
245
|
+
if (line.trim() === '') {
|
|
246
|
+
collected.push('');
|
|
247
|
+
cursor.index += 1;
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const current = indentationOf(line);
|
|
251
|
+
if (current <= indent)
|
|
252
|
+
break;
|
|
253
|
+
if (blockIndent === undefined)
|
|
254
|
+
blockIndent = current;
|
|
255
|
+
collected.push(line.slice(Math.min(blockIndent, current)));
|
|
256
|
+
cursor.index += 1;
|
|
257
|
+
}
|
|
258
|
+
while (collected.length > 0 && collected[collected.length - 1] === '') {
|
|
259
|
+
collected.pop();
|
|
260
|
+
}
|
|
261
|
+
const text = style === '|' ? collected.join('\n') : foldLines(collected);
|
|
262
|
+
if (chomping === '-')
|
|
263
|
+
return text;
|
|
264
|
+
return collected.length === 0 ? '' : `${text}\n`;
|
|
265
|
+
}
|
|
266
|
+
/** Fold block-scalar lines: single breaks become spaces, blank lines newlines. */
|
|
267
|
+
function foldLines(lines) {
|
|
268
|
+
let out = '';
|
|
269
|
+
let pendingBreaks = 0;
|
|
270
|
+
for (const line of lines) {
|
|
271
|
+
if (line === '') {
|
|
272
|
+
pendingBreaks += 1;
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (out === '') {
|
|
276
|
+
out = line;
|
|
277
|
+
pendingBreaks = 0;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
out += pendingBreaks > 0 ? '\n'.repeat(pendingBreaks) : ' ';
|
|
281
|
+
out += line;
|
|
282
|
+
pendingBreaks = 0;
|
|
283
|
+
}
|
|
284
|
+
return out;
|
|
285
|
+
}
|
|
286
|
+
/** Strip a ` #` inline comment from a plain scalar. */
|
|
287
|
+
function stripComment(text) {
|
|
288
|
+
const index = text.search(/\s#/);
|
|
289
|
+
return index < 0 ? text.trim() : text.slice(0, index).trim();
|
|
290
|
+
}
|
|
291
|
+
/** Parse a single inline scalar: flow sequence, quoted string, or plain text. */
|
|
292
|
+
function parseScalar(text) {
|
|
293
|
+
if (text.startsWith('[') && text.endsWith(']')) {
|
|
294
|
+
const inner = text.slice(1, -1).trim();
|
|
295
|
+
if (inner === '')
|
|
296
|
+
return [];
|
|
297
|
+
return splitFlow(inner).map((item) => parseScalar(item.trim()));
|
|
298
|
+
}
|
|
299
|
+
if (text.startsWith('"') && text.endsWith('"') && text.length >= 2) {
|
|
300
|
+
return unescapeDouble(text.slice(1, -1));
|
|
301
|
+
}
|
|
302
|
+
if (text.startsWith("'") && text.endsWith("'") && text.length >= 2) {
|
|
303
|
+
return text.slice(1, -1).replaceAll("''", "'");
|
|
304
|
+
}
|
|
305
|
+
return resolvePlain(text);
|
|
306
|
+
}
|
|
307
|
+
/** Resolve a plain scalar through the YAML 1.2 core schema. */
|
|
308
|
+
function resolvePlain(text) {
|
|
309
|
+
switch (text) {
|
|
310
|
+
case 'null':
|
|
311
|
+
case 'Null':
|
|
312
|
+
case 'NULL':
|
|
313
|
+
case '~':
|
|
314
|
+
return null;
|
|
315
|
+
case 'true':
|
|
316
|
+
case 'True':
|
|
317
|
+
case 'TRUE':
|
|
318
|
+
return true;
|
|
319
|
+
case 'false':
|
|
320
|
+
case 'False':
|
|
321
|
+
case 'FALSE':
|
|
322
|
+
return false;
|
|
323
|
+
default:
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
if (/^[-+]?\d+$/.test(text))
|
|
327
|
+
return Number(text);
|
|
328
|
+
if (/^[-+]?(?:\d+\.\d*|\.\d+|\d+)(?:[eE][-+]?\d+)?$/.test(text))
|
|
329
|
+
return Number(text);
|
|
330
|
+
return text;
|
|
331
|
+
}
|
|
332
|
+
/** Split flow-sequence contents on commas that are not inside quotes. */
|
|
333
|
+
function splitFlow(text) {
|
|
334
|
+
const parts = [];
|
|
335
|
+
let current = '';
|
|
336
|
+
let quote;
|
|
337
|
+
for (const char of text) {
|
|
338
|
+
if (quote !== undefined) {
|
|
339
|
+
current += char;
|
|
340
|
+
if (char === quote)
|
|
341
|
+
quote = undefined;
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
if (char === '"' || char === "'") {
|
|
345
|
+
quote = char;
|
|
346
|
+
current += char;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (char === ',') {
|
|
350
|
+
parts.push(current);
|
|
351
|
+
current = '';
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
current += char;
|
|
355
|
+
}
|
|
356
|
+
parts.push(current);
|
|
357
|
+
return parts;
|
|
358
|
+
}
|
|
359
|
+
/** Decode the double-quoted escapes present in these documents. */
|
|
360
|
+
function unescapeDouble(text) {
|
|
361
|
+
let out = '';
|
|
362
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
363
|
+
const char = text[index];
|
|
364
|
+
if (char !== '\\') {
|
|
365
|
+
out += char;
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
const next = text[index + 1];
|
|
369
|
+
index += 1;
|
|
370
|
+
switch (next) {
|
|
371
|
+
case 'n':
|
|
372
|
+
out += '\n';
|
|
373
|
+
break;
|
|
374
|
+
case 't':
|
|
375
|
+
out += '\t';
|
|
376
|
+
break;
|
|
377
|
+
case 'r':
|
|
378
|
+
out += '\r';
|
|
379
|
+
break;
|
|
380
|
+
case '"':
|
|
381
|
+
out += '"';
|
|
382
|
+
break;
|
|
383
|
+
case '\\':
|
|
384
|
+
out += '\\';
|
|
385
|
+
break;
|
|
386
|
+
default:
|
|
387
|
+
out += next ?? '';
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return out;
|
|
392
|
+
}
|
package/lib/gating.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visibility decisions for one agent's skill catalog.
|
|
3
|
+
*
|
|
4
|
+
* The harness separates two questions about a skill: whether the model may see
|
|
5
|
+
* and load it (`modelInvocable`) and whether a person may invoke it by name
|
|
6
|
+
* (`userInvocable`). That split is exactly what project-aware gating needs: a
|
|
7
|
+
* skill that does not apply to the current project should leave the model's
|
|
8
|
+
* catalog to save context and avoid wrong suggestions, while staying reachable
|
|
9
|
+
* through an explicit `/skill-name` request.
|
|
10
|
+
*
|
|
11
|
+
* The rules here are intentionally conservative:
|
|
12
|
+
*
|
|
13
|
+
* - outside a Unity project only the configured workspace skills stay visible;
|
|
14
|
+
* - an unmet editor or package requirement hides the skill;
|
|
15
|
+
* - an *unknown* fact never hides a skill, so a broken manifest cannot silently
|
|
16
|
+
* empty the catalog;
|
|
17
|
+
* - a skill the project provides itself is not offered by this plugin at all,
|
|
18
|
+
* which is what keeps a project's own customization authoritative.
|
|
19
|
+
*
|
|
20
|
+
* @module dsh-unity/lib/gating
|
|
21
|
+
*/
|
|
22
|
+
import { evaluateRequirements } from './requirements.js';
|
|
23
|
+
/**
|
|
24
|
+
* Decide the model-visibility of one skill candidate.
|
|
25
|
+
*
|
|
26
|
+
* @param candidate - candidate carrying its `requirements`.
|
|
27
|
+
* @param facts - project facts from `detectProject`.
|
|
28
|
+
* @param settings - resolved plugin settings.
|
|
29
|
+
* @returns the decision and, when hidden, a short human-readable reason.
|
|
30
|
+
*/
|
|
31
|
+
export function decideVisibility(candidate, facts, settings) {
|
|
32
|
+
if (!settings.enforceRequirements)
|
|
33
|
+
return { modelInvocable: true, reason: undefined };
|
|
34
|
+
const verdict = evaluateRequirements(candidate.requirements ?? { packages: [] }, facts);
|
|
35
|
+
if (!verdict.applicable)
|
|
36
|
+
return { modelInvocable: false, reason: verdict.reasons.join('; ') };
|
|
37
|
+
return { modelInvocable: true, reason: undefined };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the catalog this plugin serves for one agent.
|
|
41
|
+
*
|
|
42
|
+
* Every candidate stays in the list so a person can still invoke a hidden skill
|
|
43
|
+
* by name; only its `modelInvocable` flag changes. Candidates the project
|
|
44
|
+
* overrides are dropped instead, so the project's own copy wins the name.
|
|
45
|
+
*
|
|
46
|
+
* @param candidates - candidates from the skill reader.
|
|
47
|
+
* @param facts - project facts, or `undefined` outside a project.
|
|
48
|
+
* @param settings - resolved plugin settings.
|
|
49
|
+
* @param projectSkills - skill names the project supplies itself.
|
|
50
|
+
* @returns gated candidates and the reasons for every hidden skill.
|
|
51
|
+
*/
|
|
52
|
+
export function gateCatalog(candidates, facts, settings, projectSkills = new Set()) {
|
|
53
|
+
const gated = [];
|
|
54
|
+
const hidden = [];
|
|
55
|
+
const projectOverridden = [];
|
|
56
|
+
const workspaceOnly = facts === undefined && settings.gateByProject;
|
|
57
|
+
for (const candidate of candidates) {
|
|
58
|
+
if (projectSkills.has(candidate.name)) {
|
|
59
|
+
projectOverridden.push(candidate.name);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
let reason;
|
|
63
|
+
if (workspaceOnly && !settings.workspaceSkills.has(candidate.name)) {
|
|
64
|
+
reason = 'no Unity project in this session';
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const decision = decideVisibility(candidate, facts, settings);
|
|
68
|
+
if (!decision.modelInvocable)
|
|
69
|
+
reason = decision.reason ?? 'requirements not met';
|
|
70
|
+
else if (candidate.invocation.modelInvocable !== true)
|
|
71
|
+
reason = 'the skill disables model invocation';
|
|
72
|
+
}
|
|
73
|
+
if (reason === undefined) {
|
|
74
|
+
gated.push(candidate);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
hidden.push({ name: candidate.name, reason });
|
|
78
|
+
gated.push({ ...candidate, invocation: { ...candidate.invocation, modelInvocable: false } });
|
|
79
|
+
}
|
|
80
|
+
return { candidates: gated, hidden, projectOverridden };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Render the runtime-context line contributed for one agent.
|
|
84
|
+
*
|
|
85
|
+
* Kept to one short paragraph: it is re-read on every prompt assembly, so it must
|
|
86
|
+
* describe facts the model cannot infer and nothing else.
|
|
87
|
+
*
|
|
88
|
+
* @param facts - project facts.
|
|
89
|
+
* @param hidden - gated-away skills.
|
|
90
|
+
* @returns the context text, or `undefined` when there is nothing to say.
|
|
91
|
+
*/
|
|
92
|
+
export function renderContext(facts, hidden) {
|
|
93
|
+
if (facts === undefined)
|
|
94
|
+
return undefined;
|
|
95
|
+
const pipeline = facts.renderPipeline === undefined ? '' : `, ${facts.renderPipeline.toUpperCase()}`;
|
|
96
|
+
const parts = [
|
|
97
|
+
`Unity project: ${facts.root} (Editor ${facts.editorVersion ?? 'unknown'}${pipeline}, Editor ${facts.editorOpen ? 'open' : 'closed'}, unity CLI ${facts.cliAvailable ? 'available' : 'not found'})`,
|
|
98
|
+
];
|
|
99
|
+
if (hidden.length > 0) {
|
|
100
|
+
const listed = hidden.slice(0, 6).map((entry) => `${entry.name} (${entry.reason})`);
|
|
101
|
+
const rest = hidden.length - listed.length;
|
|
102
|
+
parts.push(`skills hidden for this project: ${listed.join(', ')}${rest > 0 ? `, and ${rest} more` : ''}`);
|
|
103
|
+
}
|
|
104
|
+
return `${parts.join('. ')}.`;
|
|
105
|
+
}
|
package/lib/harness.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural declarations for the harness surfaces this plugin uses.
|
|
3
|
+
*
|
|
4
|
+
* The package is a plugin bundle, not a harness package: it never imports
|
|
5
|
+
* `@deepseek-ai/*` at runtime, and it deliberately keeps no build-time dependency
|
|
6
|
+
* on them so a local checkout type-checks without a network install. The
|
|
7
|
+
* interfaces below transcribe the parts of the harness contracts that matter
|
|
8
|
+
* here — the skill registry provider contract, the prompt-context contribution,
|
|
9
|
+
* the agent-scope boundary, and the optional services reached through `ctx.get`.
|
|
10
|
+
*
|
|
11
|
+
* Each type names the harness contract it mirrors. When the harness changes one
|
|
12
|
+
* of them, this file is the single place to update.
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-unity/lib/harness
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unity's curated skills as a DeepSeek Harness plugin.
|
|
3
|
+
*
|
|
4
|
+
* The package carries 34 skills under `skills/` and serves them through the
|
|
5
|
+
* harness skill registry. What distinguishes this from a directory of Markdown
|
|
6
|
+
* files is *where* and *how* they are served:
|
|
7
|
+
*
|
|
8
|
+
* - registration happens per agent, through that agent's own context, so this
|
|
9
|
+
* provider lives in the agent's scope layer and its catalog can depend on the
|
|
10
|
+
* project the agent is working in;
|
|
11
|
+
* - a Unity project is detected from the session's working directory, and skills
|
|
12
|
+
* whose `required_editor_version` / `required_packages` cannot be met leave the
|
|
13
|
+
* model's catalog while staying reachable by explicit name;
|
|
14
|
+
* - the detected project facts are contributed to the agent's runtime context, so
|
|
15
|
+
* the model states the editor version and package situation instead of guessing;
|
|
16
|
+
* - the skill directory is watched, and a frontmatter membership change
|
|
17
|
+
* invalidates the cached catalog instead of requiring a restart.
|
|
18
|
+
*
|
|
19
|
+
* @module @aqian0/dsh-unity
|
|
20
|
+
*/
|
|
21
|
+
import { join, resolve } from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import { createAgentRegistry, createGlobalProvider, serviceOf } from './registry.js';
|
|
24
|
+
import { createParseCache } from './skills.js';
|
|
25
|
+
import { startSkillsWatcher } from './watch.js';
|
|
26
|
+
/** Loader row name. */
|
|
27
|
+
export const name = 'unity-skills';
|
|
28
|
+
/** The skill registry this provider attaches to. */
|
|
29
|
+
export const inject = ['skills'];
|
|
30
|
+
/** Provider name the registry lists the catalog under. */
|
|
31
|
+
export const DEFAULT_PROVIDER_NAME = 'unity';
|
|
32
|
+
/**
|
|
33
|
+
* Default rank inside one scope layer. The catalog normally lands in the agent's
|
|
34
|
+
* own layer, where the nearest layer already wins duplicates; the rank only
|
|
35
|
+
* orders this provider against runtime (`ctx.skills.register()`) registrations,
|
|
36
|
+
* which use 250.
|
|
37
|
+
*/
|
|
38
|
+
export const DEFAULT_RANK = 240;
|
|
39
|
+
/**
|
|
40
|
+
* Skills worth showing outside a Unity project: creating a project, driving the
|
|
41
|
+
* editor from the CLI, and managing packages are all meaningful before a project
|
|
42
|
+
* exists.
|
|
43
|
+
*/
|
|
44
|
+
export const DEFAULT_WORKSPACE_SKILLS = [
|
|
45
|
+
'new-unity-project',
|
|
46
|
+
'unity-cli',
|
|
47
|
+
'unity-package-management',
|
|
48
|
+
];
|
|
49
|
+
/** Provider name reserved by the registry for per-agent runtime registrations. */
|
|
50
|
+
const RESERVED_PROVIDER = 'runtime';
|
|
51
|
+
/** Directory of this package, used to locate the packaged skills. */
|
|
52
|
+
const PACKAGE_DIR = fileURLToPath(new URL('../', import.meta.url));
|
|
53
|
+
/**
|
|
54
|
+
* Register the Unity skill provider on `ctx.skills`.
|
|
55
|
+
*
|
|
56
|
+
* @param ctx - Cordis plugin context; `skills` is injected.
|
|
57
|
+
* @param config - row config from the loader patch.
|
|
58
|
+
*/
|
|
59
|
+
export function apply(ctx, config = {}) {
|
|
60
|
+
const settings = resolveSettings(config);
|
|
61
|
+
settings.parseCache = createParseCache();
|
|
62
|
+
const registry = createAgentRegistry({ ctx, settings });
|
|
63
|
+
const disposers = [];
|
|
64
|
+
let fallbackRegistered = false;
|
|
65
|
+
/** Serve one global provider when this context cannot register per agent. */
|
|
66
|
+
const ensureFallback = () => {
|
|
67
|
+
if (fallbackRegistered)
|
|
68
|
+
return;
|
|
69
|
+
fallbackRegistered = true;
|
|
70
|
+
ctx.skills.registerProvider(() => createGlobalProvider({ settings, registry }));
|
|
71
|
+
ctx.logger.warn('unity skills: per-agent registration is unavailable in this profile, so one global provider serves every session. Project gating still follows the session directory, but agent-preset skills win duplicate names.');
|
|
72
|
+
};
|
|
73
|
+
const onCreated = async (payload) => {
|
|
74
|
+
const agent = payload?.agent;
|
|
75
|
+
try {
|
|
76
|
+
const result = await registry.add(agent);
|
|
77
|
+
if (result === 'unavailable')
|
|
78
|
+
ensureFallback();
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
ctx.logger.warn(`unity skills: agent registration failed: ${String(error)}`);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const agents = serviceOf(ctx, 'agents');
|
|
85
|
+
if (agents === undefined) {
|
|
86
|
+
ensureFallback();
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
disposers.push(ctx.on('agent/created', (payload) => onCreated(payload)), ctx.on('agent/disposed', (payload) => registry.remove(payload?.agent)));
|
|
90
|
+
for (const agent of agents.list())
|
|
91
|
+
void onCreated({ agent });
|
|
92
|
+
}
|
|
93
|
+
if (settings.watchSkills) {
|
|
94
|
+
disposers.push(startSkillsWatcher({
|
|
95
|
+
dir: settings.skillDir,
|
|
96
|
+
logger: ctx.logger,
|
|
97
|
+
onChange: () => {
|
|
98
|
+
settings.parseCache?.clear();
|
|
99
|
+
registry.invalidateAll();
|
|
100
|
+
},
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
ctx.effect(() => () => {
|
|
104
|
+
for (const dispose of disposers.splice(0)) {
|
|
105
|
+
try {
|
|
106
|
+
dispose();
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Disposal is best-effort; the fiber is going away either way.
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
registry.disposeAll();
|
|
113
|
+
}, 'unity-skills lifecycle');
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Validate row config into normalized settings.
|
|
117
|
+
*
|
|
118
|
+
* @param config - row config from the loader patch.
|
|
119
|
+
* @returns normalized settings.
|
|
120
|
+
* @throws {TypeError} when a field is present but unusable.
|
|
121
|
+
*/
|
|
122
|
+
export function resolveSettings(config) {
|
|
123
|
+
const providerName = config.providerName ?? DEFAULT_PROVIDER_NAME;
|
|
124
|
+
if (typeof providerName !== 'string' || providerName.trim() === '') {
|
|
125
|
+
throw new TypeError('unity-skills: providerName must be a non-empty string');
|
|
126
|
+
}
|
|
127
|
+
if (providerName === RESERVED_PROVIDER) {
|
|
128
|
+
throw new TypeError(`unity-skills: providerName "${RESERVED_PROVIDER}" is reserved for runtime skill registrations`);
|
|
129
|
+
}
|
|
130
|
+
const rank = config.rank ?? DEFAULT_RANK;
|
|
131
|
+
if (typeof rank !== 'number' || !Number.isFinite(rank)) {
|
|
132
|
+
throw new TypeError('unity-skills: rank must be a finite number');
|
|
133
|
+
}
|
|
134
|
+
const skillDirConfig = config.skillDir ?? join(PACKAGE_DIR, 'skills');
|
|
135
|
+
if (typeof skillDirConfig !== 'string' || skillDirConfig.trim() === '') {
|
|
136
|
+
throw new TypeError('unity-skills: skillDir must be a non-empty string');
|
|
137
|
+
}
|
|
138
|
+
const exclude = readStringArray(config.exclude, 'exclude');
|
|
139
|
+
const workspaceSkills = readStringArray(config.workspaceSkills, 'workspaceSkills') ?? DEFAULT_WORKSPACE_SKILLS;
|
|
140
|
+
return {
|
|
141
|
+
providerName,
|
|
142
|
+
rank,
|
|
143
|
+
source: 'unity',
|
|
144
|
+
skillDir: resolve(skillDirConfig),
|
|
145
|
+
exclude: new Set(exclude ?? []),
|
|
146
|
+
workspaceSkills: new Set(workspaceSkills),
|
|
147
|
+
gateByProject: readBoolean(config.gateByProject, 'gateByProject', true),
|
|
148
|
+
enforceRequirements: readBoolean(config.enforceRequirements, 'enforceRequirements', true),
|
|
149
|
+
injectContext: readBoolean(config.injectContext, 'injectContext', true),
|
|
150
|
+
watchSkills: readBoolean(config.watchSkills, 'watchSkills', true),
|
|
151
|
+
respectProjectRoots: readBoolean(config.respectProjectRoots, 'respectProjectRoots', true),
|
|
152
|
+
parseCache: undefined,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/** Read an optional string-array field. */
|
|
156
|
+
function readStringArray(value, field) {
|
|
157
|
+
if (value === undefined)
|
|
158
|
+
return undefined;
|
|
159
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== 'string' || entry.trim() === '')) {
|
|
160
|
+
throw new TypeError(`unity-skills: ${field} must be an array of non-empty strings`);
|
|
161
|
+
}
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
/** Read an optional boolean field. */
|
|
165
|
+
function readBoolean(value, field, fallback) {
|
|
166
|
+
if (value === undefined)
|
|
167
|
+
return fallback;
|
|
168
|
+
if (typeof value !== 'boolean')
|
|
169
|
+
throw new TypeError(`unity-skills: ${field} must be a boolean`);
|
|
170
|
+
return value;
|
|
171
|
+
}
|