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,120 +0,0 @@
|
|
|
1
|
-
import { commandTokens } from "./command-tokens.mjs";
|
|
2
|
-
import { safeSharedContextCommand } from "./shared-context-guard.mjs";
|
|
3
|
-
import { assertUnityCliOnlyInput } from "./unity-transport.mjs";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { contained, json, resolveExecution } from "./policy.mjs";
|
|
6
|
-
import { taskPath, check } from "./gates.mjs";
|
|
7
|
-
import { boundTask } from "./runtime.mjs";
|
|
8
|
-
import { claim, findDispatch, rejectUnclaimed, admitRepairTool, dispatchPrompt, pinnedRepairEvidence } from "./orchestration.mjs";
|
|
9
|
-
import { requireDesignReady } from "./design-readiness.mjs";
|
|
10
|
-
import { inFinalReviewPhase } from "./review-budget.mjs";
|
|
11
|
-
|
|
12
|
-
const need = (condition, message) => { if (!condition) throw new Error(message); };
|
|
13
|
-
const reads = new Set(["Read", "Glob", "Grep", "WebSearch", "WebFetch", "AskUserQuestion"]);
|
|
14
|
-
const governance = new Set(["init", "bind", "inspect", "check", "snapshot", "ref", "record", "report", "reclassify", "refresh-inputs", "reserve", "dispatch-status", "dispatch-prompt", "checkpoint", "resume", "telemetry", "export-external", "close", "job-status", "job-wait", "acceptance-status", "design-validate", "design-compare", "handoff-validate", "record-review", "slice-preview", "slice-plan", "slice-status", "budget-status"]);
|
|
15
|
-
export function parseTaskCommand(command, project = process.cwd()) {
|
|
16
|
-
const tokens = commandTokens(command);
|
|
17
|
-
if (!tokens) return null;
|
|
18
|
-
const script = tokens[1]?.replaceAll("\\", "/");
|
|
19
|
-
if (tokens[0] !== "node" || !script || path.resolve(project, script) !== path.resolve(project, ".claude/nccgs/tools/task.mjs")) return null;
|
|
20
|
-
const separator = tokens.indexOf("--");
|
|
21
|
-
const options = separator < 0 ? tokens : tokens.slice(0, separator);
|
|
22
|
-
const projectOptions = options.flatMap((t, i) => t === "--project" ? [i] : []);
|
|
23
|
-
if (projectOptions.length > 1 || options.some(t => t.startsWith("--project="))) return null;
|
|
24
|
-
if (projectOptions.length && (!options[projectOptions[0] + 1] || path.resolve(project, options[projectOptions[0] + 1]) !== path.resolve(project))) return null;
|
|
25
|
-
return { command: tokens[2], options, forwarded: separator < 0 ? null : tokens.slice(separator + 1) };
|
|
26
|
-
}
|
|
27
|
-
export function safeTaskCommand(command, project = process.cwd()) {
|
|
28
|
-
const parsed = parseTaskCommand(command, project);
|
|
29
|
-
return parsed && governance.has(parsed.command) && !parsed.forwarded ? parsed.command : null;
|
|
30
|
-
}
|
|
31
|
-
export function safeVerifyCommand(command, project = process.cwd()) {
|
|
32
|
-
const parsed = parseTaskCommand(command, project);
|
|
33
|
-
return Boolean(parsed?.command === "verify" && parsed.forwarded?.length && parsed.options.includes("--id") && parsed.options.includes("--name"));
|
|
34
|
-
}
|
|
35
|
-
export function recoveryTool(input, project = process.cwd()) {
|
|
36
|
-
return !input.agent_id && ["Bash", "PowerShell"].includes(input.tool_name) && ["report", "inspect"].includes(safeTaskCommand(input.tool_input?.command ?? "", project));
|
|
37
|
-
}
|
|
38
|
-
function ownHandoffValidation(command, project, task, dispatch) {
|
|
39
|
-
const parsed = parseTaskCommand(command, project);
|
|
40
|
-
if (!parsed || parsed.command !== "handoff-validate" || parsed.forwarded || dispatch?.status !== "running") return false;
|
|
41
|
-
const values = new Map(), args = parsed.options.slice(3);
|
|
42
|
-
for (let i = 0; i < args.length; i += 2) {
|
|
43
|
-
if (!["--id", "--dispatch", "--file", "--project"].includes(args[i]) || values.has(args[i]) || !args[i + 1] || args[i + 1].startsWith("--")) return false;
|
|
44
|
-
values.set(args[i], args[i + 1]);
|
|
45
|
-
}
|
|
46
|
-
return values.get("--id") === task?.id && values.get("--dispatch") === dispatch.id && dispatch.handoffPaths?.includes(values.get("--file"));
|
|
47
|
-
}
|
|
48
|
-
export function guardTool(project, input) {
|
|
49
|
-
assertUnityCliOnlyInput(input);
|
|
50
|
-
if (recoveryTool(input, project)) return;
|
|
51
|
-
if (resolveExecution(project).name !== "standalone") return;
|
|
52
|
-
const tool = input.tool_input ?? {}, name = input.tool_name;
|
|
53
|
-
let dispatch = findDispatch(project, input);
|
|
54
|
-
const id = dispatch?.taskId ?? boundTask(project, input.session_id);
|
|
55
|
-
const task = id ? json(taskPath(project, id)) : null;
|
|
56
|
-
if (task && task.schemaVersion !== 2) throw new Error("Legacy tasks keep compatibility gates; create a fresh standalone task after migration");
|
|
57
|
-
if (input.agent_id) need(dispatch, "Worker tool has no correlated dispatch; cannot bypass its scope or budget");
|
|
58
|
-
if (input.agent_id && dispatch?.workPacket) { requireDesignReady(project, task); return admitRepairTool(project, dispatch.id, input); }
|
|
59
|
-
if (reads.has(name)) return;
|
|
60
|
-
if (["Agent", "Task"].includes(name)) {
|
|
61
|
-
need(!input.agent_id, "NCCGS workers cannot recursively delegate");
|
|
62
|
-
need(dispatch && /^\[NCCGS-DISPATCH:[\w-]+\]/.test(tool.prompt ?? ""), "Reserve this Agent call first and prefix its prompt with [NCCGS-DISPATCH:ID]");
|
|
63
|
-
need(task && dispatch.taskId === task.id, "Dispatch task missing");
|
|
64
|
-
try {
|
|
65
|
-
need(tool.run_in_background !== true, "Managed workers must use foreground Agent calls; use task verify --background for durable engine jobs");
|
|
66
|
-
if (dispatch.kind === "review") {
|
|
67
|
-
const readiness = check(project, task, "review");
|
|
68
|
-
need(readiness.allowed, readiness.message);
|
|
69
|
-
}
|
|
70
|
-
const prompt = dispatch.workPacket || dispatch.slice ? dispatchPrompt(project, task.id, dispatch.id).prompt : null;
|
|
71
|
-
claim(project, dispatch.id, { sessionId: input.session_id, toolUseId: input.tool_use_id, agent: tool.subagent_type });
|
|
72
|
-
if (prompt) return { updatedInput: { ...tool, prompt } };
|
|
73
|
-
} catch (error) {
|
|
74
|
-
if (input.hook_event_name === "PreToolUse" && dispatch.status === "reserved" && tool.subagent_type === dispatch.agent) {
|
|
75
|
-
try { rejectUnclaimed(project, dispatch.id, { sessionId: input.session_id, toolUseId: input.tool_use_id, agent: tool.subagent_type, reason: error.message }); }
|
|
76
|
-
catch { /* A concurrent claim or uncertain state must stay fail-closed. */ }
|
|
77
|
-
}
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
const readOnly = task?.mode !== "implement" || (dispatch && dispatch.kind !== "implementation");
|
|
83
|
-
if (["Write", "Edit", "MultiEdit", "NotebookEdit"].includes(name)) {
|
|
84
|
-
const absolute = path.resolve(project, tool.file_path || tool.path || tool.notebook_path || ".");
|
|
85
|
-
const relative = path.relative(project, absolute).split(path.sep).join("/");
|
|
86
|
-
contained(project, relative);
|
|
87
|
-
need(!/^\.(?:claude|nccgs)(?:\/|$)/i.test(relative) || relative.startsWith(".nccgs/evidence/"), "Framework/governance records must be changed through the task CLI or external configuration");
|
|
88
|
-
if (relative.startsWith(".nccgs/evidence/")) {
|
|
89
|
-
need(!(dispatch?.handoffTransport === "native-result" && dispatch.handoffPaths?.includes(relative)), "Native-result handoff is captured only from the correlated final response; return text without writing this path");
|
|
90
|
-
need(!pinnedRepairEvidence(project, relative), "Reserved repair packet/context evidence is immutable; preserve it and create a fresh packet for a new eligible attempt");
|
|
91
|
-
need(!/^\.nccgs\/evidence\/(?:(?:runtime|criteria|design-checks|checkpoints|repair-operations|slices|external\/requests)\/|check-)/i.test(relative), "Captured runtime/checkpoint/verification/external request evidence is immutable and never authored by Claude");
|
|
92
|
-
if (input.agent_id && readOnly) need(task?.contract.analysisArtifacts?.includes(relative), "Read-only worker may write only declared analysis artifacts");
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
need(task && !readOnly, "Audit/plan tasks cannot edit source; declare analysis artifacts under .nccgs/evidence/analysis/");
|
|
96
|
-
requireDesignReady(project, task);
|
|
97
|
-
need(dispatch && dispatch.status === "running" && dispatch.agentId === input.agent_id, "Source writes require a running, correlated implementation dispatch");
|
|
98
|
-
const lower = relative.toLowerCase();
|
|
99
|
-
if (dispatch.slice) need(dispatch.writePaths.some(p => lower === p.toLowerCase()), "Slice writes require an exact planned file; directory ownership is not granted");
|
|
100
|
-
need(dispatch.writePaths.some(p => lower === p.toLowerCase() || lower.startsWith(p.toLowerCase() + "/")), "Write is outside this dispatch's owned paths");
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (["Bash", "PowerShell"].includes(name)) {
|
|
104
|
-
const command = tool.command ?? "";
|
|
105
|
-
if (input.agent_id && ownHandoffValidation(command, project, task, dispatch)) return;
|
|
106
|
-
need(!/\b(?:dispatch-reconcile|extend-dispatch|extend-review|import-external|migrate-execution|migrate-framework|budget-plan)\b|--stage\s+["']?(?:acceptance|astra)\b/i.test(command), "External decisions cannot be made by the Claude executor");
|
|
107
|
-
if (safeTaskCommand(command, project)) { need(!input.agent_id, "Coordinator owns lifecycle commands"); return; }
|
|
108
|
-
if (!input.agent_id && safeSharedContextCommand(command, project)) return;
|
|
109
|
-
need(task && !readOnly, "Audit/plan/review shell execution is blocked; use read tools or externally supplied verification evidence");
|
|
110
|
-
requireDesignReady(project, task);
|
|
111
|
-
// Coordinator may run declared checks after workers finish. This command
|
|
112
|
-
// can execute a verifier, so it is allowed only for implementation tasks.
|
|
113
|
-
if (!input.agent_id && safeVerifyCommand(command, project)) { need(!inFinalReviewPhase(project, input.session_id), "Final-review reserve cannot run new verification jobs; use existing receipts"); return; }
|
|
114
|
-
need(dispatch?.kind === "implementation" && dispatch.status === "running" && input.agent_id === dispatch.agentId, "Shell mutation requires a correlated implementation worker");
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (task) requireDesignReady(project, task);
|
|
118
|
-
need(task && !readOnly && dispatch?.kind === "implementation" && dispatch.status === "running" && input.agent_id === dispatch.agentId,
|
|
119
|
-
"Tool is not in the read-only allowlist; a correlated implementation dispatch is required");
|
|
120
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import crypto from "node:crypto";
|
|
4
|
-
import { artifact, atomicJson, contained, json, verifyArtifact } from "./policy.mjs";
|
|
5
|
-
import { snapshot } from "./gates.mjs";
|
|
6
|
-
|
|
7
|
-
const need = (ok, message) => { if (!ok) throw new Error(`Unity repair: ${message}`); };
|
|
8
|
-
const keys = (value, allowed) => value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).every(k => allowed.includes(k));
|
|
9
|
-
const code = /\.(?:cs|asmdef|asmref|shader|hlsl|cginc|compute|uxml|uss)$/i;
|
|
10
|
-
const asset = /\.(?:unity|prefab|asset|mat|controller|overrideController|anim)$/i;
|
|
11
|
-
export const unityCodePath = relative => relative.startsWith("Assets/") && code.test(relative);
|
|
12
|
-
export const unitySceneSafety = "loaded-scenes-clean-v1";
|
|
13
|
-
export const unityRepairProfiles = Object.freeze({
|
|
14
|
-
"unity-code": Object.freeze({ files: 8, workCalls: 24, readCalls: 12, handoffCalls: 3, durationMs: 900000 }),
|
|
15
|
-
"unity-editor": Object.freeze({ files: 8, workCalls: 20, readCalls: 8, handoffCalls: 3, durationMs: 900000 })
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
function guid(project, relative) {
|
|
19
|
-
const value = fs.readFileSync(contained(project, relative), "utf8").match(/^guid: ([a-f0-9]{32})\r?$/m)?.[1];
|
|
20
|
-
need(value, `missing or invalid Unity GUID in ${relative}`);
|
|
21
|
-
return value;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// The packet pins a chosen operation, not a general shell/MCP capability. The
|
|
25
|
-
// installed Unity CLI binds every call to this project's absolute path.
|
|
26
|
-
export function validateUnityRepair(project, packet) {
|
|
27
|
-
const profile = unityRepairProfiles[packet.repairType];
|
|
28
|
-
need(profile, "repairType must be unity-code or unity-editor");
|
|
29
|
-
need(fs.existsSync(contained(project, "ProjectSettings/ProjectVersion.txt")), "requires an existing Unity project");
|
|
30
|
-
need(packet.changes.length <= profile.files, `at most ${profile.files} exact files per packet`);
|
|
31
|
-
for (const change of packet.changes) {
|
|
32
|
-
need(keys(change, ["path", "operation", "instruction"]) && ["edit", "create"].includes(change.operation), "each change needs edit or create operation");
|
|
33
|
-
need(unityCodePath(change.path) || (packet.repairType === "unity-editor" && change.path.startsWith("Assets/") && asset.test(change.path)), "file type must match the repair profile under Assets/; no raw metadata, packages or project settings");
|
|
34
|
-
const file = contained(project, change.path);
|
|
35
|
-
need(fs.statSync(path.dirname(file)).isDirectory(), "create files only in existing folders; folder creation needs a separate scoped change");
|
|
36
|
-
if (change.operation === "edit") {
|
|
37
|
-
need(fs.existsSync(file) && fs.statSync(file).isFile(), "edit requires an existing file");
|
|
38
|
-
guid(project, `${change.path}.meta`);
|
|
39
|
-
} else need(!fs.existsSync(file) && !fs.existsSync(contained(project, `${change.path}.meta`)), "create target or companion metadata already exists");
|
|
40
|
-
}
|
|
41
|
-
need(keys(packet.unity, ["capabilities", "steps"]) && Array.isArray(packet.unity.steps) && packet.unity.steps.length <= 4, "unity requires capabilities and at most four fixed steps");
|
|
42
|
-
if (packet.unity.steps.length || packet.unity.capabilities !== undefined) {
|
|
43
|
-
need(packet.unity.capabilities?.path?.startsWith(".nccgs/evidence/") && !packet.unity.capabilities.path.startsWith(".nccgs/evidence/work-packets/"), "pin Unity command discovery evidence");
|
|
44
|
-
verifyArtifact(project, packet.unity.capabilities);
|
|
45
|
-
}
|
|
46
|
-
need((packet.repairType === "unity-code" && packet.changes.every(c => c.operation === "edit")) || packet.unity.steps.length > 0, "asset repairs and new code require an Editor/import step before completion");
|
|
47
|
-
const ids = new Set();
|
|
48
|
-
for (const step of packet.unity.steps) {
|
|
49
|
-
need(keys(step, ["id", "command", "arguments", "timeoutMs"]) && /^[a-zA-Z][\w-]{0,39}$/.test(step.id ?? "") && !ids.has(step.id), "steps need unique bounded IDs");
|
|
50
|
-
ids.add(step.id);
|
|
51
|
-
need(/^[a-zA-Z][\w-]{0,79}$/.test(step.command ?? "") && Array.isArray(step.arguments) && step.arguments.length <= 8 &&
|
|
52
|
-
step.arguments.every(a => typeof a === "string" && a.length <= 8000 && !a.startsWith("-") && !a.includes("\0")), "use a discovered command and positional arguments only; routing/global flags are generated");
|
|
53
|
-
need(Number.isSafeInteger(step.timeoutMs) && step.timeoutMs >= 1000 && step.timeoutMs <= 60000, "step timeoutMs must be 1000-60000; long verification belongs to managed jobs");
|
|
54
|
-
need(step.command === "eval" && step.arguments.length === 1, "new Editor steps require eval with one C# statement body so the dirty-scene check runs atomically before the operation");
|
|
55
|
-
need(!/^\s*(?:global\s+)?using\s+(?:static\s+)?[\w.]+\s*(?:=|;)/m.test(step.arguments[0]), "eval bodies must use fully qualified types; top-level using directives cannot follow the scene guard");
|
|
56
|
-
}
|
|
57
|
-
const { files, ...limits } = profile;
|
|
58
|
-
return limits;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function captureUnityRepairScope(project, dispatch, source) {
|
|
62
|
-
if (dispatch.workPacket?.schemaVersion !== 2) return;
|
|
63
|
-
const metaGuids = Object.fromEntries(dispatch.workPacket.changes.map(c => [c.path, c.operation === "edit" ? guid(project, `${c.path}.meta`) : null]));
|
|
64
|
-
const relative = `.nccgs/evidence/work-packets/${dispatch.id}-scope.json`;
|
|
65
|
-
atomicJson(contained(project, relative), { schemaVersion: 1, taskId: dispatch.taskId, dispatchId: dispatch.id,
|
|
66
|
-
sourceSnapshot: source.sha256, fileEntries: source.fileEntries, metaGuids });
|
|
67
|
-
dispatch.workPacket.scope = artifact(project, relative);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function verifyUnityRepairScope(project, dispatch, complete = false) {
|
|
71
|
-
if (dispatch.workPacket?.schemaVersion !== 2) return;
|
|
72
|
-
const p = dispatch.workPacket, baseline = json(verifyArtifact(project, p.scope));
|
|
73
|
-
need(baseline.dispatchId === dispatch.id && baseline.taskId === dispatch.taskId && baseline.sourceSnapshot === dispatch.snapshot, "scope baseline identity changed");
|
|
74
|
-
const before = new Map(baseline.fileEntries), after = new Map(snapshot(project, null, { includeFiles: true }).fileEntries);
|
|
75
|
-
const owned = new Set(p.changes.flatMap(c => [c.path, `${c.path}.meta`]));
|
|
76
|
-
for (const [file, hash] of before) {
|
|
77
|
-
need(after.has(file), `source file removed: ${file}; deletions/renames are outside this packet`);
|
|
78
|
-
need(after.get(file) === hash || owned.has(file), `source changed outside exact ownership: ${file}`);
|
|
79
|
-
}
|
|
80
|
-
for (const file of after.keys()) need(before.has(file) || owned.has(file), `source created outside exact ownership: ${file}`);
|
|
81
|
-
for (const c of p.changes) {
|
|
82
|
-
const meta = `${c.path}.meta`, present = after.has(meta);
|
|
83
|
-
if (present) {
|
|
84
|
-
const current = guid(project, meta);
|
|
85
|
-
need(!baseline.metaGuids[c.path] || current === baseline.metaGuids[c.path], `existing GUID changed: ${meta}`);
|
|
86
|
-
}
|
|
87
|
-
if (complete) need(after.has(c.path) && present, `output or imported metadata missing: ${c.path}; finish import before native completion`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function repairEditorCommand(dispatch, step) {
|
|
92
|
-
return `node .claude/nccgs/tools/task.mjs repair-editor --id ${dispatch.taskId} --dispatch ${dispatch.id} --step ${step.id}`;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function unityEditorToolScope(dispatch, input) {
|
|
96
|
-
if (dispatch.workPacket?.schemaVersion !== 2 || input.tool_name !== "Bash") return null;
|
|
97
|
-
const tool = input.tool_input ?? {}, step = dispatch.workPacket.unity.steps.find(s => repairEditorCommand(dispatch, s) === tool.command);
|
|
98
|
-
need(step && keys(tool, ["command", "timeout", "description", "run_in_background"]) && tool.run_in_background !== true &&
|
|
99
|
-
Number.isSafeInteger(tool.timeout) && tool.timeout >= step.timeoutMs + 5000 && tool.timeout <= 120000,
|
|
100
|
-
"only the fixed repair-editor command is permitted, foreground, with timeout at least step timeoutMs + 5000");
|
|
101
|
-
return { bucket: "work", read: false, editorStep: step.id };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function unityEditorInvocation(project, step, safety = null) {
|
|
105
|
-
need(safety === null || safety === unitySceneSafety, "unknown pinned scene safety policy");
|
|
106
|
-
let sceneGuard = null, args = step.arguments;
|
|
107
|
-
if (safety) {
|
|
108
|
-
need(step.command === "eval" && args.length === 1, "guarded Editor step requires one eval body");
|
|
109
|
-
sceneGuard = { policy: safety, token: crypto.randomUUID() };
|
|
110
|
-
// Same Editor eval, before any packet statement: includes untitled/additive
|
|
111
|
-
// loaded scenes. Never auto-save, discard or switch a dirty scene.
|
|
112
|
-
const prefix = `{ for (int nccgsSceneIndex = 0; nccgsSceneIndex < UnityEngine.SceneManagement.SceneManager.sceneCount; nccgsSceneIndex++) { var nccgsScene = UnityEngine.SceneManagement.SceneManager.GetSceneAt(nccgsSceneIndex); if (nccgsScene.isDirty) return new { nccgsSceneGuard = "${safety}", token = "${sceneGuard.token}", blockedScene = string.IsNullOrEmpty(nccgsScene.path) ? "<untitled>" : nccgsScene.path }; } }\n`;
|
|
113
|
-
args = [prefix + args[0]];
|
|
114
|
-
}
|
|
115
|
-
return { ...(sceneGuard ? { sceneGuard } : {}), executable: process.platform === "win32" ? "unity.exe" : "unity", arguments: ["command", step.command, ...args,
|
|
116
|
-
"--caller", "plugin", "--skill", "unity-cli",
|
|
117
|
-
"--project-path", fs.realpathSync(project), "--timeout", String(Math.ceil(step.timeoutMs / 1000)), "--format", "json", "--no-pager", "--non-interactive"] };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function blockedUnityScene(invocation, result) {
|
|
121
|
-
if (!invocation.sceneGuard || result.status !== 0 || result.error || result.signal) return null;
|
|
122
|
-
try {
|
|
123
|
-
const response = JSON.parse(result.stdout), envelope = response.data?.result, value = envelope?.result;
|
|
124
|
-
if (response.success === true && envelope.success === true && value?.nccgsSceneGuard === invocation.sceneGuard.policy &&
|
|
125
|
-
value.token === invocation.sceneGuard.token && typeof value.blockedScene === "string") return value.blockedScene;
|
|
126
|
-
} catch { /* Unknown output retains existing conservative execution handling. */ }
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { conflictingLaunchOption } from "./autonomy.mjs";
|
|
4
|
-
|
|
5
|
-
const object = value => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6
|
-
const unityIdentity = /(?:^|[^a-z0-9])(?:unity(?:mcp)?|mcpforunity(?:server)?|coplay(?:dev)?|anklebreaker)(?=$|[^a-z0-9])/i;
|
|
7
|
-
const unityName = value => unityIdentity.test(value)
|
|
8
|
-
|| unityIdentity.test(String(value).replace(/([a-z0-9])([A-Z])/g, "$1 $2"));
|
|
9
|
-
const unityProvider = value => /mcpforunity|mcp-for-unity|unity[-_]mcp|coplay(?:dev|\.dev)|com\.anklebreaker/i.test(value);
|
|
10
|
-
const fail = message => { throw new Error(`Unity CLI-only: ${message}`); };
|
|
11
|
-
// The only argv allowed before strict isolation: the framework-owned permission
|
|
12
|
-
// pair produced by autonomy.mjs permissionModeArgs. No other prefix is accepted.
|
|
13
|
-
const ownedPrefix = prefix => Array.isArray(prefix) && prefix.length === 2 && prefix[0] === "--permission-mode"
|
|
14
|
-
&& ["default", "bypassPermissions"].includes(prefix[1]);
|
|
15
|
-
|
|
16
|
-
// Default sessions do not discover MCP servers from user settings or plugins.
|
|
17
|
-
// An external caller may explicitly supply a non-Unity MCP configuration. Keep
|
|
18
|
-
// file arguments as paths: never copy their possible credentials into run state.
|
|
19
|
-
// `prefix` is the fixed framework-owned launch prefix (permission mode). Strict
|
|
20
|
-
// isolation follows it directly, before every caller-controlled argument, so a
|
|
21
|
-
// forwarded option missing its value can never consume the isolation flag.
|
|
22
|
-
export function unityCliMcpArgs(args, project, prefix) {
|
|
23
|
-
if (!ownedPrefix(prefix)) fail("launch requires the fixed NCCGS --permission-mode default|bypassPermissions prefix");
|
|
24
|
-
let config = null, strict = false;
|
|
25
|
-
const remaining = [];
|
|
26
|
-
for (let i = 0; i < args.length; i++) {
|
|
27
|
-
const arg = args[i];
|
|
28
|
-
if (arg === "--") { remaining.push(...args.slice(i)); break; }
|
|
29
|
-
if (arg === "--strict-mcp-config") {
|
|
30
|
-
if (strict) fail("duplicate --strict-mcp-config");
|
|
31
|
-
strict = true; continue;
|
|
32
|
-
}
|
|
33
|
-
if (arg.startsWith("--strict-mcp-config=")) fail("strict MCP isolation cannot be disabled");
|
|
34
|
-
if (arg === "--mcp-config" || arg.startsWith("--mcp-config=")) {
|
|
35
|
-
if (config !== null) fail("use one explicit MCP configuration");
|
|
36
|
-
config = arg === "--mcp-config" ? args[++i] : arg.slice("--mcp-config=".length);
|
|
37
|
-
if (typeof config !== "string" || !config.trim() || config.startsWith("--")) fail("--mcp-config requires JSON or a JSON file");
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
remaining.push(arg);
|
|
41
|
-
}
|
|
42
|
-
config ??= '{"mcpServers":{}}';
|
|
43
|
-
let value;
|
|
44
|
-
try {
|
|
45
|
-
const text = config.trim().startsWith("{") ? config : fs.readFileSync(path.resolve(project, config), "utf8");
|
|
46
|
-
value = JSON.parse(text.replace(/^\uFEFF/, ""));
|
|
47
|
-
} catch { fail("MCP configuration must be readable valid JSON; no fallback to global servers"); }
|
|
48
|
-
if (!object(value) || Object.keys(value).some(k => k !== "mcpServers") || !object(value.mcpServers))
|
|
49
|
-
fail("MCP configuration must contain only a mcpServers object");
|
|
50
|
-
for (const [name, server] of Object.entries(value.mcpServers)) {
|
|
51
|
-
if (!object(server)) fail("invalid MCP server definition");
|
|
52
|
-
const command = typeof server.command === "string" && server.command.trim();
|
|
53
|
-
const url = typeof server.url === "string" && server.url.trim();
|
|
54
|
-
if ((!command && !url) || (command && url)
|
|
55
|
-
|| (server.args !== undefined && (!Array.isArray(server.args) || !server.args.every(x => typeof x === "string"))))
|
|
56
|
-
fail("invalid MCP command/endpoint definition");
|
|
57
|
-
const route = [server.command, server.url, ...(Array.isArray(server.args) ? server.args : [])].filter(x => typeof x === "string").join(" ");
|
|
58
|
-
if (unityName(name) || unityProvider(route) || /\bunity(?:\.exe)?\s+mcp\b/i.test(route))
|
|
59
|
-
fail("Unity MCP servers are forbidden; use direct Unity CLI/Pipeline commands");
|
|
60
|
-
}
|
|
61
|
-
// Claude's config option is variadic. End it at argv end or the explicit
|
|
62
|
-
// option terminator, so no prompt or unchecked second config can be consumed.
|
|
63
|
-
// A trailing caller option missing its value may consume "--mcp-config"; the
|
|
64
|
-
// strict flag stays effective, so that fails closed with no MCP servers.
|
|
65
|
-
const boundary = remaining.indexOf("--");
|
|
66
|
-
const caller = boundary < 0 ? remaining : remaining.slice(0, boundary);
|
|
67
|
-
const terminated = boundary < 0 ? [] : remaining.slice(boundary);
|
|
68
|
-
return [...prefix, "--strict-mcp-config", ...caller, "--mcp-config", config, ...terminated];
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Recovery retains its original arguments and budgets. An old unsafe record is
|
|
72
|
-
// refused, not silently rewritten or relaunched with different server settings.
|
|
73
|
-
// Canonical layout: [...prefix, --strict-mcp-config, ...caller, --mcp-config,
|
|
74
|
-
// <one validated config>, (-- ...terminated)].
|
|
75
|
-
// `prefix` must be the owned pair for the run's recorded permission mode.
|
|
76
|
-
export function assertStrictUnityCliArgs(args, project, prefix) {
|
|
77
|
-
if (!ownedPrefix(prefix)) fail("retained run has no valid NCCGS permission prefix; use an authorized fresh continuation without resetting spent budgets");
|
|
78
|
-
if (!Array.isArray(args) || !args.every(x => typeof x === "string") || !args.includes("--strict-mcp-config")
|
|
79
|
-
|| !args.some(x => x === "--mcp-config" || x.startsWith("--mcp-config=")))
|
|
80
|
-
fail("retained run lacks strict MCP isolation; use an authorized fresh continuation without resetting spent budgets");
|
|
81
|
-
if (args[0] !== prefix[0] || args[1] !== prefix[1] || args[2] !== "--strict-mcp-config")
|
|
82
|
-
fail("retained arguments do not place strict MCP isolation directly after the fixed permission prefix, before caller arguments; use an authorized fresh continuation without resetting spent budgets");
|
|
83
|
-
// R09: the same ownership policy as a fresh launch. Only the verified fixed
|
|
84
|
-
// permission prefix is skipped; an R08-canonical record may still carry e.g.
|
|
85
|
-
// --restricted, which would ignore project settings and hooks.
|
|
86
|
-
const owned = args.slice(prefix.length).find(arg => conflictingLaunchOption.test(arg));
|
|
87
|
-
if (owned !== undefined)
|
|
88
|
-
fail(`retained arguments contain NCCGS-owned launch option ${owned}; use an authorized fresh continuation without resetting spent budgets`);
|
|
89
|
-
const canonical = unityCliMcpArgs(args.slice(prefix.length), project, prefix);
|
|
90
|
-
if (JSON.stringify(canonical) !== JSON.stringify(args))
|
|
91
|
-
fail("retained arguments lack the canonical single-configuration boundary; use an authorized fresh continuation without resetting spent budgets");
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// This recognizes ordinary shell invocations; it does not execute or attempt to
|
|
95
|
-
// sandbox arbitrary scripts, encoded payloads, or a deliberately hostile client.
|
|
96
|
-
function tokens(command) {
|
|
97
|
-
const result = []; let word = "", quote = null;
|
|
98
|
-
const flush = () => { if (word) result.push(word); word = ""; };
|
|
99
|
-
for (let i = 0; i < command.length; i++) {
|
|
100
|
-
const c = command[i];
|
|
101
|
-
if (c === "`" && command[i + 1]) { word += command[++i]; continue; }
|
|
102
|
-
if (quote) {
|
|
103
|
-
if (c === quote) {
|
|
104
|
-
if (quote === "'" && command[i + 1] === "'") { word += "'"; i++; }
|
|
105
|
-
else quote = null;
|
|
106
|
-
} else word += c;
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
if (c === "'" || c === '"') { quote = c; continue; }
|
|
110
|
-
if (c === "{" && word === "$") {
|
|
111
|
-
const end = command.indexOf("}", i + 1);
|
|
112
|
-
if (end >= 0) { word += command.slice(i, end + 1); i = end; continue; }
|
|
113
|
-
}
|
|
114
|
-
if (c === "\n" || c === "\r") { flush(); result.push(";"); continue; }
|
|
115
|
-
if (/\s/.test(c)) { flush(); continue; }
|
|
116
|
-
if (/[;&|(){}]/.test(c)) { flush(); result.push(c); continue; }
|
|
117
|
-
word += c;
|
|
118
|
-
}
|
|
119
|
-
flush(); return result;
|
|
120
|
-
}
|
|
121
|
-
function inspectShell(command, depth = 0) {
|
|
122
|
-
if (depth > 3) fail("nested command wrappers exceed the inspected transport boundary");
|
|
123
|
-
const parts = tokens(command);
|
|
124
|
-
for (let i = 0; i < parts.length; i++) {
|
|
125
|
-
const previous = parts[i - 1];
|
|
126
|
-
const invocation = i === 0 || ["&", ";", "|", "(", "{", ".", "sudo", "env", "exec", "call", "command"].includes(previous)
|
|
127
|
-
|| /^[A-Za-z_]\w*=/.test(previous ?? "");
|
|
128
|
-
if (!invocation) continue;
|
|
129
|
-
const program = parts[i].replaceAll("\\", "/").split("/").at(-1).toLowerCase().replace(/\.exe$/, "");
|
|
130
|
-
if ((program === "unity" || /^\$(?:env:)?[\w:{}]+$/i.test(parts[i])) && parts[i + 1]?.toLowerCase() === "mcp")
|
|
131
|
-
fail("unity mcp/configure is disabled; call Unity CLI/Pipeline directly");
|
|
132
|
-
if (/^(?:mcp-for-unity|mcpforunityserver)$/.test(program)) fail("Coplay Unity MCP launch is disabled");
|
|
133
|
-
const end = parts.findIndex((x, n) => n > i && [";", "|", "&", ")"].includes(x));
|
|
134
|
-
const arguments_ = parts.slice(i + 1, end < 0 ? undefined : end);
|
|
135
|
-
if (["uvx", "uv", "pip", "pip3", "pipx", "npx", "npm", "pnpm", "bunx"].includes(program)) {
|
|
136
|
-
const following = arguments_.join(" ");
|
|
137
|
-
if (unityProvider(following)) fail("Unity MCP installation or launch is disabled");
|
|
138
|
-
}
|
|
139
|
-
if (["claude", "codex"].includes(program) && arguments_[0]?.toLowerCase() === "mcp"
|
|
140
|
-
&& ["add", "add-json", "add-from-claude-desktop"].includes(arguments_[1]?.toLowerCase())) {
|
|
141
|
-
const registration = arguments_.slice(2).join(" ");
|
|
142
|
-
if (unityName(registration) || unityProvider(registration))
|
|
143
|
-
fail("Unity MCP registration through Claude/Codex is disabled");
|
|
144
|
-
}
|
|
145
|
-
if (["python", "python3", "node"].includes(program)
|
|
146
|
-
&& unityProvider(arguments_[0] === "-m" ? arguments_[1] ?? "" : arguments_[0] ?? ""))
|
|
147
|
-
fail("Unity MCP launch is disabled");
|
|
148
|
-
if (program === "git" && parts[i + 1] === "clone" && unityProvider(parts.slice(i + 2).join(" ")))
|
|
149
|
-
fail("Unity MCP installation is disabled");
|
|
150
|
-
if (["start-process", "start"].includes(program)) {
|
|
151
|
-
const target = arguments_.join(" ");
|
|
152
|
-
if (unityProvider(target) || (/\bunity(?:\.exe)?\b/i.test(target) && /\bmcp\b/i.test(target)))
|
|
153
|
-
fail("Unity MCP launch is disabled");
|
|
154
|
-
}
|
|
155
|
-
if (["invoke-expression", "iex"].includes(program) && arguments_.length)
|
|
156
|
-
inspectShell(arguments_.join(" "), depth + 1);
|
|
157
|
-
if (["cmd", "powershell", "pwsh", "bash", "sh"].includes(program)) {
|
|
158
|
-
const option = parts.findIndex((x, n) => n > i && ["/c", "-c", "-lc", "-ic", "-command"].includes(x.toLowerCase()));
|
|
159
|
-
if (option >= 0 && parts[option + 1]) inspectShell(parts.slice(option + 1).join(" "), depth + 1);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
export function assertUnityCliOnlyInput(input) {
|
|
164
|
-
const tool = input.tool_name ?? "";
|
|
165
|
-
const server = /^mcp__/i.test(tool) ? tool.slice(5).split("__")[0]
|
|
166
|
-
: /^mcp:/i.test(tool) ? tool.slice(4).split(":")[0] : null;
|
|
167
|
-
if (server !== null && unityName(server))
|
|
168
|
-
fail("Unity MCP tools are disabled, including discovery and read-only tools");
|
|
169
|
-
if (["Bash", "PowerShell"].includes(input.tool_name)) inspectShell(input.tool_input?.command ?? "");
|
|
170
|
-
}
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import crypto from "node:crypto";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { spawnSync } from "node:child_process";
|
|
6
|
-
import { artifact, atomicJson, contained, hash, json, verifyArtifact } from "./policy.mjs";
|
|
7
|
-
import { snapshot, taskPath } from "./gates.mjs";
|
|
8
|
-
import { inputPolicy } from "./inputs.mjs";
|
|
9
|
-
import { acquireLock, ownerState, pidState } from "./process-lock.mjs";
|
|
10
|
-
import { captureCriteria, measurementBaseline } from "./criteria.mjs";
|
|
11
|
-
import { inFinalReviewPhase } from "./review-budget.mjs";
|
|
12
|
-
|
|
13
|
-
const worker = fileURLToPath(new URL("./verification-worker.mjs", import.meta.url));
|
|
14
|
-
const need = (condition, message) => { if (!condition) throw new Error(message); };
|
|
15
|
-
export function jobDirectory(project, jobId) {
|
|
16
|
-
need(typeof jobId === "string" && /^[a-f0-9-]{36}$/.test(jobId), "Invalid verification job ID");
|
|
17
|
-
return contained(project, `.nccgs/jobs/${jobId}`);
|
|
18
|
-
}
|
|
19
|
-
export function readJob(project, jobId) {
|
|
20
|
-
const job = json(path.join(jobDirectory(project, jobId), "request.json"));
|
|
21
|
-
need(job.schemaVersion === 1 && job.id === jobId && job.project === fs.realpathSync(project), "Verification job identity mismatch");
|
|
22
|
-
return job;
|
|
23
|
-
}
|
|
24
|
-
export function finishJob(project, job, result) {
|
|
25
|
-
const directory = jobDirectory(project, job.id);
|
|
26
|
-
const receipt = `.nccgs/evidence/check-${job.id}.json`;
|
|
27
|
-
if (fs.existsSync(contained(project, receipt))) return jobStatus(project, job.id, job.taskId);
|
|
28
|
-
let after = null, afterGenerated = [], snapshotError = null;
|
|
29
|
-
try {
|
|
30
|
-
const captured = snapshot(project, json(taskPath(project, job.taskId)));
|
|
31
|
-
after = captured.sha256; afterGenerated = captured.unityGeneratedFiles ?? [];
|
|
32
|
-
} catch (error) { snapshotError = error.message; }
|
|
33
|
-
const beforeGenerated = new Map((job.unityGeneratedBaseline ?? []).map(file => [file.path, file.sha256]));
|
|
34
|
-
const generatedFileChanges = afterGenerated.filter(file => beforeGenerated.get(file.path) !== file.sha256)
|
|
35
|
-
.map(file => ({ path: file.path, beforeSha256: beforeGenerated.get(file.path) ?? null, afterSha256: file.sha256 }));
|
|
36
|
-
const logPath = `.nccgs/evidence/check-${job.id}.log`;
|
|
37
|
-
fs.mkdirSync(path.dirname(contained(project, logPath)), { recursive: true });
|
|
38
|
-
if (!fs.existsSync(contained(project, logPath))) fs.writeFileSync(contained(project, logPath), result.error || "No command output captured\n");
|
|
39
|
-
else if (fs.statSync(contained(project, logPath)).size === 0) fs.appendFileSync(contained(project, logPath), "[NCCGS command produced no output]\n");
|
|
40
|
-
if (result.error || snapshotError) fs.appendFileSync(contained(project, logPath), `\n${result.error ?? ""}\n${snapshotError ?? ""}\n`);
|
|
41
|
-
const status = result.exitCode === 0 && !result.error && !result.timedOut && job.snapshot === after ? "PASS" : "FAIL";
|
|
42
|
-
atomicJson(contained(project, receipt), { schemaVersion: 1, origin: "verification-command", taskId: job.taskId, name: job.name,
|
|
43
|
-
jobId: job.id, requestKey: job.requestKey, snapshot: job.snapshot, contractHash: job.contractHash,
|
|
44
|
-
queuedAt: job.queuedAt, startedAt: result.startedAt ?? job.queuedAt, finishedAt: new Date().toISOString(),
|
|
45
|
-
timeoutMs: job.timeoutMs, supervisorDeadline: job.supervisorDeadline ?? null,
|
|
46
|
-
timedOut: result.timedOut === true, signal: result.signal ?? null,
|
|
47
|
-
snapshotError, executable: job.executable, arguments: job.arguments, exitCode: result.exitCode ?? null,
|
|
48
|
-
...(job.unityGeneratedBaseline ? { unityGeneratedFiles: { before: job.unityGeneratedBaseline, after: afterGenerated, changes: generatedFileChanges } } : {}),
|
|
49
|
-
error: result.error ?? null, sourceUnchanged: job.snapshot === after, status, log: artifact(project, logPath),
|
|
50
|
-
acceptance: captureCriteria(project, job, status) });
|
|
51
|
-
atomicJson(path.join(directory, "result.json"), { status, evidence: artifact(project, receipt) });
|
|
52
|
-
return jobStatus(project, job.id, job.taskId);
|
|
53
|
-
}
|
|
54
|
-
export function jobStatus(project, jobId, taskId) {
|
|
55
|
-
const job = readJob(project, jobId), directory = jobDirectory(project, jobId);
|
|
56
|
-
need(!taskId || taskId === job.taskId, "Verification job belongs to another task");
|
|
57
|
-
const receipt = `.nccgs/evidence/check-${job.id}.json`;
|
|
58
|
-
if (fs.existsSync(contained(project, receipt))) {
|
|
59
|
-
const resultPath = path.join(directory, "result.json");
|
|
60
|
-
const evidence = fs.existsSync(resultPath) ? json(resultPath).evidence : artifact(project, receipt);
|
|
61
|
-
const result = json(verifyArtifact(project, evidence));
|
|
62
|
-
need(result.jobId === job.id && result.taskId === job.taskId && result.snapshot === job.snapshot && result.name === job.name, "Verification receipt identity mismatch");
|
|
63
|
-
verifyArtifact(project, result.log);
|
|
64
|
-
return { jobId, taskId: job.taskId, name: job.name, status: result.status, evidence, acceptance: result.acceptance ?? null };
|
|
65
|
-
}
|
|
66
|
-
const lockPath = path.join(directory, "owner.lock");
|
|
67
|
-
if (fs.existsSync(lockPath)) {
|
|
68
|
-
let owner; try { owner = json(lockPath); } catch { /* incomplete owner */ }
|
|
69
|
-
const state = ownerState(owner);
|
|
70
|
-
if (state === "dead") {
|
|
71
|
-
const lock = acquireLock(lockPath, { jobId });
|
|
72
|
-
try { return finishJob(project, job, { error: "Verification owner exited without a terminal receipt; attempt retained, no automatic rerun" }); }
|
|
73
|
-
finally { lock.release(); }
|
|
74
|
-
}
|
|
75
|
-
return { jobId, taskId: job.taskId, name: job.name, status: state === "unknown" ? "UNCERTAIN" : "RUNNING", owner: owner ?? null };
|
|
76
|
-
}
|
|
77
|
-
const launchPath = path.join(directory, "launch.json");
|
|
78
|
-
const launch = fs.existsSync(launchPath) ? json(launchPath) : null;
|
|
79
|
-
const launchError = fs.existsSync(path.join(directory, "launch-error.json"));
|
|
80
|
-
return { jobId, taskId: job.taskId, name: job.name, status: launchError || (launch && pidState(launch.pid) === "dead") ? "UNCERTAIN" : "STARTING",
|
|
81
|
-
...(fs.existsSync(path.join(directory, "worker.log")) ? { diagnostics: fs.readFileSync(path.join(directory, "worker.log"), "utf8").slice(-4000) } : {}) };
|
|
82
|
-
}
|
|
83
|
-
export function listJobs(project, taskId) {
|
|
84
|
-
const directory = contained(project, ".nccgs/jobs");
|
|
85
|
-
if (!fs.existsSync(directory)) return [];
|
|
86
|
-
return fs.readdirSync(directory, { withFileTypes: true }).filter(e => e.isDirectory()).flatMap(e => {
|
|
87
|
-
const job = readJob(project, e.name);
|
|
88
|
-
return !taskId || job.taskId === taskId ? [jobStatus(project, job.id, job.taskId)] : [];
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
export function pendingJobs(project, taskId) { return listJobs(project, taskId).filter(job => !["PASS", "FAIL"].includes(job.status)); }
|
|
92
|
-
export function startVerification(project, taskId, options) {
|
|
93
|
-
project = fs.realpathSync(project);
|
|
94
|
-
need(!inFinalReviewPhase(project, process.env.NCCGS_SUPERVISED_SESSION), "Final-review reserve cannot run new verification jobs; use existing receipts");
|
|
95
|
-
const task = json(taskPath(project, taskId));
|
|
96
|
-
need(task.schemaVersion !== 2 || task.mode === "implement" || !(process.env.CLAUDECODE || process.env.CLAUDE_CODE_ENTRYPOINT), "Audit/plan tasks cannot run arbitrary verification commands inside Claude");
|
|
97
|
-
need(typeof options.name === "string" && options.name.trim() && options.executable, "verify requires --name CHECK -- EXECUTABLE [ARGS]");
|
|
98
|
-
const configuredTimeout = inputPolicy(project).checks[options.name]?.timeoutMs;
|
|
99
|
-
const timeoutMs = options.timeoutMs === undefined ? (configuredTimeout ?? 300000) : options.timeoutMs;
|
|
100
|
-
need(Number.isSafeInteger(timeoutMs) && timeoutMs >= 100 && timeoutMs <= 7200000, "Verification timeoutMs must be an integer from 100 to 7200000");
|
|
101
|
-
need(configuredTimeout === undefined || timeoutMs <= configuredTimeout, "Verification timeout cannot exceed the configured check timeout");
|
|
102
|
-
let supervisorDeadline;
|
|
103
|
-
if (process.env.NCCGS_SUPERVISED_SESSION) {
|
|
104
|
-
const owner = json(contained(project, `.nccgs/runs/task-${taskId}.lock`));
|
|
105
|
-
need(/^[a-f0-9-]{36}$/.test(owner.runId ?? ""), "Missing supervised verification run identity");
|
|
106
|
-
const run = json(contained(project, `.nccgs/runs/${owner.runId}/run.json`));
|
|
107
|
-
need(run.project === project && run.taskId === taskId && run.sessionId === process.env.NCCGS_SUPERVISED_SESSION &&
|
|
108
|
-
Number.isSafeInteger(run.deadline), "Supervised verification run binding mismatch");
|
|
109
|
-
supervisorDeadline = run.deadline;
|
|
110
|
-
}
|
|
111
|
-
const requestKey = options.requestKey ?? crypto.randomUUID();
|
|
112
|
-
need(/^[\w-]{1,100}$/.test(requestKey), "Verification request key must use 1-100 letters, digits, underscores or hyphens");
|
|
113
|
-
const key = hash(`${taskId}\n${requestKey}`);
|
|
114
|
-
// Keep the request-key index outside the job directories.
|
|
115
|
-
const index = contained(project, `.nccgs/job-requests/${key}.json`);
|
|
116
|
-
const lock = acquireLock(`${index}.lock`, { taskId, requestKey });
|
|
117
|
-
let measurementLock;
|
|
118
|
-
try {
|
|
119
|
-
const captured = snapshot(project, task), current = captured.sha256;
|
|
120
|
-
const spec = { taskId, name: options.name, executable: options.executable, arguments: options.arguments ?? [],
|
|
121
|
-
timeoutMs, snapshot: current, contractHash: task.contractHash ?? null,
|
|
122
|
-
...(supervisorDeadline === undefined ? {} : { supervisorDeadline }),
|
|
123
|
-
criteria: (task.contract?.acceptance ?? []).filter(c => !c.manual && c.check === options.name) };
|
|
124
|
-
const requestHash = hash(JSON.stringify(spec));
|
|
125
|
-
if (fs.existsSync(index)) {
|
|
126
|
-
const previous = json(index);
|
|
127
|
-
need(previous.requestHash === requestHash, "Verification request key reused with changed source/command/contract; use a new key for a new attempt");
|
|
128
|
-
return jobStatus(project, previous.jobId, taskId);
|
|
129
|
-
}
|
|
130
|
-
need(supervisorDeadline === undefined || Date.now() < supervisorDeadline, "Supervised run deadline reached; no new verification");
|
|
131
|
-
const outputPaths = spec.criteria.flatMap(c => (c.assertions ?? []).map(r => r.artifact.toLowerCase()));
|
|
132
|
-
if (outputPaths.length) {
|
|
133
|
-
measurementLock = acquireLock(contained(project, ".nccgs/measurement-start.lock"), { taskId, requestKey });
|
|
134
|
-
for (const pending of pendingJobs(project)) {
|
|
135
|
-
const other = readJob(project, pending.jobId);
|
|
136
|
-
need(!(other.criteria ?? []).some(c => (c.assertions ?? []).some(r => outputPaths.includes(r.artifact.toLowerCase()))),
|
|
137
|
-
"Another verification owns these measurement outputs; wait for its terminal receipt before starting a new attempt");
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
const baseline = measurementBaseline(project, spec.criteria);
|
|
141
|
-
const jobId = crypto.randomUUID(), directory = jobDirectory(project, jobId);
|
|
142
|
-
fs.mkdirSync(directory, { recursive: true });
|
|
143
|
-
fs.mkdirSync(contained(project, ".nccgs/evidence"), { recursive: true });
|
|
144
|
-
const job = { schemaVersion: 1, id: jobId, project, ...spec, requestKey, requestHash, measurementBaseline: baseline, queuedAt: new Date().toISOString(),
|
|
145
|
-
...(captured.unityGeneratedFiles ? { unityGeneratedBaseline: captured.unityGeneratedFiles } : {}),
|
|
146
|
-
sessionId: process.env.NCCGS_SUPERVISED_SESSION || null };
|
|
147
|
-
atomicJson(path.join(directory, "request.json"), job);
|
|
148
|
-
atomicJson(index, { jobId, requestHash }); // pinned before launch: an ambiguous crash cannot mint a duplicate
|
|
149
|
-
const launched = spawnSync(process.execPath, [worker, "launch", project, jobId], { cwd: project, encoding: "utf8", windowsHide: true, timeout: 15000 });
|
|
150
|
-
if (launched.status !== 0 || launched.error) {
|
|
151
|
-
// A launcher timeout/error may occur after its detached child was created.
|
|
152
|
-
// Preserve uncertainty and let the actual owner publish its own receipt.
|
|
153
|
-
atomicJson(path.join(directory, "launch-error.json"), { at: new Date().toISOString(), error: launched.error?.message || launched.stderr, exitCode: launched.status });
|
|
154
|
-
}
|
|
155
|
-
return jobStatus(project, jobId, taskId);
|
|
156
|
-
} finally { measurementLock?.release(); lock.release(); }
|
|
157
|
-
}
|
|
158
|
-
export function waitVerification(project, jobId, taskId, timeoutMs = 30000) {
|
|
159
|
-
need(Number.isSafeInteger(timeoutMs) && timeoutMs >= 0 && timeoutMs <= 7200000 + 30000, "Invalid job wait timeout");
|
|
160
|
-
const deadline = Date.now() + timeoutMs;
|
|
161
|
-
for (;;) {
|
|
162
|
-
const result = jobStatus(project, jobId, taskId);
|
|
163
|
-
if (["PASS", "FAIL"].includes(result.status)) {
|
|
164
|
-
const launchPath = path.join(jobDirectory(project, jobId), "launch.json");
|
|
165
|
-
// A receipt is durable before the worker exits. Synchronous callers also
|
|
166
|
-
// wait for that owner to release its cwd/handles before disposing a project.
|
|
167
|
-
if (!fs.existsSync(launchPath) || pidState(json(launchPath).pid) === "dead" || Date.now() >= deadline) return result;
|
|
168
|
-
} else if (result.status === "UNCERTAIN" || Date.now() >= deadline) return result;
|
|
169
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, Math.min(100, deadline - Date.now()));
|
|
170
|
-
}
|
|
171
|
-
}
|