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
package/cli/install.mjs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// nccgs install | update: copy the managed files into a Unity project, merge settings, scaffold .nccgs.
|
|
2
|
+
// Managed files are inventoried with hashes; a file the user changed is never overwritten (recorded as an override).
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { readJson, writeJson, writeText, readText, exists, sha256File, walk, toPosix, nowIso } from "../runtime/core/fs.mjs";
|
|
7
|
+
import { at, LAYOUT, isUnityProject, loadConfig, saveConfig, ensureLayout, DEFAULT_CONFIG, editorVersion } from "../runtime/core/project.mjs";
|
|
8
|
+
import { renderAgents } from "../runtime/core/modes.mjs";
|
|
9
|
+
|
|
10
|
+
export const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
11
|
+
export const PKG = readJson(path.join(PKG_ROOT, "package.json"));
|
|
12
|
+
export const TEMPLATE = path.join(PKG_ROOT, "template");
|
|
13
|
+
|
|
14
|
+
// Managed set: (packageRelative -> projectRelative)
|
|
15
|
+
function managedFiles() {
|
|
16
|
+
const list = [];
|
|
17
|
+
const add = (fromDir, toDir, filter = () => true) => {
|
|
18
|
+
for (const file of walk(fromDir)) {
|
|
19
|
+
const rel = toPosix(path.relative(fromDir, file));
|
|
20
|
+
if (filter(rel)) list.push({ from: file, to: path.posix.join(toDir, rel) });
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
add(path.join(PKG_ROOT, "runtime"), ".claude/nccgs/runtime");
|
|
24
|
+
add(path.join(TEMPLATE, "skills"), ".claude/skills");
|
|
25
|
+
add(path.join(TEMPLATE, "protocols"), ".claude/nccgs/protocols");
|
|
26
|
+
add(path.join(TEMPLATE, "ponytail"), ".claude/nccgs/ponytail");
|
|
27
|
+
add(path.join(PKG_ROOT, "unity-skills"), ".claude/skills", rel => rel !== "manifest.json");
|
|
28
|
+
list.push({ from: path.join(PKG_ROOT, "unity-skills", "manifest.json"), to: ".claude/nccgs/unity-skills-manifest.json" });
|
|
29
|
+
list.push({ from: path.join(TEMPLATE, "CLAUDE.md"), to: "CLAUDE.md", keepIfExists: true });
|
|
30
|
+
return list;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function install(root, { update = false, force = false, dryRun = false, mode, autonomy, rigor, skillsOnly = false } = {}) {
|
|
34
|
+
if (!isUnityProject(root)) throw new Error(`${root} is not a Unity project (needs Assets/ and ProjectSettings/ProjectVersion.txt)`);
|
|
35
|
+
const stateFile = at(root, "installState");
|
|
36
|
+
const previous = exists(stateFile) ? readJson(stateFile) : null;
|
|
37
|
+
if (update && !previous) throw new Error("NCCGS is not installed here; use `install`");
|
|
38
|
+
if (!update && previous && !force) throw new Error(`NCCGS ${previous.version} is already installed; use \`update\``);
|
|
39
|
+
const actions = []; // { action: add|replace|keep|override|skip, path }
|
|
40
|
+
const inventory = {};
|
|
41
|
+
for (const item of managedFiles()) {
|
|
42
|
+
if (skillsOnly && !item.to.startsWith(".claude/skills/") && !item.to.endsWith("unity-skills-manifest.json")) continue;
|
|
43
|
+
const target = path.join(root, item.to);
|
|
44
|
+
const incoming = sha256File(item.from);
|
|
45
|
+
const existsNow = exists(target);
|
|
46
|
+
const current = existsNow ? sha256File(target) : null;
|
|
47
|
+
const recorded = previous?.files?.[item.to] ?? null;
|
|
48
|
+
let action;
|
|
49
|
+
if (!existsNow) action = "add";
|
|
50
|
+
else if (current === incoming) action = "keep";
|
|
51
|
+
else if (item.keepIfExists && !recorded) action = "keep-user"; // e.g. the user's own CLAUDE.md
|
|
52
|
+
else if (recorded && current === recorded) action = "replace"; // unchanged managed file, new version
|
|
53
|
+
else if (force) action = "replace-forced";
|
|
54
|
+
else action = "override"; // user changed it: keep theirs, record it
|
|
55
|
+
actions.push({ action, path: item.to });
|
|
56
|
+
inventory[item.to] = ["add", "replace", "replace-forced", "keep"].includes(action) ? incoming : (current ?? incoming);
|
|
57
|
+
if (!dryRun && ["add", "replace", "replace-forced"].includes(action)) {
|
|
58
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
59
|
+
fs.copyFileSync(item.from, target);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Scaffold .nccgs (never overwritten), config, modes.
|
|
63
|
+
if (!dryRun && !skillsOnly) {
|
|
64
|
+
ensureLayout(root);
|
|
65
|
+
const config = exists(at(root, "config")) ? loadConfig(root) : structuredClone(DEFAULT_CONFIG);
|
|
66
|
+
if (!config.name) config.name = path.basename(root);
|
|
67
|
+
if (mode) config.mode = mode;
|
|
68
|
+
if (autonomy) config.autonomy = autonomy;
|
|
69
|
+
if (rigor) config.rigor = rigor;
|
|
70
|
+
saveConfig(root, config);
|
|
71
|
+
if (!exists(at(root, "state"))) writeText(at(root, "state"), "# Project state\n\nMaintained by `task close`. Newest first.\n\n");
|
|
72
|
+
const gi = path.join(root, ".nccgs", ".gitignore");
|
|
73
|
+
if (!exists(gi)) writeText(gi, "evidence/screens/\nevidence/measurements/\ncache/\nevents.jsonl\n");
|
|
74
|
+
renderAgents(root, config.mode, { templateDir: TEMPLATE });
|
|
75
|
+
mergeSettings(root);
|
|
76
|
+
}
|
|
77
|
+
const overrides = actions.filter(a => a.action === "override").map(a => a.path);
|
|
78
|
+
if (!dryRun) {
|
|
79
|
+
writeJson(stateFile, { schemaVersion: 3, version: PKG.version, installedAt: previous?.installedAt ?? nowIso(), updatedAt: nowIso(), editor: editorVersion(root), files: inventory, overrides });
|
|
80
|
+
}
|
|
81
|
+
return { version: PKG.version, dryRun, counts: count(actions), overrides, actions: dryRun ? actions.filter(a => a.action !== "keep") : undefined };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function count(actions) { return actions.reduce((acc, a) => { acc[a.action] = (acc[a.action] ?? 0) + 1; return acc; }, {}); }
|
|
85
|
+
|
|
86
|
+
// Merge our hooks and deny rules into .claude/settings.json without touching anything else.
|
|
87
|
+
export function mergeSettings(root) {
|
|
88
|
+
const fragment = readJson(path.join(TEMPLATE, "settings.fragment.json"));
|
|
89
|
+
const file = at(root, "settings");
|
|
90
|
+
const settings = exists(file) ? readJson(file) : {};
|
|
91
|
+
settings.permissions ??= {};
|
|
92
|
+
settings.permissions.deny = [...new Set([...(settings.permissions.deny ?? []), ...fragment.permissions.deny])];
|
|
93
|
+
settings.hooks ??= {};
|
|
94
|
+
for (const [event, entries] of Object.entries(fragment.hooks)) {
|
|
95
|
+
const existing = (settings.hooks[event] ?? []).filter(e => !isOurs(e));
|
|
96
|
+
settings.hooks[event] = [...existing, ...entries];
|
|
97
|
+
}
|
|
98
|
+
writeJson(file, settings);
|
|
99
|
+
}
|
|
100
|
+
export function removeSettings(root) {
|
|
101
|
+
const file = at(root, "settings");
|
|
102
|
+
if (!exists(file)) return;
|
|
103
|
+
const settings = readJson(file);
|
|
104
|
+
for (const [event, entries] of Object.entries(settings.hooks ?? {})) {
|
|
105
|
+
settings.hooks[event] = entries.filter(e => !isOurs(e));
|
|
106
|
+
if (!settings.hooks[event].length) delete settings.hooks[event];
|
|
107
|
+
}
|
|
108
|
+
if (settings.hooks && !Object.keys(settings.hooks).length) delete settings.hooks;
|
|
109
|
+
writeJson(file, settings);
|
|
110
|
+
}
|
|
111
|
+
const isOurs = entry => (entry.hooks ?? []).some(h => (h.args ?? []).some(a => String(a).includes("/.claude/nccgs/runtime/hooks/")) || String(h.command ?? "").includes(".claude/nccgs/runtime/hooks/"));
|
package/cli/release.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// nccgs release: a changelog section from the tasks closed between two points in time.
|
|
2
|
+
// Points are git refs (tags, commits; dates come from `git log -1 --format=%cI`) or ISO dates.
|
|
3
|
+
// Output: Markdown grouped by outcome, each task with its criteria score, tests, review and report link.
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { spawnToolSync } from "./spawn.mjs";
|
|
6
|
+
import { writeText, toPosix } from "../runtime/core/fs.mjs";
|
|
7
|
+
import { at, loadConfig } from "../runtime/core/project.mjs";
|
|
8
|
+
import { listTasks } from "../runtime/task/ledger.mjs";
|
|
9
|
+
import { reportModel } from "../runtime/task/report.mjs";
|
|
10
|
+
import { fmtTokens } from "../runtime/task/cost.mjs";
|
|
11
|
+
|
|
12
|
+
function refDate(root, ref) {
|
|
13
|
+
if (!ref || ref === "now") return Date.now();
|
|
14
|
+
if (/^\d{4}-\d{2}-\d{2}/.test(ref)) return Date.parse(ref);
|
|
15
|
+
const r = spawnToolSync("git", ["log", "-1", "--format=%cI", ref], { cwd: root, encoding: "utf8", windowsHide: true, timeout: 15000 });
|
|
16
|
+
if (r.status !== 0 || !r.stdout.trim()) throw new Error(`cannot resolve ${ref} to a date: not an ISO date and git says "${(r.stderr || "").trim().slice(0, 120)}"`);
|
|
17
|
+
return Date.parse(r.stdout.trim());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function release(root, { from, to = "now", name, write = true } = {}) {
|
|
21
|
+
const fromMs = from ? refDate(root, from) : 0;
|
|
22
|
+
const toMs = refDate(root, to);
|
|
23
|
+
if (!(toMs > fromMs)) throw new Error("`to` must be after `from`");
|
|
24
|
+
const config = loadConfig(root);
|
|
25
|
+
const lang = config.report?.language === "vi" ? "vi" : "en";
|
|
26
|
+
const t = lang === "vi" ? VI : EN;
|
|
27
|
+
const tasks = listTasks(root).filter(x => x.status === "closed" && Date.parse(x.closedAt) > fromMs && Date.parse(x.closedAt) <= toMs).sort((a, b) => a.closedAt < b.closedAt ? -1 : 1);
|
|
28
|
+
const models = tasks.map(task => reportModel(root, task));
|
|
29
|
+
const label = name ?? (to === "now" ? new Date(toMs).toISOString().slice(0, 10) : to);
|
|
30
|
+
const lines = [`## ${label}${from ? ` (${t.since} ${from})` : ""}`, ""];
|
|
31
|
+
const groups = [["success", t.shipped], ["partial", t.partial], ["blocked", t.blocked], ["failed", t.failed]];
|
|
32
|
+
let any = false;
|
|
33
|
+
for (const [outcome, title] of groups) {
|
|
34
|
+
const g = models.filter(m => m.task.outcome === outcome);
|
|
35
|
+
if (!g.length) continue;
|
|
36
|
+
any = true;
|
|
37
|
+
lines.push(`### ${title}`, "");
|
|
38
|
+
for (const m of g) {
|
|
39
|
+
const rel = toPosix(path.relative(root, path.join(at(root, "reports"), `${m.task.id}.md`)));
|
|
40
|
+
const bits = [`${t.criteriaShort} ${m.evaluation.summary.pass}/${m.evaluation.summary.total}`];
|
|
41
|
+
if (m.tests) bits.push(`${t.testsShort} ${m.tests.passed}/${m.tests.total}`);
|
|
42
|
+
if (m.review) bits.push(`${t.reviewShort} ${m.review.verdict}${m.review.model ? ` (${m.review.model})` : ""}`);
|
|
43
|
+
if (m.cost?.total?.messages) bits.push(`${fmtTokens(m.cost.total.output)} ${t.tokensOut}`);
|
|
44
|
+
const open = m.findings.filter(f => !f.resolved);
|
|
45
|
+
lines.push(`- **${m.task.id}** ${m.task.title} — ${bits.join(" · ")} — [${t.report}](${rel})${open.length ? ` — ${open.length} ${t.openFindings}` : ""}`);
|
|
46
|
+
}
|
|
47
|
+
lines.push("");
|
|
48
|
+
}
|
|
49
|
+
if (!any) lines.push(t.nothing, "");
|
|
50
|
+
const totals = models.reduce((a, m) => ({ tasks: a.tasks + 1, tests: a.tests + (m.tests?.total ?? 0), out: a.out + (m.cost?.total?.output ?? 0), fix: a.fix + m.task.fixRounds }), { tasks: 0, tests: 0, out: 0, fix: 0 });
|
|
51
|
+
if (any) lines.push(`${t.totals}: ${totals.tasks} ${t.tasksWord} · ${totals.tests} ${t.testsWord} · ${totals.fix} ${t.fixRounds} · ${fmtTokens(totals.out)} ${t.tokensOut}`, "");
|
|
52
|
+
const markdown = lines.join("\n");
|
|
53
|
+
let file = null;
|
|
54
|
+
if (write) { file = path.join(at(root, "nccgs"), "releases", `${label.replace(/[^\w.-]+/g, "_")}.md`); writeText(file, markdown); }
|
|
55
|
+
return { label, from: from ?? null, to, tasks: tasks.map(x => x.id), file, markdown };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const EN = { since: "since", shipped: "Shipped", partial: "Partial", blocked: "Blocked", failed: "Failed", criteriaShort: "criteria", testsShort: "tests", reviewShort: "review", tokensOut: "tokens out", report: "report", openFindings: "open finding(s)", nothing: "No tasks closed in this range.", totals: "Totals", tasksWord: "tasks", testsWord: "tests", fixRounds: "fix rounds" };
|
|
59
|
+
const VI = { since: "từ", shipped: "Đã giao", partial: "Dở dang", blocked: "Bị chặn", failed: "Thất bại", criteriaShort: "tiêu chí", testsShort: "test", reviewShort: "review", tokensOut: "token ra", report: "report", openFindings: "finding còn mở", nothing: "Không có task nào đóng trong khoảng này.", totals: "Tổng", tasksWord: "task", testsWord: "test", fixRounds: "vòng sửa" };
|
package/cli/run.mjs
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// nccgs run: launch Claude Code for a project with NCCGS's permission and transport policy.
|
|
2
|
+
// acceptEdits by default; bypassPermissions only with --autonomy full (or config.autonomy = full).
|
|
3
|
+
import { spawnTool } from "./spawn.mjs";
|
|
4
|
+
import { readJson, exists } from "../runtime/core/fs.mjs";
|
|
5
|
+
import { at, isUnityProject, loadConfig } from "../runtime/core/project.mjs";
|
|
6
|
+
import { allModes } from "../runtime/core/modes.mjs";
|
|
7
|
+
import { checkUpdates } from "./update-check.mjs";
|
|
8
|
+
|
|
9
|
+
const OWNED = /^(--permission-mode|--dangerously-skip-permissions|--allow-dangerously-skip-permissions|--strict-mcp-config|--mcp-config|--model)(=|$)/;
|
|
10
|
+
|
|
11
|
+
export async function plan(root, { mode, autonomy, forwarded = [], claudeBin = process.env.NCCGS_CLAUDE_BIN || "claude" } = {}) {
|
|
12
|
+
if (!isUnityProject(root)) throw new Error(`${root} is not a Unity project`);
|
|
13
|
+
if (!exists(at(root, "installState"))) throw new Error("NCCGS is not installed here; run `nccgs install --project <dir>`");
|
|
14
|
+
const config = loadConfig(root);
|
|
15
|
+
const modeName = mode || config.mode;
|
|
16
|
+
const modes = allModes(root);
|
|
17
|
+
if (!modes[modeName]) throw new Error(`Unknown mode ${modeName}`);
|
|
18
|
+
const auto = autonomy || config.autonomy;
|
|
19
|
+
if (!["guarded", "full"].includes(auto)) throw new Error("autonomy must be guarded | full");
|
|
20
|
+
for (const a of forwarded) if (OWNED.test(a)) throw new Error(`NCCGS owns ${a}; set it through project.json or nccgs mode`);
|
|
21
|
+
const coordinator = modes[modeName].coordinator ?? {};
|
|
22
|
+
const args = ["--permission-mode", auto === "full" ? "bypassPermissions" : "acceptEdits", "--strict-mcp-config", "--mcp-config", '{"mcpServers":{}}'];
|
|
23
|
+
if (coordinator.model && coordinator.model !== "inherit") args.push("--model", coordinator.model);
|
|
24
|
+
const env = { ...process.env, NCCGS_PROJECT_ROOT: root, NCCGS_MODE: modeName, NCCGS_AUTONOMY: auto, CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" };
|
|
25
|
+
return { root, claudeBin, args: [...args, ...forwarded], env, mode: modeName, autonomy: auto, coordinator };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function launch(root, options = {}) {
|
|
29
|
+
const p = await plan(root, options);
|
|
30
|
+
try { await checkUpdates(root); } catch {}
|
|
31
|
+
process.stderr.write(`NCCGS run · ${p.mode} · ${p.autonomy === "full" ? "bypassPermissions (full autonomy)" : "acceptEdits"} · ${p.root}\n`);
|
|
32
|
+
if (options.dryRun) return { ...p, env: undefined };
|
|
33
|
+
const child = spawnTool(p.claudeBin, p.args, { cwd: p.root, env: p.env, stdio: "inherit", windowsHide: false });
|
|
34
|
+
return new Promise(resolve => child.on("close", code => resolve({ ...p, env: undefined, exitCode: code })));
|
|
35
|
+
}
|
package/cli/spawn.mjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Spawn helpers that avoid `shell: true` + args (Node DEP0190) while still resolving .cmd shims on Windows.
|
|
2
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
3
|
+
|
|
4
|
+
const win = process.platform === "win32";
|
|
5
|
+
// Quote one argument for cmd.exe /c: wrap in double quotes, escape embedded quotes, neutralise cmd metacharacters.
|
|
6
|
+
export function quoteWin(arg) {
|
|
7
|
+
const s = String(arg);
|
|
8
|
+
const body = /[\s"]/.test(s) || s === "" ? `"${s.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/, "$1$1")}"` : s;
|
|
9
|
+
return body.replace(/([()%!^<>&|])/g, "^$1");
|
|
10
|
+
}
|
|
11
|
+
export function commandLine(bin, args) { return [bin, ...args].map(quoteWin).join(" "); }
|
|
12
|
+
|
|
13
|
+
export function spawnTool(bin, args, options = {}) {
|
|
14
|
+
if (!win) return spawn(bin, args, options);
|
|
15
|
+
return spawn("cmd.exe", ["/d", "/s", "/c", `"${commandLine(bin, args)}"`], { ...options, windowsVerbatimArguments: true });
|
|
16
|
+
}
|
|
17
|
+
export function spawnToolSync(bin, args, options = {}) {
|
|
18
|
+
if (!win) return spawnSync(bin, args, options);
|
|
19
|
+
return spawnSync("cmd.exe", ["/d", "/s", "/c", `"${commandLine(bin, args)}"`], { ...options, windowsVerbatimArguments: true });
|
|
20
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// nccgs uninstall: remove managed files that are unchanged, detach hooks, keep .nccgs/ history
|
|
2
|
+
// and anything the user modified. Everything removed is copied to .nccgs/backups/<id>/ first.
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { readJson, writeJson, exists, sha256File, nowIso } from "../runtime/core/fs.mjs";
|
|
6
|
+
import { at } from "../runtime/core/project.mjs";
|
|
7
|
+
import { removeSettings } from "./install.mjs";
|
|
8
|
+
import { openTasks } from "../runtime/task/ledger.mjs";
|
|
9
|
+
|
|
10
|
+
export function uninstall(root, { dryRun = false, force = false } = {}) {
|
|
11
|
+
const stateFile = at(root, "installState");
|
|
12
|
+
if (!exists(stateFile)) throw new Error("NCCGS is not installed here");
|
|
13
|
+
const state = readJson(stateFile);
|
|
14
|
+
const open = openTasks(root);
|
|
15
|
+
if (open.length && !force) throw new Error(`open tasks: ${open.map(t => t.id).join(", ")}. Close them or pass --force (history is kept either way)`);
|
|
16
|
+
const id = `uninstall-${nowIso().replace(/[:.]/g, "-")}`;
|
|
17
|
+
const backup = path.join(root, ".nccgs", "backups", id);
|
|
18
|
+
const removed = [], kept = [];
|
|
19
|
+
for (const [rel, sha] of Object.entries(state.files ?? {})) {
|
|
20
|
+
const file = path.join(root, rel);
|
|
21
|
+
if (!exists(file)) continue;
|
|
22
|
+
if (sha256File(file) !== sha && !force) { kept.push(rel); continue; }
|
|
23
|
+
removed.push(rel);
|
|
24
|
+
if (!dryRun) {
|
|
25
|
+
const dest = path.join(backup, rel); fs.mkdirSync(path.dirname(dest), { recursive: true }); fs.copyFileSync(file, dest); fs.unlinkSync(file);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const agentsDir = at(root, "agents");
|
|
29
|
+
if (exists(agentsDir)) for (const f of fs.readdirSync(agentsDir)) if (/^nccgs-.*\.md$/.test(f)) { removed.push(`.claude/agents/${f}`); if (!dryRun) { const file = path.join(agentsDir, f); const dest = path.join(backup, ".claude/agents", f); fs.mkdirSync(path.dirname(dest), { recursive: true }); fs.copyFileSync(file, dest); fs.unlinkSync(file); } }
|
|
30
|
+
if (!dryRun) {
|
|
31
|
+
removeSettings(root);
|
|
32
|
+
writeJson(path.join(backup, "manifest.json"), { id, at: nowIso(), version: state.version, removed, kept });
|
|
33
|
+
fs.unlinkSync(stateFile);
|
|
34
|
+
pruneEmpty(path.join(root, ".claude"));
|
|
35
|
+
}
|
|
36
|
+
return { id, dryRun, removed: removed.length, kept, backup: path.relative(root, backup), note: ".nccgs/ (tasks, evidence, reports, config) is kept" };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function pruneEmpty(dir) {
|
|
40
|
+
if (!exists(dir)) return;
|
|
41
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) if (entry.isDirectory()) pruneEmpty(path.join(dir, entry.name));
|
|
42
|
+
if (!fs.readdirSync(dir).length) fs.rmdirSync(dir);
|
|
43
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Update notices: NCCGS (npm), Unity Skills (GitHub HEAD), Unity CLI (its own notification), Pipeline.
|
|
2
|
+
// Notify only. Never installs. Cached once per day under .nccgs/cache; every source has a 3 s timeout
|
|
3
|
+
// and network failures are silent.
|
|
4
|
+
import { readJson, writeJson, exists } from "../runtime/core/fs.mjs";
|
|
5
|
+
import { at, loadConfig, pipelineVersion } from "../runtime/core/project.mjs";
|
|
6
|
+
import { PKG, PKG_ROOT } from "./install.mjs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { run } from "../runtime/core/process-tree.mjs";
|
|
9
|
+
import { UNITY_BIN, unityArgv } from "../runtime/unity/unity.mjs";
|
|
10
|
+
|
|
11
|
+
const DAY = 86400000;
|
|
12
|
+
// semver compare with prerelease: 3.0.0-alpha.1 < 3.0.0 ; 2.1.1 < 3.0.0-alpha.1
|
|
13
|
+
export function newer(latest, current) {
|
|
14
|
+
const parse = v => { const m = String(v).match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([\w.-]+))?/); return m ? { n: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ?? null } : null; };
|
|
15
|
+
const a = parse(latest), b = parse(current); if (!a || !b) return false;
|
|
16
|
+
for (let i = 0; i < 3; i++) if (a.n[i] !== b.n[i]) return a.n[i] > b.n[i];
|
|
17
|
+
if (a.pre === b.pre) return false; if (a.pre === null) return true; if (b.pre === null) return false; return a.pre > b.pre;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function fetchJson(url, timeoutMs = 3000) {
|
|
21
|
+
const ctl = new AbortController();
|
|
22
|
+
const t = setTimeout(() => ctl.abort(), timeoutMs);
|
|
23
|
+
try {
|
|
24
|
+
const r = await fetch(url, { signal: ctl.signal, headers: { "user-agent": `nccgs/${PKG.version}`, accept: "application/json" } });
|
|
25
|
+
if (!r.ok) return null;
|
|
26
|
+
return await r.json();
|
|
27
|
+
} catch { return null; } finally { clearTimeout(t); }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function checkUpdates(root, { force = false, cliVersion = null } = {}) {
|
|
31
|
+
const config = loadConfig(root);
|
|
32
|
+
const file = at(root, "updateCheck");
|
|
33
|
+
const cached = exists(file) ? readJson(file) : null;
|
|
34
|
+
const interval = config.updates.check === "weekly" ? 7 * DAY : config.updates.check === "never" ? Infinity : DAY;
|
|
35
|
+
if (!force && cached && Date.now() - Date.parse(cached.checkedAt) < interval) return cached;
|
|
36
|
+
if (config.updates.check === "never" && !force) return { checkedAt: new Date().toISOString(), notices: [], skipped: true };
|
|
37
|
+
const channels = new Set(config.updates.channels ?? []);
|
|
38
|
+
const notices = [];
|
|
39
|
+
const sources = {};
|
|
40
|
+
if (channels.has("nccgs")) {
|
|
41
|
+
const j = await fetchJson("https://registry.npmjs.org/nccgs/latest");
|
|
42
|
+
sources.nccgs = j?.version ?? null;
|
|
43
|
+
if (j?.version && newer(j.version, PKG.version)) notices.push({ component: "nccgs", current: PKG.version, latest: j.version, hint: "npx nccgs@latest update --project . --dry-run" });
|
|
44
|
+
}
|
|
45
|
+
if (channels.has("unity-skills")) {
|
|
46
|
+
const manifest = readJson(path.join(PKG_ROOT, "unity-skills", "manifest.json"), {});
|
|
47
|
+
const j = await fetchJson("https://api.github.com/repos/Unity-Technologies/skills/commits/main");
|
|
48
|
+
sources.unitySkills = j?.sha ?? null;
|
|
49
|
+
if (j?.sha && manifest.source_revision && !j.sha.startsWith(manifest.source_revision) && manifest.source_revision !== "unknown-local-copy") notices.push({ component: "unity-skills", current: manifest.source_revision.slice(0, 7), latest: j.sha.slice(0, 7), hint: "nccgs update --skills-only --dry-run" });
|
|
50
|
+
else if (j?.sha && manifest.source_revision === "unknown-local-copy") notices.push({ component: "unity-skills", current: "unknown", latest: j.sha.slice(0, 7), hint: "node scripts/sync-unity-skills.mjs to pin a commit" });
|
|
51
|
+
}
|
|
52
|
+
if (channels.has("unity-cli")) {
|
|
53
|
+
// The CLI reports its own update in the JSON envelope's notifications (seen on beta.14).
|
|
54
|
+
const r = await run(UNITY_BIN, unityArgv(["editors", "--installed", "--format", "json"]), { timeoutMs: 8000 });
|
|
55
|
+
try {
|
|
56
|
+
const j = JSON.parse(r.stdout.replace(/^/, ""));
|
|
57
|
+
const n = (j.notifications ?? []).find(x => x.code === "CLI_UPDATE_AVAILABLE");
|
|
58
|
+
sources.unityCli = n?.data?.latest ?? cliVersion;
|
|
59
|
+
if (n) notices.push({ component: "unity-cli", current: n.data.current, latest: n.data.latest, hint: n.remediation?.command ?? "unity self-update" });
|
|
60
|
+
} catch {}
|
|
61
|
+
}
|
|
62
|
+
if (channels.has("pipeline")) sources.pipeline = pipelineVersion(root); // latest version requires a registry call we do not make in alpha
|
|
63
|
+
const value = { checkedAt: new Date().toISOString(), notices, sources };
|
|
64
|
+
writeJson(file, value);
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Evidence layer verification (2026-11-04)
|
|
2
|
+
|
|
3
|
+
Machine: Windows x64, Node 24.12, Claude Code 2.1.316, Unity CLI 1.0.0-beta.14, com.unity.pipeline 0.9.1-exp.1.
|
|
4
|
+
Projects: TestNCCGS1 (6000.3.17f1) and TestNCCGS2 (6000.6.7f1), both open in the Editor.
|
|
5
|
+
|
|
6
|
+
| Capability | Command | 6000.3.17f1 | 6000.6.7f1 |
|
|
7
|
+
|---|---|---|---|
|
|
8
|
+
| Tests with the project open | `test run --mode editor` (Pipeline) - `unity test` refuses with "already open" (exit 6) | OK | OK |
|
|
9
|
+
| Enter / exit Play Mode | `editor.playmode start` / `stop` | OK | OK |
|
|
10
|
+
| First command after Play start | `script eval` | EDITOR_NOT_RUNNING for ~3 s (domain reload), then OK | OK after 1 s |
|
|
11
|
+
| Screenshot | `capture screenshot --view game --output <abs>` | OK (PNG seen) | OK |
|
|
12
|
+
| Console | `console status` / `console get` | OK | OK |
|
|
13
|
+
| Simulated input | `runtime simulate_key --key Space` | OK | OK |
|
|
14
|
+
| Performance | `diagnostics get_performance` | OK | OK |
|
|
15
|
+
| Command discovery | `command --detail compact` (166 commands, 37 groups), `--query`, `--obsolete-command-names` | OK | OK |
|
|
16
|
+
| Orphan processes after tests | none new after 10 s | 0 | not measured |
|
|
17
|
+
|
|
18
|
+
NCCGS 3.0.0-alpha.1 end-to-end on TestNCCGS1: `install` (152 files) → `doctor` 11 pass / 0 fail → `task open` (3 criteria, observe auto-added) → `verify --kind tests` (pipeline, 4 s) → `verify --kind observe` (Play, Space, 2 screenshots, console, performance, stop; 21 s; 3/3 criteria pass) → `review` prompt written → `close --outcome success` correctly refused without a review.
|
|
19
|
+
|
|
20
|
+
Consequences baked into the runtime: live/batch selection by `unity status`; `waitReady` after Play start; names resolved from the catalog cache; `--editor-version` pinned from ProjectVersion.txt; `capture game_view --save_path` avoided (writes under Assets/).
|
|
21
|
+
|
|
22
|
+
Added during phases 2–4 (all measured on 6000.3.17f1 / Pipeline 0.9.1-exp.1): `simulate_key` delivers key-down and key-up in one input update (polling misses it; `InputAction` does not); PlayMode tests only run async (`--async_tests` + `test status`); each Pipeline round trip costs ~0.9 s, so sub-second timing is scheduled inside the Editor by one `script eval` (`observe --shots`, playtests with probes at 10 Hz and reactive rules); `script eval` is a method body without `using` and can reference the project's own types; `set_run_in_background` keeps Play Mode alive when the Editor loses focus; the Editor rewrites `ProjectSettings/ShaderGraphSettings.asset` and `SceneTemplateSettings.json` on its own (excluded from snapshots).
|
package/package.json
CHANGED
|
@@ -1,47 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nccgs",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Unity-first
|
|
3
|
+
"version": "3.0.0-rc.2",
|
|
4
|
+
"description": "NCCGS 3 - a Unity-first evidence loop for Claude Code: contract, run, look, review, report.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"nccgs": "
|
|
8
|
+
"nccgs": "bin/nccgs.mjs"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=20"
|
|
9
12
|
},
|
|
10
13
|
"files": [
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
14
|
+
"bin/",
|
|
15
|
+
"cli/",
|
|
16
|
+
"runtime/",
|
|
17
|
+
"template/",
|
|
18
|
+
"unity-skills/",
|
|
15
19
|
"scripts/",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"MEMORY.md",
|
|
19
|
-
"LICENSE",
|
|
20
|
+
"docs/",
|
|
21
|
+
"tools/",
|
|
20
22
|
"README.md",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"CHANGELOG.md"
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"THIRD_PARTY_NOTICES.md"
|
|
25
26
|
],
|
|
26
|
-
"engines": {
|
|
27
|
-
"node": ">=18"
|
|
28
|
-
},
|
|
29
|
-
"publishConfig": {
|
|
30
|
-
"access": "public",
|
|
31
|
-
"tag": "latest",
|
|
32
|
-
"registry": "https://registry.npmjs.org/"
|
|
33
|
-
},
|
|
34
27
|
"scripts": {
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
28
|
+
"test": "node --test test/*.test.mjs",
|
|
29
|
+
"pack:check": "npm pack --dry-run"
|
|
30
|
+
},
|
|
31
|
+
"optionalDependencies": {
|
|
32
|
+
"koffi": "^3.3.6"
|
|
40
33
|
},
|
|
41
34
|
"keywords": [
|
|
42
35
|
"claude-code",
|
|
43
|
-
"game-development",
|
|
44
36
|
"unity",
|
|
45
|
-
"
|
|
37
|
+
"game-development",
|
|
38
|
+
"evidence"
|
|
46
39
|
]
|
|
47
40
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Diagnostics: .nccgs/diagnostics.jsonl, one line per thing that went wrong or was blocked —
|
|
2
|
+
// runtime errors, failed verifications, Unity CLI/Pipeline failures, hook blocks. Local only; nothing
|
|
3
|
+
// leaves the machine unless the person runs `nccgs feedback` and sends the bundle themselves.
|
|
4
|
+
// Rotated at 5 MB (the previous file is kept once as diagnostics.1.jsonl).
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { at } from "./project.mjs";
|
|
8
|
+
import { appendLine, readText } from "./fs.mjs";
|
|
9
|
+
|
|
10
|
+
const MAX = 5 * 1024 * 1024;
|
|
11
|
+
export const diagFile = root => path.join(at(root, "nccgs"), "diagnostics.jsonl");
|
|
12
|
+
|
|
13
|
+
export function diag(root, kind, data = {}) {
|
|
14
|
+
try {
|
|
15
|
+
const file = diagFile(root);
|
|
16
|
+
try { if (fs.existsSync(file) && fs.statSync(file).size > MAX) fs.renameSync(file, file.replace(/\.jsonl$/, ".1.jsonl")); } catch {}
|
|
17
|
+
appendLine(file, JSON.stringify({ ...clean(data), at: new Date().toISOString(), kind, pid: process.pid }));
|
|
18
|
+
} catch {}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Keep entries small and free of secrets: strings capped, absolute user paths trimmed, env never copied.
|
|
22
|
+
function clean(data) {
|
|
23
|
+
const out = {};
|
|
24
|
+
for (const [k, v] of Object.entries(data)) {
|
|
25
|
+
if (v === undefined) continue;
|
|
26
|
+
if (typeof v === "string") out[k] = v.length > 2000 ? v.slice(0, 2000) + "…" : v;
|
|
27
|
+
else if (v instanceof Error) out[k] = { message: v.message, stack: String(v.stack ?? "").split("\n").slice(0, 6).join("\n") };
|
|
28
|
+
else if (Array.isArray(v)) out[k] = v.slice(0, 50).map(x => typeof x === "string" && x.length > 500 ? x.slice(0, 500) + "…" : x);
|
|
29
|
+
else out[k] = v;
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function readDiag(root, { sinceMs = 0 } = {}) {
|
|
35
|
+
const out = [];
|
|
36
|
+
for (const f of [diagFile(root).replace(/\.jsonl$/, ".1.jsonl"), diagFile(root)]) {
|
|
37
|
+
for (const line of readText(f, "").split("\n")) {
|
|
38
|
+
if (!line.trim()) continue;
|
|
39
|
+
try { const j = JSON.parse(line); if (Date.parse(j.at) >= sinceMs) out.push(j); } catch {}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// When to suggest or send feedback. Pure functions over the ledger and diagnostics; the hooks and the
|
|
2
|
+
// task CLI call `evaluate()` and act on consent. Everything is rate-limited so a person is asked at
|
|
3
|
+
// most once per 6 hours and the periodic bundle goes at most once per `periodicDays`.
|
|
4
|
+
import { loadConfig, saveConfig } from "./project.mjs";
|
|
5
|
+
import { readDiag } from "./diag.mjs";
|
|
6
|
+
import { listTasks } from "../task/ledger.mjs";
|
|
7
|
+
|
|
8
|
+
const HOUR = 3600000, DAY = 86400000;
|
|
9
|
+
const ISSUE_KINDS = { "task.exception": 1, "hook.error": 1, "unity.failed": 3, "verify.failed": 5, "task.error": 8 };
|
|
10
|
+
|
|
11
|
+
export function evaluate(root, { now = Date.now(), config = loadConfig(root) } = {}) {
|
|
12
|
+
const fb = config.feedback ?? {};
|
|
13
|
+
if (fb.consent === "off") return { action: "none", reasons: [] };
|
|
14
|
+
const since = Date.parse(fb.lastSentAt ?? 0) || 0;
|
|
15
|
+
const diags = readDiag(root, { sinceMs: since });
|
|
16
|
+
const counts = {};
|
|
17
|
+
for (const d of diags) counts[d.kind] = (counts[d.kind] ?? 0) + 1;
|
|
18
|
+
const reasons = [];
|
|
19
|
+
for (const [kind, threshold] of Object.entries(ISSUE_KINDS)) if ((counts[kind] ?? 0) >= threshold) reasons.push(`${counts[kind]} × ${kind}`);
|
|
20
|
+
const bad = listTasks(root).filter(t => t.status === "closed" && t.outcome !== "success" && Date.parse(t.closedAt) > since && !/^T-|^PT-/.test(t.id));
|
|
21
|
+
if (bad.length) reasons.push(`${bad.length} task(s) closed ${[...new Set(bad.map(t => t.outcome))].join("/")}: ${bad.map(t => t.id).slice(0, 5).join(", ")}`);
|
|
22
|
+
const periodicDue = (fb.periodicDays ?? 7) > 0 && now - since >= (fb.periodicDays ?? 7) * DAY && listTasks(root).some(t => Date.parse(t.updatedAt ?? t.openedAt) > since);
|
|
23
|
+
if (periodicDue) reasons.push(`periodic (${fb.periodicDays ?? 7} days)`);
|
|
24
|
+
if (!reasons.length) return { action: "none", reasons: [], counts };
|
|
25
|
+
if (fb.consent === "ask") return { action: "ask-consent", reasons, counts };
|
|
26
|
+
if (fb.consent === "auto") return { action: "send", reasons, counts };
|
|
27
|
+
const suggestedRecently = now - (Date.parse(fb.lastSuggestedAt ?? 0) || 0) < 6 * HOUR;
|
|
28
|
+
return { action: suggestedRecently ? "none" : "suggest", reasons, counts };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function setConsent(root, consent) {
|
|
32
|
+
if (!["ask", "auto", "manual", "off"].includes(consent)) throw new Error("consent must be ask | auto | manual | off");
|
|
33
|
+
const config = loadConfig(root);
|
|
34
|
+
config.feedback = { ...(config.feedback ?? {}), consent };
|
|
35
|
+
saveConfig(root, config);
|
|
36
|
+
return config.feedback;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function markSuggested(root, now = new Date().toISOString()) {
|
|
40
|
+
const config = loadConfig(root);
|
|
41
|
+
config.feedback = { ...(config.feedback ?? {}), lastSuggestedAt: now };
|
|
42
|
+
saveConfig(root, config);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function markSent(root, now = new Date().toISOString()) {
|
|
46
|
+
const config = loadConfig(root);
|
|
47
|
+
config.feedback = { ...(config.feedback ?? {}), lastSentAt: now };
|
|
48
|
+
saveConfig(root, config);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const CONSENT_TEXT = {
|
|
52
|
+
en: "NCCGS can send anonymous-ish feedback bundles to its maintainers when something fails or every 7 days: versions, doctor output, per-task numbers (criteria, tests, review verdicts, fix rounds, minutes, tokens), diagnostics and any note you add. Project name and task titles are included; source code, screenshots, transcripts and credentials never are. Options: auto (send by itself), manual (only suggest `/feedback`), off (never). Change later with `npx nccgs feedback --consent <auto|manual|off>`.",
|
|
53
|
+
vi: "NCCGS có thể gửi gói feedback cho nhóm phát triển khi có lỗi hoặc mỗi 7 ngày: phiên bản, kết quả doctor, số liệu từng task (criteria, test, verdict review, vòng sửa, phút, token), diagnostics và ghi chú của bạn. Tên dự án và tiêu đề task có trong gói; mã nguồn, ảnh, transcript và credential không bao giờ có. Lựa chọn: auto (tự gửi), manual (chỉ gợi ý `/feedback`), off (không bao giờ). Đổi sau bằng `npx nccgs feedback --consent <auto|manual|off>`."
|
|
54
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Small filesystem helpers shared by the runtime and the CLI. No dependencies.
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import crypto from "node:crypto";
|
|
5
|
+
|
|
6
|
+
export const exists = p => fs.existsSync(p);
|
|
7
|
+
|
|
8
|
+
export function readJson(file, fallback = undefined) {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(fs.readFileSync(file, "utf8").replace(/^/, ""));
|
|
11
|
+
} catch (error) {
|
|
12
|
+
if (fallback !== undefined && error.code === "ENOENT") return fallback;
|
|
13
|
+
throw new Error(`Cannot read JSON ${file}: ${error.message}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Atomic write: write to a sibling temp file, then rename over the target.
|
|
18
|
+
export function writeJson(file, value) {
|
|
19
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
20
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
21
|
+
fs.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
22
|
+
fs.renameSync(tmp, file);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function writeText(file, text) {
|
|
26
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
27
|
+
fs.writeFileSync(file, text, "utf8");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function readText(file, fallback = "") {
|
|
31
|
+
try { return fs.readFileSync(file, "utf8").replace(/^/, ""); } catch { return fallback; }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function appendLine(file, line) {
|
|
35
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
36
|
+
fs.appendFileSync(file, line.endsWith("\n") ? line : line + "\n", "utf8");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const sha256 = buffer => crypto.createHash("sha256").update(buffer).digest("hex");
|
|
40
|
+
export const sha256File = file => sha256(fs.readFileSync(file));
|
|
41
|
+
|
|
42
|
+
// Resolve `relative` under `root` and refuse anything that escapes it.
|
|
43
|
+
export function contained(root, relative) {
|
|
44
|
+
const absolute = path.resolve(root, relative);
|
|
45
|
+
const rel = path.relative(root, absolute);
|
|
46
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) throw new Error(`Path escapes project: ${relative}`);
|
|
47
|
+
return absolute;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const toPosix = p => p.split(path.sep).join("/");
|
|
51
|
+
|
|
52
|
+
// Walk a directory tree (files only), skipping the given directory names.
|
|
53
|
+
export function* walk(dir, { skipDirs = new Set(), maxFiles = Infinity } = {}) {
|
|
54
|
+
const stack = [dir];
|
|
55
|
+
let count = 0;
|
|
56
|
+
while (stack.length) {
|
|
57
|
+
const current = stack.pop();
|
|
58
|
+
let entries;
|
|
59
|
+
try { entries = fs.readdirSync(current, { withFileTypes: true }); } catch { continue; }
|
|
60
|
+
for (const entry of entries) {
|
|
61
|
+
const full = path.join(current, entry.name);
|
|
62
|
+
if (entry.isDirectory()) { if (!skipDirs.has(entry.name)) stack.push(full); }
|
|
63
|
+
else if (entry.isFile()) { yield full; if (++count >= maxFiles) return; }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function copyDir(from, to, { filter = () => true, onFile } = {}) {
|
|
69
|
+
for (const file of walk(from)) {
|
|
70
|
+
const rel = path.relative(from, file);
|
|
71
|
+
if (!filter(rel)) continue;
|
|
72
|
+
const target = path.join(to, rel);
|
|
73
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
74
|
+
fs.copyFileSync(file, target);
|
|
75
|
+
onFile?.(rel, target);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const nowIso = () => new Date().toISOString();
|
|
80
|
+
export const shortId = () => crypto.randomBytes(4).toString("hex");
|