nccgs 2.1.1 → 3.0.0-rc.2
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 +76 -235
- package/LICENSE +1 -1
- package/README.md +87 -206
- package/THIRD_PARTY_NOTICES.md +6 -34
- package/bin/nccgs.mjs +96 -0
- package/cli/doctor.mjs +82 -0
- package/cli/feedback.mjs +13 -0
- package/cli/install.mjs +111 -0
- package/cli/release.mjs +59 -0
- package/cli/run.mjs +35 -0
- package/cli/spawn.mjs +20 -0
- package/cli/uninstall.mjs +43 -0
- package/cli/update-check.mjs +66 -0
- package/docs/EVIDENCE-VERIFICATION.md +22 -0
- package/package.json +23 -30
- package/runtime/core/diag.mjs +43 -0
- package/runtime/core/feedback-policy.mjs +54 -0
- package/runtime/core/fs.mjs +80 -0
- package/runtime/core/job-object.mjs +73 -0
- package/runtime/core/modes.mjs +87 -0
- package/runtime/core/process-tree.mjs +109 -0
- package/runtime/core/project.mjs +113 -0
- package/runtime/core/snapshot.mjs +114 -0
- package/runtime/hooks/common.mjs +22 -0
- package/runtime/hooks/done-guard.mjs +15 -0
- package/runtime/hooks/guard-mcp.mjs +8 -0
- package/runtime/hooks/guard-shell.mjs +16 -0
- package/runtime/hooks/guard-write.mjs +25 -0
- package/runtime/hooks/session-log.mjs +7 -0
- package/runtime/hooks/session-start.mjs +40 -0
- package/runtime/hooks/unity-transport.mjs +12 -0
- package/runtime/modes.json +39 -0
- package/runtime/task/cost.mjs +103 -0
- package/runtime/task/criteria.mjs +128 -0
- package/runtime/task/feedback.mjs +136 -0
- package/runtime/task/ledger.mjs +109 -0
- package/runtime/task/plan.mjs +69 -0
- package/runtime/task/project.mjs +79 -0
- package/runtime/task/report.mjs +252 -0
- package/runtime/task/task.mjs +238 -0
- package/runtime/unity/assets.mjs +51 -0
- package/runtime/unity/playtest.mjs +145 -0
- package/runtime/unity/unity.mjs +350 -0
- package/scripts/check-job-object.mjs +18 -0
- package/scripts/sync-unity-skills.mjs +35 -119
- package/template/CLAUDE.md +39 -0
- package/template/agents/fast-fix.md +9 -0
- package/template/agents/implementer.md +19 -0
- package/template/agents/playtester.md +15 -0
- package/template/agents/reviewer.md +19 -0
- package/template/agents/scout.md +9 -0
- package/template/ponytail/README.md +8 -0
- package/{.claude/nccgs/packages → template}/ponytail/engineering.md +10 -0
- package/template/protocols/evidence.md +52 -0
- package/template/protocols/playtest.md +45 -0
- package/template/protocols/review.md +34 -0
- package/template/protocols/unity-cli-notes.md +56 -0
- package/template/settings.fragment.json +33 -0
- package/template/skills/art-bible/SKILL.md +19 -0
- package/template/skills/asset-spec/SKILL.md +19 -0
- package/template/skills/brainstorm/SKILL.md +17 -0
- package/template/skills/feedback/SKILL.md +16 -0
- package/template/skills/map-systems/SKILL.md +25 -0
- package/template/skills/playtest/SKILL.md +17 -0
- package/template/skills/status/SKILL.md +18 -0
- package/template/skills/test/SKILL.md +34 -0
- package/template/skills/unity-foundation/SKILL.md +17 -0
- package/template/skills/vertical-slice/SKILL.md +17 -0
- package/template/skills/work/SKILL.md +65 -0
- package/tools/feedback-worker/README.md +12 -0
- package/tools/feedback-worker/worker.js +39 -0
- package/tools/feedback-worker/wrangler.toml +12 -0
- package/unity-skills/2d-pixel-perfect/SKILL.md +208 -0
- package/unity-skills/2d-pixel-perfect/references/api-reference.md +81 -0
- package/unity-skills/2d-pixel-perfect/references/camera-setup-builtin.cs +40 -0
- package/unity-skills/2d-pixel-perfect/references/camera-setup-urp.cs +49 -0
- package/unity-skills/2d-pixel-perfect/references/pipeline-detection.cs +50 -0
- package/unity-skills/2d-pixel-perfect/references/sprite-settings.cs +37 -0
- package/unity-skills/asset-transformer-toolkit/SECURITY.md +15 -0
- package/unity-skills/asset-transformer-toolkit/SKILL.md +39 -0
- package/unity-skills/asset-transformer-toolkit/references/create-importer.md +121 -0
- package/unity-skills/asset-transformer-toolkit/references/lods.md +61 -0
- package/unity-skills/asset-transformer-toolkit/references/rule-api.md +154 -0
- package/unity-skills/asset-transformer-toolkit/references/ruleblock-api.md +37 -0
- package/unity-skills/asset-transformer-toolkit/references/ruleset-api.md +138 -0
- package/unity-skills/asset-transformer-toolkit/references/rulesets-and-actions.md +227 -0
- package/unity-skills/audio-setup-mixers/SECURITY.md +16 -0
- package/unity-skills/audio-setup-mixers/SKILL.md +127 -0
- package/unity-skills/audio-setup-mixers/references/api.md +162 -0
- package/unity-skills/build-gtk/SKILL.md +242 -0
- package/unity-skills/build-gtk/references/graph-api.md +324 -0
- package/unity-skills/build-gtk/references/pitfalls.md +86 -0
- package/unity-skills/build-gtk/references/runtime-and-visualization.md +196 -0
- package/unity-skills/build-gtk/references/state-machine-api.md +286 -0
- package/unity-skills/build-live-game/SKILL.md +255 -0
- package/{.claude/skills → unity-skills}/build-live-game/references/achievements.md +132 -154
- package/{.claude/skills → unity-skills}/build-live-game/references/apis.md +10 -19
- package/{.claude/skills → unity-skills}/build-live-game/references/authentication.md +14 -20
- package/{.claude/skills → unity-skills}/build-live-game/references/battlepass.md +269 -225
- package/unity-skills/build-live-game/references/blueprints-and-samples.md +75 -0
- package/unity-skills/build-live-game/references/cloud-code-cloudbehaviours.md +1111 -0
- package/unity-skills/build-live-game/references/cloud-code-modules.md +1276 -0
- package/unity-skills/build-live-game/references/cloud-code.md +58 -0
- package/{.claude/skills → unity-skills}/build-live-game/references/cloud-save.md +15 -25
- package/{.claude/skills → unity-skills}/build-live-game/references/deployment.md +33 -18
- package/{.claude/skills → unity-skills}/build-live-game/references/player-account.md +31 -23
- package/{.claude/skills → unity-skills}/build-live-game/references/tooling.md +0 -56
- package/unity-skills/build-live-game/references/ugs-cli.md +86 -0
- package/unity-skills/craft-game-floors/SECURITY.md +23 -0
- package/unity-skills/craft-game-floors/SKILL.md +134 -0
- package/unity-skills/craft-game-floors/references/art-direction.md +85 -0
- package/unity-skills/craft-game-floors/references/camera-rigs.md +51 -0
- package/unity-skills/craft-game-floors/references/character-motion.md +35 -0
- package/unity-skills/craft-game-floors/references/game-audio.md +47 -0
- package/unity-skills/craft-game-floors/references/game-feel.md +68 -0
- package/unity-skills/craft-game-floors/references/game-shell.md +45 -0
- package/unity-skills/craft-game-floors/references/live-floor.md +35 -0
- package/unity-skills/craft-game-floors/references/placeholder-assets.md +35 -0
- package/unity-skills/craft-game-floors/references/scene-lighting.md +52 -0
- package/unity-skills/craft-game-floors/references/toon-shading.md +34 -0
- package/unity-skills/craft-game-floors/references/vfx.md +40 -0
- package/unity-skills/craft-game-floors/references/visual-scorecard.md +43 -0
- package/unity-skills/create-2d-physics/SECURITY.md +16 -0
- package/unity-skills/create-2d-physics/SKILL.md +128 -0
- package/unity-skills/create-2d-physics/references/2d-physics-core.md +155 -0
- package/unity-skills/create-2d-physics/references/legacy-2d-physics.md +45 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/SKILL.md +12 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/references/hexagonalruletile.md +71 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/references/palette-create.md +38 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/references/ruletile-createempty.md +35 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/references/ruletile-createfromsegment.md +212 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/references/ruletile.md +90 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/scripts/CreatePaletteTemplate.cs +148 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/scripts/ManualWorkflowExample.cs +63 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/scripts/RuleTileGenerator.cs +61 -0
- package/unity-skills/create-tile-palette-or-rule-tiles/scripts/TilemapRuleTileCreateFromSegment.cs +225 -0
- package/unity-skills/generate-editor-search-query/SECURITY.md +17 -0
- package/unity-skills/generate-editor-search-query/SKILL.md +117 -0
- package/unity-skills/generate-editor-search-query/references/open-search-window.md +70 -0
- package/unity-skills/generate-editor-search-query/references/query-patterns.md +124 -0
- package/{.claude/skills → unity-skills}/implement-in-app-purchases/SKILL.md +1 -2
- package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/api-notes.md +25 -28
- package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/path-convert-native-google-billing.md +1 -1
- package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/path-implement-iap-d2c.md +40 -5
- package/{.claude/skills → unity-skills}/initialize-ai-navigation/SKILL.md +4 -4
- package/{.claude/skills → unity-skills}/initialize-ai-navigation/references/navigation-system.md +3 -3
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/CHANGELOG.md +12 -0
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/README.md +9 -5
- package/unity-skills/levelplay-unity-integration/SKILL.md +442 -0
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/banner-api.md +15 -8
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/best-practices.md +604 -536
- package/unity-skills/levelplay-unity-integration/references/dependency-resolution.md +94 -0
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/ilrd-api.md +2 -2
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/initialization-api.md +221 -0
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/interstitial-api.md +11 -3
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/ios-setup.md +6 -34
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/migration-sdk-9.md +1 -1
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/privacy-settings.md +14 -29
- package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/rewarded-api.md +20 -4
- package/unity-skills/levelplay-unity-integration/references/testing-and-validation.md +222 -0
- package/unity-skills/levelplay-unity-integration/references/troubleshooting.md +99 -0
- package/unity-skills/localization/SKILL.md +347 -0
- package/{.claude/skills → unity-skills}/localization/references/api-notes.md +4 -0
- package/unity-skills/localization/resources/L10nBatchProcessor.cs +191 -0
- package/unity-skills/manage-sprite-atlas/SKILL.md +351 -0
- package/unity-skills/manage-sprite-atlas/references/addressables-delivery.md +58 -0
- package/unity-skills/manage-sprite-atlas/references/api.md +382 -0
- package/unity-skills/manage-sprite-atlas/references/best-practices.md +183 -0
- package/unity-skills/manage-sprite-atlas/references/common-errors.md +123 -0
- package/unity-skills/manage-sprite-atlas/references/custom-packing.md +147 -0
- package/unity-skills/manage-sprite-atlas/references/manual-authoring.md +39 -0
- package/unity-skills/manage-sprite-atlas/resources/authoringvsruntime.cs +176 -0
- package/unity-skills/manage-sprite-atlas/resources/buildaddressablespostprocess.cs +59 -0
- package/unity-skills/manage-sprite-atlas/resources/cacheloadedatlases.cs +145 -0
- package/unity-skills/manage-sprite-atlas/resources/cleanupbatchoperations.cs +119 -0
- package/unity-skills/manage-sprite-atlas/resources/createandconfiguremasteratlas.cs +57 -0
- package/unity-skills/manage-sprite-atlas/resources/custompackersetup.cs +88 -0
- package/unity-skills/manage-sprite-atlas/resources/deprecatedmethods.cs +142 -0
- package/unity-skills/manage-sprite-atlas/resources/dontmodifywithoutsaving.cs +120 -0
- package/unity-skills/manage-sprite-atlas/resources/dontpackinruntimebuilds.cs +190 -0
- package/unity-skills/manage-sprite-atlas/resources/dontscriptspriteatlasineditor.cs +114 -0
- package/unity-skills/manage-sprite-atlas/resources/editorconfiguration.cs +95 -0
- package/unity-skills/manage-sprite-atlas/resources/enablespritepacking.cs +172 -0
- package/unity-skills/manage-sprite-atlas/resources/gridspritepacker.cs +50 -0
- package/unity-skills/manage-sprite-atlas/resources/handlelatebinding.cs +147 -0
- package/unity-skills/manage-sprite-atlas/resources/handlenullcases.cs +141 -0
- package/unity-skills/manage-sprite-atlas/resources/migratev1tov2.cs +335 -0
- package/unity-skills/manage-sprite-atlas/resources/multipagepacker.cs +80 -0
- package/unity-skills/manage-sprite-atlas/resources/optimizetexturesettings.cs +191 -0
- package/unity-skills/manage-sprite-atlas/resources/packerdebugging.cs +158 -0
- package/unity-skills/manage-sprite-atlas/resources/packtransform.cs +51 -0
- package/unity-skills/manage-sprite-atlas/resources/platformnames.cs +127 -0
- package/unity-skills/manage-sprite-atlas/resources/queryspritesefficiently.cs +222 -0
- package/unity-skills/manage-sprite-atlas/resources/registercallbacks.cs +152 -0
- package/unity-skills/manage-sprite-atlas/resources/runtimeatlasloader.cs +15 -0
- package/unity-skills/manage-sprite-atlas/resources/runtimespriteaccess.cs +19 -0
- package/unity-skills/manage-sprite-atlas/resources/savespriteatlasasset.cs +107 -0
- package/unity-skills/manage-sprite-atlas/resources/scriptablepacker.cs +81 -0
- package/unity-skills/manage-sprite-atlas/resources/setincludeinbuild.cs +164 -0
- package/unity-skills/manage-sprite-atlas/resources/sizeoptimizedpacker.cs +88 -0
- package/unity-skills/manage-sprite-atlas/resources/spriteatlaslatebinding.cs +123 -0
- package/unity-skills/manage-sprite-atlas/resources/spriteatlasprebuildgenerator.cs +219 -0
- package/unity-skills/manage-sprite-atlas/resources/spritedata.cs +35 -0
- package/unity-skills/manage-sprite-atlas/resources/spritepack.cs +39 -0
- package/unity-skills/manage-sprite-atlas/resources/texturedata.cs +15 -0
- package/unity-skills/manage-sprite-atlas/resources/updatebuildscripts.cs +357 -0
- package/unity-skills/manage-sprite-atlas/resources/updatesettingsconfiguration.cs +135 -0
- package/unity-skills/manage-sprite-atlas/resources/usevariantswisely.cs +179 -0
- package/unity-skills/manage-sprite-atlas/resources/variantatlas.cs +39 -0
- package/unity-skills/manifest.json +1155 -0
- package/unity-skills/migrate-birp-to-urp/SECURITY.md +16 -0
- package/unity-skills/migrate-birp-to-urp/SKILL.md +543 -0
- package/unity-skills/migrate-birp-to-urp/references/capturing-the-editor.md +66 -0
- package/unity-skills/migrate-birp-to-urp/references/complex-shader-situations.md +272 -0
- package/unity-skills/migrate-birp-to-urp/references/custom-shader-triage.md +123 -0
- package/unity-skills/migrate-birp-to-urp/references/implementation-patterns.md +529 -0
- package/unity-skills/migrate-birp-to-urp/references/migration-workflow.md +265 -0
- package/unity-skills/migrate-birp-to-urp/references/quality-settings-map.md +69 -0
- package/unity-skills/new-unity-project/SECURITY.md +26 -0
- package/unity-skills/new-unity-project/SKILL.md +386 -0
- package/unity-skills/new-unity-project/references/skill-setup.md +66 -0
- package/unity-skills/optimize-audio/SECURITY.md +16 -0
- package/{.claude/skills → unity-skills}/optimize-audio/SKILL.md +17 -17
- package/{.claude/skills → unity-skills}/optimize-audio/resources/audio-import-api.md +8 -5
- package/{.claude/skills → unity-skills}/optimize-text-mesh-pro/SKILL.md +1 -11
- package/unity-skills/optimize-web/SECURITY.md +16 -0
- package/{.claude/skills → unity-skills}/optimize-web/SKILL.md +164 -27
- package/unity-skills/optimize-web/scripts/WebOptimizer.cs +46 -0
- package/unity-skills/optimize-web/scripts/toktx-examples.sh +11 -0
- package/{.claude/skills → unity-skills}/physics-3d-collision/SKILL.md +2 -2
- package/unity-skills/physics-3d-collision/references/troubleshooting.md +8 -0
- package/unity-skills/project-auditor-fixes/SKILL.md +64 -0
- package/{.claude/skills → unity-skills}/setup-multiplayer-services/SKILL.md +1 -4
- package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/SKILL.md +1 -1
- package/{.claude/skills → unity-skills}/shader-graph-create-custom-node/SKILL.md +1 -1
- package/unity-skills/sprite-editor/SECURITY.md +16 -0
- package/{.claude/skills → unity-skills}/sprite-editor/SKILL.md +9 -9
- package/{.claude/skills → unity-skills}/sprite-editor/references/templates.md +1 -1
- package/unity-skills/sprite-segment-3x3grid/SKILL.md +136 -0
- package/unity-skills/sprite-segment-3x3grid/scripts/SpriteGridAnalysis.cs +119 -0
- package/{.claude/skills → unity-skills}/ui/SKILL.md +1 -1
- package/{.claude/skills → unity-skills}/ui-imgui/SKILL.md +1 -7
- package/{.claude/skills → unity-skills}/ui-ugui/SKILL.md +3 -9
- package/{.claude/skills → unity-skills}/ui-uitk/SKILL.md +8 -14
- package/{.claude/skills → unity-skills}/ui-uitk/references/custom-elements.md +1 -1
- package/unity-skills/unity-cli/CHANGELOG.md +515 -0
- package/unity-skills/unity-cli/SECURITY.md +68 -0
- package/unity-skills/unity-cli/SKILL.md +723 -0
- package/unity-skills/unity-cli/references/auth-license-cloud.md +318 -0
- package/unity-skills/unity-cli/references/build-run-test.md +555 -0
- package/unity-skills/unity-cli/references/cloud-automation.md +736 -0
- package/{.claude/skills → unity-skills}/unity-cli/references/collaboration.md +166 -105
- package/unity-skills/unity-cli/references/config-hub.md +239 -0
- package/unity-skills/unity-cli/references/diagnostics-maintenance.md +720 -0
- package/unity-skills/unity-cli/references/docs-workflow.md +179 -0
- package/unity-skills/unity-cli/references/editors-install.md +476 -0
- package/unity-skills/unity-cli/references/integration-advanced.md +1130 -0
- package/unity-skills/unity-cli/references/playmode-verification-loop.md +279 -0
- package/unity-skills/unity-cli/references/projects-templates.md +996 -0
- package/unity-skills/unity-cli/references/version-control.md +612 -0
- package/{.claude/skills → unity-skills}/unity-package-management/SKILL.md +60 -12
- package/{.claude/skills → unity-skills}/unity-package-management/references/select-packages.md +39 -21
- package/unity-skills/unity-pipeline/SECURITY.md +17 -0
- package/unity-skills/unity-pipeline/SKILL.md +335 -0
- package/unity-skills/urp-postprocessing/SECURITY.md +16 -0
- package/{.claude/skills → unity-skills}/urp-postprocessing/SKILL.md +12 -12
- package/{.claude/skills → unity-skills}/urp-postprocessing/references/code-templates.md +39 -8
- package/{.claude/skills → unity-skills}/validate-urp-render-graph-renderer-feature/SKILL.md +1 -1
- package/.claude/agents/nccgs-adversarial-reviewer.md +0 -43
- package/.claude/agents/nccgs-engine-programmer.md +0 -27
- package/.claude/agents/nccgs-fast-implementer.md +0 -30
- package/.claude/agents/nccgs-game-designer.md +0 -26
- package/.claude/agents/nccgs-gameplay-programmer.md +0 -26
- package/.claude/agents/nccgs-qa-engineer.md +0 -27
- package/.claude/agents/nccgs-task-scout.md +0 -24
- package/.claude/agents/nccgs-ui-programmer.md +0 -27
- package/.claude/agents/nccgs-unity-build-specialist.md +0 -27
- package/.claude/agents/nccgs-unity-implementer.md +0 -28
- package/.claude/agents/nccgs-unity-systems-specialist.md +0 -27
- package/.claude/agents/nccgs-unity-ui-specialist.md +0 -27
- package/.claude/agents/nccgs-verification-engineer.md +0 -27
- package/.claude/nccgs/MEMORY.md +0 -66
- package/.claude/nccgs/THIRD_PARTY_NOTICES.md +0 -29
- package/.claude/nccgs/VERSION +0 -1
- package/.claude/nccgs/agent-library/nccgs-accessibility-specialist.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-adversarial-reviewer.md +0 -41
- package/.claude/nccgs/agent-library/nccgs-ai-programmer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-analytics-engineer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-art-direction-lead.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-audio-direction-lead.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-creative-director.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-documentation-manager.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-economy-designer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-engine-programmer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-fast-implementer.md +0 -28
- package/.claude/nccgs/agent-library/nccgs-game-design-lead.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-game-designer.md +0 -24
- package/.claude/nccgs/agent-library/nccgs-gameplay-programmer.md +0 -24
- package/.claude/nccgs/agent-library/nccgs-level-designer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-live-ops-designer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-localization-lead.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-narrative-lead.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-network-programmer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-performance-analyst.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-producer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-production-coordinator.md +0 -22
- package/.claude/nccgs/agent-library/nccgs-programming-lead.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-prototyper.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-qa-engineer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-qa-lead.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-release-engineer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-release-lead.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-security-engineer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-sound-designer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-systems-designer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-task-scout.md +0 -22
- package/.claude/nccgs/agent-library/nccgs-technical-architect.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-technical-artist.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-technical-director.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-tools-programmer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-ui-programmer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-unity-build-specialist.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-unity-content-specialist.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-unity-implementer.md +0 -26
- package/.claude/nccgs/agent-library/nccgs-unity-rendering-specialist.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-unity-systems-specialist.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-unity-ui-specialist.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-ux-designer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-verification-engineer.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-world-builder.md +0 -25
- package/.claude/nccgs/agent-library/nccgs-writer.md +0 -25
- package/.claude/nccgs/constitution.md +0 -187
- package/.claude/nccgs/hooks/agent-audit.mjs +0 -16
- package/.claude/nccgs/hooks/closure-guard.mjs +0 -59
- package/.claude/nccgs/hooks/common.mjs +0 -42
- package/.claude/nccgs/hooks/post-compact.mjs +0 -1
- package/.claude/nccgs/hooks/pre-compact.mjs +0 -8
- package/.claude/nccgs/hooks/protect-git.mjs +0 -22
- package/.claude/nccgs/hooks/protect-write.mjs +0 -17
- package/.claude/nccgs/hooks/runtime-observation.mjs +0 -11
- package/.claude/nccgs/hooks/session-start.mjs +0 -29
- package/.claude/nccgs/hooks/session-stop.mjs +0 -7
- package/.claude/nccgs/hooks/unity-transport-guard.mjs +0 -11
- package/.claude/nccgs/packages/ponytail/README.md +0 -46
- package/.claude/nccgs/packages/ponytail/manifest.json +0 -24
- package/.claude/nccgs/pipeline.json +0 -260
- package/.claude/nccgs/protocols/agent-contract.md +0 -101
- package/.claude/nccgs/protocols/astra-claude.md +0 -111
- package/.claude/nccgs/protocols/bounded-repair.md +0 -246
- package/.claude/nccgs/protocols/context-packets.md +0 -23
- package/.claude/nccgs/protocols/delivery-acceptance.md +0 -105
- package/.claude/nccgs/protocols/design-lifecycle.md +0 -139
- package/.claude/nccgs/protocols/editor-session-evidence.md +0 -52
- package/.claude/nccgs/protocols/evidence.md +0 -31
- package/.claude/nccgs/protocols/model-routing.md +0 -46
- package/.claude/nccgs/protocols/orchestration.md +0 -74
- package/.claude/nccgs/protocols/review-handoff.md +0 -101
- package/.claude/nccgs/protocols/shared-workflow-context.md +0 -33
- package/.claude/nccgs/protocols/standalone-gates.md +0 -329
- package/.claude/nccgs/protocols/standalone-pilot.md +0 -144
- package/.claude/nccgs/protocols/standalone.md +0 -207
- package/.claude/nccgs/protocols/task-autonomy.md +0 -55
- package/.claude/nccgs/protocols/task-gates.md +0 -144
- package/.claude/nccgs/protocols/task-slices.md +0 -106
- package/.claude/nccgs/protocols/unity-boundary.md +0 -31
- package/.claude/nccgs/routing.generated.md +0 -49
- package/.claude/nccgs/settings.fragment.json +0 -213
- package/.claude/nccgs/studio.json +0 -472
- package/.claude/nccgs/tools/approve-overrides.mjs +0 -81
- package/.claude/nccgs/tools/autonomy.mjs +0 -40
- package/.claude/nccgs/tools/command-process.mjs +0 -50
- package/.claude/nccgs/tools/command-tokens.mjs +0 -22
- package/.claude/nccgs/tools/compile-policy.mjs +0 -121
- package/.claude/nccgs/tools/configure-models.mjs +0 -96
- package/.claude/nccgs/tools/criteria.mjs +0 -121
- package/.claude/nccgs/tools/delivery-budget.mjs +0 -52
- package/.claude/nccgs/tools/design-readiness.mjs +0 -158
- package/.claude/nccgs/tools/editor-session-evidence.mjs +0 -66
- package/.claude/nccgs/tools/evidence.mjs +0 -153
- package/.claude/nccgs/tools/gates.mjs +0 -297
- package/.claude/nccgs/tools/handoff.mjs +0 -51
- package/.claude/nccgs/tools/hook-transport.mjs +0 -34
- package/.claude/nccgs/tools/inputs.mjs +0 -108
- package/.claude/nccgs/tools/installation-guard.mjs +0 -55
- package/.claude/nccgs/tools/integrity.mjs +0 -69
- package/.claude/nccgs/tools/lifecycle.mjs +0 -542
- package/.claude/nccgs/tools/native-completion.mjs +0 -30
- package/.claude/nccgs/tools/orchestration.mjs +0 -680
- package/.claude/nccgs/tools/paths.mjs +0 -60
- package/.claude/nccgs/tools/policy.mjs +0 -107
- package/.claude/nccgs/tools/process-lock.mjs +0 -74
- package/.claude/nccgs/tools/repair-packet.mjs +0 -106
- package/.claude/nccgs/tools/returned-handoff.mjs +0 -47
- package/.claude/nccgs/tools/review-budget.mjs +0 -171
- package/.claude/nccgs/tools/review-handoff.mjs +0 -66
- package/.claude/nccgs/tools/runtime.mjs +0 -71
- package/.claude/nccgs/tools/session-budget.mjs +0 -67
- package/.claude/nccgs/tools/shared-context-guard.mjs +0 -60
- package/.claude/nccgs/tools/shared-context.mjs +0 -25
- package/.claude/nccgs/tools/task-slices.mjs +0 -147
- package/.claude/nccgs/tools/task.mjs +0 -145
- package/.claude/nccgs/tools/tool-guard.mjs +0 -120
- package/.claude/nccgs/tools/unity-repair.mjs +0 -128
- package/.claude/nccgs/tools/unity-transport.mjs +0 -170
- package/.claude/nccgs/tools/verification-jobs.mjs +0 -171
- package/.claude/nccgs/tools/verification-worker.mjs +0 -71
- package/.claude/nccgs/tools/windows-compiler-server.cs +0 -163
- package/.claude/nccgs/tools/windows-job.cs +0 -103
- package/.claude/nccgs/unity-skills-manifest.json +0 -727
- package/.claude/nccgs/workflow-catalog.json +0 -654
- package/.claude/rules/nccgs-canonical-docs.md +0 -19
- package/.claude/rules/nccgs-editor-tools.md +0 -12
- package/.claude/rules/nccgs-localization.md +0 -12
- package/.claude/rules/nccgs-networking.md +0 -13
- package/.claude/rules/nccgs-performance.md +0 -14
- package/.claude/rules/nccgs-rendering.md +0 -16
- package/.claude/rules/nccgs-security.md +0 -13
- package/.claude/rules/nccgs-tests.md +0 -18
- package/.claude/rules/nccgs-ui.md +0 -14
- package/.claude/rules/nccgs-unity-assets.md +0 -21
- package/.claude/rules/nccgs-unity-code.md +0 -22
- package/.claude/skills/accessibility-review/SKILL.md +0 -22
- package/.claude/skills/accessibility-review/references/astra.md +0 -17
- package/.claude/skills/accessibility-review/references/legacy.md +0 -7
- package/.claude/skills/architecture-decision/SKILL.md +0 -22
- package/.claude/skills/architecture-decision/references/astra.md +0 -12
- package/.claude/skills/architecture-decision/references/legacy.md +0 -7
- package/.claude/skills/asset-audit/SKILL.md +0 -22
- package/.claude/skills/asset-audit/references/astra.md +0 -17
- package/.claude/skills/asset-audit/references/legacy.md +0 -7
- package/.claude/skills/audit/SKILL.md +0 -22
- package/.claude/skills/audit/references/astra.md +0 -17
- package/.claude/skills/audit/references/dimensions.md +0 -46
- package/.claude/skills/audit/references/legacy.md +0 -9
- package/.claude/skills/balance-review/SKILL.md +0 -22
- package/.claude/skills/balance-review/references/astra.md +0 -17
- package/.claude/skills/balance-review/references/legacy.md +0 -7
- package/.claude/skills/bug-triage/SKILL.md +0 -22
- package/.claude/skills/bug-triage/references/astra.md +0 -27
- package/.claude/skills/bug-triage/references/legacy.md +0 -7
- package/.claude/skills/build-live-game/SKILL.md +0 -317
- package/.claude/skills/build-live-game/references/cloud-code.md +0 -563
- package/.claude/skills/closure/SKILL.md +0 -22
- package/.claude/skills/closure/references/astra.md +0 -15
- package/.claude/skills/closure/references/legacy.md +0 -7
- package/.claude/skills/compatibility-review/SKILL.md +0 -22
- package/.claude/skills/compatibility-review/references/astra.md +0 -17
- package/.claude/skills/compatibility-review/references/legacy.md +0 -7
- package/.claude/skills/context-pack/SKILL.md +0 -22
- package/.claude/skills/context-pack/references/astra.md +0 -12
- package/.claude/skills/context-pack/references/legacy.md +0 -7
- package/.claude/skills/dependency-review/SKILL.md +0 -22
- package/.claude/skills/dependency-review/references/astra.md +0 -17
- package/.claude/skills/dependency-review/references/legacy.md +0 -7
- package/.claude/skills/design/SKILL.md +0 -24
- package/.claude/skills/design/references/astra.md +0 -12
- package/.claude/skills/design/references/legacy.md +0 -13
- package/.claude/skills/design-review/SKILL.md +0 -24
- package/.claude/skills/design-review/references/astra.md +0 -17
- package/.claude/skills/design-review/references/legacy.md +0 -7
- package/.claude/skills/evidence-review/SKILL.md +0 -22
- package/.claude/skills/evidence-review/references/astra.md +0 -17
- package/.claude/skills/evidence-review/references/legacy.md +0 -7
- package/.claude/skills/hotfix/SKILL.md +0 -22
- package/.claude/skills/hotfix/references/astra.md +0 -30
- package/.claude/skills/hotfix/references/legacy.md +0 -7
- package/.claude/skills/incident-recovery/SKILL.md +0 -22
- package/.claude/skills/incident-recovery/references/astra.md +0 -27
- package/.claude/skills/incident-recovery/references/legacy.md +0 -7
- package/.claude/skills/levelplay-unity-integration/SKILL.md +0 -1126
- package/.claude/skills/localization/SKILL.md +0 -135
- package/.claude/skills/localization/resources/L10nBatchProcessor.cs +0 -69
- package/.claude/skills/localize-game/SKILL.md +0 -22
- package/.claude/skills/localize-game/references/astra.md +0 -27
- package/.claude/skills/localize-game/references/legacy.md +0 -7
- package/.claude/skills/migrate-project/SKILL.md +0 -22
- package/.claude/skills/migrate-project/references/astra.md +0 -30
- package/.claude/skills/migrate-project/references/legacy.md +0 -19
- package/.claude/skills/migrate-project/references/procedure.md +0 -96
- package/.claude/skills/milestone-review/SKILL.md +0 -22
- package/.claude/skills/milestone-review/references/astra.md +0 -12
- package/.claude/skills/milestone-review/references/legacy.md +0 -7
- package/.claude/skills/nccgs-code-review/SKILL.md +0 -22
- package/.claude/skills/nccgs-code-review/references/astra.md +0 -21
- package/.claude/skills/nccgs-code-review/references/legacy.md +0 -7
- package/.claude/skills/new-unity-project/SKILL.md +0 -179
- package/.claude/skills/performance-audit/SKILL.md +0 -22
- package/.claude/skills/performance-audit/references/astra.md +0 -17
- package/.claude/skills/performance-audit/references/legacy.md +0 -7
- package/.claude/skills/physics-3d-collision/references/troubleshooting.md +0 -41
- package/.claude/skills/plan-feature/SKILL.md +0 -22
- package/.claude/skills/plan-feature/references/astra.md +0 -12
- package/.claude/skills/plan-feature/references/legacy.md +0 -7
- package/.claude/skills/playtest/SKILL.md +0 -22
- package/.claude/skills/playtest/references/astra.md +0 -31
- package/.claude/skills/playtest/references/legacy.md +0 -7
- package/.claude/skills/project-stage/SKILL.md +0 -22
- package/.claude/skills/project-stage/references/astra.md +0 -12
- package/.claude/skills/project-stage/references/legacy.md +0 -7
- package/.claude/skills/prototype-feature/SKILL.md +0 -22
- package/.claude/skills/prototype-feature/references/astra.md +0 -31
- package/.claude/skills/prototype-feature/references/legacy.md +0 -7
- package/.claude/skills/qa-plan/SKILL.md +0 -22
- package/.claude/skills/qa-plan/references/astra.md +0 -12
- package/.claude/skills/qa-plan/references/legacy.md +0 -7
- package/.claude/skills/release/SKILL.md +0 -22
- package/.claude/skills/release/references/astra.md +0 -30
- package/.claude/skills/release/references/legacy.md +0 -11
- package/.claude/skills/release-readiness/SKILL.md +0 -22
- package/.claude/skills/release-readiness/references/astra.md +0 -17
- package/.claude/skills/release-readiness/references/legacy.md +0 -7
- package/.claude/skills/retrospective/SKILL.md +0 -22
- package/.claude/skills/retrospective/references/astra.md +0 -12
- package/.claude/skills/retrospective/references/legacy.md +0 -7
- package/.claude/skills/review/SKILL.md +0 -22
- package/.claude/skills/review/references/astra.md +0 -21
- package/.claude/skills/review/references/legacy.md +0 -9
- package/.claude/skills/security-audit/SKILL.md +0 -22
- package/.claude/skills/security-audit/references/astra.md +0 -17
- package/.claude/skills/security-audit/references/legacy.md +0 -7
- package/.claude/skills/sprint-plan/SKILL.md +0 -22
- package/.claude/skills/sprint-plan/references/astra.md +0 -12
- package/.claude/skills/sprint-plan/references/legacy.md +0 -7
- package/.claude/skills/status/SKILL.md +0 -22
- package/.claude/skills/status/references/astra.md +0 -19
- package/.claude/skills/status/references/legacy.md +0 -9
- package/.claude/skills/story-readiness/SKILL.md +0 -24
- package/.claude/skills/story-readiness/references/astra.md +0 -17
- package/.claude/skills/story-readiness/references/legacy.md +0 -7
- package/.claude/skills/test/SKILL.md +0 -22
- package/.claude/skills/test/references/astra.md +0 -27
- package/.claude/skills/test/references/legacy.md +0 -9
- package/.claude/skills/ui-review/SKILL.md +0 -22
- package/.claude/skills/ui-review/references/astra.md +0 -17
- package/.claude/skills/ui-review/references/legacy.md +0 -7
- package/.claude/skills/unity-cli/CHANGELOG.md +0 -233
- package/.claude/skills/unity-cli/SECURITY.md +0 -22
- package/.claude/skills/unity-cli/SKILL.md +0 -414
- package/.claude/skills/unity-cli/references/auth-license-cloud.md +0 -146
- package/.claude/skills/unity-cli/references/build-run-test.md +0 -349
- package/.claude/skills/unity-cli/references/config-hub.md +0 -103
- package/.claude/skills/unity-cli/references/diagnostics-maintenance.md +0 -326
- package/.claude/skills/unity-cli/references/editors-install.md +0 -327
- package/.claude/skills/unity-cli/references/integration-advanced.md +0 -472
- package/.claude/skills/unity-cli/references/projects-templates.md +0 -574
- package/.claude/skills/work/SKILL.md +0 -22
- package/.claude/skills/work/references/astra.md +0 -32
- package/.claude/skills/work/references/classification.md +0 -41
- package/.claude/skills/work/references/closure.md +0 -60
- package/.claude/skills/work/references/feature-contracts.md +0 -36
- package/.claude/skills/work/references/legacy.md +0 -29
- package/.claude/skills/work/references/verification.md +0 -26
- package/CLAUDE.md +0 -10
- package/MEMORY.md +0 -109
- package/UPGRADING.md +0 -130
- package/VERSION +0 -1
- package/docs/ARCHITECTURE.md +0 -131
- package/docs/ASSET-PRODUCTION-GRAPHIFY-PLAN.md +0 -230
- package/docs/BOUNDED-REPAIR.md +0 -80
- package/docs/EDITOR-SESSION-EVIDENCE.md +0 -52
- package/docs/HANDOFF-AUTOMATION.md +0 -144
- package/docs/HUONG-DAN-MIGRATE-VA-SU-DUNG.md +0 -117
- package/docs/MIGRATION-MATRIX.md +0 -23
- package/docs/NCCGS-1.3.md +0 -13
- package/docs/NCCGS-1.4.1.md +0 -149
- package/docs/NCCGS-1.4.md +0 -184
- package/docs/NCCGS-1.5-IMPLEMENTATION-PLAN.md +0 -378
- package/docs/NCCGS-1.5-PILOT.md +0 -130
- package/docs/NCCGS-1.5.md +0 -237
- package/docs/PHASE-1-OPERATIONS.md +0 -278
- package/docs/PHASE-2-OPERATIONS.md +0 -183
- package/docs/PROJECT-POLICY.md +0 -94
- package/docs/RELEASE-STATUS.md +0 -150
- package/docs/TASK-SLICING.md +0 -57
- package/docs/UNINSTALL.md +0 -134
- package/docs/UPGRADE-QUALIFICATION.md +0 -45
- package/docs/WFK17-HOOK-REPAIR.md +0 -71
- package/docs/WORKFLOWS.md +0 -85
- package/package-assets/nccgs-project.gitignore +0 -2
- package/package-assets/setup-vivox-voice-chat-evals.gitignore +0 -7
- package/scaffold/.nccgs/autonomy.json +0 -4
- package/scaffold/.nccgs/bugs/.gitkeep +0 -1
- package/scaffold/.nccgs/closures/.gitkeep +0 -1
- package/scaffold/.nccgs/context/.gitkeep +0 -1
- package/scaffold/.nccgs/decisions/.gitkeep +0 -1
- package/scaffold/.nccgs/evidence/.gitkeep +0 -1
- package/scaffold/.nccgs/execution.json +0 -10
- package/scaffold/.nccgs/features/.gitkeep +0 -1
- package/scaffold/.nccgs/gates.json +0 -7
- package/scaffold/.nccgs/inputs.json +0 -6
- package/scaffold/.nccgs/migrations/.gitkeep +0 -1
- package/scaffold/.nccgs/playtests/.gitkeep +0 -1
- package/scaffold/.nccgs/project.yaml +0 -109
- package/scaffold/.nccgs/requirements.yaml +0 -10
- package/scaffold/.nccgs/reviews/.gitkeep +0 -1
- package/scaffold/.nccgs/state.md +0 -40
- package/scaffold/.nccgs/templates/agent-handoff.md +0 -37
- package/scaffold/.nccgs/templates/architecture-decision.md +0 -27
- package/scaffold/.nccgs/templates/closure-record.md +0 -62
- package/scaffold/.nccgs/templates/context-packet.yaml +0 -17
- package/scaffold/.nccgs/templates/design-contract.json +0 -34
- package/scaffold/.nccgs/templates/evidence-record.md +0 -23
- package/scaffold/.nccgs/templates/feature-contract.md +0 -60
- package/scaffold/.nccgs/templates/implementation-report.md +0 -52
- package/scaffold/.nccgs/templates/migration-plan.md +0 -40
- package/scaffold/.nccgs/templates/repair-packet.json +0 -14
- package/scaffold/.nccgs/templates/repair-unity-code.json +0 -18
- package/scaffold/.nccgs/templates/repair-unity-editor.json +0 -21
- package/scaffold/.nccgs/templates/task-slices.json +0 -28
- package/scaffold/.nccgs/templates/waiver.md +0 -11
- package/scripts/benchmark-snapshot.mjs +0 -205
- package/scripts/benchmark-v15.mjs +0 -173
- package/scripts/cli.mjs +0 -205
- package/scripts/doctor.mjs +0 -261
- package/scripts/install.mjs +0 -530
- package/scripts/recover-session.mjs +0 -89
- package/scripts/run.mjs +0 -86
- package/scripts/supervise.mjs +0 -152
- package/scripts/uninstall.mjs +0 -292
- package/scripts/validate.mjs +0 -285
- package/scripts/work-handoff.mjs +0 -38
- package/tests/autonomy.test.mjs +0 -126
- package/tests/benchmark-v15.test.mjs +0 -65
- package/tests/design-readiness.test.mjs +0 -200
- package/tests/editor-session-evidence.test.mjs +0 -45
- package/tests/evidence.test.mjs +0 -186
- package/tests/fixtures/compiler-shutdown.cs +0 -67
- package/tests/fixtures/native-provider.mjs +0 -61
- package/tests/framework.test.mjs +0 -740
- package/tests/gates.test.mjs +0 -479
- package/tests/hook-repair.test.mjs +0 -106
- package/tests/lifecycle-v15.test.mjs +0 -346
- package/tests/native-completion-notices.test.mjs +0 -181
- package/tests/orchestration-v15.test.mjs +0 -596
- package/tests/phase1.test.mjs +0 -427
- package/tests/phase2.test.mjs +0 -250
- package/tests/policy-v15.test.mjs +0 -234
- package/tests/ponytail-package.test.mjs +0 -75
- package/tests/returned-handoff-notices.test.mjs +0 -170
- package/tests/review-budget.test.mjs +0 -177
- package/tests/runtime-v15.test.mjs +0 -1198
- package/tests/session-budget.test.mjs +0 -34
- package/tests/task-slices.test.mjs +0 -285
- package/tests/uninstall.test.mjs +0 -477
- package/tests/unity-generated.test.mjs +0 -140
- package/tests/unity-transport.test.mjs +0 -348
- /package/{.claude/nccgs/packages → template}/ponytail/LICENSE +0 -0
- /package/{.claude/nccgs/packages → template}/ponytail/NOTICE.md +0 -0
- /package/{.claude/nccgs/packages → template}/ponytail/complexity-review.md +0 -0
- /package/{.claude/skills → unity-skills}/build-live-game/references/remote-config.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/README.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/codeless-catalog.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/convert-adapty.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/convert-essentialkit.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/convert-revenuecat.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/convert-unipay.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/migration-v4-to-v5.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/path-add-iap-to-new-project.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/path-convert-native-storekit.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/platform-notes.md +0 -0
- /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/pre-check.md +0 -0
- /package/{.claude/skills → unity-skills}/localization/resources/LocalizedFontAsset.cs +0 -0
- /package/{.claude/skills → unity-skills}/optimize-audio/resources/platform-settings.md +0 -0
- /package/{.claude/skills → unity-skills}/optimize-web/resources/WebOptimizer.cs +0 -0
- /package/{.claude/skills → unity-skills}/optimize-web/resources/toktx-examples.sh +0 -0
- /package/{.claude/skills → unity-skills}/physics-3d-collision/resources/CollisionDebugger.cs +0 -0
- /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/dgs-entrypoint.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/entrypoints.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/examples.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/implementation-fit.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/underlying-services.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/workflows-prerequisites.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/.env.example +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/README.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/promptfooconfig.yaml +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/tests/init-and-login.yaml +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/tests/text-chat.yaml +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/tests/voice-channels.yaml +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/events-and-participants.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/init-and-login.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/text-chat.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/troubleshooting.md +0 -0
- /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/voice-channels.md +0 -0
- /package/{.claude/skills → unity-skills}/shader-graph-create-custom-node/resources/all_hints.hlsl +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/references/api_reference.md +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/references/background.md +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/scripts/AutomaticSliceTexture.cs +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/scripts/GenerateNewSpriteRects.cs +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/scripts/GetTextureSourceImageSize.cs +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/scripts/GetTextureToSlice.cs +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/scripts/GridSliceTexture.cs +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/scripts/IsometricSliceTexture.cs +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/scripts/README.md +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/scripts/SetPivotExample.cs +0 -0
- /package/{.claude/skills → unity-skills}/sprite-editor/scripts/SpriteToPng.cs +0 -0
- /package/{.claude/skills → unity-skills}/ui-imgui/references/gui-elements.md +0 -0
- /package/{.claude/skills → unity-skills}/ui-imgui/references/templates.md +0 -0
- /package/{.claude/skills → unity-skills}/ui-ugui/references/scrollview-setup.md +0 -0
- /package/{.claude/skills → unity-skills}/ui-uitk/references/common-issues.md +0 -0
- /package/{.claude/skills → unity-skills}/ui-uitk/references/painter2d.md +0 -0
- /package/{.claude/skills → unity-skills}/ui-uitk/references/pointermanipulator-guide.md +0 -0
- /package/{.claude/skills → unity-skills}/ui-uitk/references/svg-icons.md +0 -0
- /package/{.claude/skills → unity-skills}/ui-uitk/references/ui-runtime-binding.md +0 -0
- /package/{.claude/skills → unity-skills}/ui-uitk/references/uss-guide.md +0 -0
- /package/{.claude/skills → unity-skills}/urp-postprocessing/references/effect-reference.md +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Windows Job Object through koffi (optional dependency). A process assigned to a job dies with
|
|
2
|
+
// everything it spawned when the job is terminated (and, with KILL_ON_JOB_CLOSE, when the handle
|
|
3
|
+
// closes), including grandchildren that re-parented themselves; taskkill /T cannot promise that.
|
|
4
|
+
// Without koffi (not installed, not Windows, load error) every function here is a no-op that returns
|
|
5
|
+
// null, and process-tree.mjs falls back to taskkill /T + the ppid walk.
|
|
6
|
+
let koffi = null, api = null, tried = false;
|
|
7
|
+
|
|
8
|
+
async function load() {
|
|
9
|
+
if (tried) return api;
|
|
10
|
+
tried = true;
|
|
11
|
+
if (process.platform !== "win32" || process.env.NCCGS_NO_JOB_OBJECT) return null;
|
|
12
|
+
try {
|
|
13
|
+
koffi = (await import("koffi")).default;
|
|
14
|
+
const k32 = koffi.load("kernel32.dll");
|
|
15
|
+
const BASIC = koffi.struct("JOBOBJECT_BASIC_LIMIT_INFORMATION", {
|
|
16
|
+
PerProcessUserTimeLimit: "int64", PerJobUserTimeLimit: "int64", LimitFlags: "uint32", MinimumWorkingSetSize: "size_t", MaximumWorkingSetSize: "size_t",
|
|
17
|
+
ActiveProcessLimit: "uint32", Affinity: "size_t", PriorityClass: "uint32", SchedulingClass: "uint32"
|
|
18
|
+
});
|
|
19
|
+
const IO = koffi.struct("IO_COUNTERS", { ReadOperationCount: "uint64", WriteOperationCount: "uint64", OtherOperationCount: "uint64", ReadTransferCount: "uint64", WriteTransferCount: "uint64", OtherTransferCount: "uint64" });
|
|
20
|
+
const EXT = koffi.struct("JOBOBJECT_EXTENDED_LIMIT_INFORMATION", { BasicLimitInformation: BASIC, IoInfo: IO, ProcessMemoryLimit: "size_t", JobMemoryLimit: "size_t", PeakProcessMemoryUsed: "size_t", PeakJobMemoryUsed: "size_t" });
|
|
21
|
+
api = {
|
|
22
|
+
EXT,
|
|
23
|
+
CreateJobObjectW: k32.func("void* __stdcall CreateJobObjectW(void* attrs, const char16_t* name)"),
|
|
24
|
+
SetInformationJobObject: k32.func("int __stdcall SetInformationJobObject(void* job, int cls, JOBOBJECT_EXTENDED_LIMIT_INFORMATION* info, uint32 len)"),
|
|
25
|
+
AssignProcessToJobObject: k32.func("int __stdcall AssignProcessToJobObject(void* job, void* process)"),
|
|
26
|
+
OpenProcess: k32.func("void* __stdcall OpenProcess(uint32 access, int inherit, uint32 pid)"),
|
|
27
|
+
TerminateJobObject: k32.func("int __stdcall TerminateJobObject(void* job, uint32 exitCode)"),
|
|
28
|
+
CloseHandle: k32.func("int __stdcall CloseHandle(void* h)"),
|
|
29
|
+
GetLastError: k32.func("uint32 __stdcall GetLastError()")
|
|
30
|
+
};
|
|
31
|
+
return api;
|
|
32
|
+
} catch { api = null; return null; }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const JobObjectExtendedLimitInformation = 9;
|
|
36
|
+
const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000;
|
|
37
|
+
const PROCESS_SET_QUOTA = 0x0100, PROCESS_TERMINATE = 0x0001;
|
|
38
|
+
|
|
39
|
+
// Create a job and put `pid` in it. `killOnClose` makes the whole tree die when the handle closes
|
|
40
|
+
// (right for a tool whose children must not outlive it); off by default so a command such as
|
|
41
|
+
// `unity open`, whose Editor child must survive, is only killed on an explicit terminate.
|
|
42
|
+
export async function createJobFor(pid, { killOnClose = false } = {}) {
|
|
43
|
+
const a = await load();
|
|
44
|
+
if (!a) return null;
|
|
45
|
+
try {
|
|
46
|
+
const job = a.CreateJobObjectW(null, null);
|
|
47
|
+
if (!job) return { job: null, error: `CreateJobObject failed (${a.GetLastError()})` };
|
|
48
|
+
const info = { BasicLimitInformation: { PerProcessUserTimeLimit: 0, PerJobUserTimeLimit: 0, LimitFlags: killOnClose ? JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE : 0, MinimumWorkingSetSize: 0, MaximumWorkingSetSize: 0, ActiveProcessLimit: 0, Affinity: 0, PriorityClass: 0, SchedulingClass: 0 },
|
|
49
|
+
IoInfo: { ReadOperationCount: 0, WriteOperationCount: 0, OtherOperationCount: 0, ReadTransferCount: 0, WriteTransferCount: 0, OtherTransferCount: 0 }, ProcessMemoryLimit: 0, JobMemoryLimit: 0, PeakProcessMemoryUsed: 0, PeakJobMemoryUsed: 0 };
|
|
50
|
+
if (!a.SetInformationJobObject(job, JobObjectExtendedLimitInformation, info, koffi.sizeof(a.EXT))) { const e = a.GetLastError(); a.CloseHandle(job); return { job: null, error: `SetInformationJobObject failed (${e})` }; }
|
|
51
|
+
const proc = a.OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE, 0, pid);
|
|
52
|
+
if (!proc) { const e = a.GetLastError(); a.CloseHandle(job); return { job: null, error: `OpenProcess failed (${e})` }; }
|
|
53
|
+
const ok = a.AssignProcessToJobObject(job, proc);
|
|
54
|
+
const err = ok ? 0 : a.GetLastError();
|
|
55
|
+
a.CloseHandle(proc);
|
|
56
|
+
if (!ok) { a.CloseHandle(job); return { job: null, error: `AssignProcessToJobObject failed (${err})` }; }
|
|
57
|
+
return { job, error: null };
|
|
58
|
+
} catch (e) { return { job: null, error: e.message }; }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function terminateJob(job) {
|
|
62
|
+
const a = await load();
|
|
63
|
+
if (!a || !job) return false;
|
|
64
|
+
try { const ok = !!a.TerminateJobObject(job, 1); a.CloseHandle(job); return ok; } catch { return false; }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function closeJob(job) {
|
|
68
|
+
const a = await load();
|
|
69
|
+
if (!a || !job) return;
|
|
70
|
+
try { a.CloseHandle(job); } catch {}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function available() { return !!(await load()); }
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Model modes: three built-in (package-owned, read-only) + custom (project-owned, .nccgs/modes.json).
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { readJson, writeJson, writeText, exists } from "./fs.mjs";
|
|
6
|
+
import { at, loadConfig, saveConfig } from "./project.mjs";
|
|
7
|
+
|
|
8
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
export const BUILTIN = readJson(path.join(here, "..", "modes.json"));
|
|
10
|
+
|
|
11
|
+
export function allModes(root) {
|
|
12
|
+
const custom = exists(at(root, "modes")) ? readJson(at(root, "modes")).modes ?? {} : {};
|
|
13
|
+
return { ...BUILTIN.modes, ...Object.fromEntries(Object.entries(custom).map(([k, v]) => [k, { ...v, custom: true }])) };
|
|
14
|
+
}
|
|
15
|
+
export function getMode(root, name) {
|
|
16
|
+
const modes = allModes(root);
|
|
17
|
+
const mode = modes[name];
|
|
18
|
+
if (!mode) throw new Error(`Unknown mode ${name}. Available: ${Object.keys(modes).join(", ")}`);
|
|
19
|
+
return mode;
|
|
20
|
+
}
|
|
21
|
+
export function validateAgentSetting(setting) {
|
|
22
|
+
const warnings = [];
|
|
23
|
+
const m = String(setting.model ?? "");
|
|
24
|
+
if (!(BUILTIN.allowed.models.includes(m) || /^claude-[\w.-]+$/.test(m))) throw new Error(`model must be one of ${BUILTIN.allowed.models.join("|")} or a claude-... ID (got ${m})`);
|
|
25
|
+
if (setting.effort !== null && setting.effort !== undefined && !BUILTIN.allowed.efforts.includes(setting.effort)) throw new Error(`effort must be one of ${BUILTIN.allowed.efforts.join("|")}`);
|
|
26
|
+
if (m === "haiku" && ["xhigh", "max"].includes(setting.effort)) warnings.push("haiku with xhigh/max effort is unusual");
|
|
27
|
+
if (m === "fable") warnings.push("fable requires a subscription that includes it; set a fallback or expect `task review` to fall back");
|
|
28
|
+
return warnings;
|
|
29
|
+
}
|
|
30
|
+
export function createMode(root, { name, from = "BALANCE" }) {
|
|
31
|
+
if (!/^[A-Za-z][\w-]{1,30}$/.test(name)) throw new Error("mode name: letters, digits, _ or -, 2-31 chars");
|
|
32
|
+
if (BUILTIN.modes[name]) throw new Error(`${name} is a built-in mode; pick another name`);
|
|
33
|
+
const base = getMode(root, from);
|
|
34
|
+
const file = at(root, "modes");
|
|
35
|
+
const custom = exists(file) ? readJson(file) : { schemaVersion: 1, modes: {} };
|
|
36
|
+
if (custom.modes[name]) throw new Error(`mode ${name} already exists`);
|
|
37
|
+
const copy = structuredClone(base); delete copy.custom; copy.description = `Custom, copied from ${from}`;
|
|
38
|
+
custom.modes[name] = copy;
|
|
39
|
+
writeJson(file, custom);
|
|
40
|
+
return copy;
|
|
41
|
+
}
|
|
42
|
+
export function setModeAgent(root, { name, agent, model, effort, fallback }) {
|
|
43
|
+
if (BUILTIN.modes[name]) throw new Error(`${name} is built-in and read-only; create a copy with \`nccgs mode create --from ${name} --name <new>\``);
|
|
44
|
+
const file = at(root, "modes");
|
|
45
|
+
const custom = exists(file) ? readJson(file) : { schemaVersion: 1, modes: {} };
|
|
46
|
+
const mode = custom.modes[name]; if (!mode) throw new Error(`custom mode ${name} not found`);
|
|
47
|
+
if (!BUILTIN.agents.includes(agent)) throw new Error(`agent must be one of ${BUILTIN.agents.join("|")}`);
|
|
48
|
+
const setting = { ...(mode[agent] ?? {}) };
|
|
49
|
+
if (model) setting.model = model;
|
|
50
|
+
if (effort !== undefined) setting.effort = effort === "none" ? null : effort;
|
|
51
|
+
if (fallback !== undefined) setting.fallback = fallback === "none" ? null : fallback;
|
|
52
|
+
const warnings = validateAgentSetting(setting);
|
|
53
|
+
mode[agent] = setting;
|
|
54
|
+
writeJson(file, custom);
|
|
55
|
+
return { setting, warnings };
|
|
56
|
+
}
|
|
57
|
+
export function useMode(root, name, { templateDir }) {
|
|
58
|
+
const mode = getMode(root, name);
|
|
59
|
+
const config = loadConfig(root);
|
|
60
|
+
config.mode = name;
|
|
61
|
+
saveConfig(root, config);
|
|
62
|
+
const warnings = [];
|
|
63
|
+
for (const agent of BUILTIN.agents) if (mode[agent]) warnings.push(...validateAgentSetting(mode[agent]).map(w => `${agent}: ${w}`));
|
|
64
|
+
const written = renderAgents(root, name, { templateDir });
|
|
65
|
+
return { mode: name, written, warnings: [...new Set(warnings)] };
|
|
66
|
+
}
|
|
67
|
+
// Agent frontmatter is static in Claude Code, so a mode change regenerates .claude/agents/*.md.
|
|
68
|
+
export function renderAgents(root, name, { templateDir }) {
|
|
69
|
+
const mode = getMode(root, name);
|
|
70
|
+
const dir = at(root, "agents");
|
|
71
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
72
|
+
const written = [];
|
|
73
|
+
for (const agent of BUILTIN.agents) {
|
|
74
|
+
if (agent === "coordinator") continue; // the main session; its model is passed to `claude --model`
|
|
75
|
+
const tpl = path.join(templateDir, "agents", `${agent}.md`);
|
|
76
|
+
if (!exists(tpl)) continue;
|
|
77
|
+
const s = mode[agent] ?? {};
|
|
78
|
+
const text = fs.readFileSync(tpl, "utf8")
|
|
79
|
+
.replace(/\{\{model\}\}/g, s.model ?? "inherit")
|
|
80
|
+
.replace(/\{\{effort_line\}\}/g, s.effort ? `effort: ${s.effort}\n` : "")
|
|
81
|
+
.replace(/\{\{mode\}\}/g, name);
|
|
82
|
+
const file = path.join(dir, `nccgs-${agent}.md`);
|
|
83
|
+
writeText(file, text);
|
|
84
|
+
written.push(path.relative(root, file));
|
|
85
|
+
}
|
|
86
|
+
return written;
|
|
87
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Cross-platform "run a command and own its whole process tree".
|
|
2
|
+
// Layer 0: let the tool exit on its own (timeout belongs to the caller's args).
|
|
3
|
+
// Layer 1: OS primitive - process group on POSIX; on Windows a Job Object (koffi, optional) with
|
|
4
|
+
// kill-on-close, falling back to taskkill /T when koffi is not installed.
|
|
5
|
+
// Layer 2: env tag (NCCGS_TREE) so re-parented descendants can still be found on POSIX.
|
|
6
|
+
// Layer 3: parent-pid walk as the fallback on both platforms.
|
|
7
|
+
// Every kill is verified by re-enumerating; the result reports dead | alive | unknown.
|
|
8
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
9
|
+
import crypto from "node:crypto";
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import { createJobFor, terminateJob, closeJob } from "./job-object.mjs";
|
|
12
|
+
|
|
13
|
+
const win = process.platform === "win32";
|
|
14
|
+
|
|
15
|
+
export function run(executable, args, { cwd, timeoutMs = 0, env = {}, input, onLine, ownTree = false } = {}) {
|
|
16
|
+
return new Promise(resolve => {
|
|
17
|
+
const tag = crypto.randomUUID();
|
|
18
|
+
const child = spawn(executable, args, {
|
|
19
|
+
cwd, windowsHide: true, detached: !win, shell: false,
|
|
20
|
+
env: { ...process.env, ...env, NCCGS_TREE: tag, UNITY_NO_AUTH_BROKER: "1" },
|
|
21
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
22
|
+
});
|
|
23
|
+
let stdout = "", stderr = "", timedOut = false, settled = false, job = null, jobError = null, jobUsed = false;
|
|
24
|
+
if (win && child.pid) createJobFor(child.pid, { killOnClose: ownTree }).then(r => { if (r) { job = r.job; jobError = r.error; jobUsed = !!r.job; } else jobError = "koffi not available"; }).catch(e => { jobError = e.message; });
|
|
25
|
+
child.stdout.on("data", d => { stdout += d; onLine?.(String(d)); });
|
|
26
|
+
child.stderr.on("data", d => { stderr += d; });
|
|
27
|
+
if (input !== undefined) child.stdin.end(input); else child.stdin.end();
|
|
28
|
+
const timer = timeoutMs > 0 ? setTimeout(async () => {
|
|
29
|
+
timedOut = true;
|
|
30
|
+
await terminate({ pid: child.pid, tag, job });
|
|
31
|
+
job = null;
|
|
32
|
+
}, timeoutMs) : null;
|
|
33
|
+
const finish = (code, signal, error) => {
|
|
34
|
+
if (settled) return; settled = true;
|
|
35
|
+
if (timer) clearTimeout(timer);
|
|
36
|
+
if (job) { closeJob(job); job = null; } // with ownTree, anything still alive in the job dies here
|
|
37
|
+
resolve({ code, signal, stdout, stderr, timedOut, error: error?.message, pid: child.pid, tag, jobObject: !win ? "n/a" : jobUsed ? "used" : `unavailable: ${jobError ?? "not created"}` });
|
|
38
|
+
};
|
|
39
|
+
child.on("error", error => finish(null, null, error));
|
|
40
|
+
child.on("close", (code, signal) => finish(code, signal));
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Kill a tree started by run(). Returns { state: "dead"|"alive"|"unknown", killed: number }.
|
|
45
|
+
export async function terminate({ pid, tag, job = null }, { graceMs = 2000 } = {}) {
|
|
46
|
+
if (!pid) return { state: "unknown", killed: 0 };
|
|
47
|
+
const before = enumerate({ pid, tag });
|
|
48
|
+
if (win) {
|
|
49
|
+
const viaJob = job ? await terminateJob(job) : false;
|
|
50
|
+
if (!viaJob) spawnSync("taskkill", ["/T", "/F", "/PID", String(pid)], { windowsHide: true, timeout: 10000 });
|
|
51
|
+
} else {
|
|
52
|
+
try { process.kill(-pid, "SIGTERM"); } catch { try { process.kill(pid, "SIGTERM"); } catch {} }
|
|
53
|
+
await sleep(graceMs);
|
|
54
|
+
for (const p of enumerate({ pid, tag })) { try { process.kill(p, "SIGKILL"); } catch {} }
|
|
55
|
+
try { process.kill(-pid, "SIGKILL"); } catch {}
|
|
56
|
+
}
|
|
57
|
+
await sleep(300);
|
|
58
|
+
const after = enumerate({ pid, tag });
|
|
59
|
+
return { state: after.length === 0 ? "dead" : "alive", killed: before.length - after.length, remaining: after };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Enumerate live pids that belong to the tree: by env tag (POSIX) or by ppid walk (both).
|
|
63
|
+
export function enumerate({ pid, tag }) {
|
|
64
|
+
const found = new Set();
|
|
65
|
+
if (!win) {
|
|
66
|
+
// Layer 2: env tag. Linux reads /proc; macOS uses `ps -E` (same-user processes only).
|
|
67
|
+
if (tag) {
|
|
68
|
+
if (fs.existsSync("/proc")) {
|
|
69
|
+
for (const entry of safeReaddir("/proc")) {
|
|
70
|
+
if (!/^\d+$/.test(entry)) continue;
|
|
71
|
+
try {
|
|
72
|
+
const environ = fs.readFileSync(`/proc/${entry}/environ`, "latin1");
|
|
73
|
+
if (environ.includes(`NCCGS_TREE=${tag}`)) found.add(Number(entry));
|
|
74
|
+
} catch {}
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
const out = spawnSync("ps", ["-axE", "-o", "pid=,command="], { encoding: "utf8", timeout: 5000 }).stdout || "";
|
|
78
|
+
for (const line of out.split("\n")) if (line.includes(`NCCGS_TREE=${tag}`)) found.add(Number(line.trim().split(/\s+/)[0]));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Layer 3: ppid walk.
|
|
82
|
+
const out = spawnSync("ps", ["-axo", "pid=,ppid="], { encoding: "utf8", timeout: 5000 }).stdout || "";
|
|
83
|
+
const children = new Map();
|
|
84
|
+
for (const line of out.split("\n")) {
|
|
85
|
+
const [p, pp] = line.trim().split(/\s+/).map(Number);
|
|
86
|
+
if (!p) continue;
|
|
87
|
+
if (!children.has(pp)) children.set(pp, []);
|
|
88
|
+
children.get(pp).push(p);
|
|
89
|
+
}
|
|
90
|
+
const stack = [pid];
|
|
91
|
+
while (stack.length) { const p = stack.pop(); if (isAlive(p)) found.add(p); for (const c of children.get(p) || []) stack.push(c); }
|
|
92
|
+
} else {
|
|
93
|
+
const ps = spawnSync("powershell", ["-NoProfile", "-Command",
|
|
94
|
+
"Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId | ConvertTo-Json -Compress"],
|
|
95
|
+
{ encoding: "utf8", windowsHide: true, timeout: 15000 });
|
|
96
|
+
let list = [];
|
|
97
|
+
try { list = JSON.parse(ps.stdout || "[]"); if (!Array.isArray(list)) list = [list]; } catch {}
|
|
98
|
+
const children = new Map();
|
|
99
|
+
for (const row of list) { const pp = row.ParentProcessId; if (!children.has(pp)) children.set(pp, []); children.get(pp).push(row.ProcessId); }
|
|
100
|
+
const alive = new Set(list.map(r => r.ProcessId));
|
|
101
|
+
const stack = [pid];
|
|
102
|
+
while (stack.length) { const p = stack.pop(); if (alive.has(p)) found.add(p); for (const c of children.get(p) || []) stack.push(c); }
|
|
103
|
+
}
|
|
104
|
+
return [...found].filter(p => p && isAlive(p));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isAlive(pid) { try { process.kill(pid, 0); return true; } catch (e) { return e.code === "EPERM"; } }
|
|
108
|
+
function safeReaddir(dir) { try { return fs.readdirSync(dir); } catch { return []; } }
|
|
109
|
+
export const sleep = ms => new Promise(r => setTimeout(r, ms));
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Project layout, configuration and Unity version detection.
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readJson, writeJson, readText, exists } from "./fs.mjs";
|
|
5
|
+
|
|
6
|
+
export const LAYOUT = {
|
|
7
|
+
nccgs: ".nccgs",
|
|
8
|
+
config: ".nccgs/project.json",
|
|
9
|
+
modes: ".nccgs/modes.json",
|
|
10
|
+
state: ".nccgs/state.md",
|
|
11
|
+
tasks: ".nccgs/tasks",
|
|
12
|
+
evidence: ".nccgs/evidence",
|
|
13
|
+
measurements: ".nccgs/evidence/measurements",
|
|
14
|
+
screens: ".nccgs/evidence/screens",
|
|
15
|
+
review: ".nccgs/evidence/review",
|
|
16
|
+
reports: ".nccgs/reports",
|
|
17
|
+
cache: ".nccgs/cache",
|
|
18
|
+
events: ".nccgs/events.jsonl",
|
|
19
|
+
updateCheck: ".nccgs/cache/update-check.json",
|
|
20
|
+
runtime: ".claude/nccgs/runtime",
|
|
21
|
+
installState: ".claude/nccgs/install-state.json",
|
|
22
|
+
agents: ".claude/agents",
|
|
23
|
+
skills: ".claude/skills",
|
|
24
|
+
settings: ".claude/settings.json"
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const DEFAULT_CONFIG = {
|
|
28
|
+
schemaVersion: 3,
|
|
29
|
+
name: "",
|
|
30
|
+
mode: "BALANCE",
|
|
31
|
+
rigor: "production", // prototype | production | release
|
|
32
|
+
autonomy: "guarded", // guarded (acceptEdits) | full (bypassPermissions)
|
|
33
|
+
report: { language: "en" },
|
|
34
|
+
updates: { check: "daily", channels: ["nccgs", "unity-skills", "unity-cli", "pipeline"] },
|
|
35
|
+
unity: { version: null, pipelineVersion: null }, // null = detected from the project
|
|
36
|
+
review: { model: null, effort: null, fallback: "opus" },
|
|
37
|
+
files: {
|
|
38
|
+
protected: [],
|
|
39
|
+
ignoreForSnapshot: ["Library", "Temp", "Logs", "obj", "Build", "Builds", ".nccgs", ".git", "node_modules", "UserSettings"],
|
|
40
|
+
// Files the Editor rewrites on its own (Play Mode, domain reload) with no source meaning. Snapshots hash
|
|
41
|
+
// content, so an identical re-save is already ignored; this list is for files whose content churns.
|
|
42
|
+
volatile: ["ProjectSettings/ShaderGraphSettings.asset", "ProjectSettings/SceneTemplateSettings.json", "ProjectSettings/BurstAotSettings_*.json", "Assets/**/*.orig"],
|
|
43
|
+
hashMaxBytes: 8388608
|
|
44
|
+
},
|
|
45
|
+
unitySkills: { disabled: [] },
|
|
46
|
+
// USD per million tokens, keyed by a substring of the model id. Empty rows = tokens only, no dollars.
|
|
47
|
+
// Fill in from https://www.anthropic.com/pricing when you want estimates; subscription plans do not bill per token.
|
|
48
|
+
pricing: {},
|
|
49
|
+
// Feedback to the NCCGS maintainers. consent: "ask" (not decided yet: the next session asks once),
|
|
50
|
+
// "auto" (bundles are sent when an issue is detected or every periodicDays), "manual" (NCCGS only
|
|
51
|
+
// suggests `/feedback`; nothing is sent by itself), "off" (never suggests, never sends).
|
|
52
|
+
// A bundle holds versions, doctor, per-task numbers, diagnostics and your note: no source, no
|
|
53
|
+
// screenshots, no transcripts, no credentials. Project name and task titles are included.
|
|
54
|
+
feedback: { consent: "ask", endpoint: "https://nccgs-feedback.buihoanghachau.workers.dev/v1/bundle", periodicDays: 7, includeReports: false, lastSentAt: null, lastSuggestedAt: null }
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export function projectRoot(explicit) {
|
|
58
|
+
const root = path.resolve(explicit || process.env.NCCGS_PROJECT_ROOT || process.env.CLAUDE_PROJECT_DIR || process.cwd());
|
|
59
|
+
return root;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function isUnityProject(root) {
|
|
63
|
+
return exists(path.join(root, "Assets")) && exists(path.join(root, "ProjectSettings", "ProjectVersion.txt"));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function at(root, key) { return path.join(root, LAYOUT[key] ?? key); }
|
|
67
|
+
|
|
68
|
+
export function loadConfig(root) {
|
|
69
|
+
const file = at(root, "config");
|
|
70
|
+
const stored = exists(file) ? readJson(file) : {};
|
|
71
|
+
return deepMerge(structuredClone(DEFAULT_CONFIG), stored);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function saveConfig(root, config) { writeJson(at(root, "config"), config); }
|
|
75
|
+
|
|
76
|
+
export function editorVersion(root) {
|
|
77
|
+
const text = readText(path.join(root, "ProjectSettings", "ProjectVersion.txt"));
|
|
78
|
+
return text.match(/m_EditorVersion:\s*(\S+)/)?.[1] ?? null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function manifestPackages(root) {
|
|
82
|
+
const manifest = readJson(path.join(root, "Packages", "manifest.json"), { dependencies: {} });
|
|
83
|
+
return manifest.dependencies ?? {};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function pipelineVersion(root) {
|
|
87
|
+
const deps = manifestPackages(root);
|
|
88
|
+
return deps["com.unity.pipeline"] ?? null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// One line that session-start injects so Claude never has to guess versions.
|
|
92
|
+
export function versionLine(root, cliVersion) {
|
|
93
|
+
const deps = manifestPackages(root);
|
|
94
|
+
const parts = [`Unity ${editorVersion(root) ?? "unknown"}`];
|
|
95
|
+
if (deps["com.unity.pipeline"]) parts.push(`pipeline ${deps["com.unity.pipeline"]}`);
|
|
96
|
+
if (cliVersion) parts.push(`CLI ${cliVersion}`);
|
|
97
|
+
for (const key of ["com.unity.render-pipelines.universal", "com.unity.inputsystem", "com.unity.test-framework"]) {
|
|
98
|
+
if (deps[key]) parts.push(`${key.split(".").pop()} ${deps[key]}`);
|
|
99
|
+
}
|
|
100
|
+
return parts.join(" · ");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function deepMerge(base, extra) {
|
|
104
|
+
if (!extra || typeof extra !== "object" || Array.isArray(extra)) return extra ?? base;
|
|
105
|
+
for (const [k, v] of Object.entries(extra)) {
|
|
106
|
+
base[k] = v && typeof v === "object" && !Array.isArray(v) && base[k] && typeof base[k] === "object" ? deepMerge(base[k], v) : v;
|
|
107
|
+
}
|
|
108
|
+
return base;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function ensureLayout(root) {
|
|
112
|
+
for (const key of ["nccgs", "tasks", "measurements", "screens", "review", "reports", "cache"]) fs.mkdirSync(at(root, key), { recursive: true });
|
|
113
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Source snapshot: a fingerprint of Assets/, Packages/ and ProjectSettings/ by file CONTENT.
|
|
2
|
+
//
|
|
3
|
+
// alpha.2 fingerprinted path+size+mtime. That was wrong for Unity: the Editor re-saves files such as
|
|
4
|
+
// ProjectSettings/ShaderGraphSettings.asset every time it enters Play Mode, so `task verify --kind observe`
|
|
5
|
+
// changed the snapshot without changing a byte of source, tests looked stale, and the report blamed
|
|
6
|
+
// the task for an edit it never made. Hashing content fixes the question the ledger asks
|
|
7
|
+
// ("did the source change since this evidence?") without exceptions for every file Unity touches.
|
|
8
|
+
//
|
|
9
|
+
// Cost: files are rehashed only when their size or mtime changed since the last snapshot
|
|
10
|
+
// (.nccgs/cache/hash-cache.json). Files above `files.hashMaxBytes` (default 8 MB, usually textures,
|
|
11
|
+
// audio, video) are fingerprinted by size+mtime; a rewritten texture still counts as a change.
|
|
12
|
+
// Known Editor-volatile files (config `files.volatile`) are excluded entirely.
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import crypto from "node:crypto";
|
|
16
|
+
import { walk, toPosix, readJson, writeJson, exists } from "./fs.mjs";
|
|
17
|
+
import { loadConfig, at } from "./project.mjs";
|
|
18
|
+
|
|
19
|
+
const ROOTS = ["Assets", "Packages", "ProjectSettings"];
|
|
20
|
+
const CACHE_VERSION = 1;
|
|
21
|
+
|
|
22
|
+
function cacheFile(root) { return path.join(at(root, "cache"), "hash-cache.json"); }
|
|
23
|
+
function mapFile(root, sha) { return path.join(at(root, "cache"), "snapshots", `${sha}.json`); }
|
|
24
|
+
|
|
25
|
+
// glob-lite: `*` within a segment, `**` across segments. Patterns are posix, relative to root.
|
|
26
|
+
export function matchesPattern(rel, pattern) {
|
|
27
|
+
const re = "^" + pattern.split("**").map(p => p.split("*").map(s => s.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join("[^/]*")).join(".*") + "$";
|
|
28
|
+
return new RegExp(re).test(rel);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isVolatile(rel, volatile) { return volatile.some(p => matchesPattern(rel, p)); }
|
|
32
|
+
|
|
33
|
+
// Returns { sha, files, at, map } where map is { "Assets/x.cs": "<sha256 or size:mtime>" }.
|
|
34
|
+
export function snapshot(root, { config = loadConfig(root), persist = true } = {}) {
|
|
35
|
+
const skip = new Set(config.files.ignoreForSnapshot);
|
|
36
|
+
const volatile = config.files.volatile ?? [];
|
|
37
|
+
const maxBytes = config.files.hashMaxBytes ?? 8 * 1024 * 1024;
|
|
38
|
+
const cachePath = cacheFile(root);
|
|
39
|
+
const cached = exists(cachePath) ? readJson(cachePath, {}) : {};
|
|
40
|
+
const cache = cached.version === CACHE_VERSION ? cached.entries ?? {} : {};
|
|
41
|
+
const next = {};
|
|
42
|
+
const map = {};
|
|
43
|
+
for (const top of ROOTS) {
|
|
44
|
+
const dir = path.join(root, top);
|
|
45
|
+
if (!fs.existsSync(dir)) continue;
|
|
46
|
+
for (const file of walk(dir, { skipDirs: skip })) {
|
|
47
|
+
const rel = toPosix(path.relative(root, file));
|
|
48
|
+
if (isVolatile(rel, volatile)) continue;
|
|
49
|
+
let st;
|
|
50
|
+
try { st = fs.statSync(file); } catch { continue; }
|
|
51
|
+
const key = `${st.size}:${Math.floor(st.mtimeMs)}`;
|
|
52
|
+
let fingerprint;
|
|
53
|
+
if (st.size > maxBytes) fingerprint = `big:${key}`;
|
|
54
|
+
else if (cache[rel]?.key === key) fingerprint = cache[rel].sha;
|
|
55
|
+
else {
|
|
56
|
+
try { fingerprint = crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex"); } catch { continue; }
|
|
57
|
+
}
|
|
58
|
+
next[rel] = { key, sha: fingerprint };
|
|
59
|
+
map[rel] = fingerprint;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const rels = Object.keys(map).sort();
|
|
63
|
+
const hash = crypto.createHash("sha256");
|
|
64
|
+
for (const rel of rels) hash.update(`${rel}\0${map[rel]}\n`);
|
|
65
|
+
const sha = hash.digest("hex");
|
|
66
|
+
if (persist) {
|
|
67
|
+
try {
|
|
68
|
+
writeJson(cachePath, { version: CACHE_VERSION, entries: next });
|
|
69
|
+
const mf = mapFile(root, sha);
|
|
70
|
+
if (!exists(mf)) writeJson(mf, { sha, at: new Date().toISOString(), files: map });
|
|
71
|
+
} catch {}
|
|
72
|
+
}
|
|
73
|
+
return { sha, files: rels.length, at: new Date().toISOString(), map };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Load the per-file map of an earlier snapshot by sha (written by snapshot()); null when unknown.
|
|
77
|
+
export function snapshotMap(root, sha) {
|
|
78
|
+
const mf = sha ? mapFile(root, sha) : null;
|
|
79
|
+
return mf && exists(mf) ? readJson(mf).files ?? null : null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Files whose content differs between an earlier snapshot and now: added, modified or removed.
|
|
83
|
+
// `since` is a snapshot object ({ sha, map? }) or a sha. Falls back to mtime when the earlier map is
|
|
84
|
+
// unknown (tasks opened by alpha.2) and `sinceMs` is given.
|
|
85
|
+
export function changedFiles(root, since, { config = loadConfig(root), sinceMs = null } = {}) {
|
|
86
|
+
const current = snapshot(root, { config });
|
|
87
|
+
const before = typeof since === "object" && since?.map ? since.map : snapshotMap(root, typeof since === "string" ? since : since?.sha);
|
|
88
|
+
if (!before) {
|
|
89
|
+
if (sinceMs == null) return Object.keys(current.map).sort();
|
|
90
|
+
const skip = new Set(config.files.ignoreForSnapshot);
|
|
91
|
+
const volatile = config.files.volatile ?? [];
|
|
92
|
+
const changed = [];
|
|
93
|
+
for (const top of ROOTS) {
|
|
94
|
+
const dir = path.join(root, top);
|
|
95
|
+
if (!fs.existsSync(dir)) continue;
|
|
96
|
+
for (const file of walk(dir, { skipDirs: skip })) {
|
|
97
|
+
const rel = toPosix(path.relative(root, file));
|
|
98
|
+
if (!isVolatile(rel, volatile) && fs.statSync(file).mtimeMs > sinceMs) changed.push(rel);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return changed.sort();
|
|
102
|
+
}
|
|
103
|
+
const changed = new Set();
|
|
104
|
+
for (const [rel, fp] of Object.entries(current.map)) if (before[rel] !== fp) changed.add(rel);
|
|
105
|
+
for (const rel of Object.keys(before)) if (!(rel in current.map)) changed.add(rel);
|
|
106
|
+
return [...changed].sort();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Is `rel` covered by the task's declared files? A `.meta` belongs to the asset it describes.
|
|
110
|
+
export function inScope(rel, files) {
|
|
111
|
+
if (!files?.length) return true;
|
|
112
|
+
const base = rel.endsWith(".meta") ? rel.slice(0, -5) : rel;
|
|
113
|
+
return files.some(p => base === p || rel === p || base.startsWith(p.replace(/\/?$/, "/")));
|
|
114
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Shared hook plumbing. Hooks are workflow guards, not a sandbox: they block the
|
|
2
|
+
// obviously destructive, warn on the risky, and log the rest.
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { projectRoot, at } from "../core/project.mjs";
|
|
5
|
+
import { appendLine } from "../core/fs.mjs";
|
|
6
|
+
import { diag } from "../core/diag.mjs";
|
|
7
|
+
|
|
8
|
+
export async function readInput() {
|
|
9
|
+
let text = "";
|
|
10
|
+
for await (const chunk of process.stdin) text += chunk;
|
|
11
|
+
try { return text.trim() ? JSON.parse(text) : {}; } catch { return {}; }
|
|
12
|
+
}
|
|
13
|
+
export const root = () => projectRoot();
|
|
14
|
+
export function block(reason, extra = {}) { diag(root(), "hook.block", { hook: path.basename(process.argv[1] ?? "hook"), reason, ...extra }); process.stderr.write(`NCCGS blocked: ${reason}\n`); process.exit(2); }
|
|
15
|
+
process.on("uncaughtException", e => { try { diag(root(), "hook.error", { hook: path.basename(process.argv[1] ?? "hook"), error: e }); } catch {} process.exit(0); });
|
|
16
|
+
export function warn(hookEventName, message) {
|
|
17
|
+
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName, additionalContext: `NCCGS warning: ${message}` } }) + "\n");
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
export function log(type, data) {
|
|
21
|
+
try { appendLine(at(root(), "events"), JSON.stringify({ at: new Date().toISOString(), type, ...data })); } catch {}
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Stop hook: a DONE claim needs a closed task. It never traps the session (stop_hook_active).
|
|
2
|
+
import { readInput, root } from "./common.mjs";
|
|
3
|
+
import { openTasks } from "../task/ledger.mjs";
|
|
4
|
+
|
|
5
|
+
const input = await readInput();
|
|
6
|
+
if (input?.stop_hook_active) process.exit(0);
|
|
7
|
+
const text = String(input?.last_assistant_message ?? "");
|
|
8
|
+
const claimsDone = /(^|\n)\s*(\*\*)?(status|state|final state|trạng thái)(\*\*)?\s*:\s*(\*\*)?done\b/i.test(text) || /\b(task|work)\s+(is\s+)?done\b[^.]*\.(\s|$)/i.test(text) && /\bDONE\b/.test(text);
|
|
9
|
+
if (!claimsDone) process.exit(0);
|
|
10
|
+
let open = [];
|
|
11
|
+
try { open = openTasks(root()); } catch {}
|
|
12
|
+
if (open.length) {
|
|
13
|
+
process.stdout.write(JSON.stringify({ decision: "block", reason: `NCCGS: ${open.map(t => t.id).join(", ")} still open. Run \`task close\` (criteria + review must pass) before reporting DONE, or report partial/blocked honestly.` }) + "\n");
|
|
14
|
+
}
|
|
15
|
+
process.exit(0);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// PreToolUse for mcp__* tools: refuse Unity MCP servers by name.
|
|
2
|
+
import { readInput, block } from "./common.mjs";
|
|
3
|
+
import { PROVIDER } from "./unity-transport.mjs";
|
|
4
|
+
const input = await readInput();
|
|
5
|
+
const tool = String(input?.tool_name ?? "");
|
|
6
|
+
const server = tool.startsWith("mcp__") ? (tool.split("__")[1] ?? "") : "";
|
|
7
|
+
if (server && PROVIDER.test(server)) block(`Unity MCP tool ${tool} is disabled by the project's transport policy`);
|
|
8
|
+
process.exit(0);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// PreToolUse for Bash|PowerShell: block destructive git/filesystem commands and any Unity MCP route.
|
|
2
|
+
import { readInput, block } from "./common.mjs";
|
|
3
|
+
import { unityMcpViolation } from "./unity-transport.mjs";
|
|
4
|
+
|
|
5
|
+
const input = await readInput();
|
|
6
|
+
const cmd = String(input?.tool_input?.command ?? "");
|
|
7
|
+
const DESTRUCTIVE = [
|
|
8
|
+
[/\bgit\s+(push\s+[^\n|;&]*(--force|-f\b)|reset\s+--hard|clean\s+-[a-z]*f|checkout\s+--\s+\.|restore\s+\.)/i, "destructive git command"],
|
|
9
|
+
[/\brm\s+-[a-z]*r[a-z]*f?\s+(\/|~|\.\.?(\s|$)|\*|Assets\b|Packages\b|ProjectSettings\b)/i, "recursive delete of a project root"],
|
|
10
|
+
[/\b(Remove-Item|rmdir|rd)\b[^\n]*\s(-Recurse|\/s)[^\n]*\s(\.|Assets|Packages|ProjectSettings|\*)\b/i, "recursive delete of a project root"],
|
|
11
|
+
[/\bgit\s+commit\s+[^\n]*--amend/i, "amending commits is reserved for the user"]
|
|
12
|
+
];
|
|
13
|
+
for (const [re, why] of DESTRUCTIVE) if (re.test(cmd)) block(`${why}: ${cmd.slice(0, 120)}`);
|
|
14
|
+
const mcp = unityMcpViolation(cmd);
|
|
15
|
+
if (mcp) block(mcp);
|
|
16
|
+
process.exit(0);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// PreToolUse for Write|Edit|MultiEdit|NotebookEdit:
|
|
2
|
+
// - block edits to vendored Unity skills and to evidence that only `task verify` may write
|
|
3
|
+
// - warn (never block) on hand-editing serialized Unity assets
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { readInput, root, block, warn } from "./common.mjs";
|
|
6
|
+
import { readJson } from "../core/fs.mjs";
|
|
7
|
+
|
|
8
|
+
const input = await readInput();
|
|
9
|
+
const raw = String(input?.tool_input?.file_path ?? input?.tool_input?.path ?? input?.tool_input?.notebook_path ?? "");
|
|
10
|
+
if (!raw) process.exit(0);
|
|
11
|
+
const project = root();
|
|
12
|
+
const rel = path.relative(project, path.resolve(project, raw)).split(path.sep).join("/");
|
|
13
|
+
|
|
14
|
+
if (rel.startsWith(".claude/skills/")) {
|
|
15
|
+
const skill = rel.split("/")[2];
|
|
16
|
+
let vendored = [];
|
|
17
|
+
try { vendored = readJson(path.join(project, ".claude/nccgs/unity-skills-manifest.json")).skills.map(s => s.name); } catch {}
|
|
18
|
+
if (vendored.includes(skill)) block(`'${skill}' is a vendored official Unity Skill; project guidance belongs in CLAUDE.md or .claude/nccgs/protocols/`);
|
|
19
|
+
}
|
|
20
|
+
if (/^\.nccgs\/evidence\/(measurements|screens)\//.test(rel)) block("evidence under measurements/ and screens/ is written only by `task verify`");
|
|
21
|
+
if (/^\.nccgs\/(tasks|reports|cache)\//.test(rel)) block("task records, reports and the snapshot cache are written only by the task CLI");
|
|
22
|
+
if (/\.(unity|prefab|asset|meta|controller|anim|physicMaterial|lighting)$/i.test(rel) && !/^\.nccgs\//.test(rel)) {
|
|
23
|
+
warn("PreToolUse", `hand-editing a serialized Unity asset (${rel}). Prefer \`unity command\` (scene/prefab/component groups) so GUIDs and references stay valid; if you must edit, keep the YAML header and fileIDs intact.`);
|
|
24
|
+
}
|
|
25
|
+
process.exit(0);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// SubagentStart/SubagentStop/PostToolUse(Agent): append usage and agent events to .nccgs/events.jsonl.
|
|
2
|
+
import { readInput, log } from "./common.mjs";
|
|
3
|
+
const input = await readInput();
|
|
4
|
+
const type = process.argv[2] || input?.hook_event_name || "event";
|
|
5
|
+
const usage = input?.tool_response?.usage ?? input?.usage ?? null;
|
|
6
|
+
log(`agent.${type}`, { sessionId: input?.session_id ?? null, transcriptPath: input?.transcript_path ?? null, agentTranscriptPath: input?.agent_transcript_path ?? null, agent: input?.tool_input?.subagent_type ?? input?.agent_type ?? null, agentId: input?.agent_id ?? null, model: input?.tool_response?.model ?? input?.model ?? null, usage });
|
|
7
|
+
process.exit(0);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// SessionStart: inject the project's Unity versions, open tasks and (cached) update notices.
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { readInput, root, log } from "./common.mjs";
|
|
5
|
+
import { versionLine, loadConfig, at } from "../core/project.mjs";
|
|
6
|
+
import { openTasks } from "../task/ledger.mjs";
|
|
7
|
+
import { readJson, exists, readText } from "../core/fs.mjs";
|
|
8
|
+
import { autoFeedback } from "../task/feedback.mjs";
|
|
9
|
+
import { markSuggested, CONSENT_TEXT } from "../core/feedback-policy.mjs";
|
|
10
|
+
|
|
11
|
+
const input = await readInput();
|
|
12
|
+
const project = root();
|
|
13
|
+
const lines = [];
|
|
14
|
+
try {
|
|
15
|
+
const cli = spawnSync(process.env.NCCGS_UNITY_BIN || "unity", [...(process.env.NCCGS_UNITY_ARGS ? process.env.NCCGS_UNITY_ARGS.split("|") : []), "--version"], { encoding: "utf8", timeout: 8000, windowsHide: true });
|
|
16
|
+
lines.push(`NCCGS project: ${versionLine(project, cli.status === 0 ? cli.stdout.trim() : null)}`);
|
|
17
|
+
} catch { lines.push(`NCCGS project: ${versionLine(project, null)}`); }
|
|
18
|
+
try {
|
|
19
|
+
const config = loadConfig(project);
|
|
20
|
+
lines.push(`NCCGS mode ${config.mode} · rigor ${config.rigor} · autonomy ${config.autonomy}`);
|
|
21
|
+
const open = openTasks(project);
|
|
22
|
+
if (open.length) lines.push(`Open tasks: ${open.map(t => `${t.id} (${t.status}, ${t.rigor})`).join(", ")}`);
|
|
23
|
+
const state = readText(at(project, "state"));
|
|
24
|
+
const recent = state.split("\n").filter(l => l.startsWith("- ")).slice(0, 3);
|
|
25
|
+
if (recent.length) lines.push(`Recent: ${recent.join(" | ")}`);
|
|
26
|
+
const check = at(project, "updateCheck");
|
|
27
|
+
if (exists(check)) {
|
|
28
|
+
const u = readJson(check);
|
|
29
|
+
const notices = (u.notices ?? []).map(n => `${n.component} ${n.current} -> ${n.latest} (${n.hint})`);
|
|
30
|
+
if (notices.length) lines.push(`Updates available (not applied): ${notices.join("; ")}`);
|
|
31
|
+
}
|
|
32
|
+
} catch {}
|
|
33
|
+
try {
|
|
34
|
+
const fb = await autoFeedback(project, { trigger: "session-start" });
|
|
35
|
+
if (fb.action === "ask-consent") lines.push(`FEEDBACK CONSENT NOT SET. Before other work, ask the user once with AskUserQuestion (options: auto / manual / off) using this text: ${CONSENT_TEXT.en} Then run \`npx nccgs feedback --project . --consent <choice>\` and continue. Reasons it came up now: ${fb.reasons.join("; ")}.`);
|
|
36
|
+
else if (fb.action === "suggest") { markSuggested(project); lines.push(`NCCGS noticed issues since the last feedback (${fb.reasons.join("; ")}). Suggest to the user, once, that \`/feedback\` would send a bundle for review; do not run it without their yes.`); }
|
|
37
|
+
else if (fb.action === "send") lines.push(fb.sent?.ok ? `Feedback bundle sent automatically (consent auto): ${fb.reasons.join("; ")}. Mention it in one line.` : `Feedback bundle could not be sent (${fb.sent?.reason ?? "unknown"}); it is saved under .nccgs/feedback/. Mention it in one line.`);
|
|
38
|
+
} catch {}
|
|
39
|
+
log("session.start", { sessionId: input?.session_id ?? null, transcriptPath: input?.transcript_path ?? null, model: input?.model ?? null });
|
|
40
|
+
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: lines.join("\n") } }) + "\n");
|