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,680 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import crypto from "node:crypto";
|
|
4
|
-
import { spawnSync } from "node:child_process";
|
|
5
|
-
import { artifact, atomicJson, contained, hash, json, loadPipeline, resolveExecution, verifyArtifact } from "./policy.mjs";
|
|
6
|
-
import { snapshot, taskPath, check } from "./gates.mjs";
|
|
7
|
-
import { acquireLock } from "./process-lock.mjs";
|
|
8
|
-
import { deliveryBudget, requireDeliveryRoom, dispatchPurpose, requireEarlyCheckpoint } from "./delivery-budget.mjs";
|
|
9
|
-
import { pinRepairPacket, verifyRepairPacket, repairPrompt, repairToolScope } from "./repair-packet.mjs";
|
|
10
|
-
import { requireDesignReady } from "./design-readiness.mjs";
|
|
11
|
-
import { handoffTemplate } from "./review-handoff.mjs";
|
|
12
|
-
import { activeSessionBudget } from "./session-budget.mjs";
|
|
13
|
-
import { plannedDispatchBudget } from "./review-budget.mjs";
|
|
14
|
-
import { captureUnityRepairScope, verifyUnityRepairScope, unityEditorInvocation, blockedUnityScene } from "./unity-repair.mjs";
|
|
15
|
-
import { validateSlicePlan, readSlicePlan, validateSliceRevision, sliceProgress, bindSlice, slicePromptContext, nextSliceRequest, sliceHash, sameSlice } from "./task-slices.mjs";
|
|
16
|
-
|
|
17
|
-
const ledgerPath = ".nccgs/orchestration.json";
|
|
18
|
-
const ledgerMarker = ".nccgs/orchestration.initialized.json";
|
|
19
|
-
const kinds = ["implementation", "analysis", "review"];
|
|
20
|
-
const states = ["reserved", "running", "uncertain", "completed", "failed", "cancelled"];
|
|
21
|
-
const active = item => ["reserved", "running", "uncertain"].includes(item.status);
|
|
22
|
-
const need = (condition, message) => { if (!condition) throw new Error(message); };
|
|
23
|
-
const now = () => new Date().toISOString();
|
|
24
|
-
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
25
|
-
function taskRecord(project, id) {
|
|
26
|
-
const task = json(taskPath(project, id));
|
|
27
|
-
need(task.schemaVersion === 2 && task.id === id, "Managed dispatch requires a standalone schema-2 task");
|
|
28
|
-
need(typeof task.contractHash === "string" && task.contractHash.length > 0, "Task contract hash missing");
|
|
29
|
-
return task;
|
|
30
|
-
}
|
|
31
|
-
function load(project) {
|
|
32
|
-
const file = contained(project, ledgerPath);
|
|
33
|
-
if (!fs.existsSync(file)) {
|
|
34
|
-
need(!fs.existsSync(contained(project, ledgerMarker)), "Orchestration ledger missing after initialization; restore history, never reset budgets");
|
|
35
|
-
return { schemaVersion: 1, tasks: {}, dispatches: {}, events: [] };
|
|
36
|
-
}
|
|
37
|
-
const ledger = json(file);
|
|
38
|
-
need(ledger.schemaVersion === 1 && ledger.tasks && ledger.dispatches && Array.isArray(ledger.events), "Invalid orchestration ledger; do not reset missing/corrupt history");
|
|
39
|
-
for (const [id, d] of Object.entries(ledger.dispatches))
|
|
40
|
-
need(d.id === id && ledger.tasks[d.taskId] && kinds.includes(d.kind) && states.includes(d.status) && d.requestKey && d.requestHash, "Corrupt dispatch ledger");
|
|
41
|
-
const reserved = ledger.events.filter(event => event.action === "reserve");
|
|
42
|
-
need(reserved.length === Object.keys(ledger.dispatches).length && new Set(reserved.map(e => e.dispatchId)).size === reserved.length, "Corrupt ledger reservation history");
|
|
43
|
-
for (const event of ledger.events) if (event.dispatchId) need(ledger.dispatches[event.dispatchId], "Corrupt ledger: event refers to missing dispatch");
|
|
44
|
-
for (const event of reserved) need(ledger.dispatches[event.dispatchId]?.taskId === event.taskId, "Corrupt ledger reservation identity");
|
|
45
|
-
const plans = new Map();
|
|
46
|
-
for (const event of ledger.events.filter(e => e.action === "slice-plan")) {
|
|
47
|
-
need(ledger.tasks[event.taskId] && event.planId && event.requestHash && event.reference?.path?.startsWith(".nccgs/evidence/slices/"), "Corrupt slice-plan history");
|
|
48
|
-
verifyArtifact(project, event.reference); plans.set(event.taskId, event);
|
|
49
|
-
}
|
|
50
|
-
for (const [id, entry] of Object.entries(ledger.tasks)) {
|
|
51
|
-
const latest = plans.get(id);
|
|
52
|
-
need(Boolean(entry.slicePlan) === Boolean(latest) && (!latest || same(entry.slicePlan, { planId: latest.planId, requestHash: latest.requestHash, reference: latest.reference })), "Slice-plan history missing or detached; restore it, never reset planned work");
|
|
53
|
-
}
|
|
54
|
-
return ledger;
|
|
55
|
-
}
|
|
56
|
-
function transaction(project, action) {
|
|
57
|
-
const lock = acquireLock(contained(project, ".nccgs/orchestration.lock"));
|
|
58
|
-
try {
|
|
59
|
-
const ledger = load(project), result = action(ledger);
|
|
60
|
-
// Marker first: a crash between these writes fails closed until recovery.
|
|
61
|
-
if (!fs.existsSync(contained(project, ledgerMarker))) atomicJson(contained(project, ledgerMarker), { schemaVersion: 1, initializedAt: now() });
|
|
62
|
-
atomicJson(contained(project, ledgerPath), ledger);
|
|
63
|
-
return result;
|
|
64
|
-
} finally { lock.release(); }
|
|
65
|
-
}
|
|
66
|
-
function chain(project, id, ledger, request = {}) {
|
|
67
|
-
const ids = [], seen = new Set();
|
|
68
|
-
for (let cursor = id; cursor;) {
|
|
69
|
-
need(!seen.has(cursor), "Task parent cycle"); seen.add(cursor);
|
|
70
|
-
const task = taskRecord(project, cursor);
|
|
71
|
-
need(task.parentId == null || typeof task.parentId === "string", "Invalid task parent");
|
|
72
|
-
const existing = Object.hasOwn(ledger.tasks, cursor) ? ledger.tasks[cursor] : null;
|
|
73
|
-
if (existing) {
|
|
74
|
-
need((existing.parentId ?? null) === (task.parentId ?? null), "Task parent changed; cannot detach spent budget");
|
|
75
|
-
if (cursor === id && request.limits) {
|
|
76
|
-
for (const [key, value] of Object.entries(request.limits)) need(existing.limits[key] === value, "Dispatch limits are pinned; do not reset/increase budget through a new request");
|
|
77
|
-
}
|
|
78
|
-
} else {
|
|
79
|
-
const limits = { maxDispatches: { FAST: task.contract?.deliveryReserve ? 6 : 4, STANDARD: 12, CONTROLLED: 24 }[task.risk] ?? 12, maxDurationMs: null, maxCostUsd: null,
|
|
80
|
-
...(cursor === id ? request.limits : {}) };
|
|
81
|
-
need(Object.keys(limits).every(k => ["maxDispatches", "maxDurationMs", "maxCostUsd"].includes(k)), "Unknown dispatch budget field");
|
|
82
|
-
need(Number.isSafeInteger(limits.maxDispatches) && limits.maxDispatches > 0 && limits.maxDispatches <= 1000, "Invalid maxDispatches budget");
|
|
83
|
-
for (const key of ["maxDurationMs", "maxCostUsd"]) need(limits[key] === null || (Number.isFinite(limits[key]) && limits[key] > 0), `Invalid ${key} budget`);
|
|
84
|
-
const deliveryReserve = task.contract?.deliveryReserve ?? null;
|
|
85
|
-
if (deliveryReserve) need(limits.maxDispatches > Object.values(deliveryReserve).reduce((a, b) => a + b, 0), "Dispatch budget cannot fit delivery plus protected repair/QA/review slots");
|
|
86
|
-
ledger.tasks[cursor] = { parentId: task.parentId ?? null, limits, deliveryReserve, registeredAt: now() };
|
|
87
|
-
}
|
|
88
|
-
ids.push(cursor); cursor = task.parentId ?? null;
|
|
89
|
-
}
|
|
90
|
-
return ids;
|
|
91
|
-
}
|
|
92
|
-
function belongs(ledger, candidate, ancestor) {
|
|
93
|
-
const seen = new Set();
|
|
94
|
-
for (let id = candidate; id; id = ledger.tasks[id]?.parentId) {
|
|
95
|
-
need(!seen.has(id), "Ledger parent cycle"); seen.add(id);
|
|
96
|
-
if (id === ancestor) return true;
|
|
97
|
-
}
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
function metric(items, name) {
|
|
101
|
-
const values = items.map(d => d.telemetry?.[name]).filter(v => Number.isFinite(v) && v >= 0);
|
|
102
|
-
return { total: items.length > 0 && values.length === items.length ? values.reduce((a, b) => a + b, 0) : null,
|
|
103
|
-
knownSubtotal: values.reduce((a, b) => a + b, 0), measured: values.length, expected: items.length,
|
|
104
|
-
coverage: items.length ? values.length / items.length : null };
|
|
105
|
-
}
|
|
106
|
-
function telemetryFrom(ledger, id, project) {
|
|
107
|
-
const items = Object.values(ledger.dispatches).filter(d => belongs(ledger, d.taskId, id));
|
|
108
|
-
for (const d of items) if (d.runtime) {
|
|
109
|
-
const trace = json(verifyArtifact(project, d.runtime));
|
|
110
|
-
verifyArtifact(project, trace.observationSource);
|
|
111
|
-
}
|
|
112
|
-
const started = items.filter(d => d.startedAt);
|
|
113
|
-
return { taskId: id, reservations: items.length, attempts: started.length,
|
|
114
|
-
metrics: Object.fromEntries(["durationMs", "toolUseCount", "totalTokens", "costUsd"].map(name => [name, metric(started, name)])),
|
|
115
|
-
outcomes: Object.fromEntries(states.map(name => [name, items.filter(d => d.status === name).length])) };
|
|
116
|
-
}
|
|
117
|
-
function overlap(a, b) { a = a.toLowerCase(); b = b.toLowerCase(); return a === b || a.startsWith(b + "/") || b.startsWith(a + "/"); }
|
|
118
|
-
function validPaths(project, paths) {
|
|
119
|
-
need(Array.isArray(paths) && paths.every(p => typeof p === "string"), "writePaths must be an explicit array");
|
|
120
|
-
for (const p of paths) {
|
|
121
|
-
contained(project, p);
|
|
122
|
-
need(!/^\.(?:nccgs|claude)(?:\/|$)/i.test(p), "Dispatch cannot own framework governance state; use task CLI and evidence artifacts");
|
|
123
|
-
}
|
|
124
|
-
return [...new Set(paths)].sort();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function sliceCapacity(project, ledger, ancestors) {
|
|
128
|
-
return ancestors.map(ancestor => {
|
|
129
|
-
const entry = ledger.tasks[ancestor], items = Object.values(ledger.dispatches).filter(d => belongs(ledger, d.taskId, ancestor));
|
|
130
|
-
let pending = 0, minimumReviews = 0;
|
|
131
|
-
for (const [id] of Object.entries(ledger.tasks).filter(([id, e]) => e.slicePlan && belongs(ledger, id, ancestor))) {
|
|
132
|
-
const task = taskRecord(project, id), progress = sliceProgress(project, task, ledger);
|
|
133
|
-
pending += progress.minimumRemainingDispatches;
|
|
134
|
-
const own = items.filter(d => d.taskId === id), reviews = own.filter(d => d.kind === "review");
|
|
135
|
-
const consumed = new Set([...Object.values(task.stages ?? {}), ...(task.history ?? []).flatMap(h => Object.values(h.stages ?? {}))].map(s => s.dispatchId).filter(Boolean));
|
|
136
|
-
const lastWork = own.filter(d => d.kind === "implementation" && d.status === "completed").at(-1);
|
|
137
|
-
const reviewed = progress.slices.every(s => s.state === "DELIVERED") && lastWork && task.stages.review?.verdict === "PASS"
|
|
138
|
-
&& task.stages.implementation?.dispatchId === lastWork.id && task.stages.review.contractHash === task.contractHash
|
|
139
|
-
&& task.stages.review.snapshot === lastWork.completedSnapshot && Date.parse(task.stages.review.recordedAt) >= Date.parse(lastWork.finishedAt);
|
|
140
|
-
const awaiting = progress.slices.every(s => s.state === "DELIVERED") && reviews.some(d => active(d) || (d.status === "completed"
|
|
141
|
-
&& d.completedSnapshot === lastWork?.completedSnapshot && Date.parse(d.finishedAt) >= Date.parse(lastWork.finishedAt) && !consumed.has(d.id)));
|
|
142
|
-
if (!reviewed && !awaiting) {
|
|
143
|
-
const used = Math.max(0, task.reviewBudget.used - reviews.filter(d => consumed.has(d.id)).length) + reviews.length;
|
|
144
|
-
need(used < task.reviewBudget.limit, `Task slices: independent-review budget exhausted for ${id}; splitting cannot create new review rounds`);
|
|
145
|
-
minimumReviews++;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
const protectedBudget = deliveryBudget(entry, items);
|
|
149
|
-
const protectedSlots = (protectedBudget?.protectedSlots ?? 0) + Math.max(0, minimumReviews - (protectedBudget?.remaining.review ?? 0));
|
|
150
|
-
need(items.length + pending + protectedSlots <= entry.limits.maxDispatches,
|
|
151
|
-
`Task slices: aggregate budget for ${ancestor} cannot fit ${pending} remaining delivery slices plus ${protectedSlots} protected slots; preserve spent attempts and replan unattempted work or use an externally authorized extension`);
|
|
152
|
-
return { taskId: ancestor, limits: entry.limits, spentDispatches: items.length, minimumRemainingSlices: pending, minimumIndependentReviews: minimumReviews, protectedSlots,
|
|
153
|
-
spareDispatches: entry.limits.maxDispatches - items.length - pending - protectedSlots };
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export function planTaskSlices(project, id, relative, commit = false) {
|
|
158
|
-
const prepare = ledger => {
|
|
159
|
-
const task = taskRecord(project, id);
|
|
160
|
-
need(task.mode === "implement" && !task.closed, "Task slices require an open implementation task");
|
|
161
|
-
const state = check(project, task, "implementation"); need(state.allowed, state.message);
|
|
162
|
-
need(typeof relative === "string" && relative.startsWith(".nccgs/evidence/slice-plans/") && relative.endsWith(".json"), "Slice plan draft must be JSON under .nccgs/evidence/slice-plans/");
|
|
163
|
-
const input = artifact(project, relative);
|
|
164
|
-
need(fs.statSync(verifyArtifact(project, input)).size <= 65536, "Slice plan exceeds 64 KiB; narrow the assignments");
|
|
165
|
-
const plan = json(verifyArtifact(project, input)), requestHash = sliceHash(plan);
|
|
166
|
-
validateSlicePlan(project, task, plan);
|
|
167
|
-
const existing = ledger.events.find(e => e.action === "slice-plan" && e.taskId === id && e.planId === plan.planId);
|
|
168
|
-
if (existing) {
|
|
169
|
-
need(existing.requestHash === requestHash, "Slice planId reused with different content");
|
|
170
|
-
return { status: ledger.tasks[id].slicePlan.planId === plan.planId ? "ALREADY_REGISTERED" : "SUPERSEDED", reference: existing.reference,
|
|
171
|
-
scope: "Original plan retained; no reactivation, attempt, budget or task change." };
|
|
172
|
-
}
|
|
173
|
-
need(plan.sourceSnapshot === state.snapshot, "Slice plan source snapshot is stale");
|
|
174
|
-
need(!Object.values(ledger.dispatches).some(d => belongs(ledger, d.taskId, id) && active(d)), "Settle active task/descendant attempts before registering another plan");
|
|
175
|
-
const ancestors = chain(project, id, ledger);
|
|
176
|
-
const old = ledger.tasks[id].slicePlan;
|
|
177
|
-
const previous = old ? { plan: json(verifyArtifact(project, old.reference)), reference: old.reference } : null;
|
|
178
|
-
validateSliceRevision(previous, plan, Object.values(ledger.dispatches).filter(d => d.taskId === id));
|
|
179
|
-
// Preview mutates only this in-memory ledger. No task/contract/approval is
|
|
180
|
-
// rewritten and no dispatch is reserved. Commit pins the normal budget once.
|
|
181
|
-
ledger.tasks[id].slicePlan = { planId: plan.planId, requestHash, reference: input };
|
|
182
|
-
const budgets = sliceCapacity(project, ledger, ancestors);
|
|
183
|
-
verifyArtifact(project, input);
|
|
184
|
-
let reference = input;
|
|
185
|
-
if (commit) {
|
|
186
|
-
const output = `.nccgs/evidence/slices/${crypto.randomUUID()}.json`;
|
|
187
|
-
atomicJson(contained(project, output), plan); reference = artifact(project, output);
|
|
188
|
-
ledger.tasks[id].slicePlan.reference = reference;
|
|
189
|
-
ledger.events.push({ action: "slice-plan", at: now(), taskId: id, planId: plan.planId, requestHash, reference,
|
|
190
|
-
supersedes: old?.reference ?? null, reason: plan.reason });
|
|
191
|
-
}
|
|
192
|
-
return { status: commit ? "REGISTERED" : "PREVIEW", taskId: id, planId: plan.planId, reference, budgets,
|
|
193
|
-
scope: "Same task, original criteria and shared budgets. Capacity is a dispatch lower bound, not a duration/cost estimate or approval." };
|
|
194
|
-
};
|
|
195
|
-
return commit ? transaction(project, prepare) : prepare(load(project));
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export function taskSliceStatus(project, id) {
|
|
199
|
-
const task = taskRecord(project, id), ledger = load(project), stored = readSlicePlan(project, task, ledger);
|
|
200
|
-
if (!stored) return { taskId: id, status: "UNPLANNED", next: null };
|
|
201
|
-
const progress = sliceProgress(project, task, ledger, stored);
|
|
202
|
-
let budgets = null, capacityError = null;
|
|
203
|
-
try { budgets = sliceCapacity(project, ledger, chain(project, id, ledger)); } catch (error) { capacityError = error.message; }
|
|
204
|
-
return { taskId: id, ...progress, budgets, capacityError, next: capacityError ? null : nextSliceRequest(task, ledger, stored, progress),
|
|
205
|
-
history: ledger.events.filter(e => e.action === "slice-plan" && e.taskId === id) };
|
|
206
|
-
}
|
|
207
|
-
export function reserve(project, id, request) {
|
|
208
|
-
return transaction(project, ledger => {
|
|
209
|
-
const task = taskRecord(project, id), policy = resolveExecution(project);
|
|
210
|
-
if (task.executionHash) need(task.executionHash === hash(JSON.stringify(policy)), "Task execution policy changed; restore pinned policy before dispatch");
|
|
211
|
-
if (task.pipelineHash) need(task.pipelineHash === hash(JSON.stringify(loadPipeline(project))), "Task pipeline changed; restore pinned policy before dispatch");
|
|
212
|
-
need(policy.name === "standalone", "Managed dispatch requires standalone execution policy");
|
|
213
|
-
need(request && typeof request === "object" && kinds.includes(request.kind), "Invalid dispatch kind");
|
|
214
|
-
if (request.kind === "implementation") requireDesignReady(project, task);
|
|
215
|
-
need(typeof request.requestKey === "string" && /^[\w-]{1,100}$/.test(request.requestKey), "Stable requestKey required for idempotent reservation");
|
|
216
|
-
need(request.reason?.trim() && typeof request.agent === "string" && /^[\w-]+$/.test(request.agent), "Dispatch needs a named agent and concrete reason");
|
|
217
|
-
const registry = json(contained(project, ".claude/nccgs/studio.json"));
|
|
218
|
-
const role = registry.agents.find(agent => agent.name === request.agent);
|
|
219
|
-
need(role, "Unknown studio agent");
|
|
220
|
-
need(request.kind !== "implementation" || !["nccgs-task-scout", "nccgs-adversarial-reviewer"].includes(request.agent), "Read-only agent cannot implement");
|
|
221
|
-
need(request.kind !== "review" || role.modelClass === "review", "Independent review requires a reviewer role");
|
|
222
|
-
const writePaths = validPaths(project, request.writePaths ?? []);
|
|
223
|
-
const handoffPaths = request.handoffPaths ?? [];
|
|
224
|
-
need(Array.isArray(handoffPaths) && handoffPaths.every(p => typeof p === "string" && p.startsWith(".nccgs/evidence/analysis/")), "Handoff paths must be explicit analysis artifact paths");
|
|
225
|
-
for (const p of handoffPaths) contained(project, p);
|
|
226
|
-
need(request.handoffTransport === undefined || ["file", "native-result"].includes(request.handoffTransport), "Unknown handoff transport");
|
|
227
|
-
if (request.handoffTransport === "native-result")
|
|
228
|
-
need(request.kind !== "implementation" && handoffPaths.length === 1, "Native result handoff requires one declared read-only artifact");
|
|
229
|
-
if (request.kind !== "implementation") for (const p of handoffPaths)
|
|
230
|
-
need(task.contract.analysisArtifacts?.includes(p), "Read-only handoff must be a declared analysis artifact");
|
|
231
|
-
need(request.kind === "implementation" || writePaths.length === 0, "Review/analysis dispatch is read-only");
|
|
232
|
-
need(task.mode === "implement" || request.kind !== "implementation", "Audit/plan tasks cannot dispatch implementation");
|
|
233
|
-
need(request.kind !== "implementation" || writePaths.length > 0, "Implementation requires owned write paths");
|
|
234
|
-
if (request.parentId !== undefined) need(request.parentId === task.parentId, "Parent must be declared in the task contract");
|
|
235
|
-
const normalized = { ...request, writePaths }, requestHash = hash(JSON.stringify(normalized));
|
|
236
|
-
const previous = Object.values(ledger.dispatches).find(d => d.taskId === id && d.requestKey === request.requestKey);
|
|
237
|
-
if (previous) { need(previous.requestHash === requestHash, "requestKey reused for different dispatch"); return previous; }
|
|
238
|
-
for (const p of handoffPaths) need(!fs.existsSync(contained(project, p)), "Handoff artifact must be fresh for this dispatch");
|
|
239
|
-
const ancestors = chain(project, id, ledger, request);
|
|
240
|
-
const protectedAllocation = plannedDispatchBudget(project, id, request);
|
|
241
|
-
const source = snapshot(project, task, { includeFiles: Boolean(request.workPacket) }), snap = source.sha256;
|
|
242
|
-
const repair = Object.values(ledger.dispatches).filter(d => d.taskId === id && d.purpose === "repair" && d.status === "completed" && d.contractHash === task.contractHash).at(-1);
|
|
243
|
-
const { purpose, feedback } = dispatchPurpose(project, task, { ...request, repairFeedback: repair?.feedback ?? null }, snap);
|
|
244
|
-
const slice = bindSlice(project, task, ledger, { ...request, writePaths }, purpose);
|
|
245
|
-
if (ledger.tasks[id].slicePlan) {
|
|
246
|
-
const state = check(project, task, "implementation"); need(state.allowed, state.message);
|
|
247
|
-
if (slice) need(!Object.values(ledger.dispatches).some(d => belongs(ledger, d.taskId, id) && active(d)), "Planned slices use sequential foreground dispatch; finish existing task/descendant work first");
|
|
248
|
-
}
|
|
249
|
-
const workPacket = purpose === "repair" ? pinRepairPacket(project, task, { ...request, writePaths }, snap) : null;
|
|
250
|
-
need(purpose === "repair" || request.workPacket === undefined, "workPacket is only supported for repair dispatches");
|
|
251
|
-
const budgetEvidence = [];
|
|
252
|
-
for (const ancestor of ancestors) {
|
|
253
|
-
const items = Object.values(ledger.dispatches).filter(d => belongs(ledger, d.taskId, ancestor)), limits = ledger.tasks[ancestor].limits;
|
|
254
|
-
need(items.length < limits.maxDispatches, `Aggregate dispatch budget exhausted for ${ancestor}; cancellation/reclassification never refunds attempts`);
|
|
255
|
-
requireDeliveryRoom(ledger.tasks[ancestor], items, purpose, ancestor);
|
|
256
|
-
requireEarlyCheckpoint(project, taskRecord(project, ancestor), ledger.tasks[ancestor], items, purpose, request.kind, snap);
|
|
257
|
-
const measured = telemetryFrom(ledger, ancestor, project);
|
|
258
|
-
for (const [limit, field] of [["maxDurationMs", "durationMs"], ["maxCostUsd", "costUsd"]]) if (limits[limit] !== null) {
|
|
259
|
-
const data = measured.metrics[field];
|
|
260
|
-
if (field === "costUsd" && (data.expected !== data.measured || process.env.NCCGS_SUPERVISED_RUN)) {
|
|
261
|
-
budgetEvidence.push(activeSessionBudget(project, ancestor, items, limits[limit]));
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
need(data.expected === data.measured, `Cannot enforce ${limit}: missing ${field} telemetry; reconcile measurements or stop`);
|
|
265
|
-
need(data.knownSubtotal < limits[limit], `${limit} budget exhausted for ${ancestor}`);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
const records = Object.values(ledger.dispatches), live = records.filter(active);
|
|
269
|
-
need(!live.some(d => d.workPacket?.schemaVersion === 2), "Typed Unity repair owns the project until completion or external reconciliation");
|
|
270
|
-
if (workPacket?.schemaVersion === 2) need(live.length === 0, "Typed Unity repair requires exclusive project ownership");
|
|
271
|
-
if (request.kind === "review") {
|
|
272
|
-
const reviewAttempts = records.filter(d => d.taskId === id && d.kind === "review");
|
|
273
|
-
const consumed = new Set([...Object.values(task.stages ?? {}), ...(task.history ?? []).flatMap(h => Object.values(h.stages ?? {}))].map(s => s.dispatchId).filter(Boolean));
|
|
274
|
-
const linked = reviewAttempts.filter(d => consumed.has(d.id)).length;
|
|
275
|
-
const used = Math.max(0, task.reviewBudget.used - linked) + reviewAttempts.length;
|
|
276
|
-
need(used < task.reviewBudget.limit, "Review dispatch budget exhausted");
|
|
277
|
-
need(!live.some(d => d.taskId === id && d.kind === "review"), "Only one reviewer may be reserved or running per task");
|
|
278
|
-
const readiness = check(project, task, "review");
|
|
279
|
-
need(readiness.allowed, readiness.message);
|
|
280
|
-
}
|
|
281
|
-
if (request.kind === "implementation") {
|
|
282
|
-
need(live.filter(d => d.kind === "implementation").length < policy.maxParallelWorkers, "Implementation concurrency limit reached");
|
|
283
|
-
need(!live.some(d => d.kind !== "implementation"), "Read-only review/analysis snapshot is reserved; finish it before writing");
|
|
284
|
-
for (const item of live) need(!item.writePaths.some(a => writePaths.some(b => overlap(a, b))), "Write ownership conflicts with another active dispatch");
|
|
285
|
-
} else need(!live.some(d => d.kind === "implementation"), "Cannot review/analyze a snapshot while implementation is active");
|
|
286
|
-
const reservation = { id: crypto.randomUUID(), taskId: id, kind: request.kind, agent: request.agent, reason: request.reason.trim(),
|
|
287
|
-
requestKey: request.requestKey, requestHash, writePaths, handoffPaths, handoffProtocol: 1,
|
|
288
|
-
...(request.handoffTransport ? { handoffTransport: request.handoffTransport } : {}), purpose, feedback, status: "reserved", createdAt: now(),
|
|
289
|
-
snapshot: snap, contractHash: task.contractHash, sessionId: null, toolUseId: null, agentId: null, telemetry: null,
|
|
290
|
-
...(budgetEvidence.length ? { budgetEvidence } : {}),
|
|
291
|
-
...(protectedAllocation ? { protectedAllocation } : {}),
|
|
292
|
-
...(slice ? { slice } : {}), ...(ledger.tasks[id].slicePlan ? { slicePlan: ledger.tasks[id].slicePlan.reference } : {}),
|
|
293
|
-
...(workPacket ? { workPacket, toolBudget: { work: 0, read: 0, handoff: 0, admissions: [] } } : {}) };
|
|
294
|
-
captureUnityRepairScope(project, reservation, source);
|
|
295
|
-
ledger.dispatches[reservation.id] = reservation;
|
|
296
|
-
sliceCapacity(project, ledger, ancestors);
|
|
297
|
-
ledger.events.push({ action: "reserve", at: reservation.createdAt, dispatchId: reservation.id, taskId: id });
|
|
298
|
-
return reservation;
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
export function claim(project, dispatchId, identity) {
|
|
302
|
-
return transaction(project, ledger => {
|
|
303
|
-
const d = ledger.dispatches[dispatchId]; need(d, "Unknown dispatch reservation");
|
|
304
|
-
for (const coverage of d.budgetEvidence ?? []) need(coverage.currentSessionId === identity.sessionId, "Dispatch must use the supervised session that owns its budget allowance");
|
|
305
|
-
if (d.protectedAllocation) need(d.protectedAllocation.sessionId === identity.sessionId, "Dispatch must use the session that owns its protected budget allocation");
|
|
306
|
-
need(identity.sessionId && identity.toolUseId && identity.agent === d.agent, "Dispatch identity/role mismatch");
|
|
307
|
-
if (d.status === "running") { need(d.sessionId === identity.sessionId && d.toolUseId === identity.toolUseId, "Dispatch already claimed by another invocation"); return d; }
|
|
308
|
-
need(d.status === "reserved", "Dispatch is not available to claim");
|
|
309
|
-
const task = taskRecord(project, d.taskId);
|
|
310
|
-
if (d.kind === "implementation") requireDesignReady(project, task);
|
|
311
|
-
need(task.contractHash === d.contractHash, "Dispatch contract stale");
|
|
312
|
-
need(snapshot(project, task).sha256 === d.snapshot, "Dispatch source snapshot stale; cancel/reconcile and reserve a fresh attempt");
|
|
313
|
-
if (d.workPacket) verifyRepairPacket(project, d);
|
|
314
|
-
if (d.slice) {
|
|
315
|
-
const current = bindSlice(project, task, ledger, { ...d, sliceId: d.slice.id }, d.purpose);
|
|
316
|
-
need(current.definitionHash === d.slice.definitionHash && sameSlice(current.dependencies, d.slice.dependencies), "Slice dependency handoffs changed after reservation");
|
|
317
|
-
}
|
|
318
|
-
need(!Object.values(ledger.dispatches).some(item => item.id !== d.id && item.sessionId === identity.sessionId && item.toolUseId === identity.toolUseId), "Tool invocation already belongs to another reservation");
|
|
319
|
-
Object.assign(d, { status: "running", sessionId: identity.sessionId, toolUseId: identity.toolUseId, startedAt: now() });
|
|
320
|
-
ledger.events.push({ action: "claim", at: d.startedAt, dispatchId }); return d;
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
export function attachAgent(project, dispatchId, agentId) {
|
|
324
|
-
return transaction(project, ledger => {
|
|
325
|
-
const d = ledger.dispatches[dispatchId]; need(d && active(d) && d.sessionId, "No claimed dispatch to bind agent");
|
|
326
|
-
need(typeof agentId === "string" && agentId, "Missing agent identity");
|
|
327
|
-
need(!d.agentId || d.agentId === agentId, "Reservation already bound to another agent");
|
|
328
|
-
d.agentId = agentId; return d;
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
export function getDispatch(project, id, dispatchId) {
|
|
332
|
-
taskRecord(project, id);
|
|
333
|
-
const d = load(project).dispatches[dispatchId];
|
|
334
|
-
need(d?.taskId === id, "Dispatch does not belong to this task");
|
|
335
|
-
return d;
|
|
336
|
-
}
|
|
337
|
-
export function dispatchPrompt(project, id, dispatchId) {
|
|
338
|
-
const task = taskRecord(project, id), d = getDispatch(project, id, dispatchId);
|
|
339
|
-
need(d.contractHash === task.contractHash, "Dispatch contract stale");
|
|
340
|
-
if (d.workPacket) {
|
|
341
|
-
verifyRepairPacket(project, d);
|
|
342
|
-
return { dispatchId, prompt: repairPrompt(task, d) };
|
|
343
|
-
}
|
|
344
|
-
need(["reserved", "running"].includes(d.status), "Prompt requires a reserved or running dispatch");
|
|
345
|
-
const state = check(project, task, d.kind === "review" ? "review" : task.mode === "implement" ? "implementation" : "analysis");
|
|
346
|
-
need(state.allowed, state.message);
|
|
347
|
-
if (d.status === "reserved" || d.kind !== "implementation") need(state.snapshot === d.snapshot, "Dispatch source snapshot stale");
|
|
348
|
-
const route = d.kind === "review" ? task.execution.profile.models.review : task.implementationRoute;
|
|
349
|
-
const handoffs = (d.handoffPaths ?? []).map(file => ({ path: file, content: handoffTemplate(task, d) }));
|
|
350
|
-
const prompt = `[NCCGS-DISPATCH:${dispatchId}]\nTask ${id}, ${d.kind}, ${task.risk}: ${task.contract.objective}\n` +
|
|
351
|
-
`Assignment: ${d.reason}\nTask record: .nccgs/tasks/${id}.json\nIntake: ${task.intake.path}\n` +
|
|
352
|
-
`Contract: ${task.contractHash}\nStarting source: ${d.snapshot}\nRequested route: ${route.model}/${route.effort ?? "unspecified"}; not observed execution.\n` +
|
|
353
|
-
`Check the installed role's maxTurns and native session overrides before launch; prompt text cannot increase capacity.\n` +
|
|
354
|
-
`Source write ownership: ${JSON.stringify(d.writePaths)}\nCanonical sources: ${JSON.stringify(task.contract.sources ?? [])}\n` +
|
|
355
|
-
`Read the pinned task contract for acceptance, checks, manual gates and design references; preserve all of them.\n` +
|
|
356
|
-
slicePromptContext(project, task, d) +
|
|
357
|
-
`Use foreground execution. Do not delegate or change task records. The coordinator owns verification and stage recording.\n` +
|
|
358
|
-
(d.kind === "review" ? "Review independently; follow .claude/nccgs/protocols/review-handoff.md. Keep negative findings and pending conditions.\n" : "Follow .claude/nccgs/protocols/agent-contract.md for this bounded assignment.\n") +
|
|
359
|
-
(d.handoffTransport === "native-result"
|
|
360
|
-
? "Return the entire assigned Markdown handoff as your sole final text response, without an outer code fence. Do not write a file or run handoff validation. The correlated native hook copies your exact text to the pinned path; all existing completion and review gates still apply.\n"
|
|
361
|
-
: handoffs.length ? "Write the assigned draft early. Fill it with actual findings; mark COMPLETE only when your assignment has finished.\n" : "No handoff path was reserved; report this to the coordinator if an artifact is required.\n") +
|
|
362
|
-
handoffs.map(h => `Handoff file: ${h.path}\nInitial draft (not evidence):\n${h.content}\n` +
|
|
363
|
-
(/^[\w./ -]+$/.test(h.path)
|
|
364
|
-
? (d.handoffTransport === "native-result" ? "Return this completed document as text; retain negative findings and pending conditions.\n" : `Before returning, validate structure with one plain command:\nnode .claude/nccgs/tools/task.mjs handoff-validate --id ${id} --dispatch ${dispatchId} --file "${h.path}"\n`)
|
|
365
|
-
: "Ask the coordinator to validate this handoff with the fixed handoff-validate command; its path needs shell-specific quoting.\n")).join("\n");
|
|
366
|
-
return { dispatchId, agent: d.agent, prompt, handoffs, scope: "Preparation only; does not launch, write artifacts, approve work or spend another attempt." };
|
|
367
|
-
}
|
|
368
|
-
export function pinnedRepairEvidence(project, relative) {
|
|
369
|
-
return Object.values(load(project).dispatches).some(d => d.workPacket &&
|
|
370
|
-
[d.workPacket.reference, ...d.workPacket.context, d.workPacket.scope, d.workPacket.unity?.capabilities].filter(Boolean).some(ref => ref.path.toLowerCase() === relative.toLowerCase()));
|
|
371
|
-
}
|
|
372
|
-
export function admitRepairTool(project, dispatchId, input) {
|
|
373
|
-
const result = transaction(project, ledger => {
|
|
374
|
-
const d = ledger.dispatches[dispatchId];
|
|
375
|
-
const uncertainHandoff = d?.workPacket?.schemaVersion === 2 && d.status === "uncertain" &&
|
|
376
|
-
["Write", "Edit", "MultiEdit"].includes(input.tool_name) && d.handoffPaths.includes(path.relative(project, path.resolve(project, input.tool_input?.file_path ?? ".")).split(path.sep).join("/"));
|
|
377
|
-
need(d?.workPacket && (d.status === "running" || uncertainHandoff) && input.agent_id && input.agent_id === d.agentId && input.session_id === d.sessionId, "Repair tool requires the running, correlated worker");
|
|
378
|
-
need(typeof input.tool_use_id === "string" && input.tool_use_id.length > 0, "Repair tool-use identity missing");
|
|
379
|
-
const budget = d.toolBudget, limits = d.workPacket.budget;
|
|
380
|
-
need(budget && Array.isArray(budget.admissions) && [budget.work, budget.read, budget.handoff].every(n => Number.isSafeInteger(n) && n >= 0), "Repair tool budget missing/corrupt; restore history, never reset it");
|
|
381
|
-
const counted = { work: 0, read: 0, handoff: 0 }, seen = new Set();
|
|
382
|
-
for (const entry of budget.admissions) {
|
|
383
|
-
need(["work", "handoff"].includes(entry.bucket) && typeof entry.read === "boolean" && typeof entry.allowed === "boolean" && entry.toolUseId && !seen.has(entry.toolUseId), "Repair admission history corrupt");
|
|
384
|
-
seen.add(entry.toolUseId); counted[entry.bucket]++; if (entry.read) counted.read++;
|
|
385
|
-
}
|
|
386
|
-
need(Object.keys(counted).every(key => budget[key] === counted[key]), "Repair counters differ from admission history; never reset spent calls");
|
|
387
|
-
const fingerprint = hash(JSON.stringify([input.tool_name, input.tool_input ?? {}]));
|
|
388
|
-
const previous = budget.admissions.find(a => a.toolUseId === input.tool_use_id);
|
|
389
|
-
if (previous) {
|
|
390
|
-
need(previous.fingerprint === fingerprint, "Repair tool-use ID reused with different input");
|
|
391
|
-
// Re-delivery must not re-admit a call after its source context changed.
|
|
392
|
-
if (previous.allowed && previous.bucket !== "handoff") {
|
|
393
|
-
verifyRepairPacket(project, d);
|
|
394
|
-
need(taskRecord(project, d.taskId).contractHash === d.contractHash, "Repair contract stale");
|
|
395
|
-
need(!(d.editorSteps ?? []).some(s => s.status !== "completed"), "Editor operation failed or remains uncertain; retain the attempt and return PARTIAL");
|
|
396
|
-
}
|
|
397
|
-
return previous;
|
|
398
|
-
}
|
|
399
|
-
let scope, reason = null;
|
|
400
|
-
try { scope = repairToolScope(project, d, input); }
|
|
401
|
-
catch (error) { scope = { bucket: "work", read: false }; reason = error.message; }
|
|
402
|
-
// Persist denied attempts too. Throwing inside this transaction would lose
|
|
403
|
-
// the accounting and let retries obtain an unlimited exploration allowance.
|
|
404
|
-
budget[scope.bucket]++;
|
|
405
|
-
if (scope.read) budget.read++;
|
|
406
|
-
try {
|
|
407
|
-
if (scope.bucket === "handoff") need(budget.handoff <= limits.handoffCalls, "Repair handoff allowance exhausted");
|
|
408
|
-
else {
|
|
409
|
-
need(budget.work <= limits.workCalls, "Repair work allowance exhausted");
|
|
410
|
-
if (scope.read) need(budget.read <= limits.readCalls, "Repair read allowance exhausted");
|
|
411
|
-
need(Date.now() - Date.parse(d.startedAt) <= limits.durationMs, "Repair work deadline reached");
|
|
412
|
-
need(taskRecord(project, d.taskId).contractHash === d.contractHash, "Repair contract stale");
|
|
413
|
-
verifyRepairPacket(project, d);
|
|
414
|
-
need(!(d.editorSteps ?? []).some(s => s.status !== "completed"), "Editor operation failed or remains uncertain; retain the attempt and return PARTIAL");
|
|
415
|
-
}
|
|
416
|
-
} catch (error) { reason = error.message; }
|
|
417
|
-
const remaining = { work: Math.max(0, limits.workCalls - budget.work), read: Math.max(0, limits.readCalls - budget.read), handoff: Math.max(0, limits.handoffCalls - budget.handoff) };
|
|
418
|
-
const entry = { toolUseId: input.tool_use_id, fingerprint, bucket: scope.bucket, read: scope.read, allowed: !reason, reason, at: now(), remaining,
|
|
419
|
-
...(scope.editorStep ? { editorStep: scope.editorStep } : {}) };
|
|
420
|
-
budget.admissions.push(entry);
|
|
421
|
-
return entry;
|
|
422
|
-
});
|
|
423
|
-
need(result.allowed, `${result.reason}. Write the assigned PARTIAL handoff and return; remaining handoff calls: ${result.remaining.handoff}`);
|
|
424
|
-
return { additionalContext: `NCCGS repair tool allowance remaining: ${result.remaining.work} work, ${result.remaining.read} reads, ${result.remaining.handoff} handoff writes. Verification belongs to the coordinator. Return the assigned handoff before native turn exhaustion.` };
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// Called only by the fixed worker CLI after its tool admission. A step is pinned
|
|
428
|
-
// before launch and never replayed automatically, including after an interruption.
|
|
429
|
-
export function runRepairEditor(project, id, dispatchId, stepId, execute = spawnSync) {
|
|
430
|
-
const prepared = transaction(project, ledger => {
|
|
431
|
-
const d = ledger.dispatches[dispatchId];
|
|
432
|
-
need(d?.taskId === id && d.status === "running" && d.workPacket?.schemaVersion === 2, "Editor step needs a running typed Unity repair");
|
|
433
|
-
const task = taskRecord(project, id);
|
|
434
|
-
need(task.contractHash === d.contractHash, "Repair contract stale");
|
|
435
|
-
requireDesignReady(project, task);
|
|
436
|
-
const readiness = check(project, task, "implementation"); need(readiness.allowed, readiness.message);
|
|
437
|
-
verifyRepairPacket(project, d); verifyUnityRepairScope(project, d);
|
|
438
|
-
const steps = d.workPacket.unity.steps, step = steps.find(s => s.id === stepId);
|
|
439
|
-
need(step, "Unknown pinned Editor step");
|
|
440
|
-
d.editorSteps ??= [];
|
|
441
|
-
need(!d.editorSteps.some(s => s.id === stepId), "Editor step already attempted; inspect its original receipt, never replay");
|
|
442
|
-
need(steps.slice(0, steps.indexOf(step)).every(s => d.editorSteps.some(e => e.id === s.id && e.status === "completed")), "Editor steps must finish in packet order");
|
|
443
|
-
need(Date.now() - Date.parse(d.startedAt) + step.timeoutMs + 1000 <= d.workPacket.budget.durationMs, "Repair deadline cannot fit this Editor step");
|
|
444
|
-
const admission = d.toolBudget.admissions.find(a => a.allowed && a.editorStep === stepId && !d.editorSteps.some(s => s.toolUseId === a.toolUseId));
|
|
445
|
-
need(admission, "Editor step requires its correlated worker tool admission");
|
|
446
|
-
const invocation = unityEditorInvocation(project, step, d.workPacket.sceneSafety ?? null);
|
|
447
|
-
d.editorSteps.push({ id: stepId, status: "running", startedAt: now(), toolUseId: admission.toolUseId });
|
|
448
|
-
ledger.events.push({ action: "repair-editor-start", at: now(), dispatchId, stepId });
|
|
449
|
-
return { step, invocation };
|
|
450
|
-
});
|
|
451
|
-
let result;
|
|
452
|
-
try { result = execute(prepared.invocation.executable, prepared.invocation.arguments, { cwd: project, shell: false, windowsHide: true,
|
|
453
|
-
encoding: "utf8", timeout: prepared.step.timeoutMs + 1000, maxBuffer: 4 * 1024 * 1024 }); }
|
|
454
|
-
catch (error) { result = { error, status: null, stdout: "", stderr: "" }; }
|
|
455
|
-
return transaction(project, ledger => {
|
|
456
|
-
const d = ledger.dispatches[dispatchId], step = d.editorSteps.find(s => s.id === stepId);
|
|
457
|
-
need(step?.status === "running", "Editor operation state changed; inspect before any continuation");
|
|
458
|
-
const notStarted = ["ENOENT", "EACCES"].includes(result.error?.code);
|
|
459
|
-
let status = result.status === 0 && !result.error && !result.signal ? "completed" : notStarted ? "failed" : "uncertain";
|
|
460
|
-
const blockedScene = blockedUnityScene(prepared.invocation, result);
|
|
461
|
-
if (blockedScene !== null) status = "failed"; // Known precondition refusal: packet body never ran.
|
|
462
|
-
let scopeError = null;
|
|
463
|
-
try { verifyRepairPacket(project, d); verifyUnityRepairScope(project, d); }
|
|
464
|
-
catch (error) { scopeError = error.message; if (status === "completed") status = "failed"; }
|
|
465
|
-
const relative = `.nccgs/evidence/repair-operations/${dispatchId}-${stepId}.json`;
|
|
466
|
-
atomicJson(contained(project, relative), { schemaVersion: 1, origin: "unity-repair-operation", taskId: id, dispatchId, stepId,
|
|
467
|
-
contractHash: d.contractHash, startedAt: step.startedAt, finishedAt: now(), status, ...prepared.invocation,
|
|
468
|
-
exitCode: result.status ?? null, signal: result.signal ?? null, error: result.error?.message ?? null, scopeError, blockedScene,
|
|
469
|
-
stdout: String(result.stdout ?? ""), stderr: String(result.stderr ?? ""),
|
|
470
|
-
note: "Editor operation receipt only; not verification, acceptance or provider execution evidence." });
|
|
471
|
-
Object.assign(step, { status, finishedAt: now(), evidence: artifact(project, relative) });
|
|
472
|
-
if (status === "uncertain") { d.status = "uncertain"; d.uncertainty = "Unity Editor operation may still be active; external reconciliation required before releasing ownership"; }
|
|
473
|
-
ledger.events.push({ action: "repair-editor-finish", at: step.finishedAt, dispatchId, stepId, status, evidence: step.evidence });
|
|
474
|
-
return { status: status === "completed" ? "EXECUTED" : "FAIL", operationStatus: status, evidence: step.evidence,
|
|
475
|
-
message: status === "completed" ? "Inspect the Editor result; finish the handoff. Required verification and independent review remain pending."
|
|
476
|
-
: blockedScene !== null ? `Unsaved scene blocked the operation: ${blockedScene}. Nothing was saved or discarded. Return PARTIAL and preserve this attempt; the owner must resolve unsaved work before a new authorized packet.`
|
|
477
|
-
: "Return PARTIAL. Preserve this attempt; do not retry or release an uncertain Editor operation without external reconciliation." };
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
// Called only by the launch guard before a native invocation is admitted. A
|
|
481
|
-
// claimed/uncertain worker can never be released through this recovery path.
|
|
482
|
-
export function rejectUnclaimed(project, dispatchId, rejection) {
|
|
483
|
-
return transaction(project, ledger => {
|
|
484
|
-
const d = ledger.dispatches[dispatchId]; need(d, "Unknown dispatch reservation");
|
|
485
|
-
need(rejection.sessionId && rejection.toolUseId && rejection.agent === d.agent && rejection.reason?.trim(), "Rejected launch identity/reason missing");
|
|
486
|
-
need(d.status === "reserved" && !d.sessionId && !d.toolUseId && !d.agentId && !d.startedAt, "Only a never-claimed reservation can be rejected automatically");
|
|
487
|
-
Object.assign(d, { status: "failed", invocationStatus: "not-started", finishedAt: now(),
|
|
488
|
-
failure: rejection.reason, launchRejection: { ...rejection, origin: "pre-tool-use-guard" } });
|
|
489
|
-
ledger.events.push({ action: "reject-unclaimed", at: d.finishedAt, dispatchId, rejection: d.launchRejection });
|
|
490
|
-
return d;
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
export function complete(project, dispatchId, input) {
|
|
494
|
-
return transaction(project, ledger => {
|
|
495
|
-
const d = ledger.dispatches[dispatchId]; need(d, "Unknown dispatch");
|
|
496
|
-
if ((["completed", "failed"].includes(d.status) || d.workStatus === "incomplete-editor") && d.runtime) { need(same(d.runtime, input.runtime), "Dispatch already completed with different evidence"); return d; }
|
|
497
|
-
need(["running", "uncertain"].includes(d.status), "Only a claimed dispatch can complete");
|
|
498
|
-
const editorUncertain = (d.editorSteps ?? []).some(s => ["running", "uncertain"].includes(s.status));
|
|
499
|
-
need(input.runtime?.path?.startsWith(".nccgs/evidence/runtime/observations/"), "Completion needs durable runtime observation");
|
|
500
|
-
const trace = json(verifyArtifact(project, input.runtime)), raw = json(verifyArtifact(project, trace.observationSource));
|
|
501
|
-
need(trace.observationSource?.path?.startsWith(".nccgs/evidence/runtime/sources/"), "Completion requires durable raw runtime source");
|
|
502
|
-
need(trace.origin === "runtime-observation" && trace.observedProvider === "claude-code", "Completion requires Claude Code runtime evidence, not configuration/Codex");
|
|
503
|
-
for (const key of ["dispatchId", "taskId", "contractHash", "sessionId", "toolUseId", "agentId", "snapshot", "status", "capturedAt", "observedProvider"])
|
|
504
|
-
need(trace[key] !== undefined && trace[key] === raw[key], `Runtime raw source ${key} mismatch`);
|
|
505
|
-
need(trace.dispatchId === d.id && trace.taskId === d.taskId && trace.contractHash === d.contractHash && trace.sessionId === d.sessionId && trace.toolUseId === d.toolUseId, "Completion identity/contract mismatch");
|
|
506
|
-
need(trace.agentId && (!d.agentId || d.agentId === trace.agentId), "Completion agent identity mismatch");
|
|
507
|
-
need(["completed", "failed"].includes(trace.status), "Incomplete/background response is not completion");
|
|
508
|
-
need(same(trace.nativeCompletion ?? null, raw.nativeCompletion ?? null), "Native completion diagnosis differs from raw source");
|
|
509
|
-
const nativeIncomplete = Boolean(raw.nativeCompletion?.reason);
|
|
510
|
-
need(Date.parse(trace.capturedAt) >= Date.parse(d.startedAt) && Date.parse(trace.capturedAt) <= Date.now(), "Completion time is invalid");
|
|
511
|
-
const task = taskRecord(project, d.taskId), finalSnapshot = snapshot(project, task).sha256;
|
|
512
|
-
need(task.contractHash === d.contractHash && trace.snapshot === finalSnapshot, "Completion covers stale contract/snapshot");
|
|
513
|
-
let returnedHandoffFailure = null;
|
|
514
|
-
if (d.handoffTransport === "native-result") {
|
|
515
|
-
need(same(trace.returnedHandoff ?? null, raw.returnedHandoff ?? null), "Returned handoff differs from raw source");
|
|
516
|
-
const captured = raw.returnedHandoff;
|
|
517
|
-
if (captured?.status !== "captured") returnedHandoffFailure = captured?.reason ?? "missing-native-result";
|
|
518
|
-
else {
|
|
519
|
-
need(d.handoffPaths.length === 1 && captured.evidence?.path === d.handoffPaths[0], "Returned handoff path mismatch");
|
|
520
|
-
verifyArtifact(project, captured.evidence);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
const mutatedReadOnly = d.kind !== "implementation" && d.snapshot !== finalSnapshot;
|
|
524
|
-
const metrics = Object.fromEntries(["durationMs", "toolUseCount", "totalTokens", "costUsd"].map(key => {
|
|
525
|
-
const value = raw[key] ?? null;
|
|
526
|
-
need(value === null || (Number.isFinite(value) && value >= 0), `Invalid measured ${key}`);
|
|
527
|
-
need(trace[key] == null || trace[key] === value, `Observed ${key} differs from raw source`);
|
|
528
|
-
return [key, value];
|
|
529
|
-
}));
|
|
530
|
-
Object.assign(d, { status: mutatedReadOnly || nativeIncomplete || trace.status === "failed" ? "failed" : "completed", agentId: trace.agentId,
|
|
531
|
-
completedSnapshot: finalSnapshot, finishedAt: now(), runtime: input.runtime, telemetry: metrics,
|
|
532
|
-
...(mutatedReadOnly ? { failure: "Read-only dispatch modified source" } : {}),
|
|
533
|
-
...(nativeIncomplete ? { failure: `Native worker incomplete: ${raw.nativeCompletion.reason}`, nativeCompletion: raw.nativeCompletion } : {}) });
|
|
534
|
-
const missing = (d.handoffPaths ?? []).filter(p => !fs.existsSync(contained(project, p)) || !fs.statSync(contained(project, p)).isFile() || fs.statSync(contained(project, p)).size === 0);
|
|
535
|
-
d.invocationStatus = raw.nativeCompletion?.reportedStatus ?? trace.status;
|
|
536
|
-
d.handoff = { status: !d.handoffPaths?.length ? "unassessed" : missing.length ? "missing" : "present", missing,
|
|
537
|
-
artifacts: (d.handoffPaths ?? []).filter(p => !missing.includes(p)).map(p => artifact(project, p)),
|
|
538
|
-
note: "Artifact presence is not product acceptance; native completion alone is not a complete handoff" };
|
|
539
|
-
const partial = d.handoffProtocol === 1 ? d.handoff.artifacts.filter(ref => {
|
|
540
|
-
const text = fs.readFileSync(verifyArtifact(project, ref), "utf8");
|
|
541
|
-
return !/^NCCGS-HANDOFF: COMPLETE\r?$/m.test(text) || /^NCCGS-HANDOFF: PARTIAL\r?$/m.test(text);
|
|
542
|
-
}).map(ref => ref.path) : [];
|
|
543
|
-
d.handoff.partial = partial;
|
|
544
|
-
if (missing.length || partial.length) {
|
|
545
|
-
d.status = "failed";
|
|
546
|
-
d.failure = missing.length ? "Required handoff artifacts are missing; reserve a new bounded attempt" : "Handoff is partial or missing its COMPLETE marker; reserve a new bounded attempt";
|
|
547
|
-
}
|
|
548
|
-
if (returnedHandoffFailure) { d.status = "failed"; d.failure = `Returned handoff rejected: ${returnedHandoffFailure}`; }
|
|
549
|
-
if (d.workPacket) {
|
|
550
|
-
try {
|
|
551
|
-
verifyRepairPacket(project, d);
|
|
552
|
-
verifyUnityRepairScope(project, d, true);
|
|
553
|
-
if (d.workPacket.schemaVersion === 2) {
|
|
554
|
-
need(d.workPacket.unity.steps.every(s => d.editorSteps?.some(e => e.id === s.id && e.status === "completed")), "Required Editor operations did not complete");
|
|
555
|
-
for (const s of d.editorSteps ?? []) verifyArtifact(project, s.evidence);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
catch (error) { d.status = "failed"; d.failure = `Repair context changed: ${error.message}`; }
|
|
559
|
-
}
|
|
560
|
-
// The native worker can finish while a resident Editor operation remains
|
|
561
|
-
// uncertain. Keep its observed usage and original handoff without releasing
|
|
562
|
-
// ownership or converting that observation into completed repair work.
|
|
563
|
-
if (editorUncertain) {
|
|
564
|
-
d.status = "uncertain";
|
|
565
|
-
d.uncertainty = "Native worker finished but Editor operation is still running or uncertain; external reconciliation required";
|
|
566
|
-
}
|
|
567
|
-
d.workStatus = editorUncertain ? "incomplete-editor" : d.status === "completed" ? "completed" : "incomplete";
|
|
568
|
-
ledger.events.push({ action: "complete", at: d.finishedAt, dispatchId, status: d.status }); return d;
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
export function markUncertain(project, dispatchId, reason) {
|
|
572
|
-
return transaction(project, ledger => {
|
|
573
|
-
const d = ledger.dispatches[dispatchId]; need(d && active(d), "No active dispatch");
|
|
574
|
-
d.status = "uncertain"; d.uncertainty = reason;
|
|
575
|
-
ledger.events.push({ action: "uncertain", at: now(), dispatchId, reason }); return d;
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
export function reconcile(project, dispatchId, decision) {
|
|
579
|
-
need(!(process.env.CLAUDECODE || process.env.CLAUDE_CODE_ENTRYPOINT), "Reconciliation releasing a slot requires an external operator");
|
|
580
|
-
need(["failed", "cancelled"].includes(decision.status) && decision.reason?.trim() && decision.reference?.trim(), "Reconcile needs explicit status, reason and observation reference");
|
|
581
|
-
return transaction(project, ledger => {
|
|
582
|
-
const d = ledger.dispatches[dispatchId]; need(d && active(d), "Only active/uncertain dispatch can be reconciled");
|
|
583
|
-
Object.assign(d, { status: decision.status, finishedAt: now(), reconciliation: decision });
|
|
584
|
-
ledger.events.push({ action: "reconcile", at: d.finishedAt, dispatchId, decision }); return d;
|
|
585
|
-
});
|
|
586
|
-
}
|
|
587
|
-
export function extendDispatch(project, id, decision) {
|
|
588
|
-
need(!(process.env.CLAUDECODE || process.env.CLAUDE_CODE_ENTRYPOINT), "Dispatch extension requires an external operator");
|
|
589
|
-
need(decision.reason?.trim() && decision.reference?.path, "Dispatch extension needs a reason and authorization artifact");
|
|
590
|
-
verifyArtifact(project, decision.reference);
|
|
591
|
-
return transaction(project, ledger => {
|
|
592
|
-
const task = taskRecord(project, id), entry = ledger.tasks[id];
|
|
593
|
-
need(entry && !task.closed, "Only an open registered task can extend dispatch limits");
|
|
594
|
-
need(!Object.values(ledger.dispatches).some(active), "Settle all active dispatches before extending limits");
|
|
595
|
-
const previousLimit = entry.limits.maxDispatches, newLimit = decision.maxDispatches;
|
|
596
|
-
need(decision.previousLimit === previousLimit, "Dispatch extension expected limit is stale");
|
|
597
|
-
need(Number.isSafeInteger(newLimit) && newLimit > previousLimit && newLimit <= 1000, "Dispatch extension must increase the finite limit");
|
|
598
|
-
const extension = { action: "extend-dispatch", taskId: id, at: now(), previousLimit, newLimit,
|
|
599
|
-
reason: decision.reason.trim(), reference: decision.reference };
|
|
600
|
-
entry.limits.maxDispatches = newLimit;
|
|
601
|
-
ledger.events.push(extension);
|
|
602
|
-
return extension; // Spent attempts, ancestor limits and protected slots remain intact.
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
export function status(project, id) {
|
|
606
|
-
taskRecord(project, id); const ledger = load(project), reservations = Object.values(ledger.dispatches).filter(d => belongs(ledger, d.taskId, id));
|
|
607
|
-
return { taskId: id, reservations, active: reservations.filter(active), limits: ledger.tasks[id]?.limits ?? null,
|
|
608
|
-
deliveryBudget: deliveryBudget(ledger.tasks[id], reservations),
|
|
609
|
-
usage: { dispatches: reservations.length, reviewDispatches: reservations.filter(d => d.kind === "review").length }, telemetry: telemetryFrom(ledger, id, project) };
|
|
610
|
-
}
|
|
611
|
-
export function telemetry(project, id) { taskRecord(project, id); return telemetryFrom(load(project), id, project); }
|
|
612
|
-
export function checkpoint(project, id, input = {}) {
|
|
613
|
-
need(input.reason?.trim(), "Checkpoint needs a reason");
|
|
614
|
-
const task = taskRecord(project, id), file = `.nccgs/evidence/checkpoints/${id}-${crypto.randomUUID()}.json`;
|
|
615
|
-
atomicJson(contained(project, file), { schemaVersion: 1, taskId: id, reason: input.reason, capturedAt: now(),
|
|
616
|
-
sourceSnapshot: snapshot(project, task).sha256, task: artifact(project, `.nccgs/tasks/${id}.json`), orchestration: status(project, id) });
|
|
617
|
-
return artifact(project, file);
|
|
618
|
-
}
|
|
619
|
-
export function resume(project, id) {
|
|
620
|
-
return transaction(project, ledger => {
|
|
621
|
-
const task = taskRecord(project, id); chain(project, id, ledger);
|
|
622
|
-
const unresolved = Object.values(ledger.dispatches).filter(d => belongs(ledger, d.taskId, id) && active(d));
|
|
623
|
-
ledger.events.push({ action: "resume", taskId: id, at: now(), unresolved: unresolved.map(d => d.id) });
|
|
624
|
-
return { taskId: id, sourceSnapshot: snapshot(project, task).sha256, needsReconciliation: unresolved.length > 0,
|
|
625
|
-
reservations: unresolved, telemetry: telemetryFrom(ledger, id, project), message: "Resume preserves attempts, observations, findings and budgets; no automatic slot expiry or approval." };
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
export function findDispatch(project, input) {
|
|
629
|
-
const ledger = load(project);
|
|
630
|
-
const marker = !input.agent_id && ["Agent", "Task"].includes(input.tool_name) ? input.tool_input?.prompt?.match(/^\[NCCGS-DISPATCH:([\w-]+)\]/)?.[1] : null;
|
|
631
|
-
if (marker) return ledger.dispatches[marker] ?? null;
|
|
632
|
-
const items = Object.values(ledger.dispatches).filter(d => d.sessionId === input.session_id &&
|
|
633
|
-
((input.tool_use_id && d.toolUseId === input.tool_use_id) || (input.agent_id && d.agentId === input.agent_id)));
|
|
634
|
-
return items.length === 1 ? items[0] : null;
|
|
635
|
-
}
|
|
636
|
-
export function correlateAgentStart(project, input) {
|
|
637
|
-
const items = Object.values(load(project).dispatches).filter(d => active(d) && d.sessionId === input.session_id && d.agent === input.agent_type && !d.agentId);
|
|
638
|
-
// SubagentStart has no tool-use ID. Ambiguous launches must never be guessed.
|
|
639
|
-
return items.length === 1 ? attachAgent(project, items[0].id, input.agent_id) : null;
|
|
640
|
-
}
|
|
641
|
-
export function validateStageDispatch(project, task, input, trace, kind) {
|
|
642
|
-
const ledger = load(project), d = ledger.dispatches[input.dispatchId];
|
|
643
|
-
need(d?.handoff?.status !== "missing", `${kind}: invocation ended but required handoff artifacts are missing; reserve a new attempt`);
|
|
644
|
-
need(!d?.handoff?.partial?.length, `${kind}: handoff is partial; reserve a new bounded attempt`);
|
|
645
|
-
need(d && d.taskId === task.id && d.kind === kind && d.status === "completed", `${kind}: completed managed dispatch required`);
|
|
646
|
-
need(d.handoff?.status !== "missing", `${kind}: invocation ended but required handoff artifacts are missing; reserve a new attempt`);
|
|
647
|
-
for (const ref of d.handoff?.artifacts ?? []) verifyArtifact(project, ref);
|
|
648
|
-
if (d.workPacket) verifyRepairPacket(project, d);
|
|
649
|
-
for (const step of d.editorSteps ?? []) verifyArtifact(project, step.evidence);
|
|
650
|
-
need(d.contractHash === task.contractHash && d.completedSnapshot === input.snapshot && same(d.runtime, input.runtime), "Stage dispatch covers different snapshot/contract/evidence");
|
|
651
|
-
need(d.sessionId === trace.sessionId && d.agentId === trace.agentId && d.toolUseId === trace.toolUseId, "Stage dispatch/runtime identity mismatch");
|
|
652
|
-
const stored = readSlicePlan(project, task, ledger);
|
|
653
|
-
if (stored) {
|
|
654
|
-
const progress = sliceProgress(project, task, ledger, stored);
|
|
655
|
-
need(progress.slices.every(s => s.state === "DELIVERED"), "All planned slices need complete current native handoffs before integrated verification/review");
|
|
656
|
-
const integration = ledger.dispatches[progress.slices.find(s => s.id === stored.plan.integration).dispatchId];
|
|
657
|
-
if (kind === "implementation") need(d.id === integration.id || (d.purpose === "repair" && d.slicePlan && Date.parse(d.createdAt) >= Date.parse(integration.finishedAt)),
|
|
658
|
-
"Record the final integration dispatch (or subsequent repair), never promote an intermediate slice to whole-task completion");
|
|
659
|
-
if (kind === "review") need(!Object.values(ledger.dispatches).some(other => belongs(ledger, other.taskId, task.id) && other.kind === "implementation"
|
|
660
|
-
&& other.sessionId === trace.sessionId && other.agentId === trace.agentId), "Review must be independent of every implementation contributor, including earlier slices and failed repairs");
|
|
661
|
-
}
|
|
662
|
-
// Recording rejects consumed IDs; read-only inspection must accept an already
|
|
663
|
-
// recorded stage without treating it as a new attempt.
|
|
664
|
-
return d;
|
|
665
|
-
}
|
|
666
|
-
export const validateReviewDispatch = (project, task, input, trace) => validateStageDispatch(project, task, input, trace, "review");
|
|
667
|
-
export function runDispatch(command, { project, id, value }) {
|
|
668
|
-
const request = () => json(contained(project, value("--request")));
|
|
669
|
-
if (command === "reserve") return reserve(project, id, request());
|
|
670
|
-
if (command === "dispatch-claim") return claim(project, value("--dispatch"), request());
|
|
671
|
-
if (command === "dispatch-complete") return complete(project, value("--dispatch"), { runtime: artifact(project, value("--file")) });
|
|
672
|
-
if (command === "dispatch-reconcile") return reconcile(project, value("--dispatch"), request());
|
|
673
|
-
if (command === "extend-dispatch") return extendDispatch(project, id, request());
|
|
674
|
-
if (command === "dispatch-status") return status(project, id);
|
|
675
|
-
if (command === "dispatch-prompt") return dispatchPrompt(project, id, value("--dispatch"));
|
|
676
|
-
if (command === "checkpoint") return checkpoint(project, id, { reason: value("--reason") });
|
|
677
|
-
if (command === "resume") return resume(project, id);
|
|
678
|
-
if (command === "telemetry") return telemetry(project, id);
|
|
679
|
-
return null;
|
|
680
|
-
}
|