create-yss-spec 2.1.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/cli.js +2 -30
- package/src/template-hash.js +44 -0
- package/template/.agents/skills/cross-repo-implementation-routing/SKILL.md +4 -3
- package/template/.agents/skills/implementation-repo-onboarding/SKILL.md +4 -2
- package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +25 -5
- package/template/.agents/skills/yss-ddd-scaffold-generator/agents/openai.yaml +1 -1
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +25 -36
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +474 -258
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.py +155 -0
- package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +2 -1
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +28 -0
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +70 -2
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +9 -0
- package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.agents/skills/yss-router/SKILL.md +4 -0
- package/template/.agents/skills/yss-router/references/router-contract.yaml +48 -2
- package/template/.agents/skills/yss-router/references/slice-implementation-contract.md +2 -0
- package/template/.agents/skills/yss-router/references/yss-skill-execution-result.md +1 -1
- package/template/.claude/skills/cross-repo-implementation-routing/SKILL.md +4 -3
- package/template/.claude/skills/implementation-repo-onboarding/SKILL.md +4 -2
- package/template/.claude/skills/yss-ddd-scaffold-generator/SKILL.md +25 -5
- package/template/.claude/skills/yss-ddd-scaffold-generator/agents/openai.yaml +1 -1
- package/template/.claude/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +25 -36
- package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +474 -258
- package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.py +155 -0
- package/template/.claude/skills/yss-frontend-scaffold-generator/SKILL.md +2 -1
- package/template/.claude/skills/yss-product-lifecycle/SKILL.md +28 -0
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +70 -2
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +9 -0
- package/template/.claude/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.claude/skills/yss-router/SKILL.md +4 -0
- package/template/.claude/skills/yss-router/references/router-contract.yaml +48 -2
- package/template/.claude/skills/yss-router/references/slice-implementation-contract.md +2 -0
- package/template/.claude/skills/yss-router/references/yss-skill-execution-result.md +1 -1
- package/template/.codex/skills/cross-repo-implementation-routing/SKILL.md +4 -3
- package/template/.codex/skills/implementation-repo-onboarding/SKILL.md +4 -2
- package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +25 -5
- package/template/.codex/skills/yss-ddd-scaffold-generator/agents/openai.yaml +1 -1
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +25 -36
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +474 -258
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.py +155 -0
- package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +2 -1
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +28 -0
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +70 -2
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +9 -0
- package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.codex/skills/yss-router/SKILL.md +4 -0
- package/template/.codex/skills/yss-router/references/router-contract.yaml +48 -2
- package/template/.codex/skills/yss-router/references/slice-implementation-contract.md +2 -0
- package/template/.codex/skills/yss-router/references/yss-skill-execution-result.md +1 -1
- package/template/.hermes/skills/cross-repo-implementation-routing/SKILL.md +4 -3
- package/template/.hermes/skills/implementation-repo-onboarding/SKILL.md +4 -2
- package/template/.hermes/skills/yss-ddd-scaffold-generator/SKILL.md +25 -5
- package/template/.hermes/skills/yss-ddd-scaffold-generator/agents/openai.yaml +1 -1
- package/template/.hermes/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +25 -36
- package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +474 -258
- package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.py +155 -0
- package/template/.hermes/skills/yss-frontend-scaffold-generator/SKILL.md +2 -1
- package/template/.hermes/skills/yss-product-lifecycle/SKILL.md +28 -0
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +70 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration.md +9 -0
- package/template/.hermes/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.hermes/skills/yss-router/SKILL.md +4 -0
- package/template/.hermes/skills/yss-router/references/router-contract.yaml +48 -2
- package/template/.hermes/skills/yss-router/references/slice-implementation-contract.md +2 -0
- package/template/.hermes/skills/yss-router/references/yss-skill-execution-result.md +1 -1
- package/template/.pi/skills/cross-repo-implementation-routing/SKILL.md +4 -3
- package/template/.pi/skills/implementation-repo-onboarding/SKILL.md +4 -2
- package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +25 -5
- package/template/.pi/skills/yss-ddd-scaffold-generator/agents/openai.yaml +1 -1
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +25 -36
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +474 -258
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.py +155 -0
- package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +2 -1
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +28 -0
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +70 -2
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +9 -0
- package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.pi/skills/yss-router/SKILL.md +4 -0
- package/template/.pi/skills/yss-router/references/router-contract.yaml +48 -2
- package/template/.pi/skills/yss-router/references/slice-implementation-contract.md +2 -0
- package/template/.pi/skills/yss-router/references/yss-skill-execution-result.md +1 -1
- package/template/.qoder/skills/cross-repo-implementation-routing/SKILL.md +4 -3
- package/template/.qoder/skills/implementation-repo-onboarding/SKILL.md +4 -2
- package/template/.qoder/skills/yss-ddd-scaffold-generator/SKILL.md +25 -5
- package/template/.qoder/skills/yss-ddd-scaffold-generator/agents/openai.yaml +1 -1
- package/template/.qoder/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +25 -36
- package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +474 -258
- package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.py +155 -0
- package/template/.qoder/skills/yss-frontend-scaffold-generator/SKILL.md +2 -1
- package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +28 -0
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +70 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +9 -0
- package/template/.qoder/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.qoder/skills/yss-router/SKILL.md +4 -0
- package/template/.qoder/skills/yss-router/references/router-contract.yaml +48 -2
- package/template/.qoder/skills/yss-router/references/slice-implementation-contract.md +2 -0
- package/template/.qoder/skills/yss-router/references/yss-skill-execution-result.md +1 -1
- package/template/.trae/skills/cross-repo-implementation-routing/SKILL.md +4 -3
- package/template/.trae/skills/implementation-repo-onboarding/SKILL.md +4 -2
- package/template/.trae/skills/yss-ddd-scaffold-generator/SKILL.md +25 -5
- package/template/.trae/skills/yss-ddd-scaffold-generator/agents/openai.yaml +1 -1
- package/template/.trae/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +25 -36
- package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +474 -258
- package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.py +155 -0
- package/template/.trae/skills/yss-frontend-scaffold-generator/SKILL.md +2 -1
- package/template/.trae/skills/yss-product-lifecycle/SKILL.md +28 -0
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +70 -2
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +9 -0
- package/template/.trae/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.trae/skills/yss-router/SKILL.md +4 -0
- package/template/.trae/skills/yss-router/references/router-contract.yaml +48 -2
- package/template/.trae/skills/yss-router/references/slice-implementation-contract.md +2 -0
- package/template/.trae/skills/yss-router/references/yss-skill-execution-result.md +1 -1
- package/template/AGENTS.md +12 -8
- package/template/docs/architecture/templates/engineering-baseline-review-template.md +14 -0
- package/template/docs/process/implementation-repo-integration.md +17 -0
- package/template/docs/process/lifecycle-artifact-map.md +3 -3
- package/template/docs/templates/build-architecture-checklist-template.md +7 -1
- package/template/docs/templates/cross-repo-slice-template.md +2 -0
- package/template/docs/templates/implementation-repo-registry-template.md +14 -0
- package/template/docs/templates/implementation-routing-template.md +35 -6
- package/template/docs/user-guide//344/272/247/345/223/201/347/224/237/345/221/275/345/221/250/346/234/237/345/267/245/344/275/234/346/265/201.md +4 -3
- package/template/docs/user-guide//347/224/237/345/221/275/345/221/250/346/234/237/346/234/200/344/275/263/345/256/236/350/267/265.md +10 -2
- package/template/scripts/implementation-path-policy.rb +50 -0
- package/template/scripts/sync-skills +5 -0
- package/template/scripts/update-skill-lock +7 -1
- package/template/scripts/verify-implementation-path-scenarios +43 -0
- package/template/scripts/verify-lifecycle-scenarios +18 -0
- package/template/scripts/verify-matt-yss-integration-scenarios +1 -1
- package/template/scripts/verify-prototype-backend-scaffold-scenarios +239 -0
- package/template/scripts/verify-scaffold-generator-scenarios +438 -0
- package/template/scripts/verify-template +11 -0
- package/template/scripts/verify-yss-router-scenarios +76 -23
- package/template/skills-lock.json +6 -6
- package/template.snapshot.json +4 -4
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/adapter/UserController.java.template +0 -84
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/application/UserConvertor.java.template +0 -21
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/application/UserService.java.template +0 -48
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/application/UserServiceImpl.java.template +0 -87
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/bootstrap/YssDatamiddleApplication.java.template +0 -28
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/config/data.sql.template +0 -2
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/config/schema.sql.template +0 -27
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/domain/User.java.template +0 -17
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserAddCmd.java.template +0 -27
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserGateway.java.template +0 -54
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserPageQuery.java.template +0 -12
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserUpdateCmd.java.template +0 -21
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserVO.java.template +0 -52
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/AuditableEntity.java.template +0 -25
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/PageUtil.java.template +0 -13
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserGatewayImpl.java.template +0 -85
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPO.java.template +0 -35
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPOConvertor.java.template +0 -28
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserRepository.java.template +0 -7
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/YssDataMybatisConfig.java.template +0 -8
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/adapter/UserController.java.template +0 -84
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/application/UserConvertor.java.template +0 -21
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/application/UserService.java.template +0 -48
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/application/UserServiceImpl.java.template +0 -87
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/bootstrap/YssDatamiddleApplication.java.template +0 -28
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/config/data.sql.template +0 -2
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/config/schema.sql.template +0 -27
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/domain/User.java.template +0 -17
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserAddCmd.java.template +0 -27
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserGateway.java.template +0 -54
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserPageQuery.java.template +0 -12
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserUpdateCmd.java.template +0 -21
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserVO.java.template +0 -52
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/AuditableEntity.java.template +0 -25
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/PageUtil.java.template +0 -13
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserGatewayImpl.java.template +0 -85
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPO.java.template +0 -35
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPOConvertor.java.template +0 -28
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserRepository.java.template +0 -7
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/YssDataMybatisConfig.java.template +0 -8
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/adapter/UserController.java.template +0 -84
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/application/UserConvertor.java.template +0 -21
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/application/UserService.java.template +0 -48
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/application/UserServiceImpl.java.template +0 -87
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/bootstrap/YssDatamiddleApplication.java.template +0 -28
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/config/data.sql.template +0 -2
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/config/schema.sql.template +0 -27
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/domain/User.java.template +0 -17
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserAddCmd.java.template +0 -27
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserGateway.java.template +0 -54
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserPageQuery.java.template +0 -12
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserUpdateCmd.java.template +0 -21
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserVO.java.template +0 -52
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/AuditableEntity.java.template +0 -25
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/PageUtil.java.template +0 -13
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserGatewayImpl.java.template +0 -85
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPO.java.template +0 -35
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPOConvertor.java.template +0 -28
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserRepository.java.template +0 -7
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/YssDataMybatisConfig.java.template +0 -8
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/adapter/UserController.java.template +0 -84
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/application/UserConvertor.java.template +0 -21
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/application/UserService.java.template +0 -48
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/application/UserServiceImpl.java.template +0 -87
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/bootstrap/YssDatamiddleApplication.java.template +0 -28
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/config/data.sql.template +0 -2
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/config/schema.sql.template +0 -27
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/domain/User.java.template +0 -17
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserAddCmd.java.template +0 -27
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserGateway.java.template +0 -54
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserPageQuery.java.template +0 -12
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserUpdateCmd.java.template +0 -21
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserVO.java.template +0 -52
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/AuditableEntity.java.template +0 -25
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/PageUtil.java.template +0 -13
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserGatewayImpl.java.template +0 -85
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPO.java.template +0 -35
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPOConvertor.java.template +0 -28
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserRepository.java.template +0 -7
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/YssDataMybatisConfig.java.template +0 -8
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/adapter/UserController.java.template +0 -84
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/application/UserConvertor.java.template +0 -21
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/application/UserService.java.template +0 -48
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/application/UserServiceImpl.java.template +0 -87
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/bootstrap/YssDatamiddleApplication.java.template +0 -28
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/config/data.sql.template +0 -2
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/config/schema.sql.template +0 -27
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/domain/User.java.template +0 -17
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserAddCmd.java.template +0 -27
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserGateway.java.template +0 -54
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserPageQuery.java.template +0 -12
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserUpdateCmd.java.template +0 -21
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserVO.java.template +0 -52
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/AuditableEntity.java.template +0 -25
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/PageUtil.java.template +0 -13
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserGatewayImpl.java.template +0 -85
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPO.java.template +0 -35
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPOConvertor.java.template +0 -28
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserRepository.java.template +0 -7
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/YssDataMybatisConfig.java.template +0 -8
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/adapter/UserController.java.template +0 -84
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/application/UserConvertor.java.template +0 -21
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/application/UserService.java.template +0 -48
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/application/UserServiceImpl.java.template +0 -87
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/bootstrap/YssDatamiddleApplication.java.template +0 -28
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/config/data.sql.template +0 -2
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/config/schema.sql.template +0 -27
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/domain/User.java.template +0 -17
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserAddCmd.java.template +0 -27
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserGateway.java.template +0 -54
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserPageQuery.java.template +0 -12
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserUpdateCmd.java.template +0 -21
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserVO.java.template +0 -52
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/AuditableEntity.java.template +0 -25
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/PageUtil.java.template +0 -13
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserGatewayImpl.java.template +0 -85
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPO.java.template +0 -35
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPOConvertor.java.template +0 -28
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserRepository.java.template +0 -7
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/YssDataMybatisConfig.java.template +0 -8
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/adapter/UserController.java.template +0 -84
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/application/UserConvertor.java.template +0 -21
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/application/UserService.java.template +0 -48
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/application/UserServiceImpl.java.template +0 -87
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/bootstrap/YssDatamiddleApplication.java.template +0 -28
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/config/data.sql.template +0 -2
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/config/schema.sql.template +0 -27
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/domain/User.java.template +0 -17
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserAddCmd.java.template +0 -27
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserGateway.java.template +0 -54
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserPageQuery.java.template +0 -12
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserUpdateCmd.java.template +0 -21
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/domain/UserVO.java.template +0 -52
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/AuditableEntity.java.template +0 -25
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/PageUtil.java.template +0 -13
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserGatewayImpl.java.template +0 -85
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPO.java.template +0 -35
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserPOConvertor.java.template +0 -28
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/UserRepository.java.template +0 -7
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/infrastructure/YssDataMybatisConfig.java.template +0 -8
|
@@ -1,43 +1,69 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
YSS DDD 脚手架生成器
|
|
5
|
-
用于快速创建基于 DDD 的后端项目结构
|
|
6
|
-
"""
|
|
3
|
+
"""YSS DDD 后端纯工程骨架生成器。"""
|
|
7
4
|
|
|
8
|
-
import os
|
|
9
|
-
import sys
|
|
10
5
|
import argparse
|
|
11
6
|
import json
|
|
12
|
-
|
|
13
|
-
from typing import Dict, List
|
|
7
|
+
import os
|
|
14
8
|
import re
|
|
15
9
|
import shutil
|
|
16
|
-
import
|
|
10
|
+
import sys
|
|
17
11
|
import tempfile
|
|
18
12
|
from datetime import datetime
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Dict, List, Optional, Tuple
|
|
15
|
+
|
|
19
16
|
|
|
20
17
|
class ScaffoldGenerator:
|
|
21
|
-
"""
|
|
18
|
+
"""只生成工程结构,不生成任何业务行为。"""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
project_name: str,
|
|
23
|
+
base_package: str,
|
|
24
|
+
output_dir: str,
|
|
25
|
+
with_example: bool = False,
|
|
26
|
+
database: str = "mysql",
|
|
27
|
+
force: bool = False,
|
|
28
|
+
contract_id: Optional[str] = None,
|
|
29
|
+
contract_version: Optional[int] = None,
|
|
30
|
+
approval_ref: Optional[str] = None,
|
|
31
|
+
router_draft_ref: Optional[str] = None,
|
|
32
|
+
persisted_ref: Optional[str] = None,
|
|
33
|
+
contract_file: Optional[str] = None,
|
|
34
|
+
overwrite_scope: Optional[str] = None,
|
|
35
|
+
rollback_ref: Optional[str] = None,
|
|
36
|
+
):
|
|
37
|
+
if with_example:
|
|
38
|
+
raise ValueError(
|
|
39
|
+
"YSS 受控脚手架只生成纯工程骨架;--with-example 已禁用,业务代码必须按批准切片合同实现"
|
|
40
|
+
)
|
|
22
41
|
|
|
23
|
-
def __init__(self, project_name: str, base_package: str, output_dir: str,
|
|
24
|
-
with_example: bool = False, database: str = 'mysql', force: bool = False):
|
|
25
42
|
self.project_name = project_name
|
|
26
43
|
self.base_package = base_package
|
|
27
44
|
self.output_dir = Path(output_dir)
|
|
45
|
+
self.repository_root = Path(__file__).resolve().parents[4]
|
|
46
|
+
self._validate_harness_output_layout()
|
|
28
47
|
self.with_example = with_example
|
|
29
48
|
self.database = database
|
|
30
49
|
self.force = force
|
|
50
|
+
self.contract_id = contract_id
|
|
51
|
+
self.contract_version = contract_version
|
|
52
|
+
self.approval_ref = approval_ref
|
|
53
|
+
self.router_draft_ref = router_draft_ref
|
|
54
|
+
self.persisted_ref = persisted_ref
|
|
55
|
+
self.contract_file = Path(contract_file).resolve() if contract_file else None
|
|
56
|
+
self.overwrite_scope = overwrite_scope
|
|
57
|
+
self.rollback_ref = rollback_ref
|
|
58
|
+
self.scaffold_contract: Dict[str, object] = {}
|
|
59
|
+
|
|
31
60
|
self.template_root = Path(__file__).resolve().parents[1] / "assets" / "templates"
|
|
32
61
|
self.config_template_dir = self.template_root / "config"
|
|
33
62
|
self.pom_template_dir = self.template_root / "pom"
|
|
34
63
|
if not self.pom_template_dir.exists():
|
|
35
64
|
self.pom_template_dir = self.config_template_dir
|
|
36
65
|
|
|
37
|
-
|
|
38
|
-
self.package_path = base_package.replace('.', '/')
|
|
39
|
-
|
|
40
|
-
# 最终项目根目录;生成期间 project_root 会指向 staging 目录
|
|
66
|
+
self.package_path = base_package.replace(".", "/")
|
|
41
67
|
self.final_project_root = self.output_dir / project_name
|
|
42
68
|
self.project_root = self.final_project_root
|
|
43
69
|
|
|
@@ -51,14 +77,19 @@ class ScaffoldGenerator:
|
|
|
51
77
|
self.db_dependency = self._resolve_db_dependency(self.database)
|
|
52
78
|
|
|
53
79
|
def generate(self):
|
|
54
|
-
"""
|
|
80
|
+
"""在受控生成合同下生成不含业务行为的工程骨架。"""
|
|
55
81
|
if self.final_project_root.exists() and not self.force:
|
|
56
82
|
raise FileExistsError(
|
|
57
83
|
f"输出目录已存在: {self.final_project_root};如确认覆盖,请显式传入 --force"
|
|
58
84
|
)
|
|
85
|
+
self._validate_contract_metadata()
|
|
86
|
+
if self._target_is_non_empty() and self.force:
|
|
87
|
+
self._validate_force_metadata()
|
|
59
88
|
|
|
60
89
|
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
61
|
-
staging_root = Path(
|
|
90
|
+
staging_root = Path(
|
|
91
|
+
tempfile.mkdtemp(prefix=f".{self.project_name}.staging-", dir=self.output_dir)
|
|
92
|
+
)
|
|
62
93
|
self.project_root = staging_root / self.project_name
|
|
63
94
|
|
|
64
95
|
try:
|
|
@@ -67,31 +98,21 @@ class ScaffoldGenerator:
|
|
|
67
98
|
print(f"📁 输出目录: {self.output_dir}")
|
|
68
99
|
print()
|
|
69
100
|
|
|
70
|
-
# 创建项目结构
|
|
71
101
|
self._create_project_structure()
|
|
72
|
-
|
|
73
|
-
# 生成 POM 文件
|
|
74
102
|
self._generate_pom_files()
|
|
75
|
-
|
|
76
|
-
# 生成配置文件
|
|
77
103
|
self._generate_config_files()
|
|
78
|
-
|
|
79
|
-
# 生成示例代码
|
|
80
|
-
if self.with_example:
|
|
81
|
-
self._generate_example_code()
|
|
82
|
-
|
|
83
|
-
# 生成数据库脚本
|
|
84
104
|
self._generate_database_scripts()
|
|
85
|
-
|
|
86
|
-
# 生成文档
|
|
87
105
|
self._generate_documentation()
|
|
88
|
-
|
|
106
|
+
self._write_generation_manifest()
|
|
89
107
|
self._copy_wrapper_files()
|
|
90
108
|
self._validate_generated_artifacts()
|
|
91
109
|
|
|
92
110
|
backup_path = None
|
|
93
111
|
if self.final_project_root.exists():
|
|
94
|
-
backup_path = self.output_dir /
|
|
112
|
+
backup_path = self.output_dir / (
|
|
113
|
+
f".{self.project_name}.backup-"
|
|
114
|
+
f"{datetime.now().strftime('%Y%m%d%H%M%S%f')}"
|
|
115
|
+
)
|
|
95
116
|
self.final_project_root.rename(backup_path)
|
|
96
117
|
self.project_root.rename(self.final_project_root)
|
|
97
118
|
self.project_root = self.final_project_root
|
|
@@ -107,18 +128,204 @@ class ScaffoldGenerator:
|
|
|
107
128
|
print(" ./mvnw validate")
|
|
108
129
|
print(" ./mvnw test")
|
|
109
130
|
print(" ./mvnw package")
|
|
110
|
-
print(" ./mvnw spring-boot:run -pl {}-bootstrap"
|
|
131
|
+
print(f" ./mvnw spring-boot:run -pl {self.project_name}-bootstrap")
|
|
111
132
|
except Exception:
|
|
112
133
|
shutil.rmtree(staging_root, ignore_errors=True)
|
|
113
134
|
raise
|
|
114
135
|
|
|
136
|
+
def _target_is_non_empty(self) -> bool:
|
|
137
|
+
if not self.final_project_root.exists():
|
|
138
|
+
return False
|
|
139
|
+
if self.final_project_root.is_file():
|
|
140
|
+
return True
|
|
141
|
+
return any(self.final_project_root.iterdir())
|
|
142
|
+
|
|
143
|
+
def _validate_harness_output_layout(self) -> None:
|
|
144
|
+
"""在当前 Harness 内只允许生成到 apps/backend/<project>/。"""
|
|
145
|
+
output_root = self.output_dir.resolve()
|
|
146
|
+
try:
|
|
147
|
+
relative = output_root.relative_to(self.repository_root)
|
|
148
|
+
except ValueError:
|
|
149
|
+
# 外部实现仓库使用其登记的 native root,不套用 Harness 目录策略。
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
parts = relative.parts
|
|
153
|
+
if len(parts) >= 2 and parts[0] == "app" and parts[1] in {"backend", "frontend"}:
|
|
154
|
+
raise ValueError(
|
|
155
|
+
"禁止使用单数 app/backend 或 app/frontend 作为工程生成路径;"
|
|
156
|
+
"Harness 内后端脚手架必须以 apps/backend 为父容器"
|
|
157
|
+
)
|
|
158
|
+
if parts == ("apps", "backend"):
|
|
159
|
+
return
|
|
160
|
+
if parts[:2] == ("apps", "frontend"):
|
|
161
|
+
raise ValueError("后端脚手架不能输出到 apps/frontend;请使用外部后端仓库或 apps/backend")
|
|
162
|
+
raise ValueError(
|
|
163
|
+
"当前 Harness 内生成后端工程时,输出目录必须是 apps/backend;"
|
|
164
|
+
"生成器会以 project_name 创建 apps/backend/<project>/"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def _validate_contract_metadata(self):
|
|
168
|
+
if self.contract_file is None or not self.contract_file.is_file():
|
|
169
|
+
raise ValueError("必须提供已持久化的结构化脚手架合同 JSON 文件: --contract-file")
|
|
170
|
+
|
|
171
|
+
try:
|
|
172
|
+
contract = json.loads(self.contract_file.read_text(encoding="utf-8"))
|
|
173
|
+
except (OSError, json.JSONDecodeError) as exception:
|
|
174
|
+
raise ValueError(f"脚手架合同文件无法读取或不是合法 JSON: {self.contract_file}") from exception
|
|
175
|
+
if not isinstance(contract, dict):
|
|
176
|
+
raise ValueError("脚手架合同必须是 JSON 对象")
|
|
177
|
+
|
|
178
|
+
required_metadata = {
|
|
179
|
+
"--contract-id": self.contract_id,
|
|
180
|
+
"--contract-version": self.contract_version,
|
|
181
|
+
"--approval-ref": self.approval_ref,
|
|
182
|
+
"--router-draft-ref": self.router_draft_ref,
|
|
183
|
+
"--persisted-ref": self.persisted_ref,
|
|
184
|
+
}
|
|
185
|
+
missing = [
|
|
186
|
+
option for option, value in required_metadata.items() if value in (None, "")
|
|
187
|
+
]
|
|
188
|
+
if self.contract_version is not None and self.contract_version < 1:
|
|
189
|
+
missing.append("--contract-version(必须为正整数)")
|
|
190
|
+
if missing:
|
|
191
|
+
raise ValueError(
|
|
192
|
+
"生成项目必须提供当前已批准脚手架合同的完整元数据: " + ", ".join(missing)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
required_fields = [
|
|
196
|
+
"schema_version",
|
|
197
|
+
"contract_id",
|
|
198
|
+
"contract_version",
|
|
199
|
+
"slice_id",
|
|
200
|
+
"status",
|
|
201
|
+
"router_draft_ref",
|
|
202
|
+
"lifecycle_approval_ref",
|
|
203
|
+
"persisted_ref",
|
|
204
|
+
"current_version",
|
|
205
|
+
"implementation_repository",
|
|
206
|
+
"backend_repository",
|
|
207
|
+
"scaffold_status",
|
|
208
|
+
"target_git_url_or_output_dir",
|
|
209
|
+
"allowed_write_paths",
|
|
210
|
+
"expected_evidence_files",
|
|
211
|
+
"verification_commands",
|
|
212
|
+
"approval",
|
|
213
|
+
"work_unit",
|
|
214
|
+
"overwrite_policy",
|
|
215
|
+
]
|
|
216
|
+
missing_contract_fields = [
|
|
217
|
+
field for field in required_fields if contract.get(field) in (None, "", [])
|
|
218
|
+
]
|
|
219
|
+
if missing_contract_fields:
|
|
220
|
+
raise ValueError(
|
|
221
|
+
"脚手架合同缺少结构化字段: " + ", ".join(missing_contract_fields)
|
|
222
|
+
)
|
|
223
|
+
if contract["schema_version"] != 1 or contract["status"] != "approved":
|
|
224
|
+
raise ValueError("脚手架合同必须是 schema_version=1 且已由生命周期批准")
|
|
225
|
+
if contract["contract_id"] != self.contract_id:
|
|
226
|
+
raise ValueError("--contract-id 与脚手架合同不一致")
|
|
227
|
+
if contract["contract_version"] != self.contract_version:
|
|
228
|
+
raise ValueError("--contract-version 与脚手架合同不一致")
|
|
229
|
+
if contract["current_version"] != contract["contract_version"]:
|
|
230
|
+
raise ValueError("脚手架合同版本不是当前版本")
|
|
231
|
+
if contract["router_draft_ref"] != self.router_draft_ref:
|
|
232
|
+
raise ValueError("--router-draft-ref 与脚手架合同不一致")
|
|
233
|
+
if contract["persisted_ref"] != self.persisted_ref:
|
|
234
|
+
raise ValueError("--persisted-ref 与脚手架合同不一致")
|
|
235
|
+
if contract["lifecycle_approval_ref"] != self.approval_ref:
|
|
236
|
+
raise ValueError("--approval-ref 与脚手架合同不一致")
|
|
237
|
+
if contract["scaffold_status"] != "required":
|
|
238
|
+
raise ValueError("脚手架生成器只接受 scaffold_status=required")
|
|
239
|
+
if not all(isinstance(contract[field], list) and contract[field] for field in (
|
|
240
|
+
"allowed_write_paths", "expected_evidence_files", "verification_commands"
|
|
241
|
+
)):
|
|
242
|
+
raise ValueError("脚手架合同的 allowed_write_paths、expected_evidence_files、verification_commands 必须非空")
|
|
243
|
+
if ".yss/scaffold-generation.json" not in " ".join(str(item) for item in contract["expected_evidence_files"]):
|
|
244
|
+
raise ValueError("脚手架合同 expected_evidence_files 必须包含 .yss/scaffold-generation.json")
|
|
245
|
+
target_ref = str(contract["target_git_url_or_output_dir"])
|
|
246
|
+
if "://" not in target_ref and not target_ref.startswith("git@"):
|
|
247
|
+
if Path(target_ref).resolve() != self.output_dir.resolve():
|
|
248
|
+
raise ValueError("脚手架合同目标目录与 --output-dir 不一致")
|
|
249
|
+
expected_commands = ["./mvnw validate", "./mvnw test", "./mvnw package"]
|
|
250
|
+
if contract["verification_commands"] != expected_commands:
|
|
251
|
+
raise ValueError("脚手架合同验证命令必须固定为三条项目根目录 ./mvnw 命令")
|
|
252
|
+
|
|
253
|
+
approval = contract["approval"]
|
|
254
|
+
if not isinstance(approval, dict) or any(
|
|
255
|
+
approval.get(field) in (None, "")
|
|
256
|
+
for field in ("approval_ref", "approver", "persisted_ref", "current_version")
|
|
257
|
+
):
|
|
258
|
+
raise ValueError("脚手架合同 approval 记录不完整")
|
|
259
|
+
if approval["approval_ref"] != self.approval_ref or approval["persisted_ref"] != self.persisted_ref:
|
|
260
|
+
raise ValueError("脚手架合同 approval 引用与命令参数不一致")
|
|
261
|
+
if approval["current_version"] != self.contract_version:
|
|
262
|
+
raise ValueError("脚手架合同 approval 不是当前版本")
|
|
263
|
+
|
|
264
|
+
work_unit = contract["work_unit"]
|
|
265
|
+
required_work_unit_fields = [
|
|
266
|
+
"id",
|
|
267
|
+
"behavior",
|
|
268
|
+
"primary_skill",
|
|
269
|
+
"supporting_skills",
|
|
270
|
+
"tdd_mode",
|
|
271
|
+
"allowed_write_paths",
|
|
272
|
+
"expected_evidence",
|
|
273
|
+
"verification_commands",
|
|
274
|
+
"controlled_generation",
|
|
275
|
+
]
|
|
276
|
+
if not isinstance(work_unit, dict) or any(
|
|
277
|
+
work_unit.get(field) in (None, "", []) for field in required_work_unit_fields
|
|
278
|
+
):
|
|
279
|
+
raise ValueError("脚手架合同 work_unit 结构不完整")
|
|
280
|
+
if (
|
|
281
|
+
work_unit.get("primary_skill") != "yss-ddd-scaffold-generator"
|
|
282
|
+
or work_unit.get("tdd_mode") != "controlled-generation"
|
|
283
|
+
or work_unit.get("controlled_generation") is not True
|
|
284
|
+
):
|
|
285
|
+
raise ValueError("脚手架合同 work_unit 必须绑定本 skill 和 controlled-generation")
|
|
286
|
+
if (
|
|
287
|
+
work_unit["verification_commands"] != contract["verification_commands"]
|
|
288
|
+
or work_unit["allowed_write_paths"] != contract["allowed_write_paths"]
|
|
289
|
+
):
|
|
290
|
+
raise ValueError("脚手架合同 work_unit 与根级验证/写路径约束不一致")
|
|
291
|
+
overwrite_policy = contract["overwrite_policy"]
|
|
292
|
+
if not isinstance(overwrite_policy, dict) or any(
|
|
293
|
+
field not in overwrite_policy for field in ("force_allowed", "overwrite_scope", "rollback_ref")
|
|
294
|
+
):
|
|
295
|
+
raise ValueError("脚手架合同 overwrite_policy 结构不完整")
|
|
296
|
+
self.scaffold_contract = contract
|
|
297
|
+
|
|
298
|
+
def _validate_force_metadata(self):
|
|
299
|
+
required_metadata = {
|
|
300
|
+
"--overwrite-scope": self.overwrite_scope,
|
|
301
|
+
"--rollback-ref": self.rollback_ref,
|
|
302
|
+
}
|
|
303
|
+
missing = [
|
|
304
|
+
option for option, value in required_metadata.items() if value in (None, "")
|
|
305
|
+
]
|
|
306
|
+
if missing:
|
|
307
|
+
raise ValueError(
|
|
308
|
+
"覆盖非空目录必须提供当前批准合同的覆盖范围和回滚引用: "
|
|
309
|
+
+ ", ".join(missing)
|
|
310
|
+
)
|
|
311
|
+
overwrite_policy = self.scaffold_contract.get("overwrite_policy", {})
|
|
312
|
+
if not isinstance(overwrite_policy, dict) or overwrite_policy.get("force_allowed") is not True:
|
|
313
|
+
raise ValueError("脚手架合同未批准非空目录覆盖")
|
|
314
|
+
if overwrite_policy.get("overwrite_scope") != self.overwrite_scope:
|
|
315
|
+
raise ValueError("--overwrite-scope 与脚手架合同不一致")
|
|
316
|
+
if overwrite_policy.get("rollback_ref") != self.rollback_ref:
|
|
317
|
+
raise ValueError("--rollback-ref 与脚手架合同不一致")
|
|
318
|
+
|
|
115
319
|
def _validate_generated_artifacts(self):
|
|
116
320
|
"""在 staging 目录提交前校验关键产物和占位符。"""
|
|
117
321
|
required_files = [
|
|
118
322
|
self.project_root / "pom.xml",
|
|
119
323
|
self.project_root / f"{self.project_name}-bootstrap" / "pom.xml",
|
|
120
|
-
self.project_root
|
|
324
|
+
self.project_root
|
|
325
|
+
/ f"{self.project_name}-bootstrap"
|
|
326
|
+
/ "src/main/resources/smart-doc.json",
|
|
121
327
|
self.project_root / "mvnw",
|
|
328
|
+
self.project_root / ".yss/scaffold-generation.json",
|
|
122
329
|
]
|
|
123
330
|
missing = [str(path) for path in required_files if not path.is_file()]
|
|
124
331
|
if missing:
|
|
@@ -126,6 +333,16 @@ class ScaffoldGenerator:
|
|
|
126
333
|
|
|
127
334
|
smart_doc_path = required_files[2]
|
|
128
335
|
json.loads(smart_doc_path.read_text(encoding="utf-8"))
|
|
336
|
+
manifest = json.loads(required_files[4].read_text(encoding="utf-8"))
|
|
337
|
+
if (
|
|
338
|
+
manifest.get("contract_id") != self.contract_id
|
|
339
|
+
or manifest.get("contract_version") != self.contract_version
|
|
340
|
+
or manifest.get("current_version") != self.contract_version
|
|
341
|
+
or manifest.get("generation_mode") != "controlled-generation"
|
|
342
|
+
or manifest.get("verification_commands")
|
|
343
|
+
!= ["./mvnw validate", "./mvnw test", "./mvnw package"]
|
|
344
|
+
):
|
|
345
|
+
raise ValueError("脚手架生成元数据清单与当前批准合同或固定验证命令不一致")
|
|
129
346
|
bootstrap_pom = required_files[1].read_text(encoding="utf-8")
|
|
130
347
|
plugin_versions = re.findall(
|
|
131
348
|
r"<artifactId>smart-doc-maven-plugin</artifactId>\s*<version>([^<]+)</version>",
|
|
@@ -134,63 +351,81 @@ class ScaffoldGenerator:
|
|
|
134
351
|
if plugin_versions != ["yss-4.0.0"]:
|
|
135
352
|
raise ValueError("smart-doc-maven-plugin 必须且只能使用 yss-4.0.0")
|
|
136
353
|
|
|
354
|
+
binary_suffixes = {".class", ".db", ".jar", ".png", ".jpg", ".jpeg", ".gif"}
|
|
137
355
|
for path in self.project_root.rglob("*"):
|
|
138
|
-
if path.is_file()
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
356
|
+
if not path.is_file() or path.suffix in binary_suffixes:
|
|
357
|
+
continue
|
|
358
|
+
content = path.read_text(encoding="utf-8")
|
|
359
|
+
if "{{" in content or "root/root" in content:
|
|
360
|
+
raise ValueError(f"生成文件包含未替换占位符或明文凭据: {path}")
|
|
142
361
|
|
|
143
362
|
def _create_project_structure(self):
|
|
144
|
-
"""
|
|
363
|
+
"""创建不含业务文件的项目目录结构。"""
|
|
145
364
|
print("📁 创建项目目录结构...")
|
|
146
|
-
|
|
147
365
|
modules = [
|
|
148
366
|
f"{self.project_name}-domain",
|
|
149
367
|
f"{self.project_name}-application",
|
|
150
368
|
f"{self.project_name}-infrastructure",
|
|
151
369
|
f"{self.project_name}-adapter",
|
|
152
|
-
f"{self.project_name}-bootstrap"
|
|
370
|
+
f"{self.project_name}-bootstrap",
|
|
153
371
|
]
|
|
154
372
|
|
|
155
373
|
for module in modules:
|
|
156
374
|
module_path = self.project_root / module
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
resources_path.mkdir(parents=True, exist_ok=True)
|
|
165
|
-
|
|
166
|
-
# 创建 src/test/java 目录
|
|
167
|
-
test_path = module_path / "src" / "test" / "java" / self.package_path
|
|
168
|
-
test_path.mkdir(parents=True, exist_ok=True)
|
|
169
|
-
|
|
375
|
+
(module_path / "src/main/java" / self.package_path).mkdir(
|
|
376
|
+
parents=True, exist_ok=True
|
|
377
|
+
)
|
|
378
|
+
(module_path / "src/main/resources").mkdir(parents=True, exist_ok=True)
|
|
379
|
+
(module_path / "src/test/java" / self.package_path).mkdir(
|
|
380
|
+
parents=True, exist_ok=True
|
|
381
|
+
)
|
|
170
382
|
print(f" ✓ {module}")
|
|
171
383
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
384
|
+
web_module = (
|
|
385
|
+
self.project_root
|
|
386
|
+
/ f"{self.project_name}-adapter"
|
|
387
|
+
/ f"{self.project_name}-web"
|
|
388
|
+
)
|
|
389
|
+
(web_module / "src/main/java" / self.package_path / "rest").mkdir(
|
|
390
|
+
parents=True, exist_ok=True
|
|
391
|
+
)
|
|
176
392
|
print(f" ✓ {self.project_name}-adapter/{self.project_name}-web")
|
|
177
393
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
db_path.mkdir(parents=True, exist_ok=True)
|
|
181
|
-
print(f" ✓ db")
|
|
394
|
+
(self.project_root / "db").mkdir(parents=True, exist_ok=True)
|
|
395
|
+
print(" ✓ db")
|
|
182
396
|
|
|
183
397
|
def _generate_pom_files(self):
|
|
184
|
-
"""生成 Maven POM
|
|
398
|
+
"""生成 Maven POM 文件。"""
|
|
185
399
|
print("\n📝 生成 Maven POM 文件...")
|
|
186
|
-
pom_templates = [
|
|
400
|
+
pom_templates: List[Tuple[Path, Path]] = [
|
|
187
401
|
(self.pom_template_dir / "parent-pom.xml.template", self.project_root / "pom.xml"),
|
|
188
|
-
(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
(
|
|
193
|
-
|
|
402
|
+
(
|
|
403
|
+
self.pom_template_dir / "domain-pom.xml.template",
|
|
404
|
+
self.project_root / f"{self.project_name}-domain" / "pom.xml",
|
|
405
|
+
),
|
|
406
|
+
(
|
|
407
|
+
self.pom_template_dir / "application-pom.xml.template",
|
|
408
|
+
self.project_root / f"{self.project_name}-application" / "pom.xml",
|
|
409
|
+
),
|
|
410
|
+
(
|
|
411
|
+
self.pom_template_dir / "infrastructure-pom.xml.template",
|
|
412
|
+
self.project_root / f"{self.project_name}-infrastructure" / "pom.xml",
|
|
413
|
+
),
|
|
414
|
+
(
|
|
415
|
+
self.pom_template_dir / "adapter-pom.xml.template",
|
|
416
|
+
self.project_root / f"{self.project_name}-adapter" / "pom.xml",
|
|
417
|
+
),
|
|
418
|
+
(
|
|
419
|
+
self.pom_template_dir / "web-pom.xml.template",
|
|
420
|
+
self.project_root
|
|
421
|
+
/ f"{self.project_name}-adapter"
|
|
422
|
+
/ f"{self.project_name}-web"
|
|
423
|
+
/ "pom.xml",
|
|
424
|
+
),
|
|
425
|
+
(
|
|
426
|
+
self.pom_template_dir / "bootstrap-pom.xml.template",
|
|
427
|
+
self.project_root / f"{self.project_name}-bootstrap" / "pom.xml",
|
|
428
|
+
),
|
|
194
429
|
]
|
|
195
430
|
self._render_and_write_templates(pom_templates)
|
|
196
431
|
print(" ✓ 父级 pom.xml")
|
|
@@ -202,142 +437,41 @@ class ScaffoldGenerator:
|
|
|
202
437
|
print(" ✓ bootstrap pom.xml")
|
|
203
438
|
|
|
204
439
|
def _generate_config_files(self):
|
|
205
|
-
"""
|
|
440
|
+
"""生成不含业务行为的工程配置文件。"""
|
|
206
441
|
print("\n⚙️ 生成配置文件...")
|
|
207
|
-
config_templates = [
|
|
208
|
-
(
|
|
209
|
-
|
|
210
|
-
|
|
442
|
+
config_templates: List[Tuple[Path, Path]] = [
|
|
443
|
+
(
|
|
444
|
+
self.config_template_dir / "application.yml.template",
|
|
445
|
+
self.project_root
|
|
446
|
+
/ f"{self.project_name}-bootstrap"
|
|
447
|
+
/ "src/main/resources/application.yml",
|
|
448
|
+
),
|
|
449
|
+
(
|
|
450
|
+
self.config_template_dir / "logback-spring.xml.template",
|
|
451
|
+
self.project_root
|
|
452
|
+
/ f"{self.project_name}-bootstrap"
|
|
453
|
+
/ "src/main/resources/logback-spring.xml",
|
|
454
|
+
),
|
|
455
|
+
(
|
|
456
|
+
self.config_template_dir / "smart-doc.json.template",
|
|
457
|
+
self.project_root
|
|
458
|
+
/ f"{self.project_name}-bootstrap"
|
|
459
|
+
/ "src/main/resources/smart-doc.json",
|
|
460
|
+
),
|
|
211
461
|
]
|
|
212
462
|
self._render_and_write_templates(config_templates)
|
|
213
463
|
print(" ✓ application.yml")
|
|
214
464
|
print(" ✓ logback-spring.xml")
|
|
215
465
|
print(" ✓ smart-doc.json")
|
|
216
466
|
|
|
217
|
-
def _generate_example_code(self):
|
|
218
|
-
"""生成示例代码"""
|
|
219
|
-
print("\n💻 生成示例代码 (User CRUD)...")
|
|
220
|
-
domain_root = self.project_root / f"{self.project_name}-domain" / "src" / "main" / "java" / self.package_path
|
|
221
|
-
application_root = self.project_root / f"{self.project_name}-application" / "src" / "main" / "java" / self.package_path
|
|
222
|
-
infrastructure_root = self.project_root / f"{self.project_name}-infrastructure" / "src" / "main" / "java" / self.package_path
|
|
223
|
-
adapter_root = self.project_root / f"{self.project_name}-adapter" / f"{self.project_name}-web" / "src" / "main" / "java" / self.package_path
|
|
224
|
-
bootstrap_root = self.project_root / f"{self.project_name}-bootstrap" / "src" / "main" / "java" / self.package_path
|
|
225
|
-
|
|
226
|
-
example_templates = [
|
|
227
|
-
(self.template_root / "domain" / "UserAddCmd.java.template", domain_root / "client" / "dto" / "cmd" / "UserAddCmd.java"),
|
|
228
|
-
(self.template_root / "domain" / "UserUpdateCmd.java.template", domain_root / "client" / "dto" / "cmd" / "UserUpdateCmd.java"),
|
|
229
|
-
(self.template_root / "domain" / "UserPageQuery.java.template", domain_root / "client" / "dto" / "query" / "UserPageQuery.java"),
|
|
230
|
-
(self.template_root / "domain" / "UserVO.java.template", domain_root / "client" / "vo" / "UserVO.java"),
|
|
231
|
-
(self.template_root / "domain" / "UserGateway.java.template", domain_root / "domain" / "user" / "gateway" / "UserGateway.java"),
|
|
232
|
-
(self.template_root / "domain" / "User.java.template", domain_root / "domain" / "user" / "model" / "User.java"),
|
|
233
|
-
(self.template_root / "application" / "UserService.java.template", application_root / "core" / "service" / "UserService.java"),
|
|
234
|
-
(self.template_root / "application" / "UserServiceImpl.java.template", application_root / "core" / "service" / "impl" / "UserServiceImpl.java"),
|
|
235
|
-
(self.template_root / "application" / "UserConvertor.java.template", application_root / "core" / "service" / "convertor" / "UserConvertor.java"),
|
|
236
|
-
(self.template_root / "infrastructure" / "AuditableEntity.java.template", infrastructure_root / "repository" / "entity" / "AuditableEntity.java"),
|
|
237
|
-
(self.template_root / "infrastructure" / "UserPO.java.template", infrastructure_root / "repository" / "entity" / "UserPO.java"),
|
|
238
|
-
(self.template_root / "infrastructure" / "UserRepository.java.template", infrastructure_root / "repository" / "UserRepository.java"),
|
|
239
|
-
(self.template_root / "infrastructure" / "UserGatewayImpl.java.template", infrastructure_root / "repository" / "gateway" / "impl" / "UserGatewayImpl.java"),
|
|
240
|
-
(self.template_root / "infrastructure" / "UserPOConvertor.java.template", infrastructure_root / "repository" / "convertor" / "UserPOConvertor.java"),
|
|
241
|
-
(self.template_root / "infrastructure" / "PageUtil.java.template", infrastructure_root / "repository" / "util" / "PageUtil.java"),
|
|
242
|
-
(self.template_root / "infrastructure" / "YssDataMybatisConfig.java.template", infrastructure_root / "repository" / "config" / "YssDataMybatisConfig.java"),
|
|
243
|
-
(self.template_root / "adapter" / "UserController.java.template", adapter_root / "rest" / "UserController.java"),
|
|
244
|
-
(self.template_root / "bootstrap" / "YssDatamiddleApplication.java.template", bootstrap_root / "YssDatamiddleApplication.java"),
|
|
245
|
-
]
|
|
246
|
-
self._render_and_write_templates(example_templates)
|
|
247
|
-
print(" ✓ Domain 层: UserAddCmd, UserUpdateCmd, UserPageQuery, UserVO, UserGateway, User")
|
|
248
|
-
print(" ✓ Application 层: UserService, UserServiceImpl, UserConvertor")
|
|
249
|
-
print(" ✓ Infrastructure 层: UserPO, UserRepository, UserGatewayImpl, UserPOConvertor, PageUtil,YssDataMybatisConfig")
|
|
250
|
-
print(" ✓ Adapter 层: UserController")
|
|
251
|
-
print(" ✓ Bootstrap 层: YssDatamiddleApplication 启动类")
|
|
252
|
-
|
|
253
467
|
def _generate_database_scripts(self):
|
|
254
|
-
"""
|
|
255
|
-
print("\n🗃️
|
|
256
|
-
|
|
257
|
-
# 针对 SQLite 的特殊处理
|
|
258
|
-
if self.database == 'sqlite':
|
|
259
|
-
schema_content = """-- 用户表
|
|
260
|
-
CREATE TABLE t_user (
|
|
261
|
-
id INTEGER PRIMARY KEY,
|
|
262
|
-
username VARCHAR(50) NOT NULL,
|
|
263
|
-
email VARCHAR(100),
|
|
264
|
-
status INTEGER NOT NULL DEFAULT 1,
|
|
265
|
-
description VARCHAR(500),
|
|
266
|
-
deleted INTEGER NOT NULL DEFAULT 0,
|
|
267
|
-
created_by VARCHAR(50),
|
|
268
|
-
created_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
269
|
-
last_modified_by VARCHAR(50),
|
|
270
|
-
last_modified_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
271
|
-
);
|
|
272
|
-
|
|
273
|
-
CREATE UNIQUE INDEX uk_username ON t_user (username);
|
|
274
|
-
CREATE INDEX idx_status ON t_user (status);
|
|
275
|
-
CREATE INDEX idx_created_date ON t_user (created_date);
|
|
276
|
-
|
|
277
|
-
-- Leaf Alloc 表
|
|
278
|
-
CREATE TABLE leaf_alloc (
|
|
279
|
-
biz_tag VARCHAR(128) NOT NULL PRIMARY KEY,
|
|
280
|
-
max_id BIGINT NOT NULL,
|
|
281
|
-
step INT NOT NULL,
|
|
282
|
-
description VARCHAR(256),
|
|
283
|
-
update_time VARCHAR(256)
|
|
284
|
-
);
|
|
285
|
-
"""
|
|
286
|
-
# 直接写入 schema.sql
|
|
287
|
-
schema_path = self.project_root / "db" / "schema.sql"
|
|
288
|
-
self._write_file(schema_path, schema_content)
|
|
289
|
-
|
|
290
|
-
# data.sql 模板处理 (如果有差异也可以在这里处理,暂时复用模板但需注意语法)
|
|
291
|
-
# SQLite 的 data.sql 可以复用 MySQL 的 INSERT 语句,只要没有特殊函数
|
|
292
|
-
data_templates = [
|
|
293
|
-
(self.config_template_dir / "data.sql.template", self.project_root / "db" / "data.sql"),
|
|
294
|
-
]
|
|
295
|
-
self._render_and_write_templates(data_templates)
|
|
296
|
-
|
|
297
|
-
# 初始化 SQLite 数据库
|
|
298
|
-
print(" Initializing SQLite database...")
|
|
299
|
-
try:
|
|
300
|
-
db_file = self.project_root / f"{self.project_name}-bootstrap" / f"{self.db_name}.db"
|
|
301
|
-
# 如果文件存在先删除,确保干净的初始化
|
|
302
|
-
if db_file.exists():
|
|
303
|
-
db_file.unlink()
|
|
304
|
-
|
|
305
|
-
conn = sqlite3.connect(str(db_file))
|
|
306
|
-
cursor = conn.cursor()
|
|
307
|
-
|
|
308
|
-
# 执行 schema.sql
|
|
309
|
-
if schema_path.exists():
|
|
310
|
-
cursor.executescript(schema_path.read_text(encoding='utf-8'))
|
|
311
|
-
print(" ✓ Executed schema.sql")
|
|
312
|
-
|
|
313
|
-
# 执行 data.sql
|
|
314
|
-
data_path = self.project_root / "db" / "data.sql"
|
|
315
|
-
if data_path.exists():
|
|
316
|
-
cursor.executescript(data_path.read_text(encoding='utf-8'))
|
|
317
|
-
print(" ✓ Executed data.sql")
|
|
318
|
-
|
|
319
|
-
conn.commit()
|
|
320
|
-
conn.close()
|
|
321
|
-
print(f" ✓ Created database: {db_file.name}")
|
|
322
|
-
except Exception as e:
|
|
323
|
-
print(f" ❌ Failed to initialize SQLite database: {e}")
|
|
324
|
-
|
|
325
|
-
else:
|
|
326
|
-
# 默认 (MySQL) 处理
|
|
327
|
-
db_templates = [
|
|
328
|
-
(self.config_template_dir / "schema.sql.template", self.project_root / "db" / "schema.sql"),
|
|
329
|
-
(self.config_template_dir / "data.sql.template", self.project_root / "db" / "data.sql"),
|
|
330
|
-
]
|
|
331
|
-
self._render_and_write_templates(db_templates)
|
|
332
|
-
|
|
333
|
-
print(" ✓ schema.sql (建表脚本)")
|
|
334
|
-
print(" ✓ data.sql (初始化数据)")
|
|
468
|
+
"""只保留数据库目录布局,不生成业务表或初始化数据。"""
|
|
469
|
+
print("\n🗃️ 保留数据库目录布局...")
|
|
470
|
+
print(" ✓ db/(业务 schema 和初始化数据由批准切片合同生成)")
|
|
335
471
|
|
|
336
472
|
def _generate_documentation(self):
|
|
337
|
-
"""
|
|
473
|
+
"""生成不包含业务 API 的项目说明。"""
|
|
338
474
|
print("\n📚 生成项目文档...")
|
|
339
|
-
readme_path = self.project_root / "README.md"
|
|
340
|
-
api_path = self.project_root / "API.md"
|
|
341
475
|
readme_content = self._render_text(
|
|
342
476
|
"# {{project_name}}\n\n"
|
|
343
477
|
"## 模块说明\n\n"
|
|
@@ -346,28 +480,54 @@ CREATE TABLE leaf_alloc (
|
|
|
346
480
|
"- {{project_name}}-infrastructure\n"
|
|
347
481
|
"- {{project_name}}-adapter\n"
|
|
348
482
|
"- {{project_name}}-bootstrap\n\n"
|
|
483
|
+
"业务 API、领域模型、数据结构和权限行为必须在冻结的 "
|
|
484
|
+
"Slice Implementation Contract 下,由对应 YSS skill 逐切片实现。\n\n"
|
|
349
485
|
"## 快速开始\n\n"
|
|
350
486
|
"```bash\n"
|
|
351
487
|
"cd {{project_name}}\n"
|
|
352
488
|
"./mvnw clean compile\n"
|
|
353
489
|
"./mvnw spring-boot:run -pl {{project_name}}-bootstrap\n"
|
|
354
490
|
"```\n",
|
|
355
|
-
self._template_vars()
|
|
356
|
-
)
|
|
357
|
-
api_content = self._render_text(
|
|
358
|
-
"# {{project_name}} API\n\n"
|
|
359
|
-
"## 用户接口\n\n"
|
|
360
|
-
"- POST /api/users/page\n"
|
|
361
|
-
"- GET /api/users/{id}\n"
|
|
362
|
-
"- POST /api/users\n"
|
|
363
|
-
"- PUT /api/users\n"
|
|
364
|
-
"- DELETE /api/users/{id}\n",
|
|
365
|
-
self._template_vars()
|
|
491
|
+
self._template_vars(),
|
|
366
492
|
)
|
|
367
|
-
self._write_file(
|
|
368
|
-
self._write_file(api_path, api_content)
|
|
493
|
+
self._write_file(self.project_root / "README.md", readme_content)
|
|
369
494
|
print(" ✓ README.md")
|
|
370
|
-
|
|
495
|
+
|
|
496
|
+
def _write_generation_manifest(self):
|
|
497
|
+
"""把脚手架合同引用和生成输入写入非业务元数据清单。"""
|
|
498
|
+
manifest = {
|
|
499
|
+
"schema_version": 1,
|
|
500
|
+
"contract_id": self.contract_id,
|
|
501
|
+
"contract_version": self.contract_version,
|
|
502
|
+
"approval_ref": self.approval_ref,
|
|
503
|
+
"router_draft_ref": self.router_draft_ref,
|
|
504
|
+
"persisted_ref": self.persisted_ref,
|
|
505
|
+
"contract_file_ref": str(self.contract_file),
|
|
506
|
+
"slice_id": self.scaffold_contract["slice_id"],
|
|
507
|
+
"lifecycle_approval_ref": self.scaffold_contract["lifecycle_approval_ref"],
|
|
508
|
+
"current_version": self.scaffold_contract["current_version"],
|
|
509
|
+
"approver": self.scaffold_contract["approval"]["approver"],
|
|
510
|
+
"allowed_write_paths": self.scaffold_contract["allowed_write_paths"],
|
|
511
|
+
"expected_evidence_files": self.scaffold_contract["expected_evidence_files"],
|
|
512
|
+
"project_name": self.project_name,
|
|
513
|
+
"base_package": self.base_package,
|
|
514
|
+
"database": self.database,
|
|
515
|
+
"generation_mode": "controlled-generation",
|
|
516
|
+
"force": self.force,
|
|
517
|
+
"overwrite_scope": self.overwrite_scope,
|
|
518
|
+
"rollback_ref": self.rollback_ref,
|
|
519
|
+
"verification_commands": [
|
|
520
|
+
"./mvnw validate",
|
|
521
|
+
"./mvnw test",
|
|
522
|
+
"./mvnw package",
|
|
523
|
+
],
|
|
524
|
+
"generated_at": datetime.now().astimezone().isoformat(),
|
|
525
|
+
}
|
|
526
|
+
self._write_file(
|
|
527
|
+
self.project_root / ".yss/scaffold-generation.json",
|
|
528
|
+
json.dumps(manifest, ensure_ascii=False, indent=2) + "\n",
|
|
529
|
+
)
|
|
530
|
+
print(" ✓ .yss/scaffold-generation.json")
|
|
371
531
|
|
|
372
532
|
def _copy_wrapper_files(self):
|
|
373
533
|
wrapper_dir = self.template_root.parent / "wrapper"
|
|
@@ -384,7 +544,7 @@ CREATE TABLE leaf_alloc (
|
|
|
384
544
|
shutil.rmtree(mvn_dir_target)
|
|
385
545
|
shutil.copytree(mvn_dir_source, mvn_dir_target)
|
|
386
546
|
|
|
387
|
-
def _render_and_write_templates(self, items: List[
|
|
547
|
+
def _render_and_write_templates(self, items: List[Tuple[Path, Path]]):
|
|
388
548
|
variables = self._template_vars()
|
|
389
549
|
for template_path, output_path in items:
|
|
390
550
|
content = self._load_template(template_path)
|
|
@@ -418,7 +578,7 @@ CREATE TABLE leaf_alloc (
|
|
|
418
578
|
"driver_class": self.driver_class,
|
|
419
579
|
"db_name": self.db_name,
|
|
420
580
|
"jdbc_url": self.jdbc_url,
|
|
421
|
-
"db_dependency": self.db_dependency
|
|
581
|
+
"db_dependency": self.db_dependency,
|
|
422
582
|
}
|
|
423
583
|
|
|
424
584
|
def _resolve_group_id(self, base_package: str) -> str:
|
|
@@ -432,16 +592,19 @@ CREATE TABLE leaf_alloc (
|
|
|
432
592
|
"mysql": "com.mysql.cj.jdbc.Driver",
|
|
433
593
|
"postgres": "org.postgresql.Driver",
|
|
434
594
|
"oracle": "oracle.jdbc.OracleDriver",
|
|
435
|
-
"sqlite": "org.sqlite.JDBC"
|
|
595
|
+
"sqlite": "org.sqlite.JDBC",
|
|
436
596
|
}
|
|
437
597
|
return drivers.get(database, "com.mysql.cj.jdbc.Driver")
|
|
438
598
|
|
|
439
599
|
def _resolve_jdbc_url(self, database: str, db_name: str) -> str:
|
|
440
600
|
if database == "sqlite":
|
|
441
601
|
return f"jdbc:sqlite:{db_name}.db"
|
|
442
|
-
|
|
443
|
-
return
|
|
444
|
-
|
|
602
|
+
if database == "mysql":
|
|
603
|
+
return (
|
|
604
|
+
f"jdbc:mysql://localhost:3306/{db_name}?useUnicode=true&"
|
|
605
|
+
"characterEncoding=utf8&serverTimezone=Asia/Shanghai"
|
|
606
|
+
)
|
|
607
|
+
if database == "postgres":
|
|
445
608
|
return f"jdbc:postgresql://localhost:5432/{db_name}"
|
|
446
609
|
return ""
|
|
447
610
|
|
|
@@ -452,81 +615,134 @@ CREATE TABLE leaf_alloc (
|
|
|
452
615
|
<artifactId>sqlite-jdbc</artifactId>
|
|
453
616
|
<version>3.51.1.0</version>
|
|
454
617
|
</dependency>"""
|
|
455
|
-
|
|
618
|
+
if database == "mysql":
|
|
456
619
|
return """<dependency>
|
|
457
620
|
<groupId>com.mysql</groupId>
|
|
458
621
|
<artifactId>mysql-connector-j</artifactId>
|
|
459
622
|
<version>8.4.0</version>
|
|
460
623
|
<scope>compile</scope>
|
|
461
624
|
</dependency>"""
|
|
462
|
-
|
|
625
|
+
if database == "postgres":
|
|
463
626
|
return """<dependency>
|
|
464
627
|
<groupId>org.postgresql</groupId>
|
|
465
628
|
<artifactId>postgresql</artifactId>
|
|
466
629
|
<version>42.7.3</version>
|
|
467
630
|
</dependency>"""
|
|
468
|
-
|
|
469
631
|
return ""
|
|
470
632
|
|
|
471
633
|
|
|
472
634
|
def main():
|
|
473
|
-
"""
|
|
635
|
+
"""命令行入口。"""
|
|
474
636
|
parser = argparse.ArgumentParser(
|
|
475
|
-
description=
|
|
637
|
+
description="YSS DDD 脚手架生成器",
|
|
476
638
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
477
|
-
epilog=
|
|
639
|
+
epilog="""
|
|
478
640
|
示例:
|
|
479
641
|
python generate_scaffold.py --project-name my-service --base-package com.yss.myservice --output-dir /path/to/repo
|
|
480
|
-
python generate_scaffold.py --project-name
|
|
481
|
-
|
|
642
|
+
python generate_scaffold.py --project-name order-service --base-package com.yss.order --output-dir /path/to/repo --database mysql
|
|
643
|
+
""",
|
|
482
644
|
)
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
parser.add_argument(
|
|
489
|
-
|
|
645
|
+
parser.add_argument(
|
|
646
|
+
"--project-name",
|
|
647
|
+
required=True,
|
|
648
|
+
help="项目名称 (kebab-case, 例如: user-service)",
|
|
649
|
+
)
|
|
650
|
+
parser.add_argument(
|
|
651
|
+
"--base-package",
|
|
652
|
+
required=True,
|
|
653
|
+
help="基础包名 (例如: com.yss.user)",
|
|
654
|
+
)
|
|
655
|
+
parser.add_argument("--output-dir", required=True, help="输出目录;必须显式指定")
|
|
490
656
|
example_group = parser.add_mutually_exclusive_group()
|
|
491
|
-
example_group.add_argument(
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
657
|
+
example_group.add_argument(
|
|
658
|
+
"--with-example",
|
|
659
|
+
dest="with_example",
|
|
660
|
+
action="store_true",
|
|
661
|
+
help="已禁用:业务示例必须按批准切片合同生成",
|
|
662
|
+
)
|
|
663
|
+
example_group.add_argument(
|
|
664
|
+
"--without-example",
|
|
665
|
+
dest="with_example",
|
|
666
|
+
action="store_false",
|
|
667
|
+
help="不生成示例代码(默认)",
|
|
668
|
+
)
|
|
495
669
|
parser.set_defaults(with_example=False)
|
|
496
|
-
parser.add_argument(
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
670
|
+
parser.add_argument(
|
|
671
|
+
"--database",
|
|
672
|
+
default="mysql",
|
|
673
|
+
choices=["mysql"],
|
|
674
|
+
help="数据库类型;当前仅支持经过验证的 mysql(默认)",
|
|
675
|
+
)
|
|
676
|
+
parser.add_argument(
|
|
677
|
+
"--force",
|
|
678
|
+
action="store_true",
|
|
679
|
+
help="显式允许写入非空输出目录;必须同时提供批准合同元数据",
|
|
680
|
+
)
|
|
681
|
+
parser.add_argument("--contract-id", help="脚手架合同 ID;生成时必填")
|
|
682
|
+
parser.add_argument(
|
|
683
|
+
"--contract-version",
|
|
684
|
+
type=int,
|
|
685
|
+
help="脚手架合同版本;生成时必填",
|
|
686
|
+
)
|
|
687
|
+
parser.add_argument(
|
|
688
|
+
"--approval-ref",
|
|
689
|
+
help="生命周期批准引用;生成时必填",
|
|
690
|
+
)
|
|
691
|
+
parser.add_argument(
|
|
692
|
+
"--router-draft-ref",
|
|
693
|
+
help="Router 脚手架合同 draft 引用;生成时必填",
|
|
694
|
+
)
|
|
695
|
+
parser.add_argument(
|
|
696
|
+
"--persisted-ref",
|
|
697
|
+
help="已持久化脚手架合同引用;生成时必填",
|
|
698
|
+
)
|
|
699
|
+
parser.add_argument(
|
|
700
|
+
"--contract-file",
|
|
701
|
+
required=True,
|
|
702
|
+
help="已批准且已持久化的结构化脚手架合同 JSON 文件;生成时必填",
|
|
703
|
+
)
|
|
704
|
+
parser.add_argument(
|
|
705
|
+
"--overwrite-scope",
|
|
706
|
+
help="合同批准的覆盖范围;非空目录使用 --force 时必填",
|
|
707
|
+
)
|
|
708
|
+
parser.add_argument(
|
|
709
|
+
"--rollback-ref",
|
|
710
|
+
help="可回滚 checkpoint 引用;非空目录使用 --force 时必填",
|
|
711
|
+
)
|
|
501
712
|
|
|
502
713
|
args = parser.parse_args()
|
|
503
714
|
|
|
504
|
-
|
|
505
|
-
if not re.match(r'^[a-z][a-z0-9-]*$', args.project_name):
|
|
715
|
+
if not re.match(r"^[a-z][a-z0-9-]*$", args.project_name):
|
|
506
716
|
print("❌ 错误: 项目名称必须是 kebab-case 格式 (例如: user-service)")
|
|
507
717
|
sys.exit(1)
|
|
508
|
-
|
|
509
|
-
# 验证包名格式
|
|
510
|
-
if not re.match(r'^[a-z](?:[a-z0-9]*)(?:\.[a-z](?:[a-z0-9]*)?)*$', args.base_package):
|
|
718
|
+
if not re.match(r"^[a-z](?:[a-z0-9]*)(?:\.[a-z](?:[a-z0-9]*)?)*$", args.base_package):
|
|
511
719
|
print("❌ 错误: 包名格式不正确 (例如: com.yss.user)")
|
|
512
720
|
sys.exit(1)
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
generator = ScaffoldGenerator(
|
|
516
|
-
project_name=args.project_name,
|
|
517
|
-
base_package=args.base_package,
|
|
518
|
-
output_dir=args.output_dir,
|
|
519
|
-
with_example=args.with_example,
|
|
520
|
-
database=args.database,
|
|
521
|
-
force=args.force
|
|
522
|
-
)
|
|
721
|
+
if args.with_example:
|
|
722
|
+
parser.error("--with-example 已禁用;业务代码必须由批准的 YSS Slice skill 逐切片生成")
|
|
523
723
|
|
|
524
724
|
try:
|
|
725
|
+
generator = ScaffoldGenerator(
|
|
726
|
+
project_name=args.project_name,
|
|
727
|
+
base_package=args.base_package,
|
|
728
|
+
output_dir=args.output_dir,
|
|
729
|
+
with_example=args.with_example,
|
|
730
|
+
database=args.database,
|
|
731
|
+
force=args.force,
|
|
732
|
+
contract_id=args.contract_id,
|
|
733
|
+
contract_version=args.contract_version,
|
|
734
|
+
approval_ref=args.approval_ref,
|
|
735
|
+
router_draft_ref=args.router_draft_ref,
|
|
736
|
+
persisted_ref=args.persisted_ref,
|
|
737
|
+
contract_file=args.contract_file,
|
|
738
|
+
overwrite_scope=args.overwrite_scope,
|
|
739
|
+
rollback_ref=args.rollback_ref,
|
|
740
|
+
)
|
|
525
741
|
generator.generate()
|
|
526
|
-
except Exception as
|
|
527
|
-
print(f"\n❌ 生成失败: {str(
|
|
742
|
+
except Exception as exception:
|
|
743
|
+
print(f"\n❌ 生成失败: {str(exception)}")
|
|
528
744
|
sys.exit(1)
|
|
529
745
|
|
|
530
746
|
|
|
531
|
-
if __name__ ==
|
|
747
|
+
if __name__ == "__main__":
|
|
532
748
|
main()
|