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.
Files changed (705) hide show
  1. package/CHANGELOG.md +76 -235
  2. package/LICENSE +1 -1
  3. package/README.md +87 -206
  4. package/THIRD_PARTY_NOTICES.md +6 -34
  5. package/bin/nccgs.mjs +96 -0
  6. package/cli/doctor.mjs +82 -0
  7. package/cli/feedback.mjs +13 -0
  8. package/cli/install.mjs +111 -0
  9. package/cli/release.mjs +59 -0
  10. package/cli/run.mjs +35 -0
  11. package/cli/spawn.mjs +20 -0
  12. package/cli/uninstall.mjs +43 -0
  13. package/cli/update-check.mjs +66 -0
  14. package/docs/EVIDENCE-VERIFICATION.md +22 -0
  15. package/package.json +23 -30
  16. package/runtime/core/diag.mjs +43 -0
  17. package/runtime/core/feedback-policy.mjs +54 -0
  18. package/runtime/core/fs.mjs +80 -0
  19. package/runtime/core/job-object.mjs +73 -0
  20. package/runtime/core/modes.mjs +87 -0
  21. package/runtime/core/process-tree.mjs +109 -0
  22. package/runtime/core/project.mjs +113 -0
  23. package/runtime/core/snapshot.mjs +114 -0
  24. package/runtime/hooks/common.mjs +22 -0
  25. package/runtime/hooks/done-guard.mjs +15 -0
  26. package/runtime/hooks/guard-mcp.mjs +8 -0
  27. package/runtime/hooks/guard-shell.mjs +16 -0
  28. package/runtime/hooks/guard-write.mjs +25 -0
  29. package/runtime/hooks/session-log.mjs +7 -0
  30. package/runtime/hooks/session-start.mjs +40 -0
  31. package/runtime/hooks/unity-transport.mjs +12 -0
  32. package/runtime/modes.json +39 -0
  33. package/runtime/task/cost.mjs +103 -0
  34. package/runtime/task/criteria.mjs +128 -0
  35. package/runtime/task/feedback.mjs +136 -0
  36. package/runtime/task/ledger.mjs +109 -0
  37. package/runtime/task/plan.mjs +69 -0
  38. package/runtime/task/project.mjs +79 -0
  39. package/runtime/task/report.mjs +252 -0
  40. package/runtime/task/task.mjs +238 -0
  41. package/runtime/unity/assets.mjs +51 -0
  42. package/runtime/unity/playtest.mjs +145 -0
  43. package/runtime/unity/unity.mjs +350 -0
  44. package/scripts/check-job-object.mjs +18 -0
  45. package/scripts/sync-unity-skills.mjs +35 -119
  46. package/template/CLAUDE.md +39 -0
  47. package/template/agents/fast-fix.md +9 -0
  48. package/template/agents/implementer.md +19 -0
  49. package/template/agents/playtester.md +15 -0
  50. package/template/agents/reviewer.md +19 -0
  51. package/template/agents/scout.md +9 -0
  52. package/template/ponytail/README.md +8 -0
  53. package/{.claude/nccgs/packages → template}/ponytail/engineering.md +10 -0
  54. package/template/protocols/evidence.md +52 -0
  55. package/template/protocols/playtest.md +45 -0
  56. package/template/protocols/review.md +34 -0
  57. package/template/protocols/unity-cli-notes.md +56 -0
  58. package/template/settings.fragment.json +33 -0
  59. package/template/skills/art-bible/SKILL.md +19 -0
  60. package/template/skills/asset-spec/SKILL.md +19 -0
  61. package/template/skills/brainstorm/SKILL.md +17 -0
  62. package/template/skills/feedback/SKILL.md +16 -0
  63. package/template/skills/map-systems/SKILL.md +25 -0
  64. package/template/skills/playtest/SKILL.md +17 -0
  65. package/template/skills/status/SKILL.md +18 -0
  66. package/template/skills/test/SKILL.md +34 -0
  67. package/template/skills/unity-foundation/SKILL.md +17 -0
  68. package/template/skills/vertical-slice/SKILL.md +17 -0
  69. package/template/skills/work/SKILL.md +65 -0
  70. package/tools/feedback-worker/README.md +12 -0
  71. package/tools/feedback-worker/worker.js +39 -0
  72. package/tools/feedback-worker/wrangler.toml +12 -0
  73. package/unity-skills/2d-pixel-perfect/SKILL.md +208 -0
  74. package/unity-skills/2d-pixel-perfect/references/api-reference.md +81 -0
  75. package/unity-skills/2d-pixel-perfect/references/camera-setup-builtin.cs +40 -0
  76. package/unity-skills/2d-pixel-perfect/references/camera-setup-urp.cs +49 -0
  77. package/unity-skills/2d-pixel-perfect/references/pipeline-detection.cs +50 -0
  78. package/unity-skills/2d-pixel-perfect/references/sprite-settings.cs +37 -0
  79. package/unity-skills/asset-transformer-toolkit/SECURITY.md +15 -0
  80. package/unity-skills/asset-transformer-toolkit/SKILL.md +39 -0
  81. package/unity-skills/asset-transformer-toolkit/references/create-importer.md +121 -0
  82. package/unity-skills/asset-transformer-toolkit/references/lods.md +61 -0
  83. package/unity-skills/asset-transformer-toolkit/references/rule-api.md +154 -0
  84. package/unity-skills/asset-transformer-toolkit/references/ruleblock-api.md +37 -0
  85. package/unity-skills/asset-transformer-toolkit/references/ruleset-api.md +138 -0
  86. package/unity-skills/asset-transformer-toolkit/references/rulesets-and-actions.md +227 -0
  87. package/unity-skills/audio-setup-mixers/SECURITY.md +16 -0
  88. package/unity-skills/audio-setup-mixers/SKILL.md +127 -0
  89. package/unity-skills/audio-setup-mixers/references/api.md +162 -0
  90. package/unity-skills/build-gtk/SKILL.md +242 -0
  91. package/unity-skills/build-gtk/references/graph-api.md +324 -0
  92. package/unity-skills/build-gtk/references/pitfalls.md +86 -0
  93. package/unity-skills/build-gtk/references/runtime-and-visualization.md +196 -0
  94. package/unity-skills/build-gtk/references/state-machine-api.md +286 -0
  95. package/unity-skills/build-live-game/SKILL.md +255 -0
  96. package/{.claude/skills → unity-skills}/build-live-game/references/achievements.md +132 -154
  97. package/{.claude/skills → unity-skills}/build-live-game/references/apis.md +10 -19
  98. package/{.claude/skills → unity-skills}/build-live-game/references/authentication.md +14 -20
  99. package/{.claude/skills → unity-skills}/build-live-game/references/battlepass.md +269 -225
  100. package/unity-skills/build-live-game/references/blueprints-and-samples.md +75 -0
  101. package/unity-skills/build-live-game/references/cloud-code-cloudbehaviours.md +1111 -0
  102. package/unity-skills/build-live-game/references/cloud-code-modules.md +1276 -0
  103. package/unity-skills/build-live-game/references/cloud-code.md +58 -0
  104. package/{.claude/skills → unity-skills}/build-live-game/references/cloud-save.md +15 -25
  105. package/{.claude/skills → unity-skills}/build-live-game/references/deployment.md +33 -18
  106. package/{.claude/skills → unity-skills}/build-live-game/references/player-account.md +31 -23
  107. package/{.claude/skills → unity-skills}/build-live-game/references/tooling.md +0 -56
  108. package/unity-skills/build-live-game/references/ugs-cli.md +86 -0
  109. package/unity-skills/craft-game-floors/SECURITY.md +23 -0
  110. package/unity-skills/craft-game-floors/SKILL.md +134 -0
  111. package/unity-skills/craft-game-floors/references/art-direction.md +85 -0
  112. package/unity-skills/craft-game-floors/references/camera-rigs.md +51 -0
  113. package/unity-skills/craft-game-floors/references/character-motion.md +35 -0
  114. package/unity-skills/craft-game-floors/references/game-audio.md +47 -0
  115. package/unity-skills/craft-game-floors/references/game-feel.md +68 -0
  116. package/unity-skills/craft-game-floors/references/game-shell.md +45 -0
  117. package/unity-skills/craft-game-floors/references/live-floor.md +35 -0
  118. package/unity-skills/craft-game-floors/references/placeholder-assets.md +35 -0
  119. package/unity-skills/craft-game-floors/references/scene-lighting.md +52 -0
  120. package/unity-skills/craft-game-floors/references/toon-shading.md +34 -0
  121. package/unity-skills/craft-game-floors/references/vfx.md +40 -0
  122. package/unity-skills/craft-game-floors/references/visual-scorecard.md +43 -0
  123. package/unity-skills/create-2d-physics/SECURITY.md +16 -0
  124. package/unity-skills/create-2d-physics/SKILL.md +128 -0
  125. package/unity-skills/create-2d-physics/references/2d-physics-core.md +155 -0
  126. package/unity-skills/create-2d-physics/references/legacy-2d-physics.md +45 -0
  127. package/unity-skills/create-tile-palette-or-rule-tiles/SKILL.md +12 -0
  128. package/unity-skills/create-tile-palette-or-rule-tiles/references/hexagonalruletile.md +71 -0
  129. package/unity-skills/create-tile-palette-or-rule-tiles/references/palette-create.md +38 -0
  130. package/unity-skills/create-tile-palette-or-rule-tiles/references/ruletile-createempty.md +35 -0
  131. package/unity-skills/create-tile-palette-or-rule-tiles/references/ruletile-createfromsegment.md +212 -0
  132. package/unity-skills/create-tile-palette-or-rule-tiles/references/ruletile.md +90 -0
  133. package/unity-skills/create-tile-palette-or-rule-tiles/scripts/CreatePaletteTemplate.cs +148 -0
  134. package/unity-skills/create-tile-palette-or-rule-tiles/scripts/ManualWorkflowExample.cs +63 -0
  135. package/unity-skills/create-tile-palette-or-rule-tiles/scripts/RuleTileGenerator.cs +61 -0
  136. package/unity-skills/create-tile-palette-or-rule-tiles/scripts/TilemapRuleTileCreateFromSegment.cs +225 -0
  137. package/unity-skills/generate-editor-search-query/SECURITY.md +17 -0
  138. package/unity-skills/generate-editor-search-query/SKILL.md +117 -0
  139. package/unity-skills/generate-editor-search-query/references/open-search-window.md +70 -0
  140. package/unity-skills/generate-editor-search-query/references/query-patterns.md +124 -0
  141. package/{.claude/skills → unity-skills}/implement-in-app-purchases/SKILL.md +1 -2
  142. package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/api-notes.md +25 -28
  143. package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/path-convert-native-google-billing.md +1 -1
  144. package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/path-implement-iap-d2c.md +40 -5
  145. package/{.claude/skills → unity-skills}/initialize-ai-navigation/SKILL.md +4 -4
  146. package/{.claude/skills → unity-skills}/initialize-ai-navigation/references/navigation-system.md +3 -3
  147. package/{.claude/skills → unity-skills}/levelplay-unity-integration/CHANGELOG.md +12 -0
  148. package/{.claude/skills → unity-skills}/levelplay-unity-integration/README.md +9 -5
  149. package/unity-skills/levelplay-unity-integration/SKILL.md +442 -0
  150. package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/banner-api.md +15 -8
  151. package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/best-practices.md +604 -536
  152. package/unity-skills/levelplay-unity-integration/references/dependency-resolution.md +94 -0
  153. package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/ilrd-api.md +2 -2
  154. package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/initialization-api.md +221 -0
  155. package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/interstitial-api.md +11 -3
  156. package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/ios-setup.md +6 -34
  157. package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/migration-sdk-9.md +1 -1
  158. package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/privacy-settings.md +14 -29
  159. package/{.claude/skills → unity-skills}/levelplay-unity-integration/references/rewarded-api.md +20 -4
  160. package/unity-skills/levelplay-unity-integration/references/testing-and-validation.md +222 -0
  161. package/unity-skills/levelplay-unity-integration/references/troubleshooting.md +99 -0
  162. package/unity-skills/localization/SKILL.md +347 -0
  163. package/{.claude/skills → unity-skills}/localization/references/api-notes.md +4 -0
  164. package/unity-skills/localization/resources/L10nBatchProcessor.cs +191 -0
  165. package/unity-skills/manage-sprite-atlas/SKILL.md +351 -0
  166. package/unity-skills/manage-sprite-atlas/references/addressables-delivery.md +58 -0
  167. package/unity-skills/manage-sprite-atlas/references/api.md +382 -0
  168. package/unity-skills/manage-sprite-atlas/references/best-practices.md +183 -0
  169. package/unity-skills/manage-sprite-atlas/references/common-errors.md +123 -0
  170. package/unity-skills/manage-sprite-atlas/references/custom-packing.md +147 -0
  171. package/unity-skills/manage-sprite-atlas/references/manual-authoring.md +39 -0
  172. package/unity-skills/manage-sprite-atlas/resources/authoringvsruntime.cs +176 -0
  173. package/unity-skills/manage-sprite-atlas/resources/buildaddressablespostprocess.cs +59 -0
  174. package/unity-skills/manage-sprite-atlas/resources/cacheloadedatlases.cs +145 -0
  175. package/unity-skills/manage-sprite-atlas/resources/cleanupbatchoperations.cs +119 -0
  176. package/unity-skills/manage-sprite-atlas/resources/createandconfiguremasteratlas.cs +57 -0
  177. package/unity-skills/manage-sprite-atlas/resources/custompackersetup.cs +88 -0
  178. package/unity-skills/manage-sprite-atlas/resources/deprecatedmethods.cs +142 -0
  179. package/unity-skills/manage-sprite-atlas/resources/dontmodifywithoutsaving.cs +120 -0
  180. package/unity-skills/manage-sprite-atlas/resources/dontpackinruntimebuilds.cs +190 -0
  181. package/unity-skills/manage-sprite-atlas/resources/dontscriptspriteatlasineditor.cs +114 -0
  182. package/unity-skills/manage-sprite-atlas/resources/editorconfiguration.cs +95 -0
  183. package/unity-skills/manage-sprite-atlas/resources/enablespritepacking.cs +172 -0
  184. package/unity-skills/manage-sprite-atlas/resources/gridspritepacker.cs +50 -0
  185. package/unity-skills/manage-sprite-atlas/resources/handlelatebinding.cs +147 -0
  186. package/unity-skills/manage-sprite-atlas/resources/handlenullcases.cs +141 -0
  187. package/unity-skills/manage-sprite-atlas/resources/migratev1tov2.cs +335 -0
  188. package/unity-skills/manage-sprite-atlas/resources/multipagepacker.cs +80 -0
  189. package/unity-skills/manage-sprite-atlas/resources/optimizetexturesettings.cs +191 -0
  190. package/unity-skills/manage-sprite-atlas/resources/packerdebugging.cs +158 -0
  191. package/unity-skills/manage-sprite-atlas/resources/packtransform.cs +51 -0
  192. package/unity-skills/manage-sprite-atlas/resources/platformnames.cs +127 -0
  193. package/unity-skills/manage-sprite-atlas/resources/queryspritesefficiently.cs +222 -0
  194. package/unity-skills/manage-sprite-atlas/resources/registercallbacks.cs +152 -0
  195. package/unity-skills/manage-sprite-atlas/resources/runtimeatlasloader.cs +15 -0
  196. package/unity-skills/manage-sprite-atlas/resources/runtimespriteaccess.cs +19 -0
  197. package/unity-skills/manage-sprite-atlas/resources/savespriteatlasasset.cs +107 -0
  198. package/unity-skills/manage-sprite-atlas/resources/scriptablepacker.cs +81 -0
  199. package/unity-skills/manage-sprite-atlas/resources/setincludeinbuild.cs +164 -0
  200. package/unity-skills/manage-sprite-atlas/resources/sizeoptimizedpacker.cs +88 -0
  201. package/unity-skills/manage-sprite-atlas/resources/spriteatlaslatebinding.cs +123 -0
  202. package/unity-skills/manage-sprite-atlas/resources/spriteatlasprebuildgenerator.cs +219 -0
  203. package/unity-skills/manage-sprite-atlas/resources/spritedata.cs +35 -0
  204. package/unity-skills/manage-sprite-atlas/resources/spritepack.cs +39 -0
  205. package/unity-skills/manage-sprite-atlas/resources/texturedata.cs +15 -0
  206. package/unity-skills/manage-sprite-atlas/resources/updatebuildscripts.cs +357 -0
  207. package/unity-skills/manage-sprite-atlas/resources/updatesettingsconfiguration.cs +135 -0
  208. package/unity-skills/manage-sprite-atlas/resources/usevariantswisely.cs +179 -0
  209. package/unity-skills/manage-sprite-atlas/resources/variantatlas.cs +39 -0
  210. package/unity-skills/manifest.json +1155 -0
  211. package/unity-skills/migrate-birp-to-urp/SECURITY.md +16 -0
  212. package/unity-skills/migrate-birp-to-urp/SKILL.md +543 -0
  213. package/unity-skills/migrate-birp-to-urp/references/capturing-the-editor.md +66 -0
  214. package/unity-skills/migrate-birp-to-urp/references/complex-shader-situations.md +272 -0
  215. package/unity-skills/migrate-birp-to-urp/references/custom-shader-triage.md +123 -0
  216. package/unity-skills/migrate-birp-to-urp/references/implementation-patterns.md +529 -0
  217. package/unity-skills/migrate-birp-to-urp/references/migration-workflow.md +265 -0
  218. package/unity-skills/migrate-birp-to-urp/references/quality-settings-map.md +69 -0
  219. package/unity-skills/new-unity-project/SECURITY.md +26 -0
  220. package/unity-skills/new-unity-project/SKILL.md +386 -0
  221. package/unity-skills/new-unity-project/references/skill-setup.md +66 -0
  222. package/unity-skills/optimize-audio/SECURITY.md +16 -0
  223. package/{.claude/skills → unity-skills}/optimize-audio/SKILL.md +17 -17
  224. package/{.claude/skills → unity-skills}/optimize-audio/resources/audio-import-api.md +8 -5
  225. package/{.claude/skills → unity-skills}/optimize-text-mesh-pro/SKILL.md +1 -11
  226. package/unity-skills/optimize-web/SECURITY.md +16 -0
  227. package/{.claude/skills → unity-skills}/optimize-web/SKILL.md +164 -27
  228. package/unity-skills/optimize-web/scripts/WebOptimizer.cs +46 -0
  229. package/unity-skills/optimize-web/scripts/toktx-examples.sh +11 -0
  230. package/{.claude/skills → unity-skills}/physics-3d-collision/SKILL.md +2 -2
  231. package/unity-skills/physics-3d-collision/references/troubleshooting.md +8 -0
  232. package/unity-skills/project-auditor-fixes/SKILL.md +64 -0
  233. package/{.claude/skills → unity-skills}/setup-multiplayer-services/SKILL.md +1 -4
  234. package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/SKILL.md +1 -1
  235. package/{.claude/skills → unity-skills}/shader-graph-create-custom-node/SKILL.md +1 -1
  236. package/unity-skills/sprite-editor/SECURITY.md +16 -0
  237. package/{.claude/skills → unity-skills}/sprite-editor/SKILL.md +9 -9
  238. package/{.claude/skills → unity-skills}/sprite-editor/references/templates.md +1 -1
  239. package/unity-skills/sprite-segment-3x3grid/SKILL.md +136 -0
  240. package/unity-skills/sprite-segment-3x3grid/scripts/SpriteGridAnalysis.cs +119 -0
  241. package/{.claude/skills → unity-skills}/ui/SKILL.md +1 -1
  242. package/{.claude/skills → unity-skills}/ui-imgui/SKILL.md +1 -7
  243. package/{.claude/skills → unity-skills}/ui-ugui/SKILL.md +3 -9
  244. package/{.claude/skills → unity-skills}/ui-uitk/SKILL.md +8 -14
  245. package/{.claude/skills → unity-skills}/ui-uitk/references/custom-elements.md +1 -1
  246. package/unity-skills/unity-cli/CHANGELOG.md +515 -0
  247. package/unity-skills/unity-cli/SECURITY.md +68 -0
  248. package/unity-skills/unity-cli/SKILL.md +723 -0
  249. package/unity-skills/unity-cli/references/auth-license-cloud.md +318 -0
  250. package/unity-skills/unity-cli/references/build-run-test.md +555 -0
  251. package/unity-skills/unity-cli/references/cloud-automation.md +736 -0
  252. package/{.claude/skills → unity-skills}/unity-cli/references/collaboration.md +166 -105
  253. package/unity-skills/unity-cli/references/config-hub.md +239 -0
  254. package/unity-skills/unity-cli/references/diagnostics-maintenance.md +720 -0
  255. package/unity-skills/unity-cli/references/docs-workflow.md +179 -0
  256. package/unity-skills/unity-cli/references/editors-install.md +476 -0
  257. package/unity-skills/unity-cli/references/integration-advanced.md +1130 -0
  258. package/unity-skills/unity-cli/references/playmode-verification-loop.md +279 -0
  259. package/unity-skills/unity-cli/references/projects-templates.md +996 -0
  260. package/unity-skills/unity-cli/references/version-control.md +612 -0
  261. package/{.claude/skills → unity-skills}/unity-package-management/SKILL.md +60 -12
  262. package/{.claude/skills → unity-skills}/unity-package-management/references/select-packages.md +39 -21
  263. package/unity-skills/unity-pipeline/SECURITY.md +17 -0
  264. package/unity-skills/unity-pipeline/SKILL.md +335 -0
  265. package/unity-skills/urp-postprocessing/SECURITY.md +16 -0
  266. package/{.claude/skills → unity-skills}/urp-postprocessing/SKILL.md +12 -12
  267. package/{.claude/skills → unity-skills}/urp-postprocessing/references/code-templates.md +39 -8
  268. package/{.claude/skills → unity-skills}/validate-urp-render-graph-renderer-feature/SKILL.md +1 -1
  269. package/.claude/agents/nccgs-adversarial-reviewer.md +0 -43
  270. package/.claude/agents/nccgs-engine-programmer.md +0 -27
  271. package/.claude/agents/nccgs-fast-implementer.md +0 -30
  272. package/.claude/agents/nccgs-game-designer.md +0 -26
  273. package/.claude/agents/nccgs-gameplay-programmer.md +0 -26
  274. package/.claude/agents/nccgs-qa-engineer.md +0 -27
  275. package/.claude/agents/nccgs-task-scout.md +0 -24
  276. package/.claude/agents/nccgs-ui-programmer.md +0 -27
  277. package/.claude/agents/nccgs-unity-build-specialist.md +0 -27
  278. package/.claude/agents/nccgs-unity-implementer.md +0 -28
  279. package/.claude/agents/nccgs-unity-systems-specialist.md +0 -27
  280. package/.claude/agents/nccgs-unity-ui-specialist.md +0 -27
  281. package/.claude/agents/nccgs-verification-engineer.md +0 -27
  282. package/.claude/nccgs/MEMORY.md +0 -66
  283. package/.claude/nccgs/THIRD_PARTY_NOTICES.md +0 -29
  284. package/.claude/nccgs/VERSION +0 -1
  285. package/.claude/nccgs/agent-library/nccgs-accessibility-specialist.md +0 -25
  286. package/.claude/nccgs/agent-library/nccgs-adversarial-reviewer.md +0 -41
  287. package/.claude/nccgs/agent-library/nccgs-ai-programmer.md +0 -25
  288. package/.claude/nccgs/agent-library/nccgs-analytics-engineer.md +0 -25
  289. package/.claude/nccgs/agent-library/nccgs-art-direction-lead.md +0 -25
  290. package/.claude/nccgs/agent-library/nccgs-audio-direction-lead.md +0 -25
  291. package/.claude/nccgs/agent-library/nccgs-creative-director.md +0 -25
  292. package/.claude/nccgs/agent-library/nccgs-documentation-manager.md +0 -25
  293. package/.claude/nccgs/agent-library/nccgs-economy-designer.md +0 -25
  294. package/.claude/nccgs/agent-library/nccgs-engine-programmer.md +0 -25
  295. package/.claude/nccgs/agent-library/nccgs-fast-implementer.md +0 -28
  296. package/.claude/nccgs/agent-library/nccgs-game-design-lead.md +0 -25
  297. package/.claude/nccgs/agent-library/nccgs-game-designer.md +0 -24
  298. package/.claude/nccgs/agent-library/nccgs-gameplay-programmer.md +0 -24
  299. package/.claude/nccgs/agent-library/nccgs-level-designer.md +0 -25
  300. package/.claude/nccgs/agent-library/nccgs-live-ops-designer.md +0 -25
  301. package/.claude/nccgs/agent-library/nccgs-localization-lead.md +0 -25
  302. package/.claude/nccgs/agent-library/nccgs-narrative-lead.md +0 -25
  303. package/.claude/nccgs/agent-library/nccgs-network-programmer.md +0 -25
  304. package/.claude/nccgs/agent-library/nccgs-performance-analyst.md +0 -25
  305. package/.claude/nccgs/agent-library/nccgs-producer.md +0 -25
  306. package/.claude/nccgs/agent-library/nccgs-production-coordinator.md +0 -22
  307. package/.claude/nccgs/agent-library/nccgs-programming-lead.md +0 -25
  308. package/.claude/nccgs/agent-library/nccgs-prototyper.md +0 -25
  309. package/.claude/nccgs/agent-library/nccgs-qa-engineer.md +0 -25
  310. package/.claude/nccgs/agent-library/nccgs-qa-lead.md +0 -25
  311. package/.claude/nccgs/agent-library/nccgs-release-engineer.md +0 -25
  312. package/.claude/nccgs/agent-library/nccgs-release-lead.md +0 -25
  313. package/.claude/nccgs/agent-library/nccgs-security-engineer.md +0 -25
  314. package/.claude/nccgs/agent-library/nccgs-sound-designer.md +0 -25
  315. package/.claude/nccgs/agent-library/nccgs-systems-designer.md +0 -25
  316. package/.claude/nccgs/agent-library/nccgs-task-scout.md +0 -22
  317. package/.claude/nccgs/agent-library/nccgs-technical-architect.md +0 -25
  318. package/.claude/nccgs/agent-library/nccgs-technical-artist.md +0 -25
  319. package/.claude/nccgs/agent-library/nccgs-technical-director.md +0 -25
  320. package/.claude/nccgs/agent-library/nccgs-tools-programmer.md +0 -25
  321. package/.claude/nccgs/agent-library/nccgs-ui-programmer.md +0 -25
  322. package/.claude/nccgs/agent-library/nccgs-unity-build-specialist.md +0 -25
  323. package/.claude/nccgs/agent-library/nccgs-unity-content-specialist.md +0 -25
  324. package/.claude/nccgs/agent-library/nccgs-unity-implementer.md +0 -26
  325. package/.claude/nccgs/agent-library/nccgs-unity-rendering-specialist.md +0 -25
  326. package/.claude/nccgs/agent-library/nccgs-unity-systems-specialist.md +0 -25
  327. package/.claude/nccgs/agent-library/nccgs-unity-ui-specialist.md +0 -25
  328. package/.claude/nccgs/agent-library/nccgs-ux-designer.md +0 -25
  329. package/.claude/nccgs/agent-library/nccgs-verification-engineer.md +0 -25
  330. package/.claude/nccgs/agent-library/nccgs-world-builder.md +0 -25
  331. package/.claude/nccgs/agent-library/nccgs-writer.md +0 -25
  332. package/.claude/nccgs/constitution.md +0 -187
  333. package/.claude/nccgs/hooks/agent-audit.mjs +0 -16
  334. package/.claude/nccgs/hooks/closure-guard.mjs +0 -59
  335. package/.claude/nccgs/hooks/common.mjs +0 -42
  336. package/.claude/nccgs/hooks/post-compact.mjs +0 -1
  337. package/.claude/nccgs/hooks/pre-compact.mjs +0 -8
  338. package/.claude/nccgs/hooks/protect-git.mjs +0 -22
  339. package/.claude/nccgs/hooks/protect-write.mjs +0 -17
  340. package/.claude/nccgs/hooks/runtime-observation.mjs +0 -11
  341. package/.claude/nccgs/hooks/session-start.mjs +0 -29
  342. package/.claude/nccgs/hooks/session-stop.mjs +0 -7
  343. package/.claude/nccgs/hooks/unity-transport-guard.mjs +0 -11
  344. package/.claude/nccgs/packages/ponytail/README.md +0 -46
  345. package/.claude/nccgs/packages/ponytail/manifest.json +0 -24
  346. package/.claude/nccgs/pipeline.json +0 -260
  347. package/.claude/nccgs/protocols/agent-contract.md +0 -101
  348. package/.claude/nccgs/protocols/astra-claude.md +0 -111
  349. package/.claude/nccgs/protocols/bounded-repair.md +0 -246
  350. package/.claude/nccgs/protocols/context-packets.md +0 -23
  351. package/.claude/nccgs/protocols/delivery-acceptance.md +0 -105
  352. package/.claude/nccgs/protocols/design-lifecycle.md +0 -139
  353. package/.claude/nccgs/protocols/editor-session-evidence.md +0 -52
  354. package/.claude/nccgs/protocols/evidence.md +0 -31
  355. package/.claude/nccgs/protocols/model-routing.md +0 -46
  356. package/.claude/nccgs/protocols/orchestration.md +0 -74
  357. package/.claude/nccgs/protocols/review-handoff.md +0 -101
  358. package/.claude/nccgs/protocols/shared-workflow-context.md +0 -33
  359. package/.claude/nccgs/protocols/standalone-gates.md +0 -329
  360. package/.claude/nccgs/protocols/standalone-pilot.md +0 -144
  361. package/.claude/nccgs/protocols/standalone.md +0 -207
  362. package/.claude/nccgs/protocols/task-autonomy.md +0 -55
  363. package/.claude/nccgs/protocols/task-gates.md +0 -144
  364. package/.claude/nccgs/protocols/task-slices.md +0 -106
  365. package/.claude/nccgs/protocols/unity-boundary.md +0 -31
  366. package/.claude/nccgs/routing.generated.md +0 -49
  367. package/.claude/nccgs/settings.fragment.json +0 -213
  368. package/.claude/nccgs/studio.json +0 -472
  369. package/.claude/nccgs/tools/approve-overrides.mjs +0 -81
  370. package/.claude/nccgs/tools/autonomy.mjs +0 -40
  371. package/.claude/nccgs/tools/command-process.mjs +0 -50
  372. package/.claude/nccgs/tools/command-tokens.mjs +0 -22
  373. package/.claude/nccgs/tools/compile-policy.mjs +0 -121
  374. package/.claude/nccgs/tools/configure-models.mjs +0 -96
  375. package/.claude/nccgs/tools/criteria.mjs +0 -121
  376. package/.claude/nccgs/tools/delivery-budget.mjs +0 -52
  377. package/.claude/nccgs/tools/design-readiness.mjs +0 -158
  378. package/.claude/nccgs/tools/editor-session-evidence.mjs +0 -66
  379. package/.claude/nccgs/tools/evidence.mjs +0 -153
  380. package/.claude/nccgs/tools/gates.mjs +0 -297
  381. package/.claude/nccgs/tools/handoff.mjs +0 -51
  382. package/.claude/nccgs/tools/hook-transport.mjs +0 -34
  383. package/.claude/nccgs/tools/inputs.mjs +0 -108
  384. package/.claude/nccgs/tools/installation-guard.mjs +0 -55
  385. package/.claude/nccgs/tools/integrity.mjs +0 -69
  386. package/.claude/nccgs/tools/lifecycle.mjs +0 -542
  387. package/.claude/nccgs/tools/native-completion.mjs +0 -30
  388. package/.claude/nccgs/tools/orchestration.mjs +0 -680
  389. package/.claude/nccgs/tools/paths.mjs +0 -60
  390. package/.claude/nccgs/tools/policy.mjs +0 -107
  391. package/.claude/nccgs/tools/process-lock.mjs +0 -74
  392. package/.claude/nccgs/tools/repair-packet.mjs +0 -106
  393. package/.claude/nccgs/tools/returned-handoff.mjs +0 -47
  394. package/.claude/nccgs/tools/review-budget.mjs +0 -171
  395. package/.claude/nccgs/tools/review-handoff.mjs +0 -66
  396. package/.claude/nccgs/tools/runtime.mjs +0 -71
  397. package/.claude/nccgs/tools/session-budget.mjs +0 -67
  398. package/.claude/nccgs/tools/shared-context-guard.mjs +0 -60
  399. package/.claude/nccgs/tools/shared-context.mjs +0 -25
  400. package/.claude/nccgs/tools/task-slices.mjs +0 -147
  401. package/.claude/nccgs/tools/task.mjs +0 -145
  402. package/.claude/nccgs/tools/tool-guard.mjs +0 -120
  403. package/.claude/nccgs/tools/unity-repair.mjs +0 -128
  404. package/.claude/nccgs/tools/unity-transport.mjs +0 -170
  405. package/.claude/nccgs/tools/verification-jobs.mjs +0 -171
  406. package/.claude/nccgs/tools/verification-worker.mjs +0 -71
  407. package/.claude/nccgs/tools/windows-compiler-server.cs +0 -163
  408. package/.claude/nccgs/tools/windows-job.cs +0 -103
  409. package/.claude/nccgs/unity-skills-manifest.json +0 -727
  410. package/.claude/nccgs/workflow-catalog.json +0 -654
  411. package/.claude/rules/nccgs-canonical-docs.md +0 -19
  412. package/.claude/rules/nccgs-editor-tools.md +0 -12
  413. package/.claude/rules/nccgs-localization.md +0 -12
  414. package/.claude/rules/nccgs-networking.md +0 -13
  415. package/.claude/rules/nccgs-performance.md +0 -14
  416. package/.claude/rules/nccgs-rendering.md +0 -16
  417. package/.claude/rules/nccgs-security.md +0 -13
  418. package/.claude/rules/nccgs-tests.md +0 -18
  419. package/.claude/rules/nccgs-ui.md +0 -14
  420. package/.claude/rules/nccgs-unity-assets.md +0 -21
  421. package/.claude/rules/nccgs-unity-code.md +0 -22
  422. package/.claude/skills/accessibility-review/SKILL.md +0 -22
  423. package/.claude/skills/accessibility-review/references/astra.md +0 -17
  424. package/.claude/skills/accessibility-review/references/legacy.md +0 -7
  425. package/.claude/skills/architecture-decision/SKILL.md +0 -22
  426. package/.claude/skills/architecture-decision/references/astra.md +0 -12
  427. package/.claude/skills/architecture-decision/references/legacy.md +0 -7
  428. package/.claude/skills/asset-audit/SKILL.md +0 -22
  429. package/.claude/skills/asset-audit/references/astra.md +0 -17
  430. package/.claude/skills/asset-audit/references/legacy.md +0 -7
  431. package/.claude/skills/audit/SKILL.md +0 -22
  432. package/.claude/skills/audit/references/astra.md +0 -17
  433. package/.claude/skills/audit/references/dimensions.md +0 -46
  434. package/.claude/skills/audit/references/legacy.md +0 -9
  435. package/.claude/skills/balance-review/SKILL.md +0 -22
  436. package/.claude/skills/balance-review/references/astra.md +0 -17
  437. package/.claude/skills/balance-review/references/legacy.md +0 -7
  438. package/.claude/skills/bug-triage/SKILL.md +0 -22
  439. package/.claude/skills/bug-triage/references/astra.md +0 -27
  440. package/.claude/skills/bug-triage/references/legacy.md +0 -7
  441. package/.claude/skills/build-live-game/SKILL.md +0 -317
  442. package/.claude/skills/build-live-game/references/cloud-code.md +0 -563
  443. package/.claude/skills/closure/SKILL.md +0 -22
  444. package/.claude/skills/closure/references/astra.md +0 -15
  445. package/.claude/skills/closure/references/legacy.md +0 -7
  446. package/.claude/skills/compatibility-review/SKILL.md +0 -22
  447. package/.claude/skills/compatibility-review/references/astra.md +0 -17
  448. package/.claude/skills/compatibility-review/references/legacy.md +0 -7
  449. package/.claude/skills/context-pack/SKILL.md +0 -22
  450. package/.claude/skills/context-pack/references/astra.md +0 -12
  451. package/.claude/skills/context-pack/references/legacy.md +0 -7
  452. package/.claude/skills/dependency-review/SKILL.md +0 -22
  453. package/.claude/skills/dependency-review/references/astra.md +0 -17
  454. package/.claude/skills/dependency-review/references/legacy.md +0 -7
  455. package/.claude/skills/design/SKILL.md +0 -24
  456. package/.claude/skills/design/references/astra.md +0 -12
  457. package/.claude/skills/design/references/legacy.md +0 -13
  458. package/.claude/skills/design-review/SKILL.md +0 -24
  459. package/.claude/skills/design-review/references/astra.md +0 -17
  460. package/.claude/skills/design-review/references/legacy.md +0 -7
  461. package/.claude/skills/evidence-review/SKILL.md +0 -22
  462. package/.claude/skills/evidence-review/references/astra.md +0 -17
  463. package/.claude/skills/evidence-review/references/legacy.md +0 -7
  464. package/.claude/skills/hotfix/SKILL.md +0 -22
  465. package/.claude/skills/hotfix/references/astra.md +0 -30
  466. package/.claude/skills/hotfix/references/legacy.md +0 -7
  467. package/.claude/skills/incident-recovery/SKILL.md +0 -22
  468. package/.claude/skills/incident-recovery/references/astra.md +0 -27
  469. package/.claude/skills/incident-recovery/references/legacy.md +0 -7
  470. package/.claude/skills/levelplay-unity-integration/SKILL.md +0 -1126
  471. package/.claude/skills/localization/SKILL.md +0 -135
  472. package/.claude/skills/localization/resources/L10nBatchProcessor.cs +0 -69
  473. package/.claude/skills/localize-game/SKILL.md +0 -22
  474. package/.claude/skills/localize-game/references/astra.md +0 -27
  475. package/.claude/skills/localize-game/references/legacy.md +0 -7
  476. package/.claude/skills/migrate-project/SKILL.md +0 -22
  477. package/.claude/skills/migrate-project/references/astra.md +0 -30
  478. package/.claude/skills/migrate-project/references/legacy.md +0 -19
  479. package/.claude/skills/migrate-project/references/procedure.md +0 -96
  480. package/.claude/skills/milestone-review/SKILL.md +0 -22
  481. package/.claude/skills/milestone-review/references/astra.md +0 -12
  482. package/.claude/skills/milestone-review/references/legacy.md +0 -7
  483. package/.claude/skills/nccgs-code-review/SKILL.md +0 -22
  484. package/.claude/skills/nccgs-code-review/references/astra.md +0 -21
  485. package/.claude/skills/nccgs-code-review/references/legacy.md +0 -7
  486. package/.claude/skills/new-unity-project/SKILL.md +0 -179
  487. package/.claude/skills/performance-audit/SKILL.md +0 -22
  488. package/.claude/skills/performance-audit/references/astra.md +0 -17
  489. package/.claude/skills/performance-audit/references/legacy.md +0 -7
  490. package/.claude/skills/physics-3d-collision/references/troubleshooting.md +0 -41
  491. package/.claude/skills/plan-feature/SKILL.md +0 -22
  492. package/.claude/skills/plan-feature/references/astra.md +0 -12
  493. package/.claude/skills/plan-feature/references/legacy.md +0 -7
  494. package/.claude/skills/playtest/SKILL.md +0 -22
  495. package/.claude/skills/playtest/references/astra.md +0 -31
  496. package/.claude/skills/playtest/references/legacy.md +0 -7
  497. package/.claude/skills/project-stage/SKILL.md +0 -22
  498. package/.claude/skills/project-stage/references/astra.md +0 -12
  499. package/.claude/skills/project-stage/references/legacy.md +0 -7
  500. package/.claude/skills/prototype-feature/SKILL.md +0 -22
  501. package/.claude/skills/prototype-feature/references/astra.md +0 -31
  502. package/.claude/skills/prototype-feature/references/legacy.md +0 -7
  503. package/.claude/skills/qa-plan/SKILL.md +0 -22
  504. package/.claude/skills/qa-plan/references/astra.md +0 -12
  505. package/.claude/skills/qa-plan/references/legacy.md +0 -7
  506. package/.claude/skills/release/SKILL.md +0 -22
  507. package/.claude/skills/release/references/astra.md +0 -30
  508. package/.claude/skills/release/references/legacy.md +0 -11
  509. package/.claude/skills/release-readiness/SKILL.md +0 -22
  510. package/.claude/skills/release-readiness/references/astra.md +0 -17
  511. package/.claude/skills/release-readiness/references/legacy.md +0 -7
  512. package/.claude/skills/retrospective/SKILL.md +0 -22
  513. package/.claude/skills/retrospective/references/astra.md +0 -12
  514. package/.claude/skills/retrospective/references/legacy.md +0 -7
  515. package/.claude/skills/review/SKILL.md +0 -22
  516. package/.claude/skills/review/references/astra.md +0 -21
  517. package/.claude/skills/review/references/legacy.md +0 -9
  518. package/.claude/skills/security-audit/SKILL.md +0 -22
  519. package/.claude/skills/security-audit/references/astra.md +0 -17
  520. package/.claude/skills/security-audit/references/legacy.md +0 -7
  521. package/.claude/skills/sprint-plan/SKILL.md +0 -22
  522. package/.claude/skills/sprint-plan/references/astra.md +0 -12
  523. package/.claude/skills/sprint-plan/references/legacy.md +0 -7
  524. package/.claude/skills/status/SKILL.md +0 -22
  525. package/.claude/skills/status/references/astra.md +0 -19
  526. package/.claude/skills/status/references/legacy.md +0 -9
  527. package/.claude/skills/story-readiness/SKILL.md +0 -24
  528. package/.claude/skills/story-readiness/references/astra.md +0 -17
  529. package/.claude/skills/story-readiness/references/legacy.md +0 -7
  530. package/.claude/skills/test/SKILL.md +0 -22
  531. package/.claude/skills/test/references/astra.md +0 -27
  532. package/.claude/skills/test/references/legacy.md +0 -9
  533. package/.claude/skills/ui-review/SKILL.md +0 -22
  534. package/.claude/skills/ui-review/references/astra.md +0 -17
  535. package/.claude/skills/ui-review/references/legacy.md +0 -7
  536. package/.claude/skills/unity-cli/CHANGELOG.md +0 -233
  537. package/.claude/skills/unity-cli/SECURITY.md +0 -22
  538. package/.claude/skills/unity-cli/SKILL.md +0 -414
  539. package/.claude/skills/unity-cli/references/auth-license-cloud.md +0 -146
  540. package/.claude/skills/unity-cli/references/build-run-test.md +0 -349
  541. package/.claude/skills/unity-cli/references/config-hub.md +0 -103
  542. package/.claude/skills/unity-cli/references/diagnostics-maintenance.md +0 -326
  543. package/.claude/skills/unity-cli/references/editors-install.md +0 -327
  544. package/.claude/skills/unity-cli/references/integration-advanced.md +0 -472
  545. package/.claude/skills/unity-cli/references/projects-templates.md +0 -574
  546. package/.claude/skills/work/SKILL.md +0 -22
  547. package/.claude/skills/work/references/astra.md +0 -32
  548. package/.claude/skills/work/references/classification.md +0 -41
  549. package/.claude/skills/work/references/closure.md +0 -60
  550. package/.claude/skills/work/references/feature-contracts.md +0 -36
  551. package/.claude/skills/work/references/legacy.md +0 -29
  552. package/.claude/skills/work/references/verification.md +0 -26
  553. package/CLAUDE.md +0 -10
  554. package/MEMORY.md +0 -109
  555. package/UPGRADING.md +0 -130
  556. package/VERSION +0 -1
  557. package/docs/ARCHITECTURE.md +0 -131
  558. package/docs/ASSET-PRODUCTION-GRAPHIFY-PLAN.md +0 -230
  559. package/docs/BOUNDED-REPAIR.md +0 -80
  560. package/docs/EDITOR-SESSION-EVIDENCE.md +0 -52
  561. package/docs/HANDOFF-AUTOMATION.md +0 -144
  562. package/docs/HUONG-DAN-MIGRATE-VA-SU-DUNG.md +0 -117
  563. package/docs/MIGRATION-MATRIX.md +0 -23
  564. package/docs/NCCGS-1.3.md +0 -13
  565. package/docs/NCCGS-1.4.1.md +0 -149
  566. package/docs/NCCGS-1.4.md +0 -184
  567. package/docs/NCCGS-1.5-IMPLEMENTATION-PLAN.md +0 -378
  568. package/docs/NCCGS-1.5-PILOT.md +0 -130
  569. package/docs/NCCGS-1.5.md +0 -237
  570. package/docs/PHASE-1-OPERATIONS.md +0 -278
  571. package/docs/PHASE-2-OPERATIONS.md +0 -183
  572. package/docs/PROJECT-POLICY.md +0 -94
  573. package/docs/RELEASE-STATUS.md +0 -150
  574. package/docs/TASK-SLICING.md +0 -57
  575. package/docs/UNINSTALL.md +0 -134
  576. package/docs/UPGRADE-QUALIFICATION.md +0 -45
  577. package/docs/WFK17-HOOK-REPAIR.md +0 -71
  578. package/docs/WORKFLOWS.md +0 -85
  579. package/package-assets/nccgs-project.gitignore +0 -2
  580. package/package-assets/setup-vivox-voice-chat-evals.gitignore +0 -7
  581. package/scaffold/.nccgs/autonomy.json +0 -4
  582. package/scaffold/.nccgs/bugs/.gitkeep +0 -1
  583. package/scaffold/.nccgs/closures/.gitkeep +0 -1
  584. package/scaffold/.nccgs/context/.gitkeep +0 -1
  585. package/scaffold/.nccgs/decisions/.gitkeep +0 -1
  586. package/scaffold/.nccgs/evidence/.gitkeep +0 -1
  587. package/scaffold/.nccgs/execution.json +0 -10
  588. package/scaffold/.nccgs/features/.gitkeep +0 -1
  589. package/scaffold/.nccgs/gates.json +0 -7
  590. package/scaffold/.nccgs/inputs.json +0 -6
  591. package/scaffold/.nccgs/migrations/.gitkeep +0 -1
  592. package/scaffold/.nccgs/playtests/.gitkeep +0 -1
  593. package/scaffold/.nccgs/project.yaml +0 -109
  594. package/scaffold/.nccgs/requirements.yaml +0 -10
  595. package/scaffold/.nccgs/reviews/.gitkeep +0 -1
  596. package/scaffold/.nccgs/state.md +0 -40
  597. package/scaffold/.nccgs/templates/agent-handoff.md +0 -37
  598. package/scaffold/.nccgs/templates/architecture-decision.md +0 -27
  599. package/scaffold/.nccgs/templates/closure-record.md +0 -62
  600. package/scaffold/.nccgs/templates/context-packet.yaml +0 -17
  601. package/scaffold/.nccgs/templates/design-contract.json +0 -34
  602. package/scaffold/.nccgs/templates/evidence-record.md +0 -23
  603. package/scaffold/.nccgs/templates/feature-contract.md +0 -60
  604. package/scaffold/.nccgs/templates/implementation-report.md +0 -52
  605. package/scaffold/.nccgs/templates/migration-plan.md +0 -40
  606. package/scaffold/.nccgs/templates/repair-packet.json +0 -14
  607. package/scaffold/.nccgs/templates/repair-unity-code.json +0 -18
  608. package/scaffold/.nccgs/templates/repair-unity-editor.json +0 -21
  609. package/scaffold/.nccgs/templates/task-slices.json +0 -28
  610. package/scaffold/.nccgs/templates/waiver.md +0 -11
  611. package/scripts/benchmark-snapshot.mjs +0 -205
  612. package/scripts/benchmark-v15.mjs +0 -173
  613. package/scripts/cli.mjs +0 -205
  614. package/scripts/doctor.mjs +0 -261
  615. package/scripts/install.mjs +0 -530
  616. package/scripts/recover-session.mjs +0 -89
  617. package/scripts/run.mjs +0 -86
  618. package/scripts/supervise.mjs +0 -152
  619. package/scripts/uninstall.mjs +0 -292
  620. package/scripts/validate.mjs +0 -285
  621. package/scripts/work-handoff.mjs +0 -38
  622. package/tests/autonomy.test.mjs +0 -126
  623. package/tests/benchmark-v15.test.mjs +0 -65
  624. package/tests/design-readiness.test.mjs +0 -200
  625. package/tests/editor-session-evidence.test.mjs +0 -45
  626. package/tests/evidence.test.mjs +0 -186
  627. package/tests/fixtures/compiler-shutdown.cs +0 -67
  628. package/tests/fixtures/native-provider.mjs +0 -61
  629. package/tests/framework.test.mjs +0 -740
  630. package/tests/gates.test.mjs +0 -479
  631. package/tests/hook-repair.test.mjs +0 -106
  632. package/tests/lifecycle-v15.test.mjs +0 -346
  633. package/tests/native-completion-notices.test.mjs +0 -181
  634. package/tests/orchestration-v15.test.mjs +0 -596
  635. package/tests/phase1.test.mjs +0 -427
  636. package/tests/phase2.test.mjs +0 -250
  637. package/tests/policy-v15.test.mjs +0 -234
  638. package/tests/ponytail-package.test.mjs +0 -75
  639. package/tests/returned-handoff-notices.test.mjs +0 -170
  640. package/tests/review-budget.test.mjs +0 -177
  641. package/tests/runtime-v15.test.mjs +0 -1198
  642. package/tests/session-budget.test.mjs +0 -34
  643. package/tests/task-slices.test.mjs +0 -285
  644. package/tests/uninstall.test.mjs +0 -477
  645. package/tests/unity-generated.test.mjs +0 -140
  646. package/tests/unity-transport.test.mjs +0 -348
  647. /package/{.claude/nccgs/packages → template}/ponytail/LICENSE +0 -0
  648. /package/{.claude/nccgs/packages → template}/ponytail/NOTICE.md +0 -0
  649. /package/{.claude/nccgs/packages → template}/ponytail/complexity-review.md +0 -0
  650. /package/{.claude/skills → unity-skills}/build-live-game/references/remote-config.md +0 -0
  651. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/README.md +0 -0
  652. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/codeless-catalog.md +0 -0
  653. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/convert-adapty.md +0 -0
  654. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/convert-essentialkit.md +0 -0
  655. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/convert-revenuecat.md +0 -0
  656. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/convert-unipay.md +0 -0
  657. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/migration-v4-to-v5.md +0 -0
  658. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/path-add-iap-to-new-project.md +0 -0
  659. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/path-convert-native-storekit.md +0 -0
  660. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/platform-notes.md +0 -0
  661. /package/{.claude/skills → unity-skills}/implement-in-app-purchases/references/pre-check.md +0 -0
  662. /package/{.claude/skills → unity-skills}/localization/resources/LocalizedFontAsset.cs +0 -0
  663. /package/{.claude/skills → unity-skills}/optimize-audio/resources/platform-settings.md +0 -0
  664. /package/{.claude/skills → unity-skills}/optimize-web/resources/WebOptimizer.cs +0 -0
  665. /package/{.claude/skills → unity-skills}/optimize-web/resources/toktx-examples.sh +0 -0
  666. /package/{.claude/skills → unity-skills}/physics-3d-collision/resources/CollisionDebugger.cs +0 -0
  667. /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/dgs-entrypoint.md +0 -0
  668. /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/entrypoints.md +0 -0
  669. /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/examples.md +0 -0
  670. /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/implementation-fit.md +0 -0
  671. /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/underlying-services.md +0 -0
  672. /package/{.claude/skills → unity-skills}/setup-multiplayer-services/references/workflows-prerequisites.md +0 -0
  673. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/.env.example +0 -0
  674. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/README.md +0 -0
  675. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/promptfooconfig.yaml +0 -0
  676. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/tests/init-and-login.yaml +0 -0
  677. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/tests/text-chat.yaml +0 -0
  678. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/evals/tests/voice-channels.yaml +0 -0
  679. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/events-and-participants.md +0 -0
  680. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/init-and-login.md +0 -0
  681. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/text-chat.md +0 -0
  682. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/troubleshooting.md +0 -0
  683. /package/{.claude/skills → unity-skills}/setup-vivox-voice-chat/references/voice-channels.md +0 -0
  684. /package/{.claude/skills → unity-skills}/shader-graph-create-custom-node/resources/all_hints.hlsl +0 -0
  685. /package/{.claude/skills → unity-skills}/sprite-editor/references/api_reference.md +0 -0
  686. /package/{.claude/skills → unity-skills}/sprite-editor/references/background.md +0 -0
  687. /package/{.claude/skills → unity-skills}/sprite-editor/scripts/AutomaticSliceTexture.cs +0 -0
  688. /package/{.claude/skills → unity-skills}/sprite-editor/scripts/GenerateNewSpriteRects.cs +0 -0
  689. /package/{.claude/skills → unity-skills}/sprite-editor/scripts/GetTextureSourceImageSize.cs +0 -0
  690. /package/{.claude/skills → unity-skills}/sprite-editor/scripts/GetTextureToSlice.cs +0 -0
  691. /package/{.claude/skills → unity-skills}/sprite-editor/scripts/GridSliceTexture.cs +0 -0
  692. /package/{.claude/skills → unity-skills}/sprite-editor/scripts/IsometricSliceTexture.cs +0 -0
  693. /package/{.claude/skills → unity-skills}/sprite-editor/scripts/README.md +0 -0
  694. /package/{.claude/skills → unity-skills}/sprite-editor/scripts/SetPivotExample.cs +0 -0
  695. /package/{.claude/skills → unity-skills}/sprite-editor/scripts/SpriteToPng.cs +0 -0
  696. /package/{.claude/skills → unity-skills}/ui-imgui/references/gui-elements.md +0 -0
  697. /package/{.claude/skills → unity-skills}/ui-imgui/references/templates.md +0 -0
  698. /package/{.claude/skills → unity-skills}/ui-ugui/references/scrollview-setup.md +0 -0
  699. /package/{.claude/skills → unity-skills}/ui-uitk/references/common-issues.md +0 -0
  700. /package/{.claude/skills → unity-skills}/ui-uitk/references/painter2d.md +0 -0
  701. /package/{.claude/skills → unity-skills}/ui-uitk/references/pointermanipulator-guide.md +0 -0
  702. /package/{.claude/skills → unity-skills}/ui-uitk/references/svg-icons.md +0 -0
  703. /package/{.claude/skills → unity-skills}/ui-uitk/references/ui-runtime-binding.md +0 -0
  704. /package/{.claude/skills → unity-skills}/ui-uitk/references/uss-guide.md +0 -0
  705. /package/{.claude/skills → unity-skills}/urp-postprocessing/references/effect-reference.md +0 -0
@@ -0,0 +1,12 @@
1
+ // Unity transport policy: direct CLI + com.unity.pipeline only. No Unity MCP servers,
2
+ // no Coplay/AnkleBreaker, no `unity mcp` mode, no registering them through Claude/Codex.
3
+ export const PROVIDER = /mcp-?for-?unity|unity[-_. ]?mcp|coplay|anklebreaker|unitymcp/i;
4
+
5
+ export function unityMcpViolation(cmd) {
6
+ if (!cmd) return null;
7
+ if (/\bunity(\.exe)?\s+mcp\b/i.test(cmd)) return "`unity mcp` mode is disabled; use `unity command` / Pipeline directly";
8
+ if (/\b(claude|codex)\s+mcp\s+add(-json)?\b/i.test(cmd) && PROVIDER.test(cmd)) return "registering a Unity MCP server is disabled";
9
+ if (/\b(uvx|uv|pipx?|pip3|npx|npm|pnpm|bunx)\b/i.test(cmd) && PROVIDER.test(cmd)) return "installing or launching a Unity MCP server is disabled";
10
+ if (/\bgit\s+clone\b/i.test(cmd) && PROVIDER.test(cmd)) return "cloning a Unity MCP server is disabled";
11
+ return null;
12
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "builtin": true,
4
+ "agents": ["coordinator", "implementer", "reviewer", "fast-fix", "scout", "playtester"],
5
+ "modes": {
6
+ "FAST": {
7
+ "description": "Cheapest. Sonnet everywhere, Haiku for scouting. Good for prototypes and small fixes.",
8
+ "coordinator": { "model": "sonnet", "effort": "medium" },
9
+ "implementer": { "model": "sonnet", "effort": "high" },
10
+ "reviewer": { "model": "sonnet", "effort": "high", "fallback": null },
11
+ "fast-fix": { "model": "sonnet", "effort": "medium" },
12
+ "scout": { "model": "haiku", "effort": null },
13
+ "playtester": { "model": "sonnet", "effort": "medium" }
14
+ },
15
+ "BALANCE": {
16
+ "description": "Default. Opus for the coordinator, implementer and reviewer; Sonnet for support agents.",
17
+ "coordinator": { "model": "opus", "effort": "high" },
18
+ "implementer": { "model": "opus", "effort": "high" },
19
+ "reviewer": { "model": "opus", "effort": "high", "fallback": null },
20
+ "fast-fix": { "model": "sonnet", "effort": "high" },
21
+ "scout": { "model": "sonnet", "effort": "medium" },
22
+ "playtester": { "model": "sonnet", "effort": "high" }
23
+ },
24
+ "PERFORMANCE": {
25
+ "description": "Strongest. Opus/xhigh for building, Fable/high for independent review (falls back to Opus/xhigh when Fable is unavailable).",
26
+ "coordinator": { "model": "opus", "effort": "xhigh" },
27
+ "implementer": { "model": "opus", "effort": "xhigh" },
28
+ "reviewer": { "model": "fable", "effort": "high", "fallback": { "model": "opus", "effort": "xhigh" } },
29
+ "fast-fix": { "model": "sonnet", "effort": "high" },
30
+ "scout": { "model": "sonnet", "effort": "medium" },
31
+ "playtester": { "model": "sonnet", "effort": "high" }
32
+ }
33
+ },
34
+ "allowed": {
35
+ "models": ["haiku", "sonnet", "opus", "fable", "inherit"],
36
+ "efforts": ["low", "medium", "high", "xhigh", "max"],
37
+ "notes": "A full model ID (claude-...) is also accepted. Unusual model/effort combinations warn, they do not fail."
38
+ }
39
+ }
@@ -0,0 +1,103 @@
1
+ // Token cost per task, read from the Claude Code transcripts the hooks recorded (session.start and
2
+ // agent.* events carry transcript paths). Every assistant message in [openedAt, closedAt] counts once
3
+ // (deduplicated by message id); subagent transcripts under <session>/subagents/ count too and are
4
+ // attributed to the agent name the SubagentStart event recorded for that agentId.
5
+ // Tokens are the fact. Dollars are an estimate from config.pricing (per million tokens) and only
6
+ // appear for models that have a price row.
7
+ import fs from "node:fs";
8
+ import os from "node:os";
9
+ import path from "node:path";
10
+ import { at, loadConfig } from "../core/project.mjs";
11
+ import { exists, readText } from "../core/fs.mjs";
12
+
13
+ const USAGE_KEYS = ["input_tokens", "cache_creation_input_tokens", "cache_read_input_tokens", "output_tokens"];
14
+
15
+ export function readEvents(root) {
16
+ const text = readText(at(root, "events"), "");
17
+ const out = [];
18
+ for (const line of text.split("\n")) { if (!line.trim()) continue; try { out.push(JSON.parse(line)); } catch {} }
19
+ return out;
20
+ }
21
+
22
+ // Transcript files that can hold messages for this project: the session transcripts named by hooks
23
+ // and every subagent transcript beside them.
24
+ // Sessions recorded before transcript paths were logged (alpha.6 and earlier) are found by session id
25
+ // under ~/.claude/projects/*/<sessionId>.jsonl.
26
+ function findBySessionId(sessionId) {
27
+ const base = path.join(process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude"), "projects");
28
+ if (!exists(base)) return null;
29
+ for (const dir of fs.readdirSync(base)) {
30
+ const f = path.join(base, dir, `${sessionId}.jsonl`);
31
+ if (exists(f)) return f;
32
+ }
33
+ return null;
34
+ }
35
+
36
+ export function transcriptFiles(root, events = readEvents(root)) {
37
+ const files = new Set();
38
+ const sessions = new Set();
39
+ for (const e of events) {
40
+ for (const p of [e.transcriptPath, e.agentTranscriptPath]) if (p && exists(p)) files.add(path.resolve(p));
41
+ if (e.sessionId && !e.transcriptPath) sessions.add(e.sessionId);
42
+ }
43
+ for (const id of sessions) { const f = findBySessionId(id); if (f) files.add(f); }
44
+ for (const f of [...files]) {
45
+ const dir = path.join(path.dirname(f), path.basename(f, ".jsonl"), "subagents");
46
+ if (exists(dir)) for (const n of fs.readdirSync(dir)) if (n.endsWith(".jsonl")) files.add(path.join(dir, n));
47
+ }
48
+ return [...files];
49
+ }
50
+
51
+ function* assistantMessages(file) {
52
+ let text;
53
+ try { text = fs.readFileSync(file, "utf8"); } catch { return; }
54
+ for (const line of text.split("\n")) {
55
+ if (!line.includes('"assistant"')) continue;
56
+ let j; try { j = JSON.parse(line); } catch { continue; }
57
+ if (j.type !== "assistant" || !j.message?.usage) continue;
58
+ yield { id: j.message.id ?? j.uuid, at: Date.parse(j.timestamp), model: j.message.model ?? "unknown", agentId: j.agentId ?? null, usage: j.message.usage };
59
+ }
60
+ }
61
+
62
+ const empty = () => ({ input: 0, cacheWrite: 0, cacheRead: 0, output: 0, messages: 0 });
63
+ function add(acc, u) {
64
+ acc.input += u.input_tokens ?? 0; acc.cacheWrite += u.cache_creation_input_tokens ?? 0; acc.cacheRead += u.cache_read_input_tokens ?? 0; acc.output += u.output_tokens ?? 0; acc.messages += 1;
65
+ }
66
+
67
+ export function taskCost(root, task, { events = readEvents(root), config = loadConfig(root) } = {}) {
68
+ const from = Date.parse(task.openedAt), to = task.closedAt ? Date.parse(task.closedAt) : Date.now();
69
+ const agentNames = new Map();
70
+ for (const e of events) if (e.type === "agent.start" && e.agentId && e.agent) agentNames.set(e.agentId, e.agent);
71
+ const files = transcriptFiles(root, events);
72
+ const seen = new Set();
73
+ const byModel = {}, byAgent = {};
74
+ const total = empty();
75
+ for (const file of files) {
76
+ for (const m of assistantMessages(file)) {
77
+ if (!(m.at >= from && m.at <= to) || seen.has(m.id)) continue;
78
+ seen.add(m.id);
79
+ const agent = m.agentId ? (agentNames.get(m.agentId) ?? "subagent") : "coordinator";
80
+ byModel[m.model] ??= empty(); add(byModel[m.model], m.usage);
81
+ byAgent[agent] ??= empty(); add(byAgent[agent], m.usage);
82
+ add(total, m.usage);
83
+ }
84
+ }
85
+ const pricing = config.pricing ?? {};
86
+ let usd = 0, priced = 0;
87
+ for (const [model, t] of Object.entries(byModel)) {
88
+ const row = priceFor(model, pricing);
89
+ if (!row) continue;
90
+ priced++;
91
+ usd += (t.input * row.input + t.cacheWrite * row.cacheWrite + t.cacheRead * row.cacheRead + t.output * row.output) / 1e6;
92
+ }
93
+ return { total, byModel, byAgent, transcripts: files.length, estimatedUsd: priced ? Number(usd.toFixed(4)) : null, pricedModels: priced, unpricedModels: Object.keys(byModel).length - priced };
94
+ }
95
+
96
+ // pricing rows are keyed by a substring of the model id ("opus", "sonnet", "claude-haiku-5-5").
97
+ function priceFor(model, pricing) {
98
+ const keys = Object.keys(pricing).sort((a, b) => b.length - a.length);
99
+ const k = keys.find(k => model.includes(k));
100
+ return k ? pricing[k] : null;
101
+ }
102
+
103
+ export const fmtTokens = n => n >= 1e6 ? `${(n / 1e6).toFixed(2)}M` : n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
@@ -0,0 +1,128 @@
1
+ // Acceptance criteria: each criterion owns assertions against evidence artifacts that
2
+ // Unity (through `task verify`) produced. Claude writes criteria; it never writes artifacts.
3
+ //
4
+ // Assertion: { artifact, pointer?, op, value?, min?, max? }
5
+ // op: eq | gte | lte | exists | contains | range | image
6
+ // artifact: path relative to the project (usually under .nccgs/evidence/)
7
+ // pointer: JSON pointer into a JSON artifact (eq/gte/lte/contains/range)
8
+ import fs from "node:fs";
9
+ import path from "node:path";
10
+ import { readJson, exists } from "../core/fs.mjs";
11
+
12
+ export const OPS = ["eq", "gte", "lte", "exists", "contains", "range", "image"];
13
+
14
+ export function validateCriteria(criteria) {
15
+ const problems = [];
16
+ if (!Array.isArray(criteria) || criteria.length === 0) problems.push("criteria must be a non-empty array");
17
+ const ids = new Set();
18
+ for (const [i, c] of (criteria ?? []).entries()) {
19
+ const where = `criteria[${i}]`;
20
+ if (!c?.id || typeof c.id !== "string") problems.push(`${where}.id is required`);
21
+ else if (ids.has(c.id)) problems.push(`${where}.id duplicates ${c.id}`); else ids.add(c.id);
22
+ if (!c?.description) problems.push(`${where}.description is required`);
23
+ if (c?.kind === "manual") continue; // decided by a person at close time
24
+ if (!Array.isArray(c?.assertions) || !c.assertions.length) { problems.push(`${where}.assertions must be a non-empty array (or kind: "manual")`); continue; }
25
+ for (const [j, a] of c.assertions.entries()) {
26
+ const w = `${where}.assertions[${j}]`;
27
+ if (!a?.artifact) problems.push(`${w}.artifact is required`);
28
+ if (!OPS.includes(a?.op)) problems.push(`${w}.op must be one of ${OPS.join("|")}`);
29
+ if (["eq", "gte", "lte", "contains"].includes(a?.op) && !("value" in (a ?? {}))) problems.push(`${w}.value is required for ${a?.op}`);
30
+ if (["eq", "gte", "lte", "contains", "range"].includes(a?.op) && typeof a?.pointer !== "string") problems.push(`${w}.pointer is required for ${a?.op}`);
31
+ if (a?.op === "range" && !(Number.isFinite(a.min) || Number.isFinite(a.max))) problems.push(`${w} range needs min and/or max`);
32
+ }
33
+ }
34
+ return problems;
35
+ }
36
+
37
+ function pointer(value, ptr) {
38
+ if (!ptr || ptr === "/") return value;
39
+ let cur = value;
40
+ for (const raw of ptr.split("/").slice(1)) {
41
+ const key = raw.replace(/~1/g, "/").replace(/~0/g, "~");
42
+ if (cur === null || typeof cur !== "object") return undefined;
43
+ cur = Array.isArray(cur) ? cur[Number(key)] : cur[key];
44
+ }
45
+ return cur;
46
+ }
47
+
48
+ function pngSize(file) {
49
+ try {
50
+ const fd = fs.openSync(file, "r"); const head = Buffer.alloc(24); fs.readSync(fd, head, 0, 24, 0); fs.closeSync(fd);
51
+ if (head.toString("hex", 0, 8) !== "89504e470d0a1a0a") return null;
52
+ return { width: head.readUInt32BE(16), height: head.readUInt32BE(20) };
53
+ } catch { return null; }
54
+ }
55
+
56
+ // Evaluate one assertion against the project. Returns { status: PASS|FAIL|UNVERIFIED, actual, reason }.
57
+ export function evaluateAssertion(root, a) {
58
+ const file = path.resolve(root, a.artifact);
59
+ if (!exists(file)) return { status: "UNVERIFIED", reason: `artifact missing: ${a.artifact}` };
60
+ if (a.op === "exists") {
61
+ const size = fs.statSync(file).size;
62
+ return size > 0 ? { status: "PASS", actual: size } : { status: "FAIL", actual: 0, reason: "artifact is empty" };
63
+ }
64
+ if (a.op === "image") {
65
+ const size = pngSize(file);
66
+ if (!size) return { status: "FAIL", reason: "not a PNG" };
67
+ const min = a.minWidth ?? 64;
68
+ const ok = size.width >= min && size.height >= Math.min(min, 64) && fs.statSync(file).size > 200;
69
+ return ok ? { status: "PASS", actual: size } : { status: "FAIL", actual: size, reason: `image smaller than ${min}px` };
70
+ }
71
+ let json;
72
+ try { json = readJson(file); } catch (e) { return { status: "UNVERIFIED", reason: e.message }; }
73
+ const actual = pointer(json, a.pointer);
74
+ if (actual === undefined) return { status: "UNVERIFIED", reason: `pointer ${a.pointer} not found` };
75
+ switch (a.op) {
76
+ case "eq": return actual === a.value ? { status: "PASS", actual } : { status: "FAIL", actual, reason: `expected ${JSON.stringify(a.value)}` };
77
+ case "gte": return typeof actual === "number" && actual >= a.value ? { status: "PASS", actual } : { status: "FAIL", actual, reason: `expected >= ${a.value}` };
78
+ case "lte": return typeof actual === "number" && actual <= a.value ? { status: "PASS", actual } : { status: "FAIL", actual, reason: `expected <= ${a.value}` };
79
+ case "range": {
80
+ const ok = typeof actual === "number" && (!Number.isFinite(a.min) || actual >= a.min) && (!Number.isFinite(a.max) || actual <= a.max);
81
+ return ok ? { status: "PASS", actual } : { status: "FAIL", actual, reason: `expected within [${a.min ?? "-inf"}, ${a.max ?? "inf"}]` };
82
+ }
83
+ case "contains": {
84
+ const hay = Array.isArray(actual) ? actual : String(actual);
85
+ const ok = Array.isArray(hay) ? hay.includes(a.value) : hay.includes(String(a.value));
86
+ return ok ? { status: "PASS", actual } : { status: "FAIL", actual, reason: `expected to contain ${JSON.stringify(a.value)}` };
87
+ }
88
+ default: return { status: "UNVERIFIED", reason: `unknown op ${a.op}` };
89
+ }
90
+ }
91
+
92
+ // Evaluate all criteria. A criterion passes only when every assertion passes.
93
+ // `task close --decide id=pass|accepted|yes|ok` all mean accepted; fail|rejected|no mean rejected.
94
+ export function normalizeDecision(d) {
95
+ const v = String(d ?? "").trim().toLowerCase();
96
+ if (["accepted", "accept", "pass", "passed", "yes", "ok", "true"].includes(v)) return "accepted";
97
+ if (["rejected", "reject", "fail", "failed", "no", "false"].includes(v)) return "rejected";
98
+ return v || null;
99
+ }
100
+
101
+ export function evaluate(root, criteria, { manualDecisions = {} } = {}) {
102
+ const rows = criteria.map(c => {
103
+ if (c.kind === "manual") {
104
+ const d = normalizeDecision(manualDecisions[c.id]);
105
+ return { id: c.id, description: c.description, kind: "manual", status: d === "accepted" ? "PASS" : d === "rejected" ? "FAIL" : "PENDING", assertions: [] };
106
+ }
107
+ const results = c.assertions.map(a => ({ ...a, ...evaluateAssertion(root, a) }));
108
+ const status = results.every(r => r.status === "PASS") ? "PASS" : results.some(r => r.status === "FAIL") ? "FAIL" : "UNVERIFIED";
109
+ return { id: c.id, description: c.description, status, assertions: results };
110
+ });
111
+ const summary = { total: rows.length, pass: rows.filter(r => r.status === "PASS").length, fail: rows.filter(r => r.status === "FAIL").length, unverified: rows.filter(r => r.status === "UNVERIFIED").length, pending: rows.filter(r => r.status === "PENDING").length };
112
+ return { rows, summary, allPass: summary.pass === summary.total };
113
+ }
114
+
115
+ // Default observation criteria added when a task touches what the player sees.
116
+ export function defaultObserveCriteria(taskId) {
117
+ const m = `.nccgs/evidence/measurements/${taskId}-observe.json`;
118
+ return [{
119
+ id: "observe", description: "The game enters Play Mode without exceptions and a screenshot of the Game view is captured",
120
+ assertions: [
121
+ { artifact: m, pointer: "/enteredPlayMode", op: "eq", value: true },
122
+ { artifact: m, pointer: "/exceptionCount", op: "eq", value: 0 },
123
+ { artifact: `.nccgs/evidence/screens/${taskId}/01.png`, op: "image" }
124
+ ]
125
+ }];
126
+ }
127
+
128
+ export const PLAYER_VISIBLE = /(^|\/)(Assets\/.*\.(unity|prefab|uxml|uss|shader|shadergraph|mat|anim|controller)|Assets\/(UI|Scenes|Prefabs)\/)/i;
@@ -0,0 +1,136 @@
1
+ // nccgs feedback: one bundle a person can send after days of use — what ran, what failed, what was
2
+ // blocked, how long and how many tokens each task took, the doctor's view and any note they add.
3
+ // Everything comes from local files (ledger, events, diagnostics, reports); no code, no screenshots,
4
+ // no transcripts, no secrets. Nothing is uploaded: the bundle is written under .nccgs/feedback/ and
5
+ // the person decides where it goes.
6
+ import path from "node:path";
7
+ import os from "node:os";
8
+ import { writeJson, writeText, readText, exists, toPosix, appendLine } from "../core/fs.mjs";
9
+ import { at, loadConfig, editorVersion, pipelineVersion } from "../core/project.mjs";
10
+ import { listTasks } from "../task/ledger.mjs";
11
+ import { readEvents, taskCost, fmtTokens } from "../task/cost.mjs";
12
+ import { readDiag } from "../core/diag.mjs";
13
+ import { inScope } from "../core/snapshot.mjs";
14
+ import { readJson } from "../core/fs.mjs";
15
+ import { fileURLToPath } from "node:url";
16
+ import { evaluate, markSent } from "../core/feedback-policy.mjs";
17
+
18
+ // the runtime is installed into the project; its version is in install-state.json, falling back to the package
19
+ function nccgsVersion(root) { try { return readJson(at(root, "installState")).version; } catch { try { return readJson(path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../package.json")).version; } catch { return "unknown"; } } }
20
+
21
+ const DAY = 86400000;
22
+ const count = (arr, key) => arr.reduce((m, x) => { const k = key(x); m[k] = (m[k] ?? 0) + 1; return m; }, {});
23
+
24
+ export async function buildBundle(root, { sinceDays = 14, note = "", withReports = false, doctor = null, trigger = "manual", reasons = [] } = {}) {
25
+ const sinceMs = Date.now() - sinceDays * DAY;
26
+ const config = loadConfig(root);
27
+ const events = readEvents(root).filter(e => Date.parse(e.at) >= sinceMs);
28
+ const diags = readDiag(root, { sinceMs });
29
+ const tasks = listTasks(root).filter(t => Date.parse(t.updatedAt ?? t.openedAt) >= sinceMs);
30
+ const taskRows = tasks.map(t => {
31
+ let cost = null; try { cost = taskCost(root, t); } catch {}
32
+ const verifications = t.verifications ?? [];
33
+ return {
34
+ id: t.id, title: t.title, rigor: t.rigor, mode: t.mode, status: t.status, outcome: t.outcome ?? null, fromPlan: !!t.fromPlan,
35
+ openedAt: t.openedAt, closedAt: t.closedAt ?? null, minutes: t.closedAt ? Math.round((Date.parse(t.closedAt) - Date.parse(t.openedAt)) / 60000) : null,
36
+ criteria: (t.criteria ?? []).length, manualCriteria: (t.criteria ?? []).filter(c => c.kind === "manual").length,
37
+ verifications: { total: verifications.length, failed: verifications.filter(v => !v.ok).length, byKind: count(verifications, v => v.kind) },
38
+ reviews: (t.reviews ?? []).map(r => ({ verdict: r.verdict, model: r.model, findings: count(r.findings ?? [], f => (f.severity ?? "INFO").toUpperCase()), resolved: (r.findings ?? []).filter(f => f.resolved).length })),
39
+ fixRounds: `${t.fixRounds}/${t.maxFixRounds}`,
40
+ changedFiles: (t.changedFiles ?? []).length, outsideContract: (t.changedFiles ?? []).filter(f => !inScope(f, t.files)).length,
41
+ tokens: cost?.total?.messages ? { in: cost.total.input + cost.total.cacheWrite + cost.total.cacheRead, cached: cost.total.cacheRead, out: cost.total.output, messages: cost.total.messages, byAgent: Object.fromEntries(Object.entries(cost.byAgent).map(([k, v]) => [k, v.output])) } : null
42
+ };
43
+ });
44
+ let doc = null;
45
+ if (doctor) { try { doc = await doctor(root); doc = { summary: doc.summary, checks: doc.checks.map(c => ({ id: c.id, status: c.status, message: c.message })) }; } catch (e) { doc = { error: e.message }; } }
46
+ const bundle = {
47
+ schemaVersion: 1, generatedAt: new Date().toISOString(), sinceDays, trigger, reasons,
48
+ nccgs: nccgsVersion(root), node: process.version, platform: `${os.platform()} ${os.release()} ${os.arch()}`,
49
+ project: { editor: editorVersion(root), pipeline: pipelineVersion(root), mode: config.mode, rigor: config.rigor, autonomy: config.autonomy, reportLanguage: config.report?.language ?? "en" },
50
+ doctor: doc,
51
+ totals: {
52
+ tasks: taskRows.length, closed: taskRows.filter(t => t.status === "closed").length, byOutcome: count(taskRows.filter(t => t.status === "closed"), t => t.outcome),
53
+ verifications: taskRows.reduce((a, t) => a + t.verifications.total, 0), failedVerifications: taskRows.reduce((a, t) => a + t.verifications.failed, 0),
54
+ fixRounds: taskRows.reduce((a, t) => a + Number(t.fixRounds.split("/")[0]), 0),
55
+ tokensOut: taskRows.reduce((a, t) => a + (t.tokens?.out ?? 0), 0),
56
+ sessions: events.filter(e => e.type === "session.start").length,
57
+ agentRuns: count(events.filter(e => e.type === "agent.start"), e => e.agent || "unknown"),
58
+ diagnostics: count(diags, d => d.kind)
59
+ },
60
+ tasks: taskRows,
61
+ diagnostics: diags.slice(-300),
62
+ updateNotices: exists(at(root, "updateCheck")) ? JSON.parse(readText(at(root, "updateCheck"), "{}")).notices ?? [] : [],
63
+ state: readText(at(root, "state"), "").split("\n").filter(l => l.startsWith("- ")).slice(0, 30),
64
+ note: note || null,
65
+ reports: withReports ? Object.fromEntries(tasks.filter(t => t.report && exists(path.resolve(root, t.report))).map(t => [t.id, readText(path.resolve(root, t.report), "")])) : undefined
66
+ };
67
+ const stamp = new Date().toISOString().slice(0, 19).replace(/[:T]/g, "-").slice(0, 16);
68
+ const dir = path.join(at(root, "nccgs"), "feedback");
69
+ const jsonFile = path.join(dir, `nccgs-feedback-${stamp}.json`);
70
+ const mdFile = path.join(dir, `nccgs-feedback-${stamp}.md`);
71
+ writeJson(jsonFile, bundle);
72
+ writeText(mdFile, renderSummary(bundle));
73
+ return { jsonFile, mdFile, bundle };
74
+ }
75
+
76
+ const MAX_BYTES = 512 * 1024;
77
+
78
+ // POST the bundle to the configured endpoint. Never throws; the outcome is appended to
79
+ // .nccgs/feedback/sent.jsonl so a person can see what left the machine and when.
80
+ export async function sendBundle(root, { bundle, markdown, endpoint = loadConfig(root).feedback?.endpoint, timeoutMs = 10000 } = {}) {
81
+ const log = path.join(at(root, "nccgs"), "feedback", "sent.jsonl");
82
+ const record = async r => { try { appendLine(log, JSON.stringify({ at: new Date().toISOString(), endpoint, ...r })); } catch {} return r; };
83
+ if (!endpoint) return record({ ok: false, reason: "no endpoint configured" });
84
+ let body = JSON.stringify({ bundle, markdown });
85
+ if (body.length > MAX_BYTES) { body = JSON.stringify({ bundle: { ...bundle, diagnostics: bundle.diagnostics.slice(-50), reports: undefined, truncated: true }, markdown }); }
86
+ if (body.length > MAX_BYTES) return record({ ok: false, reason: `bundle too large (${body.length} bytes)` });
87
+ const ctl = new AbortController(); const t = setTimeout(() => ctl.abort(), timeoutMs);
88
+ try {
89
+ const r = await fetch(endpoint, { method: "POST", headers: { "content-type": "application/json", "user-agent": `nccgs/${bundle.nccgs}` }, body, signal: ctl.signal });
90
+ const text = await r.text().catch(() => "");
91
+ let id = null; try { id = JSON.parse(text).id ?? null; } catch {}
92
+ if (!r.ok) return record({ ok: false, status: r.status, reason: text.slice(0, 200) });
93
+ markSent(root);
94
+ return record({ ok: true, status: r.status, id, bytes: body.length });
95
+ } catch (e) { return record({ ok: false, reason: e.name === "AbortError" ? "timeout" : e.message }); }
96
+ finally { clearTimeout(t); }
97
+ }
98
+
99
+ // Called by hooks and `task close`: decide, and either send (consent auto) or return a suggestion.
100
+ // Returns { action, reasons, sent? } and never throws.
101
+ export async function autoFeedback(root, { trigger = "hook" } = {}) {
102
+ try {
103
+ const d = evaluate(root);
104
+ if (d.action !== "send") return d;
105
+ const { bundle, mdFile } = await buildBundle(root, { sinceDays: 14, trigger, reasons: d.reasons });
106
+ const sent = await sendBundle(root, { bundle, markdown: readText(mdFile, "") });
107
+ return { ...d, sent };
108
+ } catch (e) { return { action: "none", reasons: [], error: e.message }; }
109
+ }
110
+
111
+ export function renderSummary(b) {
112
+ const L = [];
113
+ L.push(`# NCCGS feedback · ${b.generatedAt.slice(0, 10)} · last ${b.sinceDays} days`, "");
114
+ L.push(`NCCGS ${b.nccgs} · Node ${b.node} · ${b.platform} · Unity ${b.project.editor ?? "?"} · Pipeline ${b.project.pipeline ?? "?"} · mode ${b.project.mode} · rigor ${b.project.rigor} · autonomy ${b.project.autonomy}`, "");
115
+ const t = b.totals;
116
+ L.push(`**Totals.** ${t.tasks} tasks (${t.closed} closed: ${Object.entries(t.byOutcome).map(([k, v]) => `${v} ${k}`).join(", ") || "none"}) · ${t.verifications} verifications (${t.failedVerifications} failed) · ${t.fixRounds} fix rounds · ${fmtTokens(t.tokensOut)} tokens out · ${t.sessions} sessions · agents: ${Object.entries(t.agentRuns).map(([k, v]) => `${k} ×${v}`).join(", ") || "none"}`, "");
117
+ if (b.doctor?.summary) L.push(`**Doctor.** ${b.doctor.summary.pass} pass · ${b.doctor.summary.warn} warn · ${b.doctor.summary.fail} fail${b.doctor.checks.filter(c => c.status !== "pass").map(c => `\n- ${c.status.toUpperCase()} ${c.id}: ${c.message}`).join("")}`, "");
118
+ L.push(`## Tasks`, "", `| Task | Rigor | Outcome | Verify (failed) | Review | Fix | Outside scope | Minutes | Tokens out |`, `| --- | --- | --- | --- | --- | --- | --- | --- | --- |`);
119
+ for (const x of b.tasks) L.push(`| ${x.id} ${x.title.slice(0, 40)} | ${x.rigor} | ${x.status === "closed" ? x.outcome : x.status} | ${x.verifications.total} (${x.verifications.failed}) | ${x.reviews.map(r => `${r.verdict}${Object.keys(r.findings).length ? ` ${Object.entries(r.findings).map(([k, v]) => `${k[0]}${v}`).join("/")}` : ""}`).join(" → ") || "–"} | ${x.fixRounds} | ${x.outsideContract} | ${x.minutes ?? "–"} | ${x.tokens ? fmtTokens(x.tokens.out) : "–"} |`);
120
+ L.push("");
121
+ const kinds = Object.entries(t.diagnostics);
122
+ L.push(`## Diagnostics (${b.diagnostics.length})`, "");
123
+ if (!kinds.length) L.push("Nothing recorded: no runtime errors, failed verifications, Unity failures or hook blocks in the window.", "");
124
+ else {
125
+ L.push(kinds.map(([k, v]) => `${k} ×${v}`).join(" · "), "");
126
+ const groups = {};
127
+ for (const d of b.diagnostics) { const key = `${d.kind}: ${(d.reason ?? d.message ?? d.error?.message ?? (d.errors?.[0]?.code ?? d.errors?.[0]?.message) ?? d.name ?? "").toString().slice(0, 100)}`; groups[key] = (groups[key] ?? 0) + 1; }
128
+ for (const [k, v] of Object.entries(groups).sort((a, b) => b[1] - a[1]).slice(0, 30)) L.push(`- ×${v} ${k}`);
129
+ L.push("");
130
+ }
131
+ if (b.updateNotices?.length) L.push(`## Updates pending`, "", ...b.updateNotices.map(n => `- ${n.component} ${n.current} → ${n.latest}`), "");
132
+ if (b.note) L.push(`## Note from the person`, "", b.note, "");
133
+ L.push(`## Recent closes`, "", ...(b.state.length ? b.state : ["(none)"]), "");
134
+ L.push("_Local bundle. Contains task metadata, counts, diagnostics and the note above; no source code, screenshots, transcripts or credentials. The JSON beside this file has the detail._");
135
+ return L.join("\n");
136
+ }
@@ -0,0 +1,109 @@
1
+ // Task records: .nccgs/tasks/<id>.json (schema 3). The ledger records; it does not block tool calls.
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { readJson, writeJson, exists, nowIso, shortId, appendLine } from "../core/fs.mjs";
5
+ import { at, loadConfig, ensureLayout, editorVersion } from "../core/project.mjs";
6
+ import { snapshot } from "../core/snapshot.mjs";
7
+ import { validateCriteria, defaultObserveCriteria, PLAYER_VISIBLE, evaluate } from "./criteria.mjs";
8
+
9
+ export const RIGORS = ["prototype", "production", "release"];
10
+ export const REVIEW_REQUIRED = { prototype: 0, production: 1, release: 2 };
11
+ export const FIX_ROUNDS = { prototype: 6, production: 4, release: 2 };
12
+
13
+ export const taskFile = (root, id) => path.join(at(root, "tasks"), `${id}.json`);
14
+
15
+ export function loadTask(root, id) {
16
+ const file = taskFile(root, id);
17
+ if (!exists(file)) throw new Error(`Task ${id} not found (${file})`);
18
+ return readJson(file);
19
+ }
20
+ export function saveTask(root, task) { task.updatedAt = nowIso(); writeJson(taskFile(root, task.id), task); return task; }
21
+ export function listTasks(root) {
22
+ const dir = at(root, "tasks");
23
+ if (!exists(dir)) return [];
24
+ return fs.readdirSync(dir).filter(f => f.endsWith(".json")).map(f => readJson(path.join(dir, f))).sort((a, b) => (a.openedAt < b.openedAt ? 1 : -1));
25
+ }
26
+ export function openTasks(root) { return listTasks(root).filter(t => t.status !== "closed"); }
27
+
28
+ export function event(root, type, data = {}) {
29
+ appendLine(at(root, "events"), JSON.stringify({ at: nowIso(), type, ...data }));
30
+ }
31
+
32
+ export function openTask(root, { id, title, rigor, files = [], criteria = [], mode, notes = "", plan = false }) {
33
+ ensureLayout(root);
34
+ const config = loadConfig(root);
35
+ rigor = rigor || config.rigor;
36
+ if (!RIGORS.includes(rigor)) throw new Error(`rigor must be one of ${RIGORS.join("|")}`);
37
+ id = id || `T-${new Date().toISOString().slice(0, 10).replace(/-/g, "")}-${shortId()}`;
38
+ if (exists(taskFile(root, id))) throw new Error(`Task ${id} already exists`);
39
+ if (!title) throw new Error("--title is required");
40
+ const touchesPlayerVisible = files.some(f => PLAYER_VISIBLE.test(f));
41
+ const all = [...criteria];
42
+ if (rigor !== "prototype" && touchesPlayerVisible && !all.some(c => c.id === "observe")) all.push(...defaultObserveCriteria(id));
43
+ const problems = validateCriteria(all);
44
+ if (problems.length) throw new Error(`Invalid criteria:\n- ${problems.join("\n- ")}`);
45
+ const task = {
46
+ schemaVersion: 3, id, title, rigor, mode: mode || config.mode, status: "open", notes,
47
+ unity: { editor: editorVersion(root) },
48
+ files, criteria: all, fromPlan: !!plan,
49
+ openedAt: nowIso(), updatedAt: nowIso(), closedAt: null,
50
+ snapshotAtOpen: brief(snapshot(root, { config })),
51
+ verifications: [], reviews: [], fixRounds: 0, maxFixRounds: FIX_ROUNDS[rigor],
52
+ manualDecisions: {}, outcome: null, report: null
53
+ };
54
+ saveTask(root, task);
55
+ event(root, "task.open", { id, rigor, title });
56
+ return task;
57
+ }
58
+
59
+ // The task file keeps the sha only; the per-file map lives in .nccgs/cache/snapshots/<sha>.json.
60
+ const brief = s => ({ sha: s.sha, files: s.files, at: s.at });
61
+
62
+ export function assess(root, task) {
63
+ const evaluation = evaluate(root, task.criteria, { manualDecisions: task.manualDecisions });
64
+ const current = brief(snapshot(root));
65
+ const lastVerification = task.verifications.at(-1);
66
+ const stale = lastVerification ? lastVerification.snapshot !== current.sha : true;
67
+ return { evaluation, snapshot: current, stale, lastVerification };
68
+ }
69
+
70
+ export function recordVerification(root, task, record) {
71
+ task.verifications.push({ ...record, at: nowIso(), snapshot: snapshot(root).sha });
72
+ task.status = task.status === "open" ? "verifying" : task.status;
73
+ saveTask(root, task);
74
+ event(root, "task.verify", { id: task.id, name: record.name, ok: record.ok });
75
+ }
76
+
77
+ export function reviewsNeeded(task) { return REVIEW_REQUIRED[task.rigor] ?? 1; }
78
+
79
+ // Mark a reviewer finding resolved. MEDIUM/LOW may be resolved by the coordinator with a reason (the
80
+ // report shows who and why); HIGH/BLOCKER are resolved only by a new review verdict, never by hand.
81
+ export function resolveFinding(root, task, { match, reason, by = "coordinator" }) {
82
+ const review = task.reviews.at(-1);
83
+ if (!review) throw new Error("no review recorded for this task");
84
+ if (!reason) throw new Error("--reason is required: say what changed or why the finding does not apply");
85
+ const needle = String(match).toLowerCase();
86
+ const hits = (review.findings ?? []).map((f, i) => ({ f, i })).filter(({ f, i }) => String(i) === needle || (f.title ?? f.summary ?? "").toLowerCase().includes(needle));
87
+ if (hits.length !== 1) throw new Error(hits.length ? `"${match}" matches ${hits.length} findings; use the index` : `no finding matches "${match}"`);
88
+ const { f, i } = hits[0];
89
+ if (/HIGH|BLOCKER/i.test(f.severity ?? "")) throw new Error(`${f.severity} findings are resolved only by re-review (task review --id ${task.id}, then --import)`);
90
+ if (f.resolved) throw new Error(`finding ${i} is already resolved`);
91
+ Object.assign(f, { resolved: true, resolvedBy: by, resolvedAt: nowIso(), resolvedReason: reason, resolvedSnapshot: snapshot(root).sha });
92
+ saveTask(root, task);
93
+ event(root, "task.finding.resolve", { id: task.id, index: i, severity: f.severity, by, reason });
94
+ return { index: i, finding: f };
95
+ }
96
+
97
+ export function readyToClose(root, task, outcome) {
98
+ const { evaluation, snapshot: current, stale } = assess(root, task);
99
+ const reasons = [];
100
+ if (outcome === "success") {
101
+ if (!evaluation.allPass) reasons.push(`criteria not all passing: ${evaluation.summary.fail} fail, ${evaluation.summary.unverified} unverified, ${evaluation.summary.pending} pending`);
102
+ if (stale) reasons.push("source changed after the last verification; run `task verify` again");
103
+ const latest = task.reviews.at(-1);
104
+ const passes = task.reviews.filter(r => r.verdict === "PASS" && r.snapshot === current.sha);
105
+ if (latest && latest.verdict !== "PASS" && latest.snapshot === current.sha) reasons.push(`latest review on this snapshot is ${latest.verdict}; fix and re-review`);
106
+ if (passes.length < reviewsNeeded(task)) reasons.push(`independent review PASS on the current snapshot required (${passes.length}/${reviewsNeeded(task)})`);
107
+ }
108
+ return { ok: reasons.length === 0, reasons, evaluation, snapshot: current, stale };
109
+ }
@@ -0,0 +1,69 @@
1
+ // The slice plan: .nccgs/design/slice.json, written by /map-systems, consumed by /vertical-slice and
2
+ // `task open --plan <id>`. Each item is a full task contract (title, files, criteria, notes, rigor) plus
3
+ // `dependsOn`, so a task can only be opened when its dependencies closed SUCCESS.
4
+ import path from "node:path";
5
+ import { readJson, writeJson, exists } from "../core/fs.mjs";
6
+ import { at } from "../core/project.mjs";
7
+ import { listTasks } from "./ledger.mjs";
8
+ import { validateCriteria } from "./criteria.mjs";
9
+
10
+ export const planFile = root => path.join(at(root, "nccgs"), "design", "slice.json");
11
+
12
+ export function loadPlan(root) {
13
+ const f = planFile(root);
14
+ if (!exists(f)) throw new Error("no slice plan: run /map-systems first (it writes .nccgs/design/slice.json)");
15
+ const plan = readJson(f);
16
+ const problems = validatePlan(plan);
17
+ if (problems.length) throw new Error(`slice.json invalid:\n- ${problems.join("\n- ")}`);
18
+ return plan;
19
+ }
20
+
21
+ export function validatePlan(plan) {
22
+ const problems = [];
23
+ if (!plan || typeof plan !== "object") return ["not an object"];
24
+ if (plan.schemaVersion !== 1) problems.push("schemaVersion must be 1");
25
+ if (!Array.isArray(plan.tasks) || !plan.tasks.length) return [...problems, "tasks must be a non-empty array"];
26
+ const ids = new Set();
27
+ for (const [i, t] of plan.tasks.entries()) {
28
+ const w = `tasks[${i}]`;
29
+ if (!t.id || typeof t.id !== "string") problems.push(`${w}.id required`);
30
+ else if (ids.has(t.id)) problems.push(`${w}.id ${t.id} duplicated`); else ids.add(t.id);
31
+ if (!t.title) problems.push(`${w}.title required`);
32
+ if (!Array.isArray(t.files) || !t.files.length) problems.push(`${w}.files must list the files in scope`);
33
+ if (!Array.isArray(t.criteria) || !t.criteria.length) problems.push(`${w}.criteria must be a non-empty array`);
34
+ else problems.push(...validateCriteria(t.criteria).map(p => `${w}.criteria: ${p}`));
35
+ for (const d of t.dependsOn ?? []) if (!plan.tasks.some(x => x.id === d)) problems.push(`${w}.dependsOn ${d} is not in the plan`);
36
+ }
37
+ return problems;
38
+ }
39
+
40
+ // Status of every planned task against the ledger: done | open | ready | blocked.
41
+ export function planStatus(root, plan = loadPlan(root)) {
42
+ const tasks = listTasks(root);
43
+ const byId = new Map(tasks.map(t => [t.id, t]));
44
+ return plan.tasks.map(p => {
45
+ const t = byId.get(p.id);
46
+ const state = t ? (t.status === "closed" ? (t.outcome === "success" ? "done" : `closed-${t.outcome}`) : "open") : null;
47
+ const waiting = (p.dependsOn ?? []).filter(d => byId.get(d)?.outcome !== "success");
48
+ return { id: p.id, title: p.title, state: state ?? (waiting.length ? "blocked" : "ready"), waiting, rigor: p.rigor ?? null };
49
+ });
50
+ }
51
+
52
+ export function nextPlanned(root, plan = loadPlan(root)) {
53
+ return planStatus(root, plan).find(s => s.state === "ready" || s.state === "open") ?? null;
54
+ }
55
+
56
+ export function planItem(root, id, plan = loadPlan(root)) {
57
+ const item = plan.tasks.find(t => t.id === id);
58
+ if (!item) throw new Error(`plan has no task ${id} (${plan.tasks.map(t => t.id).join(", ")})`);
59
+ const status = planStatus(root, plan).find(s => s.id === id);
60
+ if (status.state === "blocked") throw new Error(`${id} waits for ${status.waiting.join(", ")} to close SUCCESS`);
61
+ return item;
62
+ }
63
+
64
+ export function savePlan(root, plan) {
65
+ const problems = validatePlan(plan);
66
+ if (problems.length) throw new Error(`slice.json invalid:\n- ${problems.join("\n- ")}`);
67
+ writeJson(planFile(root), plan);
68
+ return planFile(root);
69
+ }