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
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { artifact, contained, hash, verifyArtifact } from "./policy.mjs";
|
|
4
|
-
|
|
5
|
-
const durableRoot = ".nccgs/evidence/runtime";
|
|
6
|
-
const legacyRoot = ".nccgs/runtime/";
|
|
7
|
-
const isRef = value => value && typeof value === "object" && typeof value.path === "string" && typeof value.sha256 === "string";
|
|
8
|
-
const encode = value => Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
9
|
-
|
|
10
|
-
function readReference(project, ref, label) {
|
|
11
|
-
try {
|
|
12
|
-
const file = verifyArtifact(project, ref);
|
|
13
|
-
const bytes = fs.readFileSync(file);
|
|
14
|
-
if (hash(bytes) !== ref.sha256) throw new Error("Evidence changed while being copied");
|
|
15
|
-
return bytes;
|
|
16
|
-
} catch (error) {
|
|
17
|
-
throw new Error(`${label}: missing, stale, or unsafe evidence '${ref?.path ?? "unknown"}': ${error.message}`);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Content-addressed copies retain the original bytes. Plan every copy before any
|
|
22
|
-
// writes so a missing legacy source cannot produce a partly migrated task.
|
|
23
|
-
function copyPlan(project) {
|
|
24
|
-
const writes = new Map();
|
|
25
|
-
const migrations = [];
|
|
26
|
-
const seenMigrations = new Set();
|
|
27
|
-
const add = (kind, bytes) => {
|
|
28
|
-
const sha256 = hash(bytes);
|
|
29
|
-
const relative = `${durableRoot}/${kind}/${sha256}.json`;
|
|
30
|
-
const file = contained(project, relative);
|
|
31
|
-
if (fs.existsSync(file)) {
|
|
32
|
-
if (!fs.statSync(file).isFile() || hash(fs.readFileSync(file)) !== sha256) {
|
|
33
|
-
throw new Error(`Durable evidence collision or corruption: ${relative}`);
|
|
34
|
-
}
|
|
35
|
-
} else writes.set(relative, bytes);
|
|
36
|
-
return { path: relative, sha256 };
|
|
37
|
-
};
|
|
38
|
-
const note = (from, to, kind) => {
|
|
39
|
-
if (from.path === to.path && from.sha256 === to.sha256) return;
|
|
40
|
-
const key = `${kind}:${from.path}:${from.sha256}:${to.path}`;
|
|
41
|
-
if (!seenMigrations.has(key)) {
|
|
42
|
-
migrations.push({ kind, from: { ...from }, to: { ...to } });
|
|
43
|
-
seenMigrations.add(key);
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const source = ref => {
|
|
47
|
-
const bytes = readReference(project, ref, "Runtime source");
|
|
48
|
-
if (ref.path.startsWith(`${durableRoot}/sources/`)) return { ...ref };
|
|
49
|
-
const durable = add("sources", bytes);
|
|
50
|
-
note(ref, durable, "source");
|
|
51
|
-
return durable;
|
|
52
|
-
};
|
|
53
|
-
const observation = (value, sourceRef) => {
|
|
54
|
-
const durableSource = source(sourceRef);
|
|
55
|
-
const normalized = { ...value, observationSource: durableSource };
|
|
56
|
-
if (sourceRef.path !== durableSource.path || sourceRef.sha256 !== durableSource.sha256) {
|
|
57
|
-
normalized.originalObservationSource = value.originalObservationSource ?? { ...sourceRef };
|
|
58
|
-
}
|
|
59
|
-
return add("observations", encode(normalized));
|
|
60
|
-
};
|
|
61
|
-
const commit = () => {
|
|
62
|
-
// Recheck destinations before writing; never overwrite an existing artifact.
|
|
63
|
-
for (const [relative, bytes] of writes) {
|
|
64
|
-
const file = contained(project, relative);
|
|
65
|
-
if (fs.existsSync(file) && (!fs.statSync(file).isFile() || hash(fs.readFileSync(file)) !== hash(bytes))) {
|
|
66
|
-
throw new Error(`Durable evidence collision or corruption: ${relative}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
for (const [relative, bytes] of writes) {
|
|
70
|
-
const file = contained(project, relative);
|
|
71
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
72
|
-
try { fs.writeFileSync(file, bytes, { flag: "wx" }); }
|
|
73
|
-
catch (error) { if (error.code !== "EEXIST") throw error; }
|
|
74
|
-
if (artifact(project, relative).sha256 !== hash(bytes)) {
|
|
75
|
-
throw new Error(`Durable evidence copy failed verification: ${relative}`);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
return { add, source, observation, note, migrations, commit };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Persist an observation and an exact durable copy of its raw source.
|
|
83
|
-
* Callers retain responsibility for validating runtime identity and provenance.
|
|
84
|
-
*/
|
|
85
|
-
export function persistRuntimeObservation(project, observation, sourceRef) {
|
|
86
|
-
if (!observation || typeof observation !== "object" || Array.isArray(observation)) {
|
|
87
|
-
throw new Error("Runtime observation must be an object");
|
|
88
|
-
}
|
|
89
|
-
const plan = copyPlan(project);
|
|
90
|
-
const result = plan.observation(observation, sourceRef);
|
|
91
|
-
plan.commit();
|
|
92
|
-
return result;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** Return a migrated clone; the caller owns task locking and atomic task writes.
|
|
96
|
-
* No source, stage, history entry, review counter, or original artifact is deleted.
|
|
97
|
-
* This does not refresh snapshots, evidence times, approvals, or task validity.
|
|
98
|
-
*/
|
|
99
|
-
export function migrateTaskEvidence(project, task) {
|
|
100
|
-
const plan = copyPlan(project);
|
|
101
|
-
const cache = new Map();
|
|
102
|
-
const migrateReference = ref => {
|
|
103
|
-
const key = `${ref.path}:${ref.sha256}`;
|
|
104
|
-
if (cache.has(key)) return { ...ref, ...cache.get(key) };
|
|
105
|
-
const bytes = readReference(project, ref, "Runtime observation");
|
|
106
|
-
let value;
|
|
107
|
-
try { value = JSON.parse(bytes.toString("utf8")); }
|
|
108
|
-
catch {
|
|
109
|
-
if (ref.path.includes("/observations/")) throw new Error(`Invalid runtime observation JSON: ${ref.path}`);
|
|
110
|
-
}
|
|
111
|
-
let result = ref;
|
|
112
|
-
if (value?.origin === "runtime-observation") {
|
|
113
|
-
if (!isRef(value.observationSource)) throw new Error(`Runtime observation has no verifiable raw source: ${ref.path}`);
|
|
114
|
-
const sourceRef = value.observationSource;
|
|
115
|
-
const source = plan.source(sourceRef);
|
|
116
|
-
const needsCopy = !ref.path.startsWith(`${durableRoot}/observations/`) || source.path !== sourceRef.path;
|
|
117
|
-
if (needsCopy) {
|
|
118
|
-
const archive = plan.add("sources", bytes);
|
|
119
|
-
plan.note(ref, archive, "observation-archive");
|
|
120
|
-
const migrated = { ...value, observationSource: source,
|
|
121
|
-
originalObservationSource: value.originalObservationSource ?? { ...sourceRef },
|
|
122
|
-
evidenceMigration: { originalObservation: { ...ref }, archivedObservation: archive,
|
|
123
|
-
...(value.evidenceMigration ? { previous: value.evidenceMigration } : {}) } };
|
|
124
|
-
result = plan.add("observations", encode(migrated));
|
|
125
|
-
plan.note(ref, result, "observation");
|
|
126
|
-
}
|
|
127
|
-
} else if (ref.path.startsWith(legacyRoot)) {
|
|
128
|
-
if (ref.path.includes("/observations/")) throw new Error(`Invalid runtime observation origin: ${ref.path}`);
|
|
129
|
-
result = plan.source(ref);
|
|
130
|
-
}
|
|
131
|
-
cache.set(key, result);
|
|
132
|
-
return { ...ref, ...result };
|
|
133
|
-
};
|
|
134
|
-
const walk = (value, key = "") => {
|
|
135
|
-
if (Array.isArray(value)) return value.map(item => walk(item, key));
|
|
136
|
-
if (!value || typeof value !== "object") return value;
|
|
137
|
-
// Original paths in our audit records describe where bytes came from; they
|
|
138
|
-
// are not live dependencies after a clean copy removes the ignored runtime.
|
|
139
|
-
if (value.action === "migrate-evidence" ||
|
|
140
|
-
(["source", "observation", "observation-archive"].includes(value.kind) && isRef(value.from) && isRef(value.to))) {
|
|
141
|
-
return structuredClone(value);
|
|
142
|
-
}
|
|
143
|
-
if (isRef(value)) {
|
|
144
|
-
// Do not revalidate unrelated old plan/report refs when migrating history.
|
|
145
|
-
if (key === "runtime" || value.path.startsWith(legacyRoot)) return migrateReference(value);
|
|
146
|
-
return { ...value };
|
|
147
|
-
}
|
|
148
|
-
return Object.fromEntries(Object.entries(value).map(([name, child]) => [name, walk(child, name)]));
|
|
149
|
-
};
|
|
150
|
-
const migrated = walk(task);
|
|
151
|
-
plan.commit();
|
|
152
|
-
return { task: migrated, migrations: plan.migrations, changed: plan.migrations.length > 0 };
|
|
153
|
-
}
|
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { performance } from "node:perf_hooks";
|
|
4
|
-
import { hash, json, contained, artifact, verifyArtifact, atomicJson, loadPipeline, resolveExecution } from "./policy.mjs";
|
|
5
|
-
import { canonicalInputs, pinInputs, inputPolicy, isOutput, isUnityGenerated, unityGeneratedState } from "./inputs.mjs";
|
|
6
|
-
import { migrateTaskEvidence } from "./evidence.mjs";
|
|
7
|
-
import { acquireLock } from "./process-lock.mjs";
|
|
8
|
-
import { initializeStandalone, checkStandalone, recordStandalone, extendStandalone, refreshStandalone,
|
|
9
|
-
reclassifyStandalone, exportExternalStandalone, importExternalStandalone } from "./lifecycle.mjs";
|
|
10
|
-
|
|
11
|
-
export const stages = ["implementation", "review", "report", "astra", "acceptance"];
|
|
12
|
-
function requireValue(condition, message) { if (!condition) throw new Error(message); }
|
|
13
|
-
export function taskPath(project, id) {
|
|
14
|
-
requireValue(typeof id === "string" && /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,79}$/.test(id), "Invalid task ID");
|
|
15
|
-
return contained(project, `.nccgs/tasks/${id}.json`);
|
|
16
|
-
}
|
|
17
|
-
export function snapshot(project, task = null, { includeFiles = false } = {}) {
|
|
18
|
-
const started = performance.now();
|
|
19
|
-
const excluded = new Set(loadPipeline(project).snapshotExcludes);
|
|
20
|
-
const policy = inputPolicy(project);
|
|
21
|
-
const inputs = canonicalInputs(project, policy);
|
|
22
|
-
const files = [];
|
|
23
|
-
let bytes = 0, readHashMs = 0;
|
|
24
|
-
function walk(relative = "") {
|
|
25
|
-
for (const entry of fs.readdirSync(path.join(project, relative), { withFileTypes: true })) {
|
|
26
|
-
if (!relative && excluded.has(entry.name)) continue;
|
|
27
|
-
const name = relative ? `${relative}/${entry.name}` : entry.name;
|
|
28
|
-
const file = contained(project, name);
|
|
29
|
-
if (isOutput(name, policy) || isUnityGenerated(name, policy)) continue;
|
|
30
|
-
if (entry.isDirectory()) walk(name);
|
|
31
|
-
else if (entry.isFile()) {
|
|
32
|
-
const readStarted = performance.now();
|
|
33
|
-
const data = fs.readFileSync(file);
|
|
34
|
-
files.push([name, hash(data)]);
|
|
35
|
-
bytes += data.length;
|
|
36
|
-
readHashMs += performance.now() - readStarted;
|
|
37
|
-
}
|
|
38
|
-
else throw new Error(`Unsupported snapshot entry: ${name}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
walk();
|
|
42
|
-
const generatedFiles = unityGeneratedState(project, policy);
|
|
43
|
-
files.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
44
|
-
return { sha256: hash(JSON.stringify({ files, canonicalInputs: inputs.sha256 })), sourceSha256: hash(JSON.stringify(files)), files: files.length,
|
|
45
|
-
bytes, canonicalInputSha256: inputs.sha256, canonicalInputFiles: inputs.entries.filter(e => e.kind === "file").length,
|
|
46
|
-
canonicalInputBytes: inputs.bytes, readHashMs: readHashMs + inputs.readHashMs, durationMs: performance.now() - started,
|
|
47
|
-
...(includeFiles ? { fileEntries: files } : {}),
|
|
48
|
-
...(generatedFiles.length ? { unityGeneratedFiles: generatedFiles } : {}) };
|
|
49
|
-
}
|
|
50
|
-
function tierRoute(pipeline, risk) {
|
|
51
|
-
const tier = pipeline.contract.taskTiers?.[risk];
|
|
52
|
-
requireValue(tier, "Task risk must be FAST, STANDARD or CONTROLLED; existing tasks without a risk tier must be recreated and evidence recorded again");
|
|
53
|
-
const route = pipeline.profiles["astra-claude"].models[tier.implementationClass];
|
|
54
|
-
requireValue(route && Number.isSafeInteger(tier.maxReviewRounds) && tier.maxReviewRounds > 0, "Invalid task tier policy");
|
|
55
|
-
return { tier, route: { class: tier.implementationClass, model: route.model, effort: route.effort } };
|
|
56
|
-
}
|
|
57
|
-
function taskRouting(pipeline, task) {
|
|
58
|
-
const { tier, route } = tierRoute(pipeline, task.risk);
|
|
59
|
-
requireValue(task.implementationRoute && ["class", "model", "effort"].every(key => task.implementationRoute[key] === route[key]), "Task implementation route missing or changed; create a new task against the current policy");
|
|
60
|
-
const budget = task.reviewBudget;
|
|
61
|
-
requireValue(budget && Number.isSafeInteger(budget.used) && budget.used >= 0 && Number.isSafeInteger(budget.limit) && Array.isArray(budget.extensions), "Task review budget missing or invalid; create a new task and record evidence again");
|
|
62
|
-
let limit = tier.maxReviewRounds;
|
|
63
|
-
for (const extension of budget.extensions) {
|
|
64
|
-
requireValue(Number.isSafeInteger(extension.rounds) && extension.rounds > 0 && extension.rounds <= tier.maxReviewRounds && extension.reason?.trim() && Number.isFinite(Date.parse(extension.at)) && extension.previousLimit === limit && extension.newLimit === limit + extension.rounds, "Invalid review budget extension audit");
|
|
65
|
-
limit = extension.newLimit;
|
|
66
|
-
}
|
|
67
|
-
requireValue(budget.limit === limit && budget.used <= limit, "Review budget does not match its extension audit");
|
|
68
|
-
return { tier, route, budget: { used: budget.used, limit, remaining: limit - budget.used } };
|
|
69
|
-
}
|
|
70
|
-
function initializeUnlocked(project, id, plan, requirements = null, risk = "STANDARD") {
|
|
71
|
-
const file = taskPath(project, id);
|
|
72
|
-
requireValue(!fs.existsSync(file), `Task already exists: ${id}`);
|
|
73
|
-
const projectGates = artifact(project, ".nccgs/gates.json");
|
|
74
|
-
const projectPolicy = artifact(project, ".nccgs/project.yaml");
|
|
75
|
-
requireValue(json(verifyArtifact(project, projectGates)).policySha256 === projectPolicy.sha256, "Astra must map/review project gates against the current project.yaml hash");
|
|
76
|
-
const pipeline = loadPipeline(project);
|
|
77
|
-
const { tier, route } = tierRoute(pipeline, risk);
|
|
78
|
-
const task = { schemaVersion: 1, id, profile: "astra-claude", risk, implementationRoute: route,
|
|
79
|
-
reviewBudget: { used: 0, limit: tier.maxReviewRounds, extensions: [] },
|
|
80
|
-
createdAt: new Date().toISOString(), pipelineHash: hash(JSON.stringify(pipeline)), plan: artifact(project, plan), projectPolicy, projectGates, requirements: requirements ? artifact(project, requirements) : null, canonicalInputs: pinInputs(project), stages: {}, history: [] };
|
|
81
|
-
atomicJson(file, task);
|
|
82
|
-
return task;
|
|
83
|
-
}
|
|
84
|
-
function runtime(project, task, stage, expected, snap) {
|
|
85
|
-
const file = verifyArtifact(project, stage.runtime);
|
|
86
|
-
const trace = json(file);
|
|
87
|
-
requireValue(trace.schemaVersion === 1 && trace.origin === "runtime-observation", "Runtime evidence must be an observation, not configuration");
|
|
88
|
-
requireValue(trace.taskId === task.id && trace.snapshot === snap, "Runtime evidence belongs to another task/snapshot");
|
|
89
|
-
requireValue(trace.status === "completed" && trace.sessionId && trace.agentId, "Runtime observation is incomplete");
|
|
90
|
-
requireValue(Date.parse(trace.capturedAt) >= Date.parse(task.createdAt) && Date.parse(trace.capturedAt) <= Date.now(), "Runtime observation has invalid time");
|
|
91
|
-
requireValue(Date.parse(trace.capturedAt) >= Date.parse(task.canonicalInputs.pinnedAt), "Runtime observation predates current input pin; capture a fresh run");
|
|
92
|
-
const models = trace.modelsUsed?.length ? trace.modelsUsed : [trace.observedModel];
|
|
93
|
-
const matches = (model) => expected.model === "fable" ? /^claude-fable-\d[\w.-]*$/.test(model ?? "")
|
|
94
|
-
: expected.model === "sonnet" ? /^claude-sonnet-\d[\w.-]*$/.test(model ?? "") : model === expected.model;
|
|
95
|
-
requireValue(matches(trace.observedModel) && models.every(matches), "Observed model/fallback does not satisfy pipeline");
|
|
96
|
-
requireValue(trace.observedEffort === expected.effort, "Observed effort missing or mismatched; configuration is not proof");
|
|
97
|
-
requireValue(trace.observationSource, "Runtime observation requires a source artifact");
|
|
98
|
-
const source = json(verifyArtifact(project, trace.observationSource));
|
|
99
|
-
requireValue((source.observedModel ?? source.resolvedModel) === trace.observedModel && source.observedEffort === trace.observedEffort, "Observation differs from its raw model/effort source");
|
|
100
|
-
requireValue(source.taskId === task.id && source.snapshot === snap && source.sessionId === trace.sessionId && source.agentId === trace.agentId, "Observation source identity/snapshot mismatch");
|
|
101
|
-
requireValue(source.capturedAt === trace.capturedAt && source.status === trace.status, "Observation source time/status mismatch");
|
|
102
|
-
const sourceModels = source.modelsUsed?.length ? source.modelsUsed : [source.observedModel ?? source.resolvedModel];
|
|
103
|
-
requireValue(JSON.stringify(sourceModels) === JSON.stringify(models), "Observation dropped or changed source fallback history");
|
|
104
|
-
requireValue(stage.runtime.path.startsWith(".nccgs/evidence/runtime/observations/") && trace.observationSource.path.startsWith(".nccgs/evidence/runtime/sources/"), "Runtime evidence is not durable; run task migrate-evidence before closure");
|
|
105
|
-
return trace;
|
|
106
|
-
}
|
|
107
|
-
function reviewEvidence(project, task, stage, expected, snap, implementer, allowNegative = false) {
|
|
108
|
-
const trace = runtime(project, task, stage, expected, snap);
|
|
109
|
-
requireValue(`${trace.sessionId}/${trace.agentId}` !== implementer, "Review must be independent of implementation");
|
|
110
|
-
requireValue(Date.parse(trace.capturedAt) >= Date.parse(task.stages.implementation.recordedAt), "Review runtime predates implementation evidence");
|
|
111
|
-
requireValue(Array.isArray(stage.findings) && typeof stage.criteriaMet === "boolean", "Review requires findings and an acceptance criteria assessment");
|
|
112
|
-
requireValue(stage.verdict === "PASS" || (allowNegative && ["CHANGES_REQUIRED", "BLOCKED"].includes(stage.verdict)), "Fable review has not passed");
|
|
113
|
-
if (stage.verdict === "PASS") {
|
|
114
|
-
requireValue(!stage.findings.some(f => ["BLOCKER", "HIGH"].includes(f.severity) && f.status !== "RESOLVED"), "Review has open blocking findings");
|
|
115
|
-
requireValue(stage.criteriaMet === true, "Required acceptance criteria are not proven");
|
|
116
|
-
}
|
|
117
|
-
verifyArtifact(project, stage.evidence);
|
|
118
|
-
}
|
|
119
|
-
export function check(project, task, target = "done") {
|
|
120
|
-
if (task.schemaVersion === 2) return checkStandalone(project, task, target);
|
|
121
|
-
requireValue(task.schemaVersion === 1 && task.profile === "astra-claude", "Unsupported task record");
|
|
122
|
-
taskPath(project, task.id);
|
|
123
|
-
const pipeline = loadPipeline(project);
|
|
124
|
-
requireValue(task.pipelineHash === hash(JSON.stringify(pipeline)), "Pipeline policy changed; create a new task against the new policy");
|
|
125
|
-
const routing = taskRouting(pipeline, task);
|
|
126
|
-
requireValue(task.canonicalInputs?.schemaVersion === 1 && Number.isFinite(Date.parse(task.canonicalInputs.pinnedAt)), "Legacy task lacks canonical input pins; run task refresh-inputs --reason TEXT and record fresh evidence");
|
|
127
|
-
requireValue(task.canonicalInputs.sha256 === canonicalInputs(project).sha256, "Canonical inputs are stale; review the changes, run task refresh-inputs --reason TEXT, and record fresh evidence");
|
|
128
|
-
verifyArtifact(project, task.plan);
|
|
129
|
-
verifyArtifact(project, task.projectPolicy);
|
|
130
|
-
const obligations = [task.projectGates, task.requirements].filter(Boolean).map(ref => json(verifyArtifact(project, ref)));
|
|
131
|
-
requireValue(obligations.length > 0, "Project gate manifest is required");
|
|
132
|
-
for (const spec of obligations) requireValue(spec.schemaVersion === 1 && [spec.requiredChecks, spec.requiredArtifacts, spec.manualGates].every(Array.isArray), "Invalid gate manifest schema");
|
|
133
|
-
const snap = snapshot(project).sha256;
|
|
134
|
-
const end = target === "done" ? 5 : stages.indexOf(target);
|
|
135
|
-
requireValue(end >= 0, "Invalid gate target");
|
|
136
|
-
let previous = Date.parse(task.createdAt);
|
|
137
|
-
let implementer;
|
|
138
|
-
for (const name of stages.slice(0, end)) {
|
|
139
|
-
const stage = task.stages[name];
|
|
140
|
-
requireValue(stage && stage.snapshot === snap, `${name}: missing or stale for current snapshot`);
|
|
141
|
-
const at = Date.parse(stage.recordedAt);
|
|
142
|
-
requireValue(Number.isFinite(at) && at >= previous && at <= Date.now(), `${name}: invalid sequence timestamp`);
|
|
143
|
-
previous = at;
|
|
144
|
-
if (name === "implementation" || name === "review") {
|
|
145
|
-
if (name === "implementation") {
|
|
146
|
-
const trace = runtime(project, task, stage, routing.route, snap);
|
|
147
|
-
implementer = `${trace.sessionId}/${trace.agentId}`;
|
|
148
|
-
requireValue(Array.isArray(stage.checks) && stage.checks.length > 0, "Implementation requires verification evidence");
|
|
149
|
-
for (const test of stage.checks) {
|
|
150
|
-
requireValue(test.name && test.status === "PASS", "Verification contains missing/failed/unproven checks");
|
|
151
|
-
const evidenceFile = verifyArtifact(project, test.evidence);
|
|
152
|
-
if (test.evidence.path.endsWith(".json")) {
|
|
153
|
-
const evidence = json(evidenceFile);
|
|
154
|
-
if (evidence.origin === "verification-command") {
|
|
155
|
-
requireValue(evidence.taskId === task.id && evidence.name === test.name && evidence.snapshot === snap && evidence.status === "PASS" && evidence.exitCode === 0 && evidence.sourceUnchanged === true, "Recorded verification execution failed or is stale");
|
|
156
|
-
requireValue(Date.parse(evidence.startedAt) >= Date.parse(task.canonicalInputs.pinnedAt), "Verification execution predates current input pin; rerun the check");
|
|
157
|
-
verifyArtifact(project, evidence.log);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
for (const spec of obligations) for (const name of spec.requiredChecks) requireValue(stage.checks.some(c => c.name === name && c.status === "PASS"), `Required check missing: ${name}`);
|
|
162
|
-
} else {
|
|
163
|
-
reviewEvidence(project, task, stage, pipeline.profiles[task.profile].models.review, snap, implementer);
|
|
164
|
-
}
|
|
165
|
-
} else if (name === "report") {
|
|
166
|
-
verifyArtifact(project, stage.evidence);
|
|
167
|
-
for (const spec of obligations) for (const relative of spec.requiredArtifacts) {
|
|
168
|
-
const ref = stage.artifacts?.find(item => item.path === relative);
|
|
169
|
-
requireValue(ref, `Required closure artifact missing: ${relative}`);
|
|
170
|
-
verifyArtifact(project, ref);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
const approval = json(verifyArtifact(project, stage.evidence));
|
|
175
|
-
const actor = name === "astra" ? "Astra" : "Product Owner";
|
|
176
|
-
const decision = name === "astra" ? "PASS" : "ACCEPTED";
|
|
177
|
-
requireValue(approval.actor === actor && approval.decision === decision, `${name}: explicit ${actor} decision required`);
|
|
178
|
-
requireValue(approval.taskId === task.id && approval.snapshot === snap, `${name}: sign-off covers a different snapshot`);
|
|
179
|
-
requireValue(approval.statement?.trim() && approval.reference?.trim(), `${name}: decision statement and source reference required`);
|
|
180
|
-
requireValue(Date.parse(approval.decidedAt) >= Date.parse(task.stages[name === "astra" ? "report" : "astra"].recordedAt) && Date.parse(approval.decidedAt) <= at, `${name}: sign-off predates its prerequisite`);
|
|
181
|
-
if (name === "acceptance") for (const spec of obligations) for (const id of spec.manualGates) requireValue(approval.gates?.some(g => g.id === id && g.decision === "ACCEPTED" && g.reference?.trim()), `Manual gate missing: ${id}`);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
const exhausted = target === "review" && routing.budget.remaining === 0;
|
|
185
|
-
return { allowed: !exhausted, target, snapshot: snap, risk: task.risk, implementationRoute: routing.route, reviewBudget: routing.budget,
|
|
186
|
-
...(exhausted ? { message: `Review budget exhausted (${routing.budget.used}/${routing.budget.limit}); stop and escalate. An external operator may explicitly extend-review with a reason; exhausted budget never means PASS` } : {}),
|
|
187
|
-
phase: exhausted ? "REVIEW_BUDGET_EXHAUSTED" : target === "done" ? "DONE" : `READY_FOR_${target.toUpperCase()}` };
|
|
188
|
-
}
|
|
189
|
-
function recordUnlocked(project, id, name, input) {
|
|
190
|
-
const existing = json(taskPath(project, id));
|
|
191
|
-
if (existing.schemaVersion === 2) return recordStandalone(project, existing, name, input);
|
|
192
|
-
requireValue(stages.includes(name), "Unknown pipeline stage");
|
|
193
|
-
if (["astra", "acceptance"].includes(name) && (process.env.CLAUDECODE || process.env.CLAUDE_CODE_ENTRYPOINT)) throw new Error("External sign-offs must be imported outside the Claude session");
|
|
194
|
-
const file = taskPath(project, id);
|
|
195
|
-
const task = json(file);
|
|
196
|
-
const status = check(project, task, name);
|
|
197
|
-
requireValue(status.allowed, status.message);
|
|
198
|
-
requireValue(input.snapshot === status.snapshot, "Submitted evidence does not cover the current snapshot");
|
|
199
|
-
if (name === "review") {
|
|
200
|
-
const pipeline = loadPipeline(project);
|
|
201
|
-
const implementation = runtime(project, task, task.stages.implementation, status.implementationRoute, status.snapshot);
|
|
202
|
-
reviewEvidence(project, task, input, pipeline.profiles[task.profile].models.review, status.snapshot, `${implementation.sessionId}/${implementation.agentId}`, true);
|
|
203
|
-
task.reviewBudget.used += 1;
|
|
204
|
-
}
|
|
205
|
-
task.history.push({ recordedAt: new Date().toISOString(), replacedFrom: name, stages: structuredClone(task.stages) });
|
|
206
|
-
for (const downstream of stages.slice(stages.indexOf(name))) delete task.stages[downstream];
|
|
207
|
-
task.stages[name] = { ...input, recordedAt: new Date().toISOString() };
|
|
208
|
-
// Failed reviews can be retained as evidence but never unlock the next stage.
|
|
209
|
-
const externalDecision = ["astra", "acceptance"].includes(name) ? json(verifyArtifact(project, input.evidence)).decision : null;
|
|
210
|
-
const negative = (name === "review" && ["CHANGES_REQUIRED", "BLOCKED"].includes(input.verdict)) || ["CHANGES_REQUIRED", "REJECTED"].includes(externalDecision);
|
|
211
|
-
if (!negative) {
|
|
212
|
-
const next = stages[stages.indexOf(name) + 1] ?? "done";
|
|
213
|
-
check(project, task, next);
|
|
214
|
-
}
|
|
215
|
-
delete task.closed;
|
|
216
|
-
atomicJson(file, task);
|
|
217
|
-
return task;
|
|
218
|
-
}
|
|
219
|
-
function extendReviewUnlocked(project, id, reason, rounds) {
|
|
220
|
-
const existing = json(taskPath(project, id));
|
|
221
|
-
if (existing.schemaVersion === 2) return extendStandalone(project, existing, reason, rounds);
|
|
222
|
-
requireValue(!(process.env.CLAUDECODE || process.env.CLAUDE_CODE_ENTRYPOINT), "Review budget extensions must be requested outside the Claude session");
|
|
223
|
-
requireValue(typeof reason === "string" && reason.trim(), "Review budget extension requires a reason");
|
|
224
|
-
const file = taskPath(project, id);
|
|
225
|
-
const task = json(file);
|
|
226
|
-
check(project, task, "implementation");
|
|
227
|
-
const { tier } = taskRouting(loadPipeline(project), task);
|
|
228
|
-
requireValue(Number.isSafeInteger(rounds) && rounds > 0 && rounds <= tier.maxReviewRounds, `Review budget extension requires an integer from 1 to ${tier.maxReviewRounds}`);
|
|
229
|
-
requireValue(Number.isSafeInteger(task.reviewBudget.limit + rounds), "Review budget limit is too large");
|
|
230
|
-
const extension = { at: new Date().toISOString(), reason: reason.trim(), rounds, previousLimit: task.reviewBudget.limit, newLimit: task.reviewBudget.limit + rounds };
|
|
231
|
-
task.reviewBudget.limit = extension.newLimit;
|
|
232
|
-
task.reviewBudget.extensions.push(extension);
|
|
233
|
-
task.history.push({ recordedAt: extension.at, action: "extend-review", ...extension });
|
|
234
|
-
atomicJson(file, task);
|
|
235
|
-
return task;
|
|
236
|
-
}
|
|
237
|
-
function closeUnlocked(project, id) {
|
|
238
|
-
const file = taskPath(project, id);
|
|
239
|
-
const task = json(file);
|
|
240
|
-
const status = check(project, task, "done");
|
|
241
|
-
task.closed = { snapshot: status.snapshot, at: new Date().toISOString() };
|
|
242
|
-
atomicJson(file, task);
|
|
243
|
-
return status;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function refreshInputsUnlocked(project, id, reason) {
|
|
247
|
-
const existing = json(taskPath(project, id));
|
|
248
|
-
if (existing.schemaVersion === 2) return refreshStandalone(project, existing, reason);
|
|
249
|
-
requireValue(typeof reason === "string" && reason.trim(), "Input refresh requires a reason");
|
|
250
|
-
const file = taskPath(project, id);
|
|
251
|
-
const task = json(file);
|
|
252
|
-
requireValue(task.schemaVersion === 1 && task.profile === "astra-claude", "Unsupported task record");
|
|
253
|
-
const pipeline = loadPipeline(project);
|
|
254
|
-
requireValue(task.pipelineHash === hash(JSON.stringify(pipeline)), "Input refresh cannot migrate a changed pipeline");
|
|
255
|
-
taskRouting(pipeline, task);
|
|
256
|
-
const projectPolicy = artifact(project, ".nccgs/project.yaml");
|
|
257
|
-
const projectGates = artifact(project, ".nccgs/gates.json");
|
|
258
|
-
requireValue(json(verifyArtifact(project, projectGates)).policySha256 === projectPolicy.sha256, "Project gates must be remapped to the current project.yaml hash before input refresh");
|
|
259
|
-
const plan = artifact(project, task.plan.path);
|
|
260
|
-
const requirements = task.requirements ? artifact(project, task.requirements.path) : null;
|
|
261
|
-
const pins = pinInputs(project);
|
|
262
|
-
task.history.push({ action: "refresh-inputs", recordedAt: pins.pinnedAt, reason: reason.trim(),
|
|
263
|
-
canonicalInputs: task.canonicalInputs ?? null, plan: task.plan, projectPolicy: task.projectPolicy,
|
|
264
|
-
projectGates: task.projectGates, requirements: task.requirements, stages: structuredClone(task.stages), closed: task.closed ?? null });
|
|
265
|
-
Object.assign(task, { canonicalInputs: pins, plan, projectPolicy, projectGates, requirements, stages: {} });
|
|
266
|
-
delete task.closed;
|
|
267
|
-
// Validate new mappings before committing; a failed refresh leaves the task intact.
|
|
268
|
-
check(project, task, "implementation");
|
|
269
|
-
atomicJson(file, task);
|
|
270
|
-
return task;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
function mutate(project, id, action) {
|
|
274
|
-
const lock = acquireLock(`${taskPath(project, id)}.lock`, { taskId: id });
|
|
275
|
-
try { return action(); } finally { lock.release(); }
|
|
276
|
-
}
|
|
277
|
-
export const withTask = mutate;
|
|
278
|
-
export const initialize = (project, id, plan, requirements = null, risk = null, options = {}) => mutate(project, id, () =>
|
|
279
|
-
resolveExecution(project).name === "standalone"
|
|
280
|
-
? initializeStandalone(project, id, { ...options, plan, requirements, ...(risk ? { risk } : {}) })
|
|
281
|
-
: initializeUnlocked(project, id, plan, requirements, risk || "STANDARD"));
|
|
282
|
-
export const record = (project, id, stage, evidence) => mutate(project, id, () => recordUnlocked(project, id, stage, evidence));
|
|
283
|
-
export const extendReview = (project, id, reason, rounds) => mutate(project, id, () => extendReviewUnlocked(project, id, reason, rounds));
|
|
284
|
-
export const close = (project, id) => mutate(project, id, () => closeUnlocked(project, id));
|
|
285
|
-
export const refreshInputs = (project, id, reason) => mutate(project, id, () => refreshInputsUnlocked(project, id, reason));
|
|
286
|
-
export const reclassify = (project, id, changes) => mutate(project, id, () => reclassifyStandalone(project, json(taskPath(project, id)), changes));
|
|
287
|
-
export const exportExternal = (project, id, relative) => mutate(project, id, () => exportExternalStandalone(project, json(taskPath(project, id)), relative));
|
|
288
|
-
export const importExternal = (project, id, relative) => mutate(project, id, () => importExternalStandalone(project, json(taskPath(project, id)), relative));
|
|
289
|
-
export const migrateEvidence = (project, id) => mutate(project, id, () => {
|
|
290
|
-
const file = taskPath(project, id);
|
|
291
|
-
const result = migrateTaskEvidence(project, json(file));
|
|
292
|
-
if (result.changed) {
|
|
293
|
-
result.task.history.push({ action: "migrate-evidence", recordedAt: new Date().toISOString(), migrations: result.migrations });
|
|
294
|
-
atomicJson(file, result.task);
|
|
295
|
-
}
|
|
296
|
-
return { id, changed: result.changed, migrations: result.migrations };
|
|
297
|
-
});
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import { artifact, json, verifyArtifact } from "./policy.mjs";
|
|
3
|
-
import { check, record, taskPath } from "./gates.mjs";
|
|
4
|
-
import { getDispatch } from "./orchestration.mjs";
|
|
5
|
-
import { readReviewHandoff, validateReviewStructure } from "./review-handoff.mjs";
|
|
6
|
-
|
|
7
|
-
const need = (ok, message) => { if (!ok) throw new Error(`Handoff: ${message}`); };
|
|
8
|
-
|
|
9
|
-
function context(project, id, dispatchId, relative) {
|
|
10
|
-
const task = json(taskPath(project, id)), dispatch = getDispatch(project, id, dispatchId);
|
|
11
|
-
need(dispatch.contractHash === task.contractHash, "dispatch contract is stale");
|
|
12
|
-
need(dispatch.handoffPaths?.includes(relative), "file must be this dispatch's declared handoff");
|
|
13
|
-
need(["running", "completed"].includes(dispatch.status), "handoff inspection requires a running or completed dispatch");
|
|
14
|
-
const state = check(project, task, task.mode === "implement" ? "implementation" : "analysis");
|
|
15
|
-
need(state.allowed, state.message);
|
|
16
|
-
const expected = dispatch.status === "completed" ? dispatch.completedSnapshot : dispatch.kind === "implementation" ? state.snapshot : dispatch.snapshot;
|
|
17
|
-
need(state.snapshot === expected, "source snapshot is stale");
|
|
18
|
-
// A completed handoff is always read through its captured reference. A new hash
|
|
19
|
-
// cannot legitimize edits made after completion.
|
|
20
|
-
const evidence = dispatch.status === "completed"
|
|
21
|
-
? dispatch.handoff?.artifacts?.find(ref => ref.path === relative) : artifact(project, relative);
|
|
22
|
-
need(evidence, "completed dispatch did not pin this handoff");
|
|
23
|
-
const content = fs.readFileSync(verifyArtifact(project, evidence), "utf8");
|
|
24
|
-
return { task, dispatch, snapshot: state.snapshot, evidence, content };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function validateHandoff(project, id, dispatchId, relative) {
|
|
28
|
-
const ctx = context(project, id, dispatchId, relative);
|
|
29
|
-
const markers = [...ctx.content.matchAll(/^NCCGS-HANDOFF: (PARTIAL|COMPLETE)\r?$/gm)];
|
|
30
|
-
need(markers.length === 1, "exactly one PARTIAL or COMPLETE marker is required");
|
|
31
|
-
const complete = markers[0][1] === "COMPLETE";
|
|
32
|
-
if (ctx.dispatch.kind === "review") {
|
|
33
|
-
const { value } = readReviewHandoff(ctx.content, ctx.task, ctx.snapshot, false);
|
|
34
|
-
validateReviewStructure(value, ctx.task);
|
|
35
|
-
}
|
|
36
|
-
verifyArtifact(project, ctx.evidence);
|
|
37
|
-
return { status: "VALID", taskId: id, dispatchId, evidence: ctx.evidence, complete,
|
|
38
|
-
scope: "Structure only; not native completion, semantic review, verification or acceptance. No task, budget or handoff was changed." };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function recordReviewHandoff(project, id, dispatchId, relative) {
|
|
42
|
-
const ctx = context(project, id, dispatchId, relative);
|
|
43
|
-
need(ctx.dispatch.kind === "review" && ctx.dispatch.status === "completed", "a completed independent review dispatch is required");
|
|
44
|
-
need(ctx.task.execution.reviewContractRequired === true, "automatic import requires the reviewer-owned contract policy; legacy records retain their workflow");
|
|
45
|
-
const { value } = readReviewHandoff(ctx.content, ctx.task, ctx.snapshot);
|
|
46
|
-
// No caller-supplied verdict, findings, conditions, runtime or snapshot. The
|
|
47
|
-
// existing record path checks independence, telemetry, criteria and budgets,
|
|
48
|
-
// appends history, and rejects reusing a dispatch. It never closes the task.
|
|
49
|
-
return record(project, id, "review", { snapshot: ctx.snapshot, dispatchId, runtime: ctx.dispatch.runtime, evidence: ctx.evidence,
|
|
50
|
-
verdict: value.verdict, criteriaMet: value.criteriaMet, findings: value.findings, conditions: value.conditions });
|
|
51
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// Exact managed-hook identity across legacy shell and direct-executable forms.
|
|
2
|
-
// Never identify a hook by the executable alone: many custom hooks use node.
|
|
3
|
-
const scriptPattern = /^(?:\$\{CLAUDE_PROJECT_DIR\}\/)?(\.claude\/nccgs\/hooks\/[\w-]+\.mjs)$/;
|
|
4
|
-
const phases = new Set(['pre', 'stop', 'start', 'failure']);
|
|
5
|
-
|
|
6
|
-
export function managedHookKey(hook) {
|
|
7
|
-
if (!hook || hook.type !== 'command' || typeof hook.command !== 'string') return null;
|
|
8
|
-
let script, args;
|
|
9
|
-
if (Object.hasOwn(hook, 'args')) {
|
|
10
|
-
if (hook.command !== 'node' || !Array.isArray(hook.args) || !hook.args.every(x => typeof x === 'string')) return null;
|
|
11
|
-
[script, ...args] = hook.args;
|
|
12
|
-
} else {
|
|
13
|
-
const match = hook.command.match(/^node (?:"([^"\r\n]+)"|([^\s"'`$;&|<>]+))(?: (pre|stop|start|failure))?$/);
|
|
14
|
-
if (!match) return null;
|
|
15
|
-
script = match[1] ?? match[2];
|
|
16
|
-
args = match[3] ? [match[3]] : [];
|
|
17
|
-
}
|
|
18
|
-
const relative = typeof script === 'string' ? script.match(scriptPattern)?.[1] : null;
|
|
19
|
-
if (!relative || args.length > 1 || args.some(x => !phases.has(x))) return null;
|
|
20
|
-
return JSON.stringify([relative, ...args]);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function requiredHookPresent(actual, expected) {
|
|
24
|
-
return actual && actual.type === expected.type && actual.command === expected.command
|
|
25
|
-
&& JSON.stringify(actual.args) === JSON.stringify(expected.args)
|
|
26
|
-
&& actual.onFailure === expected.onFailure
|
|
27
|
-
&& actual.if === undefined && actual.once !== true && actual.async !== true
|
|
28
|
-
&& (actual.timeout === undefined || actual.timeout >= expected.timeout);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function referencesNccgsHook(hook) {
|
|
32
|
-
return [hook?.command, ...(Array.isArray(hook?.args) ? hook.args : [])]
|
|
33
|
-
.some(x => typeof x === 'string' && /(?:^|[\\/])\.claude[\\/]nccgs[\\/]/i.test(x));
|
|
34
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import { performance } from "node:perf_hooks";
|
|
3
|
-
import { contained, json, hash } from "./policy.mjs";
|
|
4
|
-
|
|
5
|
-
export const inputManifest = ".nccgs/inputs.json";
|
|
6
|
-
export function inputPolicy(project) {
|
|
7
|
-
const file = contained(project, inputManifest);
|
|
8
|
-
const policy = fs.existsSync(file) ? json(file) : { schemaVersion: 1, canonicalInputs: [], outputDirectories: [], checks: {} };
|
|
9
|
-
if (policy.schemaVersion !== 1 || !Array.isArray(policy.canonicalInputs) || !Array.isArray(policy.outputDirectories)
|
|
10
|
-
|| !policy.checks || typeof policy.checks !== "object" || Array.isArray(policy.checks)) throw new Error("Invalid .nccgs/inputs.json schema");
|
|
11
|
-
for (const key of Object.keys(policy)) if (!["schemaVersion", "canonicalInputs", "outputDirectories", "checks", "unityGeneratedFiles"].includes(key)) throw new Error(`Unknown input manifest field: ${key}`);
|
|
12
|
-
const generated = policy.unityGeneratedFiles === undefined ? [] : policy.unityGeneratedFiles;
|
|
13
|
-
if (!Array.isArray(generated) || generated.length > 256) throw new Error("unityGeneratedFiles must be an array of at most 256 exact file paths");
|
|
14
|
-
const seenGenerated = new Set();
|
|
15
|
-
for (const relative of generated) {
|
|
16
|
-
const file = contained(project, relative);
|
|
17
|
-
// Opt-in derived metadata only. Never ignore whole directories, wildcards,
|
|
18
|
-
// nested tool projects, source, assets, packages or project settings.
|
|
19
|
-
if (!/^[^/]+\.(?:csproj|sln|slnx)$/.test(relative)
|
|
20
|
-
&& !/^\.vscode\/(?:extensions|launch|settings)\.json$/.test(relative)
|
|
21
|
-
&& !/^UserSettings\/(?:EditorUserSettings\.asset|Search\.settings)$/.test(relative)) {
|
|
22
|
-
throw new Error(`Unsupported Unity generated file: ${relative}`);
|
|
23
|
-
}
|
|
24
|
-
const key = relative.toLowerCase();
|
|
25
|
-
if (seenGenerated.has(key)) throw new Error(`Duplicate Unity generated file: ${relative}`);
|
|
26
|
-
seenGenerated.add(key);
|
|
27
|
-
if (fs.existsSync(file) && !fs.statSync(file).isFile()) throw new Error(`Unity generated path is not a file: ${relative}`);
|
|
28
|
-
for (const input of policy.canonicalInputs) if (overlaps(input, relative)) throw new Error(`Canonical input/generated file overlap: ${input} and ${relative}`);
|
|
29
|
-
}
|
|
30
|
-
if (generated.length) {
|
|
31
|
-
const version = contained(project, "ProjectSettings/ProjectVersion.txt");
|
|
32
|
-
if (!fs.existsSync(version) || !/^m_EditorVersion: \d+\.\d+\.\d+[abfp]\d+\s*$/m.test(fs.readFileSync(version, "utf8"))
|
|
33
|
-
|| !fs.existsSync(contained(project, "Packages/manifest.json")) || !fs.statSync(contained(project, "Assets")).isDirectory()) {
|
|
34
|
-
throw new Error("unityGeneratedFiles requires a Unity project (Assets, Packages/manifest.json, ProjectSettings/ProjectVersion.txt)");
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
for (const relative of [...policy.canonicalInputs, ...policy.outputDirectories]) contained(project, relative);
|
|
38
|
-
for (const relative of policy.outputDirectories) {
|
|
39
|
-
// Keep source roots in the snapshot. Unity build destinations must be deliberately
|
|
40
|
-
// placed below these dedicated roots; arbitrary ignore globs are not supported.
|
|
41
|
-
if (!/^(Build|Builds)\/[A-Za-z0-9_-][A-Za-z0-9_./ -]*$/.test(relative)) throw new Error("Output directories must be explicit subdirectories of Build/ or Builds/");
|
|
42
|
-
const file = contained(project, relative);
|
|
43
|
-
if (fs.existsSync(file) && !fs.statSync(file).isDirectory()) throw new Error(`Output path is not a directory: ${relative}`);
|
|
44
|
-
for (const input of policy.canonicalInputs) if (overlaps(input, relative)) throw new Error(`Canonical input/output overlap: ${input} and ${relative}`);
|
|
45
|
-
}
|
|
46
|
-
for (const relative of policy.canonicalInputs) {
|
|
47
|
-
if (relative.toLowerCase() === ".nccgs" || /^\.nccgs\/(evidence|runtime|tasks|backups|closures)(\/|$)/i.test(relative)) throw new Error(`Generated state cannot be a canonical input: ${relative}`);
|
|
48
|
-
}
|
|
49
|
-
for (const [name, config] of Object.entries(policy.checks)) {
|
|
50
|
-
if (!name.trim() || !config || typeof config !== "object" || Array.isArray(config)
|
|
51
|
-
|| Object.keys(config).some(key => key !== "timeoutMs") || !Number.isSafeInteger(config.timeoutMs)
|
|
52
|
-
|| config.timeoutMs < 100 || config.timeoutMs > 7200000) throw new Error(`Check ${name}: timeoutMs must be an integer from 100 to 7200000`);
|
|
53
|
-
}
|
|
54
|
-
return policy;
|
|
55
|
-
}
|
|
56
|
-
function overlaps(a, b) {
|
|
57
|
-
a = a.toLowerCase(); b = b.toLowerCase();
|
|
58
|
-
return a === b || a.startsWith(`${b}/`) || b.startsWith(`${a}/`);
|
|
59
|
-
}
|
|
60
|
-
export function isOutput(relative, policy) {
|
|
61
|
-
const normalize = name => process.platform === "win32" ? name.toLowerCase() : name;
|
|
62
|
-
return policy.outputDirectories.some(dir => normalize(relative) === normalize(dir) || normalize(relative).startsWith(`${normalize(dir)}/`));
|
|
63
|
-
}
|
|
64
|
-
export function isUnityGenerated(relative, policy) {
|
|
65
|
-
const normalize = name => process.platform === "win32" ? name.toLowerCase() : name;
|
|
66
|
-
return (policy.unityGeneratedFiles ?? []).some(file => normalize(relative) === normalize(file));
|
|
67
|
-
}
|
|
68
|
-
export function unityGeneratedState(project, policy) {
|
|
69
|
-
return (policy.unityGeneratedFiles ?? []).map(relative => {
|
|
70
|
-
const file = contained(project, relative);
|
|
71
|
-
return { path: relative, sha256: fs.existsSync(file) ? hash(fs.readFileSync(file)) : null };
|
|
72
|
-
}).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
73
|
-
}
|
|
74
|
-
export function canonicalInputs(project, policy = inputPolicy(project)) {
|
|
75
|
-
const entries = new Map();
|
|
76
|
-
let bytes = 0, readHashMs = 0;
|
|
77
|
-
function capture(relative, optional = false) {
|
|
78
|
-
if (entries.has(relative)) return;
|
|
79
|
-
const file = contained(project, relative);
|
|
80
|
-
if (!fs.existsSync(file)) {
|
|
81
|
-
if (!optional) throw new Error(`Canonical input missing: ${relative}`);
|
|
82
|
-
entries.set(relative, { path: relative, kind: "missing" });
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
const stat = fs.statSync(file);
|
|
86
|
-
if (stat.isDirectory()) {
|
|
87
|
-
entries.set(relative, { path: relative, kind: "directory" });
|
|
88
|
-
for (const name of fs.readdirSync(file).sort()) capture(`${relative}/${name}`);
|
|
89
|
-
} else if (stat.isFile()) {
|
|
90
|
-
const start = performance.now();
|
|
91
|
-
const data = fs.readFileSync(file);
|
|
92
|
-
entries.set(relative, { path: relative, sha256: hash(data), kind: "file" });
|
|
93
|
-
readHashMs += performance.now() - start;
|
|
94
|
-
bytes += data.length;
|
|
95
|
-
} else throw new Error(`Unsupported canonical input: ${relative}`);
|
|
96
|
-
}
|
|
97
|
-
capture(inputManifest, true);
|
|
98
|
-
capture(".nccgs/requirements.yaml", true);
|
|
99
|
-
capture(".nccgs/autonomy.json", true);
|
|
100
|
-
capture(".nccgs/decisions", true);
|
|
101
|
-
for (const relative of policy.canonicalInputs) capture(relative);
|
|
102
|
-
const files = [...entries.values()].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
103
|
-
return { schemaVersion: 1, sha256: hash(JSON.stringify(files)), entries: files, bytes, readHashMs };
|
|
104
|
-
}
|
|
105
|
-
export function pinInputs(project) {
|
|
106
|
-
const { schemaVersion, sha256, entries } = canonicalInputs(project);
|
|
107
|
-
return { schemaVersion, sha256, entries, pinnedAt: new Date().toISOString() };
|
|
108
|
-
}
|