create-yss-spec 2.2.10 → 3.0.0
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/README.md +1 -1
- package/package.json +1 -1
- package/template/.agents/skills/ask-matt/SKILL.md +1 -1
- package/template/.agents/skills/wayfinder/SKILL.md +2 -2
- package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +14 -3
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/ARCHITECTURE.md +3 -3
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +12 -1
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +2 -1
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +45 -11
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +164 -0
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +18 -4
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +172 -0
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +14 -1
- package/template/.agents/skills/yss-domain/SKILL.md +2 -1
- package/template/.agents/skills/yss-domain/agents/openai.yaml +2 -2
- package/template/.agents/skills/yss-domain/references/domain-layer-guide.md +2 -0
- package/template/.agents/skills/yss-dto/SKILL.md +6 -0
- package/template/.agents/skills/yss-dto/references/openapi-wire-profile.yaml +6 -0
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +1 -1
- package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -10
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.agents/skills/yss-repository/SKILL.md +15 -13
- package/template/.agents/skills/yss-repository/agents/openai.yaml +2 -2
- package/template/.agents/skills/yss-repository/references/infrastructure-layer-guide.md +1 -1
- package/template/.agents/skills/yss-research/SKILL.md +73 -0
- package/template/.agents/skills/yss-research/agents/openai.yaml +3 -0
- package/template/.agents/skills/yss-research/assets/evidence-template.yaml +68 -0
- package/template/.agents/skills/yss-research/assets/research-brief-template.md +36 -0
- package/template/.agents/skills/yss-research/references/evidence-contract.md +42 -0
- package/template/.agents/skills/yss-research/scripts/validate-research-package.mjs +128 -0
- package/template/.agents/skills/yss-research/tests/run-scenarios.mjs +81 -0
- package/template/.agents/skills/yss-router/references/router-contract.yaml +7 -3
- package/template/.agents/skills/yss-stage-decision/SKILL.md +2 -1
- package/template/.agents/skills/yss-web-controller/SKILL.md +16 -10
- package/template/.agents/skills/yss-web-controller/agents/openai.yaml +2 -2
- package/template/.agents/skills/yss-web-controller/assets/templates/Controller.java.template +11 -11
- package/template/.agents/skills/yss-web-controller/assets/templates/WebConvertor.java.template +4 -7
- package/template/.agents/skills/yss-web-controller/assets/templates/web/dto/CreateRequest.java.template +2 -2
- package/template/.agents/skills/yss-web-controller/assets/templates/web/dto/PageRequest.java.template +4 -7
- package/template/.agents/skills/yss-web-controller/assets/templates/web/dto/UpdateRequest.java.template +2 -2
- package/template/.agents/skills/yss-web-controller/references/web-adapter-layer-guide.md +6 -4
- package/template/.agents/skills/yss-web-controller/references/web-generation-contract.schema.json +97 -0
- package/template/.agents/skills/yss-web-controller/scripts/generate_controller.mjs +141 -20
- package/template/.agents/skills/yss-web-controller/scripts/generate_controller.test.mjs +131 -35
- package/template/.claude/skills/ask-matt/SKILL.md +1 -1
- package/template/.claude/skills/wayfinder/SKILL.md +2 -2
- package/template/.claude/skills/yss-ddd-scaffold-generator/SKILL.md +14 -3
- package/template/.claude/skills/yss-ddd-scaffold-generator/references/ARCHITECTURE.md +3 -3
- package/template/.claude/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +12 -1
- package/template/.claude/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +2 -1
- package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +45 -11
- package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +164 -0
- package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +18 -4
- package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +172 -0
- package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +14 -1
- package/template/.claude/skills/yss-domain/SKILL.md +2 -1
- package/template/.claude/skills/yss-domain/agents/openai.yaml +2 -2
- package/template/.claude/skills/yss-domain/references/domain-layer-guide.md +2 -0
- package/template/.claude/skills/yss-dto/SKILL.md +6 -0
- package/template/.claude/skills/yss-dto/references/openapi-wire-profile.yaml +6 -0
- package/template/.claude/skills/yss-product-lifecycle/SKILL.md +1 -1
- package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -10
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.claude/skills/yss-repository/SKILL.md +15 -13
- package/template/.claude/skills/yss-repository/agents/openai.yaml +2 -2
- package/template/.claude/skills/yss-repository/references/infrastructure-layer-guide.md +1 -1
- package/template/.claude/skills/yss-research/SKILL.md +73 -0
- package/template/.claude/skills/yss-research/agents/openai.yaml +3 -0
- package/template/.claude/skills/yss-research/assets/evidence-template.yaml +68 -0
- package/template/.claude/skills/yss-research/assets/research-brief-template.md +36 -0
- package/template/.claude/skills/yss-research/references/evidence-contract.md +42 -0
- package/template/.claude/skills/yss-research/scripts/validate-research-package.mjs +128 -0
- package/template/.claude/skills/yss-research/tests/run-scenarios.mjs +81 -0
- package/template/.claude/skills/yss-router/references/router-contract.yaml +7 -3
- package/template/.claude/skills/yss-stage-decision/SKILL.md +2 -1
- package/template/.claude/skills/yss-web-controller/SKILL.md +16 -10
- package/template/.claude/skills/yss-web-controller/agents/openai.yaml +2 -2
- package/template/.claude/skills/yss-web-controller/assets/templates/Controller.java.template +11 -11
- package/template/.claude/skills/yss-web-controller/assets/templates/WebConvertor.java.template +4 -7
- package/template/.claude/skills/yss-web-controller/assets/templates/web/dto/CreateRequest.java.template +2 -2
- package/template/.claude/skills/yss-web-controller/assets/templates/web/dto/PageRequest.java.template +4 -7
- package/template/.claude/skills/yss-web-controller/assets/templates/web/dto/UpdateRequest.java.template +2 -2
- package/template/.claude/skills/yss-web-controller/references/web-adapter-layer-guide.md +6 -4
- package/template/.claude/skills/yss-web-controller/references/web-generation-contract.schema.json +97 -0
- package/template/.claude/skills/yss-web-controller/scripts/generate_controller.mjs +141 -20
- package/template/.claude/skills/yss-web-controller/scripts/generate_controller.test.mjs +131 -35
- package/template/.codex/skills/ask-matt/SKILL.md +1 -1
- package/template/.codex/skills/product-design/package.json +4 -2
- package/template/.codex/skills/product-design/skills/research/SKILL.md +22 -0
- package/template/.codex/skills/product-design/skills/research/assets/evidence-template.yaml +65 -0
- package/template/.codex/skills/product-design/skills/research/assets/research-brief-template.md +33 -0
- package/template/.codex/skills/product-design/skills/research/references/evidence-audited.md +80 -0
- package/template/.codex/skills/product-design/skills/research/scripts/validate-research-package.mjs +149 -0
- package/template/.codex/skills/product-design/skills/research/tests/run-scenarios.mjs +72 -0
- package/template/.codex/skills/wayfinder/SKILL.md +2 -2
- package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +14 -3
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/ARCHITECTURE.md +3 -3
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +12 -1
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +2 -1
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +45 -11
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +164 -0
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +18 -4
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +172 -0
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +14 -1
- package/template/.codex/skills/yss-domain/SKILL.md +2 -1
- package/template/.codex/skills/yss-domain/agents/openai.yaml +2 -2
- package/template/.codex/skills/yss-domain/references/domain-layer-guide.md +2 -0
- package/template/.codex/skills/yss-dto/SKILL.md +6 -0
- package/template/.codex/skills/yss-dto/references/openapi-wire-profile.yaml +6 -0
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +1 -1
- package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -10
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.codex/skills/yss-repository/SKILL.md +15 -13
- package/template/.codex/skills/yss-repository/agents/openai.yaml +2 -2
- package/template/.codex/skills/yss-repository/references/infrastructure-layer-guide.md +1 -1
- package/template/.codex/skills/yss-research/SKILL.md +73 -0
- package/template/.codex/skills/yss-research/agents/openai.yaml +3 -0
- package/template/.codex/skills/yss-research/assets/evidence-template.yaml +68 -0
- package/template/.codex/skills/yss-research/assets/research-brief-template.md +36 -0
- package/template/.codex/skills/yss-research/references/evidence-contract.md +42 -0
- package/template/.codex/skills/yss-research/scripts/validate-research-package.mjs +128 -0
- package/template/.codex/skills/yss-research/tests/run-scenarios.mjs +81 -0
- package/template/.codex/skills/yss-router/references/router-contract.yaml +7 -3
- package/template/.codex/skills/yss-stage-decision/SKILL.md +2 -1
- package/template/.codex/skills/yss-web-controller/SKILL.md +16 -10
- package/template/.codex/skills/yss-web-controller/agents/openai.yaml +2 -2
- package/template/.codex/skills/yss-web-controller/assets/templates/Controller.java.template +11 -11
- package/template/.codex/skills/yss-web-controller/assets/templates/WebConvertor.java.template +4 -7
- package/template/.codex/skills/yss-web-controller/assets/templates/web/dto/CreateRequest.java.template +2 -2
- package/template/.codex/skills/yss-web-controller/assets/templates/web/dto/PageRequest.java.template +4 -7
- package/template/.codex/skills/yss-web-controller/assets/templates/web/dto/UpdateRequest.java.template +2 -2
- package/template/.codex/skills/yss-web-controller/references/web-adapter-layer-guide.md +6 -4
- package/template/.codex/skills/yss-web-controller/references/web-generation-contract.schema.json +97 -0
- package/template/.codex/skills/yss-web-controller/scripts/generate_controller.mjs +141 -20
- package/template/.codex/skills/yss-web-controller/scripts/generate_controller.test.mjs +131 -35
- package/template/.cursor/skills/ask-matt/SKILL.md +1 -1
- package/template/.cursor/skills/wayfinder/SKILL.md +2 -2
- package/template/.cursor/skills/yss-ddd-scaffold-generator/SKILL.md +14 -3
- package/template/.cursor/skills/yss-ddd-scaffold-generator/references/ARCHITECTURE.md +3 -3
- package/template/.cursor/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +12 -1
- package/template/.cursor/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +2 -1
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +45 -11
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +164 -0
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +18 -4
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +172 -0
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +14 -1
- package/template/.cursor/skills/yss-domain/SKILL.md +2 -1
- package/template/.cursor/skills/yss-domain/agents/openai.yaml +2 -2
- package/template/.cursor/skills/yss-domain/references/domain-layer-guide.md +2 -0
- package/template/.cursor/skills/yss-dto/SKILL.md +6 -0
- package/template/.cursor/skills/yss-dto/references/openapi-wire-profile.yaml +6 -0
- package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +1 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -10
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.cursor/skills/yss-repository/SKILL.md +15 -13
- package/template/.cursor/skills/yss-repository/agents/openai.yaml +2 -2
- package/template/.cursor/skills/yss-repository/references/infrastructure-layer-guide.md +1 -1
- package/template/.cursor/skills/yss-research/SKILL.md +73 -0
- package/template/.cursor/skills/yss-research/agents/openai.yaml +3 -0
- package/template/.cursor/skills/yss-research/assets/evidence-template.yaml +68 -0
- package/template/.cursor/skills/yss-research/assets/research-brief-template.md +36 -0
- package/template/.cursor/skills/yss-research/references/evidence-contract.md +42 -0
- package/template/.cursor/skills/yss-research/scripts/validate-research-package.mjs +128 -0
- package/template/.cursor/skills/yss-research/tests/run-scenarios.mjs +81 -0
- package/template/.cursor/skills/yss-router/references/router-contract.yaml +7 -3
- package/template/.cursor/skills/yss-stage-decision/SKILL.md +2 -1
- package/template/.cursor/skills/yss-web-controller/SKILL.md +16 -10
- package/template/.cursor/skills/yss-web-controller/agents/openai.yaml +2 -2
- package/template/.cursor/skills/yss-web-controller/assets/templates/Controller.java.template +11 -11
- package/template/.cursor/skills/yss-web-controller/assets/templates/WebConvertor.java.template +4 -7
- package/template/.cursor/skills/yss-web-controller/assets/templates/web/dto/CreateRequest.java.template +2 -2
- package/template/.cursor/skills/yss-web-controller/assets/templates/web/dto/PageRequest.java.template +4 -7
- package/template/.cursor/skills/yss-web-controller/assets/templates/web/dto/UpdateRequest.java.template +2 -2
- package/template/.cursor/skills/yss-web-controller/references/web-adapter-layer-guide.md +6 -4
- package/template/.cursor/skills/yss-web-controller/references/web-generation-contract.schema.json +97 -0
- package/template/.cursor/skills/yss-web-controller/scripts/generate_controller.mjs +141 -20
- package/template/.cursor/skills/yss-web-controller/scripts/generate_controller.test.mjs +131 -35
- package/template/.hermes/skills/ask-matt/SKILL.md +1 -1
- package/template/.hermes/skills/wayfinder/SKILL.md +2 -2
- package/template/.hermes/skills/yss-ddd-scaffold-generator/SKILL.md +14 -3
- package/template/.hermes/skills/yss-ddd-scaffold-generator/references/ARCHITECTURE.md +3 -3
- package/template/.hermes/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +12 -1
- package/template/.hermes/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +2 -1
- package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +45 -11
- package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +164 -0
- package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +18 -4
- package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +172 -0
- package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +14 -1
- package/template/.hermes/skills/yss-domain/SKILL.md +2 -1
- package/template/.hermes/skills/yss-domain/agents/openai.yaml +2 -2
- package/template/.hermes/skills/yss-domain/references/domain-layer-guide.md +2 -0
- package/template/.hermes/skills/yss-dto/SKILL.md +6 -0
- package/template/.hermes/skills/yss-dto/references/openapi-wire-profile.yaml +6 -0
- package/template/.hermes/skills/yss-product-lifecycle/SKILL.md +1 -1
- package/template/.hermes/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -10
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.hermes/skills/yss-repository/SKILL.md +15 -13
- package/template/.hermes/skills/yss-repository/agents/openai.yaml +2 -2
- package/template/.hermes/skills/yss-repository/references/infrastructure-layer-guide.md +1 -1
- package/template/.hermes/skills/yss-research/SKILL.md +73 -0
- package/template/.hermes/skills/yss-research/agents/openai.yaml +3 -0
- package/template/.hermes/skills/yss-research/assets/evidence-template.yaml +68 -0
- package/template/.hermes/skills/yss-research/assets/research-brief-template.md +36 -0
- package/template/.hermes/skills/yss-research/references/evidence-contract.md +42 -0
- package/template/.hermes/skills/yss-research/scripts/validate-research-package.mjs +128 -0
- package/template/.hermes/skills/yss-research/tests/run-scenarios.mjs +81 -0
- package/template/.hermes/skills/yss-router/references/router-contract.yaml +7 -3
- package/template/.hermes/skills/yss-stage-decision/SKILL.md +2 -1
- package/template/.hermes/skills/yss-web-controller/SKILL.md +16 -10
- package/template/.hermes/skills/yss-web-controller/agents/openai.yaml +2 -2
- package/template/.hermes/skills/yss-web-controller/assets/templates/Controller.java.template +11 -11
- package/template/.hermes/skills/yss-web-controller/assets/templates/WebConvertor.java.template +4 -7
- package/template/.hermes/skills/yss-web-controller/assets/templates/web/dto/CreateRequest.java.template +2 -2
- package/template/.hermes/skills/yss-web-controller/assets/templates/web/dto/PageRequest.java.template +4 -7
- package/template/.hermes/skills/yss-web-controller/assets/templates/web/dto/UpdateRequest.java.template +2 -2
- package/template/.hermes/skills/yss-web-controller/references/web-adapter-layer-guide.md +6 -4
- package/template/.hermes/skills/yss-web-controller/references/web-generation-contract.schema.json +97 -0
- package/template/.hermes/skills/yss-web-controller/scripts/generate_controller.mjs +141 -20
- package/template/.hermes/skills/yss-web-controller/scripts/generate_controller.test.mjs +131 -35
- package/template/.pi/skills/ask-matt/SKILL.md +1 -1
- package/template/.pi/skills/wayfinder/SKILL.md +2 -2
- package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +14 -3
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/ARCHITECTURE.md +3 -3
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +12 -1
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +2 -1
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +45 -11
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +164 -0
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +18 -4
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +172 -0
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +14 -1
- package/template/.pi/skills/yss-domain/SKILL.md +2 -1
- package/template/.pi/skills/yss-domain/agents/openai.yaml +2 -2
- package/template/.pi/skills/yss-domain/references/domain-layer-guide.md +2 -0
- package/template/.pi/skills/yss-dto/SKILL.md +6 -0
- package/template/.pi/skills/yss-dto/references/openapi-wire-profile.yaml +6 -0
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +1 -1
- package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -10
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.pi/skills/yss-repository/SKILL.md +15 -13
- package/template/.pi/skills/yss-repository/agents/openai.yaml +2 -2
- package/template/.pi/skills/yss-repository/references/infrastructure-layer-guide.md +1 -1
- package/template/.pi/skills/yss-research/SKILL.md +73 -0
- package/template/.pi/skills/yss-research/agents/openai.yaml +3 -0
- package/template/.pi/skills/yss-research/assets/evidence-template.yaml +68 -0
- package/template/.pi/skills/yss-research/assets/research-brief-template.md +36 -0
- package/template/.pi/skills/yss-research/references/evidence-contract.md +42 -0
- package/template/.pi/skills/yss-research/scripts/validate-research-package.mjs +128 -0
- package/template/.pi/skills/yss-research/tests/run-scenarios.mjs +81 -0
- package/template/.pi/skills/yss-router/references/router-contract.yaml +7 -3
- package/template/.pi/skills/yss-stage-decision/SKILL.md +2 -1
- package/template/.pi/skills/yss-web-controller/SKILL.md +16 -10
- package/template/.pi/skills/yss-web-controller/agents/openai.yaml +2 -2
- package/template/.pi/skills/yss-web-controller/assets/templates/Controller.java.template +11 -11
- package/template/.pi/skills/yss-web-controller/assets/templates/WebConvertor.java.template +4 -7
- package/template/.pi/skills/yss-web-controller/assets/templates/web/dto/CreateRequest.java.template +2 -2
- package/template/.pi/skills/yss-web-controller/assets/templates/web/dto/PageRequest.java.template +4 -7
- package/template/.pi/skills/yss-web-controller/assets/templates/web/dto/UpdateRequest.java.template +2 -2
- package/template/.pi/skills/yss-web-controller/references/web-adapter-layer-guide.md +6 -4
- package/template/.pi/skills/yss-web-controller/references/web-generation-contract.schema.json +97 -0
- package/template/.pi/skills/yss-web-controller/scripts/generate_controller.mjs +141 -20
- package/template/.pi/skills/yss-web-controller/scripts/generate_controller.test.mjs +131 -35
- package/template/.qoder/skills/ask-matt/SKILL.md +1 -1
- package/template/.qoder/skills/wayfinder/SKILL.md +2 -2
- package/template/.qoder/skills/yss-ddd-scaffold-generator/SKILL.md +14 -3
- package/template/.qoder/skills/yss-ddd-scaffold-generator/references/ARCHITECTURE.md +3 -3
- package/template/.qoder/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +12 -1
- package/template/.qoder/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +2 -1
- package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +45 -11
- package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +164 -0
- package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +18 -4
- package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +172 -0
- package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +14 -1
- package/template/.qoder/skills/yss-domain/SKILL.md +2 -1
- package/template/.qoder/skills/yss-domain/agents/openai.yaml +2 -2
- package/template/.qoder/skills/yss-domain/references/domain-layer-guide.md +2 -0
- package/template/.qoder/skills/yss-dto/SKILL.md +6 -0
- package/template/.qoder/skills/yss-dto/references/openapi-wire-profile.yaml +6 -0
- package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +1 -1
- package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -10
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.qoder/skills/yss-repository/SKILL.md +15 -13
- package/template/.qoder/skills/yss-repository/agents/openai.yaml +2 -2
- package/template/.qoder/skills/yss-repository/references/infrastructure-layer-guide.md +1 -1
- package/template/.qoder/skills/yss-research/SKILL.md +73 -0
- package/template/.qoder/skills/yss-research/agents/openai.yaml +3 -0
- package/template/.qoder/skills/yss-research/assets/evidence-template.yaml +68 -0
- package/template/.qoder/skills/yss-research/assets/research-brief-template.md +36 -0
- package/template/.qoder/skills/yss-research/references/evidence-contract.md +42 -0
- package/template/.qoder/skills/yss-research/scripts/validate-research-package.mjs +128 -0
- package/template/.qoder/skills/yss-research/tests/run-scenarios.mjs +81 -0
- package/template/.qoder/skills/yss-router/references/router-contract.yaml +7 -3
- package/template/.qoder/skills/yss-stage-decision/SKILL.md +2 -1
- package/template/.qoder/skills/yss-web-controller/SKILL.md +16 -10
- package/template/.qoder/skills/yss-web-controller/agents/openai.yaml +2 -2
- package/template/.qoder/skills/yss-web-controller/assets/templates/Controller.java.template +11 -11
- package/template/.qoder/skills/yss-web-controller/assets/templates/WebConvertor.java.template +4 -7
- package/template/.qoder/skills/yss-web-controller/assets/templates/web/dto/CreateRequest.java.template +2 -2
- package/template/.qoder/skills/yss-web-controller/assets/templates/web/dto/PageRequest.java.template +4 -7
- package/template/.qoder/skills/yss-web-controller/assets/templates/web/dto/UpdateRequest.java.template +2 -2
- package/template/.qoder/skills/yss-web-controller/references/web-adapter-layer-guide.md +6 -4
- package/template/.qoder/skills/yss-web-controller/references/web-generation-contract.schema.json +97 -0
- package/template/.qoder/skills/yss-web-controller/scripts/generate_controller.mjs +141 -20
- package/template/.qoder/skills/yss-web-controller/scripts/generate_controller.test.mjs +131 -35
- package/template/.trae/skills/ask-matt/SKILL.md +1 -1
- package/template/.trae/skills/wayfinder/SKILL.md +2 -2
- package/template/.trae/skills/yss-ddd-scaffold-generator/SKILL.md +14 -3
- package/template/.trae/skills/yss-ddd-scaffold-generator/references/ARCHITECTURE.md +3 -3
- package/template/.trae/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +12 -1
- package/template/.trae/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +2 -1
- package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +45 -11
- package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +164 -0
- package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +18 -4
- package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +172 -0
- package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +14 -1
- package/template/.trae/skills/yss-domain/SKILL.md +2 -1
- package/template/.trae/skills/yss-domain/agents/openai.yaml +2 -2
- package/template/.trae/skills/yss-domain/references/domain-layer-guide.md +2 -0
- package/template/.trae/skills/yss-dto/SKILL.md +6 -0
- package/template/.trae/skills/yss-dto/references/openapi-wire-profile.yaml +6 -0
- package/template/.trae/skills/yss-product-lifecycle/SKILL.md +1 -1
- package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -10
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.trae/skills/yss-repository/SKILL.md +15 -13
- package/template/.trae/skills/yss-repository/agents/openai.yaml +2 -2
- package/template/.trae/skills/yss-repository/references/infrastructure-layer-guide.md +1 -1
- package/template/.trae/skills/yss-research/SKILL.md +73 -0
- package/template/.trae/skills/yss-research/agents/openai.yaml +3 -0
- package/template/.trae/skills/yss-research/assets/evidence-template.yaml +68 -0
- package/template/.trae/skills/yss-research/assets/research-brief-template.md +36 -0
- package/template/.trae/skills/yss-research/references/evidence-contract.md +42 -0
- package/template/.trae/skills/yss-research/scripts/validate-research-package.mjs +128 -0
- package/template/.trae/skills/yss-research/tests/run-scenarios.mjs +81 -0
- package/template/.trae/skills/yss-router/references/router-contract.yaml +7 -3
- package/template/.trae/skills/yss-stage-decision/SKILL.md +2 -1
- package/template/.trae/skills/yss-web-controller/SKILL.md +16 -10
- package/template/.trae/skills/yss-web-controller/agents/openai.yaml +2 -2
- package/template/.trae/skills/yss-web-controller/assets/templates/Controller.java.template +11 -11
- package/template/.trae/skills/yss-web-controller/assets/templates/WebConvertor.java.template +4 -7
- package/template/.trae/skills/yss-web-controller/assets/templates/web/dto/CreateRequest.java.template +2 -2
- package/template/.trae/skills/yss-web-controller/assets/templates/web/dto/PageRequest.java.template +4 -7
- package/template/.trae/skills/yss-web-controller/assets/templates/web/dto/UpdateRequest.java.template +2 -2
- package/template/.trae/skills/yss-web-controller/references/web-adapter-layer-guide.md +6 -4
- package/template/.trae/skills/yss-web-controller/references/web-generation-contract.schema.json +97 -0
- package/template/.trae/skills/yss-web-controller/scripts/generate_controller.mjs +141 -20
- package/template/.trae/skills/yss-web-controller/scripts/generate_controller.test.mjs +131 -35
- package/template/AGENTS.md +2 -2
- package/template/CONTEXT.md +1 -1
- package/template/docs/agents/digital-human-roles.yaml +2 -2
- package/template/docs/agents/yss-skill-registry.yaml +18 -3
- package/template/docs/process/MATT-POCOCK-ENGINEERING-SKILLS.md +1 -0
- package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +1 -1
- package/template/scripts/lib/scenario-checks.mjs +8 -4
- package/template/scripts/lib/skill-registry.mjs +49 -5
- package/template/scripts/lib/skill-supply-chain.mjs +3 -2
- package/template/scripts/verify-yss-dto-openapi-profile +8 -0
- package/template/skills-lock.json +30 -30
- package/template.snapshot.json +4 -4
- package/template/.agents/skills/research/SKILL.md +0 -12
- package/template/.agents/skills/research/agents/openai.yaml +0 -3
- package/template/.claude/skills/research/SKILL.md +0 -12
- package/template/.claude/skills/research/agents/openai.yaml +0 -3
- package/template/.codex/skills/research/SKILL.md +0 -12
- package/template/.codex/skills/research/agents/openai.yaml +0 -3
- package/template/.cursor/skills/research/SKILL.md +0 -12
- package/template/.cursor/skills/research/agents/openai.yaml +0 -3
- package/template/.hermes/skills/research/SKILL.md +0 -12
- package/template/.hermes/skills/research/agents/openai.yaml +0 -3
- package/template/.pi/skills/research/SKILL.md +0 -12
- package/template/.pi/skills/research/agents/openai.yaml +0 -3
- package/template/.qoder/skills/research/SKILL.md +0 -12
- package/template/.qoder/skills/research/agents/openai.yaml +0 -3
- package/template/.trae/skills/research/SKILL.md +0 -12
- package/template/.trae/skills/research/agents/openai.yaml +0 -3
|
@@ -28,7 +28,7 @@ description: 用于生成完整的 YSS DDD 多模块后端脚手架。当用户
|
|
|
28
28
|
2. 优先运行 `node scripts/generate_and_verify_scaffold.mjs`,在同一个受控工作流中生成骨架并执行真实 Maven 验证。`generate_scaffold.mjs` 只是底层生成原语,单独返回 0 不代表脚手架完成。
|
|
29
29
|
3. 检查生成的模块名、POM、机械启动入口、基础配置文件和包路径。
|
|
30
30
|
4. 受控工作流必须在生成项目根目录实际执行 `./mvnw validate`、`./mvnw test` 和 `./mvnw package`;三条命令全部返回 0 后才能报告完成。
|
|
31
|
-
5. 三条 Wrapper 命令通过只得到 `empty-scaffold-verified
|
|
31
|
+
5. 三条 Wrapper 命令通过只得到 `empty-scaffold-verified`。如需声称已满足下游技能的首切片就绪条件,必须使用 `node scripts/run_first_slice_verification.mjs` 校验批准且版本当前的 Slice Implementation Contract、完整分层产物、skill tree digest 与根 Wrapper;只有验证器成功更新 Manifest 后才得到 `first-slice-verified`。
|
|
32
32
|
|
|
33
33
|
受控验证命令由本 skill 的 `node scripts/run_scaffold_verification.mjs` 固定执行;验证器先检查 `.yss/scaffold-generation.json` 的合同元数据和 Wrapper、Java、项目级 Maven settings/profile、仓库凭据是否就绪,再在指定 evidence 目录写入每条命令的 stdout/stderr、`exit_code`、`failure_category`、耗时、执行时间和 `scaffold-verification.json`。仓库或凭据失败归为 `repository-access`,与 `project-model`、`compilation`、`bootstrap-entrypoint`、`test-failure`、`packaging` 分开;任何一条命令失败或未执行都必须阻断。
|
|
34
34
|
|
|
@@ -55,6 +55,15 @@ node scripts/generate_and_verify_scaffold.mjs \
|
|
|
55
55
|
--evidence-dir /path/to/evidence/scaffold
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
完成批准的 golden first slice 后运行:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node scripts/run_first_slice_verification.mjs \
|
|
62
|
+
--project-root /path/to/implementation-repo/my-service \
|
|
63
|
+
--slice-contract-file /path/to/approved-slice-contract.json \
|
|
64
|
+
--evidence-dir /path/to/evidence/first-slice
|
|
65
|
+
```
|
|
66
|
+
|
|
58
67
|
## 生成结果应包含
|
|
59
68
|
|
|
60
69
|
- 父工程 POM
|
|
@@ -75,7 +84,7 @@ node scripts/generate_and_verify_scaffold.mjs \
|
|
|
75
84
|
- Harness 内多项目布局必须使用 `apps/backend/<project>/`;`apps/backend/` 只能是生成器的父容器,`app/backend/`、`app/frontend/` 及其子路径一律拒绝。`git-submodule` gitlink、空挂载点、detached HEAD 工作树不得覆盖生成,即使传入 `--force` 也不得当成普通目录,且不得走「请显式传入 `--force`」普通目录覆盖 / rename 路径。`--output-dir` 指向 detached HEAD 子仓时不得 mkdir、staging 或生成工程。先 `git submodule update --init` 并在子仓附加分支工作树内生成。生成器必须先调用 `gitSubmoduleScaffoldViolation`,再在 exists / `--force` / rename 之前调用 `refuseGitlinkAsRegularDirectory`。
|
|
76
85
|
- 不要在 skill 里硬编码用户业务字段或真实连接信息。
|
|
77
86
|
- 生成后要检查依赖关系是否仍符合分层约束。
|
|
78
|
-
-
|
|
87
|
+
- 生成时的静态依赖由技能注册表与 Router 共同约束为 `yss-backend-scaffold-parent`、`alibaba-java-code-style`。生成后必须回到 Router,并按批准切片加载 `yss-domain`、`yss-application`、`yss-repository`、`yss-mybatis`、`yss-web-controller`、`yss-dto`、`yss-exception`、`yss-validation`、`mapstruct`、`lombok`、`alibaba-java-code-style` 等实际命中的行为 skill。
|
|
79
88
|
- 当前脚手架第一阶段仅支持经过验证的 `mysql`;未提供完整模板和验证的数据库类型不得伪装成已支持。
|
|
80
89
|
- 生成后的后端工程必须使用项目根目录 `./mvnw ...` 执行构建、测试、运行和 CI 验证;不得在 README、实施记录、Ticket、Review 或 Release 中默认写裸 `mvn ...`。既有仓库确实无法使用 wrapper 时,必须记录受控例外。
|
|
81
90
|
- 原型确认后,`scaffold_status=required` 才能进入本 skill;本 skill 的生成边界是工程结构、POM、配置、Wrapper 和机械模板,不是业务实现。
|
|
@@ -83,7 +92,8 @@ node scripts/generate_and_verify_scaffold.mjs \
|
|
|
83
92
|
- 新脚手架合同只接受 schema v2,必须分别携带 `project_name`、`base_package` 和 `maven_coordinates`;后者包含项目 `group_id` / `project_version`、父 POM GAV 与 `yss_components_version`,并由 CLI 原样传入。schema v1 为 `unsupported`,直接拒绝且不自动升级。
|
|
84
93
|
- 合同 `profiles` 只支持 `target-domain-model`、`mybatis-plus`、`mysql`、`spring-boot-2.7-jdk8`、`javax`、`web`、`yss-internal`。普通 MyBatis、Boot 3、独立 client module、client-in-domain 和其他旧架构均为 `unsupported`,不提供回退分支。
|
|
85
94
|
- 运行生成器必须传入 `--contract-file`;生成器会校验合同 `status=approved`、`current_version`、`primary_skill`、`controlled-generation`、实际输出路径和固定三条验证命令,不接受仅凭任意字符串引用的放行。
|
|
86
|
-
- 生成项目必须写入 Manifest v2 `.yss/scaffold-generation.json`,记录合同 digest、Target Profile、模板 digest
|
|
95
|
+
- 生成项目必须写入 Manifest v2 `.yss/scaffold-generation.json`,记录合同 digest、Target Profile、模板 digest、下游完整 skill tree digest、脚手架父合同与 Router 合同 digest、generator-owned 文件 hash、严格 `generation_policy` 和完成等级;清单缺失或不一致时不得交给后续 Router。
|
|
96
|
+
- `first-slice-verified` 只能由 `run_first_slice_verification.mjs` 写入。手工改 Manifest、只生成 Controller、只通过局部模块测试或仅有结构扫描都不能升级完成等级。
|
|
87
97
|
- 严禁把领域规则、状态机、权限、事务、复杂查询、错误映射、业务字段或用户可见行为塞进脚手架生成步骤。`./mvnw validate`、输出目录存在或“生成成功”都不等于生命周期批准、架构放行或 `ready-for-agent`。
|
|
88
98
|
- 生命周期脚手架生成必须关闭 `--with-example`,不得把 User CRUD 或业务字段当作样板。生成器严格 `initialize-only`:非空目标、`--force`、旧项目迁移和当前模板升级一律 `unsupported`。未来若支持同一 Target Profile 内的模板升级,必须另行设计和批准,当前不预留可执行承诺。
|
|
89
99
|
- 脚手架完成后,所有后续生成的后端代码必须回到 `yss-router`,消费批准且版本当前的 Slice Implementation Contract 和对应 YSS skill;业务行为使用 `behavior-tdd`,机械生成才使用 `controlled-generation`。
|
|
@@ -98,6 +108,7 @@ node scripts/generate_and_verify_scaffold.mjs \
|
|
|
98
108
|
- 主脚本:`scripts/generate_scaffold.mjs`
|
|
99
109
|
- 推荐的一键生成验证入口:`scripts/generate_and_verify_scaffold.mjs`
|
|
100
110
|
- 受控验证器:`scripts/run_scaffold_verification.mjs`
|
|
111
|
+
- 首切片验证器:`scripts/run_first_slice_verification.mjs`
|
|
101
112
|
- 模板目录:`assets/templates/`
|
|
102
113
|
- 分层细化参考:`references/yss-backend-scaffold-parent/` 及其子 skill
|
|
103
114
|
|
|
@@ -104,13 +104,13 @@ Domain Error -> Application propagation/translation -> Web Exception Translator
|
|
|
104
104
|
|
|
105
105
|
- Scaffold 只生成机械模块、POM、Wrapper、配置、架构规则和 Manifest,不生成生产业务 CRUD。
|
|
106
106
|
- 初始生成器为 `initialize-only`,非空目标失败。
|
|
107
|
-
- Manifest v2
|
|
107
|
+
- Manifest v2 记录模板、脚手架父合同、Router 合同、downstream 完整 skill tree digest 与 generator-owned 文件 hash。
|
|
108
108
|
- 当前不支持模板升级,不得重跑初始生成器覆盖业务工程。未来如需支持同一 Target Profile 内的模板版本升级,必须另行设计、批准并验证。
|
|
109
109
|
|
|
110
110
|
## 5. 完成等级
|
|
111
111
|
|
|
112
112
|
- `generated`:文件已原子生成,尚未完成 Wrapper 验证。
|
|
113
113
|
- `empty-scaffold-verified`:根目录 `./mvnw validate/test/package` 全部通过。
|
|
114
|
-
- `first-slice-verified
|
|
114
|
+
- `first-slice-verified`:批准且版本当前的 golden first slice 已具备 Domain 模型/Gateway、Application Service 实现/事务/Query Port、Repository/Mapper/GatewayImpl/QueryAdapter、DTO/Web/Exception 与分层测试;下游完整 skill tree digest 无漂移,且根 Wrapper 全部通过。该状态只能由 `scripts/run_first_slice_verification.mjs` 写入。
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
只有首切片验证器可以把 Manifest 从 `empty-scaffold-verified` 升级到最后一级;手工写值、局部测试或结构扫描均无效。只有最后一级可以声明已满足下游 YSS skills 的首切片就绪条件。
|
|
@@ -102,7 +102,18 @@ metadata-service/
|
|
|
102
102
|
|
|
103
103
|
## 4. 后续路由
|
|
104
104
|
|
|
105
|
-
`empty-scaffold-verified` 不等于业务切片可实现。后续必须回到 `yss-router`,消费批准且版本当前的 Slice Implementation Contract,再按影响面加载 `yss-domain`、`yss-application`、`yss-repository`、`yss-mybatis`、`yss-dto`、`yss-exception`、`yss-
|
|
105
|
+
`empty-scaffold-verified` 不等于业务切片可实现。后续必须回到 `yss-router`,消费批准且版本当前的 Slice Implementation Contract,再按影响面加载 `yss-domain`、`yss-application`、`yss-repository`、`yss-mybatis`、`yss-web-controller`、`yss-dto`、`yss-exception`、`yss-validation`、`mapstruct`、`lombok`、`alibaba-java-code-style` 等 skill,并使用 `behavior-tdd` 实现业务行为。
|
|
106
|
+
|
|
107
|
+
完成 golden first slice 后,必须运行:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
node .agents/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs \
|
|
111
|
+
--project-root /path/to/implementation-repo/metadata-service \
|
|
112
|
+
--slice-contract-file /path/to/approved-slice-contract.json \
|
|
113
|
+
--evidence-dir /path/to/evidence/first-slice
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
只有该验证器确认合同、全层产物、skill tree digest 与根 Wrapper 全部通过,并更新 Manifest 后,才能标记 `first-slice-verified`。
|
|
106
117
|
|
|
107
118
|
目标目录必须不存在。`--force`、旧项目迁移和当前模板升级均为 `unsupported`。旧项目继续按原工程维护;现代化改造必须单独立项、先评估再逐切片迁移。
|
|
108
119
|
|
|
@@ -45,7 +45,7 @@ infrastructure-+
|
|
|
45
45
|
- Maven 内部仓库通过命名 profile `yss-internal` 与环境变量注入;共享模板不写内部 URL 或凭据。
|
|
46
46
|
- Wrapper 必须带 checksum;DEBUG 和 MyBatis stdout SQL 只允许在 `application-local.yml`。
|
|
47
47
|
- `./mvnw validate`、`./mvnw test`、`./mvnw package` 全部成功只得到 `empty-scaffold-verified`。
|
|
48
|
-
-
|
|
48
|
+
- 只有批准且版本当前的 golden first slice 真实组合 Domain/Application/Infrastructure/Web、通过下游 skill tree drift 校验与根 Wrapper,才能由 `run_first_slice_verification.mjs` 写入 `first-slice-verified`。
|
|
49
49
|
|
|
50
50
|
## 下游权威技能
|
|
51
51
|
|
|
@@ -53,5 +53,6 @@ infrastructure-+
|
|
|
53
53
|
- Application:`yss-application`
|
|
54
54
|
- Persistence:`yss-repository` + `yss-mybatis`
|
|
55
55
|
- Web:`yss-web-controller` + `yss-dto` + `yss-exception`
|
|
56
|
+
- 横切实现约束:`yss-validation` + `mapstruct` + `lombok` + `alibaba-java-code-style`
|
|
56
57
|
|
|
57
58
|
业务代码必须回到 `yss-router`,消费批准且版本当前的 Slice Implementation Contract,并采用 `behavior-tdd`;脚手架只生成机械工程资产。
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
3
4
|
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
5
|
import os from "node:os";
|
|
5
6
|
import path from "node:path";
|
|
@@ -7,9 +8,11 @@ import test from "node:test";
|
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
8
9
|
|
|
9
10
|
import { generate as generateWeb, parseArgs as parseWebArgs } from "../../yss-web-controller/scripts/generate_controller.mjs";
|
|
11
|
+
import { runFirstSliceVerification } from "./run_first_slice_verification.mjs";
|
|
10
12
|
|
|
11
13
|
const scripts = path.dirname(fileURLToPath(import.meta.url));
|
|
12
14
|
const generator = path.join(scripts, "generate_scaffold.mjs");
|
|
15
|
+
const dtoWireProfileFile = path.resolve(scripts, "../../yss-dto/references/openapi-wire-profile.yaml");
|
|
13
16
|
const execute = (file, args, options = {}) => new Promise((resolve) => execFile(file, args, { encoding: "utf8", ...options }, (error, stdout, stderr) => resolve({ code: error?.code ?? 0, stdout, stderr })));
|
|
14
17
|
|
|
15
18
|
function scaffoldContract(output) {
|
|
@@ -57,12 +60,19 @@ async function prepareGoldenProject(t) {
|
|
|
57
60
|
const generated = await execute(process.execPath, [generator, ...args]);
|
|
58
61
|
assert.equal(generated.code, 0, generated.stderr);
|
|
59
62
|
const project = path.join(output, "golden-service");
|
|
63
|
+
const manifestPath = path.join(project, ".yss", "scaffold-generation.json");
|
|
64
|
+
const emptyVerificationPath = path.join(root, "empty-scaffold-verification.json");
|
|
65
|
+
await writeFile(emptyVerificationPath, JSON.stringify({ status: "passed", completion_level: "empty-scaffold-verified", commands: ["./mvnw validate", "./mvnw test", "./mvnw package"] }));
|
|
66
|
+
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
67
|
+
manifest.completion_level = "empty-scaffold-verified";
|
|
68
|
+
manifest.empty_scaffold_verification_ref = emptyVerificationPath;
|
|
69
|
+
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
60
70
|
const java = "src/main/java/com/yss/golden";
|
|
61
71
|
const testJava = "src/test/java/com/yss/golden";
|
|
62
72
|
await writeJava(project, `golden-service-domain/${java}/domain/quality/model/QualityRule.java`, `package com.yss.golden.domain.quality.model;
|
|
63
73
|
public final class QualityRule { private final Long id; private final String name; public QualityRule(Long id, String name) { if (name == null || name.trim().isEmpty()) throw new IllegalArgumentException("quality-rule-name-required"); this.id=id; this.name=name; } public Long getId(){return id;} public String getName(){return name;} }`);
|
|
64
74
|
await writeJava(project, `golden-service-domain/${java}/domain/quality/gateway/QualityRuleGateway.java`, `package com.yss.golden.domain.quality.gateway;
|
|
65
|
-
import com.yss.golden.domain.quality.model.QualityRule; public interface QualityRuleGateway { void save(QualityRule rule); }`);
|
|
75
|
+
import com.yss.golden.domain.quality.model.QualityRule; import java.util.Optional; public interface QualityRuleGateway { Optional<QualityRule> findById(Long id); void save(QualityRule rule); void delete(Long id); }`);
|
|
66
76
|
await writeJava(project, `golden-service-domain/${testJava}/domain/quality/model/QualityRuleTest.java`, `package com.yss.golden.domain.quality.model;
|
|
67
77
|
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertThrows; class QualityRuleTest { @Test void rejectsBlankName(){ assertThrows(IllegalArgumentException.class, () -> new QualityRule(1L, " ")); } }`);
|
|
68
78
|
for (const [relative, source] of Object.entries({
|
|
@@ -72,16 +82,26 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertion
|
|
|
72
82
|
[`golden-service-application/${java}/application/result/QualityRuleResult.java`]: `package com.yss.golden.application.result; import java.io.Serializable; public class QualityRuleResult implements Serializable { private Long id; private String ruleName; public Long getId(){return id;} public void setId(Long value){this.id=value;} public String getRuleName(){return ruleName;} public void setRuleName(String value){this.ruleName=value;} }`,
|
|
73
83
|
[`golden-service-application/${java}/application/port/QualityRuleQueryPort.java`]: `package com.yss.golden.application.port; import com.yss.cloud.dto.result.PageResult; import com.yss.golden.application.query.QualityRulePageQuery; import com.yss.golden.application.result.QualityRuleResult; public interface QualityRuleQueryPort { PageResult<QualityRuleResult> page(QualityRulePageQuery query); }`,
|
|
74
84
|
[`golden-service-application/${java}/application/service/QualityRuleService.java`]: `package com.yss.golden.application.service; import com.yss.cloud.dto.result.PageResult; import com.yss.golden.application.command.*; import com.yss.golden.application.query.QualityRulePageQuery; import com.yss.golden.application.result.QualityRuleResult; public interface QualityRuleService { PageResult<QualityRuleResult> page(QualityRulePageQuery query); QualityRuleResult detail(Long id); Long add(QualityRuleCreateCommand command); Boolean update(QualityRuleUpdateCommand command); Boolean delete(Long id); }`,
|
|
85
|
+
[`golden-service-application/${java}/application/service/impl/QualityRuleServiceImpl.java`]: `package com.yss.golden.application.service.impl;
|
|
86
|
+
import com.yss.cloud.dto.result.PageResult; import com.yss.golden.application.command.*; import com.yss.golden.application.port.QualityRuleQueryPort; import com.yss.golden.application.query.QualityRulePageQuery; import com.yss.golden.application.result.QualityRuleResult; import com.yss.golden.application.service.QualityRuleService; import com.yss.golden.domain.quality.gateway.QualityRuleGateway; import com.yss.golden.domain.quality.model.QualityRule; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;
|
|
87
|
+
@Service public class QualityRuleServiceImpl implements QualityRuleService { private final QualityRuleGateway gateway; private final QualityRuleQueryPort queryPort; public QualityRuleServiceImpl(QualityRuleGateway gateway, QualityRuleQueryPort queryPort){this.gateway=gateway;this.queryPort=queryPort;} public PageResult<QualityRuleResult> page(QualityRulePageQuery query){return queryPort.page(query);} public QualityRuleResult detail(Long id){QualityRule rule=gateway.findById(id).orElseThrow(IllegalArgumentException::new); QualityRuleResult result=new QualityRuleResult(); result.setId(rule.getId()); result.setRuleName(rule.getName()); return result;} @Transactional public Long add(QualityRuleCreateCommand command){QualityRule rule=new QualityRule(null, command.getRuleName()); gateway.save(rule); return rule.getId();} @Transactional public Boolean update(QualityRuleUpdateCommand command){gateway.save(new QualityRule(command.getId(), command.getRuleName())); return true;} @Transactional public Boolean delete(Long id){gateway.delete(id); return true;} }`,
|
|
75
88
|
[`golden-service-application/${java}/application/error/QualityRuleConflictException.java`]: `package com.yss.golden.application.error; public final class QualityRuleConflictException extends RuntimeException { public QualityRuleConflictException(String message) { super(message); } }`,
|
|
76
89
|
[`golden-service-application/${java}/application/error/QualityRuleSystemException.java`]: `package com.yss.golden.application.error; public final class QualityRuleSystemException extends RuntimeException { public QualityRuleSystemException(String message, Throwable cause) { super(message, cause); } }`,
|
|
77
90
|
[`golden-service-infrastructure/${java}/infrastructure/persistence/po/QualityRulePO.java`]: `package com.yss.golden.infrastructure.persistence.po; public class QualityRulePO { private Long id; private String name; public Long getId(){return id;} public void setId(Long value){this.id=value;} public String getName(){return name;} public void setName(String value){this.name=value;} }`,
|
|
78
|
-
[`golden-service-infrastructure/${java}/infrastructure/persistence/convertor/QualityRulePersistenceConvertor.java`]: `package com.yss.golden.infrastructure.persistence.convertor; import com.yss.golden.domain.quality.model.QualityRule; import com.yss.golden.infrastructure.persistence.po.QualityRulePO; import org.mapstruct.Mapper; @Mapper(componentModel="spring") public interface QualityRulePersistenceConvertor { QualityRule toDomain(QualityRulePO source); QualityRulePO toPO(QualityRule source); }
|
|
91
|
+
[`golden-service-infrastructure/${java}/infrastructure/persistence/convertor/QualityRulePersistenceConvertor.java`]: `package com.yss.golden.infrastructure.persistence.convertor; import com.yss.golden.domain.quality.model.QualityRule; import com.yss.golden.infrastructure.persistence.po.QualityRulePO; import org.mapstruct.Mapper; @Mapper(componentModel="spring") public interface QualityRulePersistenceConvertor { QualityRule toDomain(QualityRulePO source); QualityRulePO toPO(QualityRule source); }`,
|
|
92
|
+
[`golden-service-infrastructure/${java}/infrastructure/persistence/repository/QualityRuleRepository.java`]: `package com.yss.golden.infrastructure.persistence.repository; import com.yss.golden.infrastructure.persistence.po.QualityRulePO; import java.util.List; import org.apache.ibatis.annotations.*; @Mapper public interface QualityRuleRepository { @Select("select id, rule_name as name from quality_rule where id = #{id}") QualityRulePO selectById(Long id); @Select("select id, rule_name as name from quality_rule") List<QualityRulePO> selectAll(); @Insert("insert into quality_rule(rule_name) values(#{name})") int insert(QualityRulePO po); @Delete("delete from quality_rule where id = #{id}") int deleteById(Long id); }`,
|
|
93
|
+
[`golden-service-infrastructure/${java}/infrastructure/persistence/gateway/QualityRuleGatewayImpl.java`]: `package com.yss.golden.infrastructure.persistence.gateway; import com.yss.golden.domain.quality.gateway.QualityRuleGateway; import com.yss.golden.domain.quality.model.QualityRule; import com.yss.golden.infrastructure.persistence.convertor.QualityRulePersistenceConvertor; import com.yss.golden.infrastructure.persistence.repository.QualityRuleRepository; import java.util.Optional; import org.springframework.stereotype.Repository; @Repository public class QualityRuleGatewayImpl implements QualityRuleGateway { private final QualityRuleRepository repository; private final QualityRulePersistenceConvertor convertor; public QualityRuleGatewayImpl(QualityRuleRepository repository, QualityRulePersistenceConvertor convertor){this.repository=repository;this.convertor=convertor;} public Optional<QualityRule> findById(Long id){return Optional.ofNullable(repository.selectById(id)).map(convertor::toDomain);} public void save(QualityRule rule){repository.insert(convertor.toPO(rule));} public void delete(Long id){repository.deleteById(id);} }`,
|
|
94
|
+
[`golden-service-infrastructure/${java}/infrastructure/query/adapter/QualityRuleQueryAdapter.java`]: `package com.yss.golden.infrastructure.query.adapter; import com.yss.cloud.dto.result.PageResult; import com.yss.golden.application.port.QualityRuleQueryPort; import com.yss.golden.application.query.QualityRulePageQuery; import com.yss.golden.application.result.QualityRuleResult; import java.util.Collections; import org.springframework.stereotype.Repository; @Repository public class QualityRuleQueryAdapter implements QualityRuleQueryPort { public PageResult<QualityRuleResult> page(QualityRulePageQuery query){return PageResult.of(Collections.emptyList(), 0L, query.getPageSize(), query.getPageIndex());} }`
|
|
79
95
|
})) await writeJava(project, relative, source);
|
|
96
|
+
await writeJava(project, `golden-service-application/${testJava}/application/service/QualityRuleServiceTest.java`, `package com.yss.golden.application.service; import com.yss.golden.application.command.QualityRuleCreateCommand; import com.yss.golden.application.port.QualityRuleQueryPort; import com.yss.golden.application.service.impl.QualityRuleServiceImpl; import com.yss.golden.domain.quality.gateway.QualityRuleGateway; import org.junit.jupiter.api.Test; import static org.mockito.Mockito.*; class QualityRuleServiceTest { @Test void createPersistsThroughDomainGateway(){QualityRuleGateway gateway=mock(QualityRuleGateway.class); QualityRuleCreateCommand command=new QualityRuleCreateCommand(); command.setRuleName("rule"); new QualityRuleServiceImpl(gateway, mock(QualityRuleQueryPort.class)).add(command); verify(gateway).save(any());} }`);
|
|
97
|
+
await writeJava(project, `golden-service-infrastructure/${testJava}/infrastructure/persistence/QualityRuleGatewayIntegrationTest.java`, `package com.yss.golden.infrastructure.persistence; import com.yss.golden.infrastructure.persistence.convertor.QualityRulePersistenceConvertor; import com.yss.golden.infrastructure.persistence.po.QualityRulePO; import org.junit.jupiter.api.Test; import org.mapstruct.factory.Mappers; import static org.junit.jupiter.api.Assertions.assertEquals; class QualityRuleGatewayIntegrationTest { @Test void persistenceMappingRoundTrips(){QualityRulePO po=new QualityRulePO(); po.setId(1L); po.setName("rule"); assertEquals("rule", Mappers.getMapper(QualityRulePersistenceConvertor.class).toDomain(po).getName());} }`);
|
|
80
98
|
const metadata = path.join(root, "metadata.json");
|
|
81
99
|
const webContract = path.join(root, "web-contract.json");
|
|
100
|
+
const dtoWireProfileDigest = createHash("sha256").update(await readFile(dtoWireProfileFile)).digest("hex");
|
|
82
101
|
await writeFile(metadata, JSON.stringify({ tables: [{ table_name: "quality_rule", table_comment: "质量规则", columns: [{ name: "id", sql_type: "bigint", primary: true, nullable: false }, { name: "rule_name", sql_type: "varchar(64)", nullable: false }] }] }));
|
|
83
|
-
|
|
84
|
-
await
|
|
102
|
+
const webProject = path.join(project, "golden-service-adapter", "golden-service-web");
|
|
103
|
+
await writeFile(webContract, JSON.stringify({ schema_version: 2, contract_id: "golden-slice-1", contract_version: 1, current_version: 1, slice_id: "quality-rule-first-slice", status: "approved", integration_mode: "scaffold-v2", implementation_project_root: project, scaffold_manifest_ref: manifestPath, base_package: "com.yss.golden", module_name: "golden", domain_segment: "quality", application_service_package: "com.yss.golden.application.service", architecture_profile: "target-domain-model", platform_profile: "spring-boot-2.7-jdk8", validation_namespace: "javax", dto_placement: "web", dto_wire_profile_ref: dtoWireProfileFile, dto_wire_profile_digest: dtoWireProfileDigest, openapi_freeze_ref: "openapi://quality-rule@1", allowed_write_paths: [path.join(webProject, "src/main/java/com/yss/golden/rest")], expected_evidence_files: ["first-slice-verification.json"], verification_commands: ["./mvnw test", "./mvnw package"], fields: { quality_rule: { create: ["rule_name"], update: ["id", "rule_name"], query: ["rule_name"], pagination: ["pageIndex", "pageSize"], response: ["id", "rule_name"] } } }));
|
|
104
|
+
await generateWeb(parseWebArgs(["--metadata-file", metadata, "--contract-file", webContract, "--dto-wire-profile-file", dtoWireProfileFile, "--scaffold-manifest-file", manifestPath, "--base-package", "com.yss.golden", "--module-name", "golden", "--domain-segment", "quality", "--web-project-dir", webProject, "--application-service-package", "com.yss.golden.application.service", "--validation-namespace", "javax"]), { log() {}, warn() {} });
|
|
85
105
|
await writeJava(project, `golden-service-adapter/golden-service-web/${java}/rest/advice/TargetProfileExceptionAdvice.java`, `package com.yss.golden.rest.advice;
|
|
86
106
|
import com.yss.golden.application.error.QualityRuleConflictException;
|
|
87
107
|
import com.yss.golden.application.error.QualityRuleSystemException;
|
|
@@ -147,7 +167,10 @@ class GoldenExceptionIntegrationTest {
|
|
|
147
167
|
@GetMapping("/exception-probe/unknown") void unknown() { throw new RuntimeException("runtime-secret"); }
|
|
148
168
|
}
|
|
149
169
|
}`);
|
|
150
|
-
|
|
170
|
+
const sliceContract = path.join(root, "slice-contract.json");
|
|
171
|
+
const requiredSkills = ["yss-domain", "yss-application", "yss-repository", "yss-mybatis", "yss-web-controller", "yss-dto", "yss-exception", "yss-validation", "mapstruct", "lombok", "alibaba-java-code-style"];
|
|
172
|
+
await writeFile(sliceContract, JSON.stringify({ schema_version: 1, contract_id: "golden-slice-1", contract_version: 1, slice_id: "quality-rule-first-slice", status: "approved", readiness: { blockers: [], stale_inputs: [] }, common: { required_skills: requiredSkills }, backend: { status: "required", affected_layers: ["domain", "application", "infrastructure", "web"], required_skills: requiredSkills }, work_units: [{ id: "slice-backend", contract_id: "golden-slice-1", contract_version: 1, work_unit: { primary_skill: "yss-domain" } }] }));
|
|
173
|
+
return { root, project, sliceContract };
|
|
151
174
|
}
|
|
152
175
|
|
|
153
176
|
test("golden first slice 组合 Domain/Application/Infrastructure/Web 且不发生 DTO/PO 穿层", async (t) => {
|
|
@@ -158,25 +181,36 @@ test("golden first slice 组合 Domain/Application/Infrastructure/Web 且不发
|
|
|
158
181
|
const controller = await readFile(path.join(project, "golden-service-adapter", "golden-service-web", "src/main/java/com/yss/golden/rest/QualityRuleController.java"), "utf8");
|
|
159
182
|
const convertor = await readFile(path.join(project, "golden-service-adapter", "golden-service-web", "src/main/java/com/yss/golden/rest/convertor/QualityRuleWebConvertor.java"), "utf8");
|
|
160
183
|
const pageRequest = await readFile(path.join(project, "golden-service-adapter", "golden-service-web", "src/main/java/com/yss/golden/rest/dto/request/QualityRulePageRequest.java"), "utf8");
|
|
184
|
+
const serviceImpl = await readFile(path.join(project, "golden-service-application", "src/main/java/com/yss/golden/application/service/impl/QualityRuleServiceImpl.java"), "utf8");
|
|
185
|
+
const repository = await readFile(path.join(project, "golden-service-infrastructure", "src/main/java/com/yss/golden/infrastructure/persistence/repository/QualityRuleRepository.java"), "utf8");
|
|
186
|
+
const gatewayImpl = await readFile(path.join(project, "golden-service-infrastructure", "src/main/java/com/yss/golden/infrastructure/persistence/gateway/QualityRuleGatewayImpl.java"), "utf8");
|
|
187
|
+
const queryAdapter = await readFile(path.join(project, "golden-service-infrastructure", "src/main/java/com/yss/golden/infrastructure/query/adapter/QualityRuleQueryAdapter.java"), "utf8");
|
|
161
188
|
assert.doesNotMatch(domainPom, /yss-component-dto|yss-component-exception|spring-web|swagger/);
|
|
162
189
|
assert.match(applicationPom, /yss-component-dto/);
|
|
163
190
|
assert.doesNotMatch(webPom, /golden-service-domain|golden-service-infrastructure/);
|
|
164
191
|
assert.doesNotMatch(`${controller}\n${convertor}`, /\.domain\.|\.infrastructure\.|\.repository\.|Mappers\.getMapper|INSTANCE/);
|
|
165
192
|
assert.match(convertor, /@Mapper\(componentModel = "spring"\)/);
|
|
166
193
|
assert.doesNotMatch(pageRequest, /offset|needTotalCount|tempTotalCount|extends PageQuery/);
|
|
194
|
+
assert.match(pageRequest, /pageIndex/);
|
|
195
|
+
assert.match(pageRequest, /pageSize/);
|
|
196
|
+
assert.doesNotMatch(pageRequest, /orderBy|orderDirection|groupBy/);
|
|
197
|
+
assert.match(serviceImpl, /implements QualityRuleService/);
|
|
198
|
+
assert.match(serviceImpl, /@Transactional/);
|
|
199
|
+
assert.match(repository, /@Mapper/);
|
|
200
|
+
assert.match(gatewayImpl, /implements QualityRuleGateway/);
|
|
201
|
+
assert.match(queryAdapter, /implements QualityRuleQueryPort/);
|
|
167
202
|
});
|
|
168
203
|
|
|
169
|
-
test("golden first slice 通过真实 Wrapper
|
|
204
|
+
test("golden first slice 通过真实 Wrapper 后才写入 first-slice-verified", { timeout: 300_000 }, async (t) => {
|
|
170
205
|
if (!["YSS_MAVEN_REPOSITORY_URL", "MAVEN_REPO_USERNAME", "MAVEN_REPO_PASSWORD"].every((name) => process.env[name])) {
|
|
171
206
|
t.skip("缺少受控 YSS Maven 仓库环境;不得声明 first-slice-verified");
|
|
172
207
|
return;
|
|
173
208
|
}
|
|
174
|
-
const { project } = await prepareGoldenProject(t);
|
|
209
|
+
const { project, sliceContract, root } = await prepareGoldenProject(t);
|
|
175
210
|
await chmod(path.join(project, "mvnw"), 0o755);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
211
|
+
const result = await runFirstSliceVerification(project, path.join(root, "first-slice-evidence"), sliceContract, process.env);
|
|
212
|
+
assert.equal(result.status, "passed", JSON.stringify(result, null, 2));
|
|
213
|
+
assert.equal(JSON.parse(await readFile(path.join(project, ".yss/scaffold-generation.json"), "utf8")).completion_level, "first-slice-verified");
|
|
180
214
|
});
|
|
181
215
|
|
|
182
216
|
test("真实 YSS exception starter 的自动配置、优先级、三类映射和序列化均受保护", { timeout: 300_000 }, async (t) => {
|
package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { chmod, mkdir, mkdtemp, readFile, readdir, writeFile } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
import { runFirstSliceVerification } from "./run_first_slice_verification.mjs";
|
|
10
|
+
|
|
11
|
+
const requiredSkills = ["yss-domain", "yss-application", "yss-repository", "yss-mybatis", "yss-web-controller", "yss-dto", "yss-exception", "yss-validation", "mapstruct", "lombok", "alibaba-java-code-style"];
|
|
12
|
+
const scripts = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const repositoryRoot = path.resolve(scripts, "../../../..");
|
|
14
|
+
|
|
15
|
+
async function treeDigest(root) {
|
|
16
|
+
const relativeFiles = [];
|
|
17
|
+
async function visit(directory) {
|
|
18
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
19
|
+
const absolute = path.join(directory, entry.name);
|
|
20
|
+
if (entry.isDirectory()) await visit(absolute);
|
|
21
|
+
else if (entry.isFile()) relativeFiles.push(path.relative(root, absolute).split(path.sep).join("/"));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
await visit(root);
|
|
25
|
+
const hash = createHash("sha256");
|
|
26
|
+
for (const relative of relativeFiles.sort()) hash.update(relative).update("\0").update(await readFile(path.join(root, relative))).update("\0");
|
|
27
|
+
return hash.digest("hex");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function readiness() {
|
|
31
|
+
const downstreamSkills = {};
|
|
32
|
+
for (const skill of requiredSkills) downstreamSkills[skill] = await treeDigest(path.join(repositoryRoot, ".agents", "skills", skill));
|
|
33
|
+
const digest = async (relative) => createHash("sha256").update(await readFile(path.join(repositoryRoot, relative))).digest("hex");
|
|
34
|
+
return {
|
|
35
|
+
downstream_skills: downstreamSkills,
|
|
36
|
+
contracts: {
|
|
37
|
+
scaffold_parent: await digest(".agents/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md"),
|
|
38
|
+
router_contract: await digest(".agents/skills/yss-router/references/router-contract.yaml")
|
|
39
|
+
},
|
|
40
|
+
architecture_ruleset: "b".repeat(64)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function write(project, relative, content = "fixture\n") {
|
|
45
|
+
const target = path.join(project, relative);
|
|
46
|
+
await mkdir(path.dirname(target), { recursive: true });
|
|
47
|
+
await writeFile(target, content);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function fixture({ omitGatewayImpl = false, omitReadiness = false } = {}) {
|
|
51
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "yss-first-slice-verification-"));
|
|
52
|
+
const project = path.join(root, "demo-service");
|
|
53
|
+
const evidence = path.join(root, "evidence");
|
|
54
|
+
const manifestPath = path.join(project, ".yss", "scaffold-generation.json");
|
|
55
|
+
const contractPath = path.join(root, "slice-contract.json");
|
|
56
|
+
await mkdir(path.dirname(manifestPath), { recursive: true });
|
|
57
|
+
await writeFile(manifestPath, JSON.stringify({
|
|
58
|
+
schema_version: 2,
|
|
59
|
+
contract_id: "scaffold-1",
|
|
60
|
+
contract_version: 1,
|
|
61
|
+
scaffold_request_id: "scaffold-request-1",
|
|
62
|
+
contract_digest: "a".repeat(64),
|
|
63
|
+
profiles: { architecture: "target-domain-model", persistence: "mybatis-plus", database: "mysql", platform: "spring-boot-2.7-jdk8", validation_namespace: "javax", dto_placement: "web", repository: "yss-internal" },
|
|
64
|
+
ownership: { generated_files: [] },
|
|
65
|
+
readiness: omitReadiness ? { downstream_skills: {}, contracts: {}, architecture_ruleset: "b".repeat(64) } : await readiness(),
|
|
66
|
+
generation_policy: { mode: "initialize-only", existing_target: "unsupported", old_project_migration: "unsupported", template_upgrade: "unsupported" },
|
|
67
|
+
completion_level: "empty-scaffold-verified",
|
|
68
|
+
approval_ref: "approval-1",
|
|
69
|
+
approver: "maintainer",
|
|
70
|
+
lifecycle_approval_ref: "approval-1",
|
|
71
|
+
router_draft_ref: "router-1",
|
|
72
|
+
persisted_ref: "persisted-1",
|
|
73
|
+
contract_file_ref: contractPath,
|
|
74
|
+
current_version: 1,
|
|
75
|
+
allowed_write_paths: ["."],
|
|
76
|
+
expected_evidence_files: [".yss/scaffold-generation.json"],
|
|
77
|
+
verification_commands: ["./mvnw validate", "./mvnw test", "./mvnw package"],
|
|
78
|
+
generation_mode: "controlled-generation",
|
|
79
|
+
maven_coordinates_source: "approved-contract"
|
|
80
|
+
}));
|
|
81
|
+
await writeFile(contractPath, JSON.stringify({
|
|
82
|
+
schema_version: 1,
|
|
83
|
+
contract_id: "slice-1",
|
|
84
|
+
contract_version: 1,
|
|
85
|
+
slice_id: "quality-rule-first-slice",
|
|
86
|
+
status: "approved",
|
|
87
|
+
readiness: { blockers: [], stale_inputs: [] },
|
|
88
|
+
common: { required_skills: requiredSkills },
|
|
89
|
+
backend: { status: "required", affected_layers: ["domain", "application", "infrastructure", "web"], required_skills: requiredSkills },
|
|
90
|
+
work_units: [{ id: "slice-backend", contract_id: "slice-1", contract_version: 1, work_unit: { primary_skill: "yss-domain" } }]
|
|
91
|
+
}));
|
|
92
|
+
await write(project, "mvnw", "#!/bin/sh\nexit 0\n");
|
|
93
|
+
await chmod(path.join(project, "mvnw"), 0o755);
|
|
94
|
+
await write(project, ".mvn/settings.xml", "<settings/>\n");
|
|
95
|
+
await write(project, ".mvn/maven.config", "-s .mvn/settings.xml -P yss-internal\n");
|
|
96
|
+
const files = [
|
|
97
|
+
"demo-service-domain/src/main/java/com/yss/demo/domain/quality/model/QualityRule.java",
|
|
98
|
+
"demo-service-domain/src/main/java/com/yss/demo/domain/quality/gateway/QualityRuleGateway.java",
|
|
99
|
+
"demo-service-domain/src/test/java/com/yss/demo/domain/quality/model/QualityRuleTest.java",
|
|
100
|
+
"demo-service-application/src/main/java/com/yss/demo/application/command/QualityRuleCreateCommand.java",
|
|
101
|
+
"demo-service-application/src/main/java/com/yss/demo/application/query/QualityRulePageQuery.java",
|
|
102
|
+
"demo-service-application/src/main/java/com/yss/demo/application/result/QualityRuleResult.java",
|
|
103
|
+
"demo-service-application/src/main/java/com/yss/demo/application/service/QualityRuleService.java",
|
|
104
|
+
"demo-service-application/src/main/java/com/yss/demo/application/service/impl/QualityRuleServiceImpl.java",
|
|
105
|
+
"demo-service-application/src/test/java/com/yss/demo/application/service/QualityRuleServiceTest.java",
|
|
106
|
+
"demo-service-infrastructure/src/main/java/com/yss/demo/infrastructure/persistence/po/QualityRulePO.java",
|
|
107
|
+
"demo-service-infrastructure/src/main/java/com/yss/demo/infrastructure/persistence/repository/QualityRuleRepository.java",
|
|
108
|
+
"demo-service-infrastructure/src/main/java/com/yss/demo/infrastructure/persistence/convertor/QualityRulePersistenceConvertor.java",
|
|
109
|
+
"demo-service-infrastructure/src/main/java/com/yss/demo/infrastructure/query/adapter/QualityRuleQueryAdapter.java",
|
|
110
|
+
"demo-service-infrastructure/src/test/java/com/yss/demo/infrastructure/persistence/QualityRuleGatewayIntegrationTest.java",
|
|
111
|
+
"demo-service-adapter/demo-service-web/src/main/java/com/yss/demo/rest/QualityRuleController.java",
|
|
112
|
+
"demo-service-adapter/demo-service-web/src/main/java/com/yss/demo/rest/convertor/QualityRuleWebConvertor.java",
|
|
113
|
+
"demo-service-adapter/demo-service-web/src/main/java/com/yss/demo/rest/dto/request/QualityRuleCreateRequest.java",
|
|
114
|
+
"demo-service-adapter/demo-service-web/src/main/java/com/yss/demo/rest/dto/response/QualityRuleResponse.java",
|
|
115
|
+
"demo-service-adapter/demo-service-web/src/test/java/com/yss/demo/rest/QualityRuleContractTest.java"
|
|
116
|
+
];
|
|
117
|
+
if (!omitGatewayImpl) files.push("demo-service-infrastructure/src/main/java/com/yss/demo/infrastructure/persistence/gateway/QualityRuleGatewayImpl.java");
|
|
118
|
+
for (const relative of files) await write(project, relative);
|
|
119
|
+
return { root, project, evidence, manifestPath, contractPath };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const environment = { ...process.env, JAVA_HOME: "/fixture/java", YSS_MAVEN_REPOSITORY_URL: "https://repo.example.invalid", MAVEN_REPO_USERNAME: "user", MAVEN_REPO_PASSWORD: "secret" };
|
|
123
|
+
|
|
124
|
+
test("refuses first-slice promotion when a required persistence seam is absent", async () => {
|
|
125
|
+
const data = await fixture({ omitGatewayImpl: true });
|
|
126
|
+
const report = await runFirstSliceVerification(data.project, data.evidence, data.contractPath, environment);
|
|
127
|
+
assert.equal(report.status, "failed");
|
|
128
|
+
assert.ok(report.missing_artifacts.includes("infrastructure-gateway-implementation"));
|
|
129
|
+
const manifest = JSON.parse(await readFile(data.manifestPath, "utf8"));
|
|
130
|
+
assert.equal(manifest.completion_level, "empty-scaffold-verified");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("refuses first-slice promotion when downstream skill or contract digests are absent", async () => {
|
|
134
|
+
const data = await fixture({ omitReadiness: true });
|
|
135
|
+
const report = await runFirstSliceVerification(data.project, data.evidence, data.contractPath, environment);
|
|
136
|
+
assert.equal(report.status, "failed");
|
|
137
|
+
assert.ok(report.downstream_skill_drift.includes("yss-domain:digest-missing"));
|
|
138
|
+
assert.ok(report.downstream_skill_drift.includes("router_contract:digest-missing"));
|
|
139
|
+
const manifest = JSON.parse(await readFile(data.manifestPath, "utf8"));
|
|
140
|
+
assert.equal(manifest.completion_level, "empty-scaffold-verified");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("refuses first-slice promotion when a work unit references a stale contract version", async () => {
|
|
144
|
+
const data = await fixture();
|
|
145
|
+
const contract = JSON.parse(await readFile(data.contractPath, "utf8"));
|
|
146
|
+
contract.work_units[0].contract_version = 0;
|
|
147
|
+
await writeFile(data.contractPath, JSON.stringify(contract));
|
|
148
|
+
const report = await runFirstSliceVerification(data.project, data.evidence, data.contractPath, environment);
|
|
149
|
+
assert.equal(report.status, "failed");
|
|
150
|
+
assert.ok(report.contract_failures.includes("work-unit-contract-version-mismatch:slice-backend"));
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("promotes a complete approved slice only after all root wrapper commands pass", async () => {
|
|
154
|
+
const data = await fixture();
|
|
155
|
+
const report = await runFirstSliceVerification(data.project, data.evidence, data.contractPath, environment);
|
|
156
|
+
assert.equal(report.status, "passed");
|
|
157
|
+
assert.equal(report.completion_level, "first-slice-verified");
|
|
158
|
+
assert.deepEqual(report.commands.map((item) => item.exit_code), [0, 0, 0]);
|
|
159
|
+
const manifest = JSON.parse(await readFile(data.manifestPath, "utf8"));
|
|
160
|
+
assert.equal(manifest.completion_level, "first-slice-verified");
|
|
161
|
+
assert.equal(manifest.first_slice_contract.contract_id, "slice-1");
|
|
162
|
+
assert.equal(manifest.first_slice_contract.slice_id, "quality-rule-first-slice");
|
|
163
|
+
assert.equal(JSON.parse(await readFile(path.join(data.evidence, "first-slice-verification.json"), "utf8")).status, "passed");
|
|
164
|
+
});
|
|
@@ -25,7 +25,19 @@ const SUPPORTED_PROFILES = Object.freeze({
|
|
|
25
25
|
dto_placement: "web",
|
|
26
26
|
repository: "yss-internal"
|
|
27
27
|
});
|
|
28
|
-
const DOWNSTREAM_SKILLS = [
|
|
28
|
+
const DOWNSTREAM_SKILLS = [
|
|
29
|
+
"yss-domain",
|
|
30
|
+
"yss-application",
|
|
31
|
+
"yss-repository",
|
|
32
|
+
"yss-mybatis",
|
|
33
|
+
"yss-web-controller",
|
|
34
|
+
"yss-dto",
|
|
35
|
+
"yss-exception",
|
|
36
|
+
"yss-validation",
|
|
37
|
+
"mapstruct",
|
|
38
|
+
"lombok",
|
|
39
|
+
"alibaba-java-code-style"
|
|
40
|
+
];
|
|
29
41
|
function fail(message) { throw new Error(message); }
|
|
30
42
|
function isoNow() { return new Date().toISOString(); }
|
|
31
43
|
function localDate() { return new Date().toISOString().slice(0, 10); }
|
|
@@ -324,10 +336,12 @@ class ScaffoldGenerator {
|
|
|
324
336
|
}
|
|
325
337
|
const downstream = {};
|
|
326
338
|
for (const skill of DOWNSTREAM_SKILLS) {
|
|
327
|
-
const
|
|
328
|
-
downstream[skill] = await isFile(
|
|
339
|
+
const skillRoot = path.join(REPOSITORY_ROOT, ".agents", "skills", skill);
|
|
340
|
+
downstream[skill] = await isFile(path.join(skillRoot, "SKILL.md")) ? await treeDigest(skillRoot) : "unavailable";
|
|
329
341
|
}
|
|
330
|
-
const
|
|
342
|
+
const scaffoldParent = path.join(SKILL_ROOT, "references", "yss-backend-scaffold-parent", "SKILL.md");
|
|
343
|
+
const routerContract = path.join(REPOSITORY_ROOT, ".agents", "skills", "yss-router", "references", "router-contract.yaml");
|
|
344
|
+
const manifest = { schema_version: 2, contract_id: this.options.contractId, contract_version: this.options.contractVersion, scaffold_request_id: contract.scaffold_request_id, approval_ref: this.options.approvalRef, router_draft_ref: this.options.routerDraftRef, persisted_ref: this.options.persistedRef, contract_file_ref: this.contractFile, contract_digest: this.contractDigest, lifecycle_approval_ref: contract.lifecycle_approval_ref, current_version: contract.current_version, approver: contract.approval.approver, allowed_write_paths: contract.allowed_write_paths, expected_evidence_files: contract.expected_evidence_files, project_name: this.projectName, base_package: this.basePackage, bootstrap_main_class: `${this.basePackage}.${this.applicationClassName}`, bootstrap_main_source: this.bootstrapMainSource, maven_coordinates: this.mavenCoordinates, maven_coordinates_source: this.mavenCoordinatesSource, profiles: this.profiles, database: this.options.database, generation_mode: "controlled-generation", completion_level: "generated", generator: { id: "yss-ddd-scaffold-generator", template_digest: await treeDigest(path.join(SKILL_ROOT, "assets")) }, ownership: { generated_files: generatedFiles, user_owned_globs: ["**/src/main/java/**", "**/src/test/java/**", "db/**"] }, readiness: { downstream_skills: downstream, contracts: { scaffold_parent: sha256(await readFile(scaffoldParent)), router_contract: sha256(await readFile(routerContract)) }, architecture_ruleset: sha256(await readFile(path.join(this.javaTemplateDir, "architecture-rules-test.java.template"))) }, generation_policy: { mode: "initialize-only", existing_target: "unsupported", old_project_migration: "unsupported", template_upgrade: "unsupported" }, verification_commands: COMMANDS, generated_at: isoNow() };
|
|
331
345
|
await writeText(path.join(this.projectRoot, ".yss", "scaffold-generation.json"), `${JSON.stringify(manifest, null, 2)}\n`); console.log(" ✓ .yss/scaffold-generation.json");
|
|
332
346
|
}
|
|
333
347
|
async copyWrapperFiles() {
|