create-yss-spec 3.5.6 → 3.5.8
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/bin/create-yss-spec.js +3 -1
- package/cli-core.lock.json +10 -6
- package/package.json +4 -1
- package/src/api/_sync-service.js +3 -1
- package/src/command-runner.mjs +44 -9
- package/src/content-identity.js +111 -0
- package/src/runtime-store.mjs +650 -0
- package/src/template/asset-runtime.js +4 -1
- package/src/template/instance-runtime.js +23 -7
- package/src/validation/metadata.js +8 -0
- package/template/.agents/skills/.strategic-design-skills-manifest.json +1 -1
- package/template/.agents/skills/alibaba-java-code-style/SKILL.md +30 -36
- package/template/.agents/skills/archify/SKILL.md +2 -2
- package/template/.agents/skills/archify/scripts/yss-safe-deliver.mjs +10 -6
- package/template/.agents/skills/archify/test/yss-safe-deliver.test.mjs +9 -2
- package/template/.agents/skills/code-review/SKILL.md +19 -11
- package/template/.agents/skills/code-review/references/candidate-capture.md +1 -1
- package/template/.agents/skills/code-review/references/legacy-convergence.md +3 -1
- package/template/.agents/skills/code-review/references/review-axis-checklists.md +2 -0
- package/template/.agents/skills/code-review/references/yss-review-standards.md +4 -2
- package/template/.agents/skills/competitive-intelligence/SKILL.md +32 -74
- package/template/.agents/skills/file-export-download/SKILL.md +4 -73
- package/template/.agents/skills/file-export-download/references/binary-contract-example.md +26 -0
- package/template/.agents/skills/file-export-download/references/download-call-example.md +45 -0
- package/template/.agents/skills/formily-foundation/SKILL.md +6 -105
- package/template/.agents/skills/formily-foundation/references/async-save-example.md +57 -0
- package/template/.agents/skills/formily-foundation/references/query-layout.md +50 -0
- package/template/.agents/skills/formily-linkage-effects/SKILL.md +3 -116
- package/template/.agents/skills/formily-linkage-effects/references/linkage-example.md +116 -0
- package/template/.agents/skills/formily-mode-slot-detail/SKILL.md +3 -81
- package/template/.agents/skills/formily-mode-slot-detail/references/mode-slot-example.md +81 -0
- package/template/.agents/skills/formily-step-flow/SKILL.md +3 -143
- package/template/.agents/skills/formily-step-flow/references/step-flow-example.md +143 -0
- package/template/.agents/skills/handoff/SKILL.md +3 -1
- package/template/.agents/skills/i-have-adhd/SKILL.md +2 -2
- package/template/.agents/skills/i-have-adhd/references/yss-adaptation.md +2 -2
- package/template/.agents/skills/i-have-adhd/tests/verify-integration.mjs +7 -2
- package/template/.agents/skills/implement/SKILL.md +2 -2
- package/template/.agents/skills/llm-wiki/references/transactions.md +2 -2
- package/template/.agents/skills/llm-wiki/scripts/core.mjs +40 -2
- package/template/.agents/skills/llm-wiki/scripts/transaction.mjs +30 -27
- package/template/.agents/skills/llm-wiki/scripts/v2.test.mjs +38 -2
- package/template/.agents/skills/lombok/SKILL.md +2 -0
- package/template/.agents/skills/mapstruct/SKILL.md +2 -0
- package/template/.agents/skills/tdd/SKILL.md +2 -2
- package/template/.agents/skills/theme-token-usage/SKILL.md +6 -5
- package/template/.agents/skills/wayfinder/references/chart-map.md +2 -2
- package/template/.agents/skills/wayfinder/references/ticket-types.md +1 -1
- package/template/.agents/skills/yss-api-integration/SKILL.md +13 -50
- package/template/.agents/skills/yss-api-integration/references/orval-list-example.md +38 -0
- package/template/.agents/skills/yss-application/SKILL.md +11 -5
- package/template/.agents/skills/yss-audit-log/SKILL.md +8 -6
- package/template/.agents/skills/yss-audit-log/references/README.md +5 -5
- package/template/.agents/skills/yss-cache/SKILL.md +4 -4
- package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +7 -8
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +13 -6
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/command-examples.md +2 -0
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +28 -1
- package/template/.agents/skills/yss-design-system/SKILL.md +2 -2
- package/template/.agents/skills/yss-distributed-id/SKILL.md +4 -4
- package/template/.agents/skills/yss-dto/SKILL.md +9 -9
- package/template/.agents/skills/yss-dto/references/README.md +4 -4
- package/template/.agents/skills/yss-dto/references/wire-validation-checklist.md +4 -4
- package/template/.agents/skills/yss-excel-mvc/SKILL.md +4 -4
- package/template/.agents/skills/yss-exception/SKILL.md +42 -48
- package/template/.agents/skills/yss-formily-schema-generator/SKILL.md +26 -170
- package/template/.agents/skills/yss-formily-schema-generator/references/workflow.md +49 -193
- package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +14 -10
- package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +2 -6
- package/template/.agents/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +15 -1
- package/template/.agents/skills/yss-layered-mvc-scaffold-generator/SKILL.md +1 -1
- package/template/.agents/skills/yss-mybatis/SKILL.md +4 -4
- package/template/.agents/skills/yss-openapi-draft-review/SKILL.md +6 -4
- package/template/.agents/skills/yss-openapi-draft-review/references/review-output.md +2 -0
- package/template/.agents/skills/yss-openapi-draft-review/references/semantic-review.md +3 -3
- package/template/.agents/skills/yss-openapi-governance/SKILL.md +5 -7
- package/template/.agents/skills/yss-openapi-governance/references/governance-output.md +2 -0
- package/template/.agents/skills/yss-openapi-governance/references/governance-workflow.md +3 -3
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +23 -21
- package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
- package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +25 -5
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +100 -4
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +35 -12
- package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +3 -1
- package/template/.agents/skills/yss-product-lifecycle/references/user-decisions.md +3 -3
- package/template/.agents/skills/yss-prototype-stage/SKILL.md +1 -5
- package/template/.agents/skills/yss-repository/SKILL.md +2 -2
- package/template/.agents/skills/yss-research/SKILL.md +39 -48
- package/template/.agents/skills/yss-research/assets/competitive-evidence-template.yaml +146 -0
- package/template/.agents/skills/yss-research/references/competitive-analysis.md +76 -0
- package/template/.agents/skills/yss-research/references/competitive-analysis.schema.json +324 -0
- package/template/.agents/skills/yss-research/references/evidence-contract.md +8 -0
- package/template/.agents/skills/yss-research/scripts/lib/competitive-analysis.mjs +185 -0
- package/template/.agents/skills/yss-research/scripts/render-competitive-outputs.mjs +16 -0
- package/template/.agents/skills/yss-research/scripts/validate-research-package.mjs +6 -2
- package/template/.agents/skills/yss-research/tests/competitive-scenarios.test.mjs +270 -0
- package/template/.agents/skills/yss-resilience4j/SKILL.md +25 -31
- package/template/.agents/skills/yss-security-algorithm/SKILL.md +37 -43
- package/template/.agents/skills/yss-skill-source-index-refresh/SKILL.md +29 -36
- package/template/.agents/skills/yss-skill-source-index-refresh/references/backend-component-platform-compatibility.md +1 -1
- package/template/.agents/skills/yss-stage-decision/SKILL.md +2 -5
- package/template/.agents/skills/yss-tactical-design/SKILL.md +1 -1
- package/template/.agents/skills/yss-tactical-design/references/output-template.md +3 -3
- package/template/.agents/skills/yss-tactical-design/references/tactical-design-contract.md +1 -1
- package/template/.agents/skills/yss-technical-design/SKILL.md +6 -5
- package/template/.agents/skills/yss-ui/SKILL.md +7 -1
- package/template/.agents/skills/yss-ui/assets/docs/guide/gitlab-ci-integration.md +2 -2
- package/template/.agents/skills/yss-ui/references/checklist.md +38 -96
- package/template/.agents/skills/yss-ui/references/component-routing.md +3 -1
- package/template/.agents/skills/yss-ui/references/quick-recipes.md +17 -272
- package/template/.agents/skills/yss-ui/references/specialized-components.md +3 -3
- package/template/.agents/skills/yss-ui-business-page-generation/SKILL.md +1 -1
- package/template/.agents/skills/yss-up-springboot3/SKILL.md +19 -21
- package/template/.agents/skills/yss-userinfo/SKILL.md +27 -33
- package/template/.agents/skills/yss-validation/SKILL.md +26 -32
- package/template/.agents/skills/yss-web-controller/SKILL.md +11 -44
- package/template/.agents/skills/yss-web-controller/references/crud-generation.md +38 -0
- package/template/.agents/skills/ytable-usage/SKILL.md +2 -2
- package/template/.agents/skills/ytree-usage/SKILL.md +2 -80
- package/template/.agents/skills/ytree-usage/references/tree-and-confirmation-example.md +81 -0
- package/template/.codex/skills/alibaba-java-code-style/SKILL.md +30 -36
- package/template/.codex/skills/archify/SKILL.md +2 -2
- package/template/.codex/skills/archify/scripts/yss-safe-deliver.mjs +10 -6
- package/template/.codex/skills/archify/test/yss-safe-deliver.test.mjs +9 -2
- package/template/.codex/skills/code-review/SKILL.md +19 -11
- package/template/.codex/skills/code-review/references/candidate-capture.md +1 -1
- package/template/.codex/skills/code-review/references/legacy-convergence.md +3 -1
- package/template/.codex/skills/code-review/references/review-axis-checklists.md +2 -0
- package/template/.codex/skills/code-review/references/yss-review-standards.md +4 -2
- package/template/.codex/skills/competitive-intelligence/SKILL.md +32 -74
- package/template/.codex/skills/file-export-download/SKILL.md +4 -73
- package/template/.codex/skills/file-export-download/references/binary-contract-example.md +26 -0
- package/template/.codex/skills/file-export-download/references/download-call-example.md +45 -0
- package/template/.codex/skills/formily-foundation/SKILL.md +6 -105
- package/template/.codex/skills/formily-foundation/references/async-save-example.md +57 -0
- package/template/.codex/skills/formily-foundation/references/query-layout.md +50 -0
- package/template/.codex/skills/formily-linkage-effects/SKILL.md +3 -116
- package/template/.codex/skills/formily-linkage-effects/references/linkage-example.md +116 -0
- package/template/.codex/skills/formily-mode-slot-detail/SKILL.md +3 -81
- package/template/.codex/skills/formily-mode-slot-detail/references/mode-slot-example.md +81 -0
- package/template/.codex/skills/formily-step-flow/SKILL.md +3 -143
- package/template/.codex/skills/formily-step-flow/references/step-flow-example.md +143 -0
- package/template/.codex/skills/handoff/SKILL.md +3 -1
- package/template/.codex/skills/i-have-adhd/SKILL.md +2 -2
- package/template/.codex/skills/i-have-adhd/references/yss-adaptation.md +2 -2
- package/template/.codex/skills/i-have-adhd/tests/verify-integration.mjs +7 -2
- package/template/.codex/skills/implement/SKILL.md +2 -2
- package/template/.codex/skills/llm-wiki/references/transactions.md +2 -2
- package/template/.codex/skills/llm-wiki/scripts/core.mjs +40 -2
- package/template/.codex/skills/llm-wiki/scripts/transaction.mjs +30 -27
- package/template/.codex/skills/llm-wiki/scripts/v2.test.mjs +38 -2
- package/template/.codex/skills/lombok/SKILL.md +2 -0
- package/template/.codex/skills/mapstruct/SKILL.md +2 -0
- package/template/.codex/skills/product-design/references/communication-protocol.md +3 -3
- package/template/.codex/skills/product-design/references/critical-overrides.md +4 -5
- package/template/.codex/skills/product-design/skills/audit/SKILL.md +2 -4
- package/template/.codex/skills/product-design/skills/get-context/SKILL.md +6 -8
- package/template/.codex/skills/product-design/skills/ideate/SKILL.md +3 -3
- package/template/.codex/skills/product-design/skills/image-to-code/SKILL.md +3 -5
- package/template/.codex/skills/product-design/skills/index/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/prototype/SKILL.md +2 -4
- package/template/.codex/skills/product-design/skills/research/SKILL.md +4 -6
- package/template/.codex/skills/product-design/skills/research/assets/research-brief-template.md +3 -3
- package/template/.codex/skills/product-design/skills/share/SKILL.md +2 -4
- package/template/.codex/skills/product-design/skills/url-to-code/SKILL.md +2 -4
- package/template/.codex/skills/product-design/skills/user-context/SKILL.md +1 -1
- package/template/.codex/skills/tdd/SKILL.md +2 -2
- package/template/.codex/skills/theme-token-usage/SKILL.md +6 -5
- package/template/.codex/skills/wayfinder/references/chart-map.md +2 -2
- package/template/.codex/skills/wayfinder/references/ticket-types.md +1 -1
- package/template/.codex/skills/yss-api-integration/SKILL.md +13 -50
- package/template/.codex/skills/yss-api-integration/references/orval-list-example.md +38 -0
- package/template/.codex/skills/yss-application/SKILL.md +11 -5
- package/template/.codex/skills/yss-audit-log/SKILL.md +8 -6
- package/template/.codex/skills/yss-audit-log/references/README.md +5 -5
- package/template/.codex/skills/yss-cache/SKILL.md +4 -4
- package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +7 -8
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +13 -6
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/command-examples.md +2 -0
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +28 -1
- package/template/.codex/skills/yss-design-system/SKILL.md +2 -2
- package/template/.codex/skills/yss-distributed-id/SKILL.md +4 -4
- package/template/.codex/skills/yss-dto/SKILL.md +9 -9
- package/template/.codex/skills/yss-dto/references/README.md +4 -4
- package/template/.codex/skills/yss-dto/references/wire-validation-checklist.md +4 -4
- package/template/.codex/skills/yss-excel-mvc/SKILL.md +4 -4
- package/template/.codex/skills/yss-exception/SKILL.md +42 -48
- package/template/.codex/skills/yss-formily-schema-generator/SKILL.md +26 -170
- package/template/.codex/skills/yss-formily-schema-generator/references/workflow.md +49 -193
- package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +14 -10
- package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +2 -6
- package/template/.codex/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +15 -1
- package/template/.codex/skills/yss-layered-mvc-scaffold-generator/SKILL.md +1 -1
- package/template/.codex/skills/yss-mybatis/SKILL.md +4 -4
- package/template/.codex/skills/yss-openapi-draft-review/SKILL.md +6 -4
- package/template/.codex/skills/yss-openapi-draft-review/references/review-output.md +2 -0
- package/template/.codex/skills/yss-openapi-draft-review/references/semantic-review.md +3 -3
- package/template/.codex/skills/yss-openapi-governance/SKILL.md +5 -7
- package/template/.codex/skills/yss-openapi-governance/references/governance-output.md +2 -0
- package/template/.codex/skills/yss-openapi-governance/references/governance-workflow.md +3 -3
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +23 -21
- package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
- package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +25 -5
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +100 -4
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +35 -12
- package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +3 -1
- package/template/.codex/skills/yss-product-lifecycle/references/user-decisions.md +3 -3
- package/template/.codex/skills/yss-prototype-stage/SKILL.md +1 -5
- package/template/.codex/skills/yss-repository/SKILL.md +2 -2
- package/template/.codex/skills/yss-research/SKILL.md +39 -48
- package/template/.codex/skills/yss-research/assets/competitive-evidence-template.yaml +146 -0
- package/template/.codex/skills/yss-research/references/competitive-analysis.md +76 -0
- package/template/.codex/skills/yss-research/references/competitive-analysis.schema.json +324 -0
- package/template/.codex/skills/yss-research/references/evidence-contract.md +8 -0
- package/template/.codex/skills/yss-research/scripts/lib/competitive-analysis.mjs +185 -0
- package/template/.codex/skills/yss-research/scripts/render-competitive-outputs.mjs +16 -0
- package/template/.codex/skills/yss-research/scripts/validate-research-package.mjs +6 -2
- package/template/.codex/skills/yss-research/tests/competitive-scenarios.test.mjs +270 -0
- package/template/.codex/skills/yss-resilience4j/SKILL.md +25 -31
- package/template/.codex/skills/yss-security-algorithm/SKILL.md +37 -43
- package/template/.codex/skills/yss-skill-source-index-refresh/SKILL.md +29 -36
- package/template/.codex/skills/yss-skill-source-index-refresh/references/backend-component-platform-compatibility.md +1 -1
- package/template/.codex/skills/yss-stage-decision/SKILL.md +2 -5
- package/template/.codex/skills/yss-tactical-design/SKILL.md +1 -1
- package/template/.codex/skills/yss-tactical-design/references/output-template.md +3 -3
- package/template/.codex/skills/yss-tactical-design/references/tactical-design-contract.md +1 -1
- package/template/.codex/skills/yss-technical-design/SKILL.md +6 -5
- package/template/.codex/skills/yss-ui/SKILL.md +7 -1
- package/template/.codex/skills/yss-ui/assets/docs/guide/gitlab-ci-integration.md +2 -2
- package/template/.codex/skills/yss-ui/references/checklist.md +38 -96
- package/template/.codex/skills/yss-ui/references/component-routing.md +3 -1
- package/template/.codex/skills/yss-ui/references/quick-recipes.md +17 -272
- package/template/.codex/skills/yss-ui/references/specialized-components.md +3 -3
- package/template/.codex/skills/yss-ui-business-page-generation/SKILL.md +1 -1
- package/template/.codex/skills/yss-up-springboot3/SKILL.md +19 -21
- package/template/.codex/skills/yss-userinfo/SKILL.md +27 -33
- package/template/.codex/skills/yss-validation/SKILL.md +26 -32
- package/template/.codex/skills/yss-web-controller/SKILL.md +11 -44
- package/template/.codex/skills/yss-web-controller/references/crud-generation.md +38 -0
- package/template/.codex/skills/ytable-usage/SKILL.md +2 -2
- package/template/.codex/skills/ytree-usage/SKILL.md +2 -80
- package/template/.codex/skills/ytree-usage/references/tree-and-confirmation-example.md +81 -0
- package/template/.cursor/skills/alibaba-java-code-style/SKILL.md +30 -36
- package/template/.cursor/skills/archify/SKILL.md +2 -2
- package/template/.cursor/skills/archify/scripts/yss-safe-deliver.mjs +10 -6
- package/template/.cursor/skills/archify/test/yss-safe-deliver.test.mjs +9 -2
- package/template/.cursor/skills/code-review/SKILL.md +19 -11
- package/template/.cursor/skills/code-review/references/candidate-capture.md +1 -1
- package/template/.cursor/skills/code-review/references/legacy-convergence.md +3 -1
- package/template/.cursor/skills/code-review/references/review-axis-checklists.md +2 -0
- package/template/.cursor/skills/code-review/references/yss-review-standards.md +4 -2
- package/template/.cursor/skills/competitive-intelligence/SKILL.md +32 -74
- package/template/.cursor/skills/file-export-download/SKILL.md +4 -73
- package/template/.cursor/skills/file-export-download/references/binary-contract-example.md +26 -0
- package/template/.cursor/skills/file-export-download/references/download-call-example.md +45 -0
- package/template/.cursor/skills/formily-foundation/SKILL.md +6 -105
- package/template/.cursor/skills/formily-foundation/references/async-save-example.md +57 -0
- package/template/.cursor/skills/formily-foundation/references/query-layout.md +50 -0
- package/template/.cursor/skills/formily-linkage-effects/SKILL.md +3 -116
- package/template/.cursor/skills/formily-linkage-effects/references/linkage-example.md +116 -0
- package/template/.cursor/skills/formily-mode-slot-detail/SKILL.md +3 -81
- package/template/.cursor/skills/formily-mode-slot-detail/references/mode-slot-example.md +81 -0
- package/template/.cursor/skills/formily-step-flow/SKILL.md +3 -143
- package/template/.cursor/skills/formily-step-flow/references/step-flow-example.md +143 -0
- package/template/.cursor/skills/handoff/SKILL.md +3 -1
- package/template/.cursor/skills/i-have-adhd/SKILL.md +2 -2
- package/template/.cursor/skills/i-have-adhd/references/yss-adaptation.md +2 -2
- package/template/.cursor/skills/i-have-adhd/tests/verify-integration.mjs +7 -2
- package/template/.cursor/skills/implement/SKILL.md +2 -2
- package/template/.cursor/skills/llm-wiki/references/transactions.md +2 -2
- package/template/.cursor/skills/llm-wiki/scripts/core.mjs +40 -2
- package/template/.cursor/skills/llm-wiki/scripts/transaction.mjs +30 -27
- package/template/.cursor/skills/llm-wiki/scripts/v2.test.mjs +38 -2
- package/template/.cursor/skills/lombok/SKILL.md +2 -0
- package/template/.cursor/skills/mapstruct/SKILL.md +2 -0
- package/template/.cursor/skills/tdd/SKILL.md +2 -2
- package/template/.cursor/skills/theme-token-usage/SKILL.md +6 -5
- package/template/.cursor/skills/wayfinder/references/chart-map.md +2 -2
- package/template/.cursor/skills/wayfinder/references/ticket-types.md +1 -1
- package/template/.cursor/skills/yss-api-integration/SKILL.md +13 -50
- package/template/.cursor/skills/yss-api-integration/references/orval-list-example.md +38 -0
- package/template/.cursor/skills/yss-application/SKILL.md +11 -5
- package/template/.cursor/skills/yss-audit-log/SKILL.md +8 -6
- package/template/.cursor/skills/yss-audit-log/references/README.md +5 -5
- package/template/.cursor/skills/yss-cache/SKILL.md +4 -4
- package/template/.cursor/skills/yss-ddd-scaffold-generator/SKILL.md +7 -8
- package/template/.cursor/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +13 -6
- package/template/.cursor/skills/yss-ddd-scaffold-generator/references/command-examples.md +2 -0
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +28 -1
- package/template/.cursor/skills/yss-design-system/SKILL.md +2 -2
- package/template/.cursor/skills/yss-distributed-id/SKILL.md +4 -4
- package/template/.cursor/skills/yss-dto/SKILL.md +9 -9
- package/template/.cursor/skills/yss-dto/references/README.md +4 -4
- package/template/.cursor/skills/yss-dto/references/wire-validation-checklist.md +4 -4
- package/template/.cursor/skills/yss-excel-mvc/SKILL.md +4 -4
- package/template/.cursor/skills/yss-exception/SKILL.md +42 -48
- package/template/.cursor/skills/yss-formily-schema-generator/SKILL.md +26 -170
- package/template/.cursor/skills/yss-formily-schema-generator/references/workflow.md +49 -193
- package/template/.cursor/skills/yss-frontend-scaffold-generator/SKILL.md +14 -10
- package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +2 -6
- package/template/.cursor/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +15 -1
- package/template/.cursor/skills/yss-layered-mvc-scaffold-generator/SKILL.md +1 -1
- package/template/.cursor/skills/yss-mybatis/SKILL.md +4 -4
- package/template/.cursor/skills/yss-openapi-draft-review/SKILL.md +6 -4
- package/template/.cursor/skills/yss-openapi-draft-review/references/review-output.md +2 -0
- package/template/.cursor/skills/yss-openapi-draft-review/references/semantic-review.md +3 -3
- package/template/.cursor/skills/yss-openapi-governance/SKILL.md +5 -7
- package/template/.cursor/skills/yss-openapi-governance/references/governance-output.md +2 -0
- package/template/.cursor/skills/yss-openapi-governance/references/governance-workflow.md +3 -3
- package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +23 -21
- package/template/.cursor/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +25 -5
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +100 -4
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +35 -12
- package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +3 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/user-decisions.md +3 -3
- package/template/.cursor/skills/yss-prototype-stage/SKILL.md +1 -5
- package/template/.cursor/skills/yss-repository/SKILL.md +2 -2
- package/template/.cursor/skills/yss-research/SKILL.md +39 -48
- package/template/.cursor/skills/yss-research/assets/competitive-evidence-template.yaml +146 -0
- package/template/.cursor/skills/yss-research/references/competitive-analysis.md +76 -0
- package/template/.cursor/skills/yss-research/references/competitive-analysis.schema.json +324 -0
- package/template/.cursor/skills/yss-research/references/evidence-contract.md +8 -0
- package/template/.cursor/skills/yss-research/scripts/lib/competitive-analysis.mjs +185 -0
- package/template/.cursor/skills/yss-research/scripts/render-competitive-outputs.mjs +16 -0
- package/template/.cursor/skills/yss-research/scripts/validate-research-package.mjs +6 -2
- package/template/.cursor/skills/yss-research/tests/competitive-scenarios.test.mjs +270 -0
- package/template/.cursor/skills/yss-resilience4j/SKILL.md +25 -31
- package/template/.cursor/skills/yss-security-algorithm/SKILL.md +37 -43
- package/template/.cursor/skills/yss-skill-source-index-refresh/SKILL.md +29 -36
- package/template/.cursor/skills/yss-skill-source-index-refresh/references/backend-component-platform-compatibility.md +1 -1
- package/template/.cursor/skills/yss-stage-decision/SKILL.md +2 -5
- package/template/.cursor/skills/yss-tactical-design/SKILL.md +1 -1
- package/template/.cursor/skills/yss-tactical-design/references/output-template.md +3 -3
- package/template/.cursor/skills/yss-tactical-design/references/tactical-design-contract.md +1 -1
- package/template/.cursor/skills/yss-technical-design/SKILL.md +6 -5
- package/template/.cursor/skills/yss-ui/SKILL.md +7 -1
- package/template/.cursor/skills/yss-ui/assets/docs/guide/gitlab-ci-integration.md +2 -2
- package/template/.cursor/skills/yss-ui/references/checklist.md +38 -96
- package/template/.cursor/skills/yss-ui/references/component-routing.md +3 -1
- package/template/.cursor/skills/yss-ui/references/quick-recipes.md +17 -272
- package/template/.cursor/skills/yss-ui/references/specialized-components.md +3 -3
- package/template/.cursor/skills/yss-ui-business-page-generation/SKILL.md +1 -1
- package/template/.cursor/skills/yss-up-springboot3/SKILL.md +19 -21
- package/template/.cursor/skills/yss-userinfo/SKILL.md +27 -33
- package/template/.cursor/skills/yss-validation/SKILL.md +26 -32
- package/template/.cursor/skills/yss-web-controller/SKILL.md +11 -44
- package/template/.cursor/skills/yss-web-controller/references/crud-generation.md +38 -0
- package/template/.cursor/skills/ytable-usage/SKILL.md +2 -2
- package/template/.cursor/skills/ytree-usage/SKILL.md +2 -80
- package/template/.cursor/skills/ytree-usage/references/tree-and-confirmation-example.md +81 -0
- package/template/.pi/skills/alibaba-java-code-style/SKILL.md +30 -36
- package/template/.pi/skills/archify/SKILL.md +2 -2
- package/template/.pi/skills/archify/scripts/yss-safe-deliver.mjs +10 -6
- package/template/.pi/skills/archify/test/yss-safe-deliver.test.mjs +9 -2
- package/template/.pi/skills/code-review/SKILL.md +19 -11
- package/template/.pi/skills/code-review/references/candidate-capture.md +1 -1
- package/template/.pi/skills/code-review/references/legacy-convergence.md +3 -1
- package/template/.pi/skills/code-review/references/review-axis-checklists.md +2 -0
- package/template/.pi/skills/code-review/references/yss-review-standards.md +4 -2
- package/template/.pi/skills/competitive-intelligence/SKILL.md +32 -74
- package/template/.pi/skills/file-export-download/SKILL.md +4 -73
- package/template/.pi/skills/file-export-download/references/binary-contract-example.md +26 -0
- package/template/.pi/skills/file-export-download/references/download-call-example.md +45 -0
- package/template/.pi/skills/formily-foundation/SKILL.md +6 -105
- package/template/.pi/skills/formily-foundation/references/async-save-example.md +57 -0
- package/template/.pi/skills/formily-foundation/references/query-layout.md +50 -0
- package/template/.pi/skills/formily-linkage-effects/SKILL.md +3 -116
- package/template/.pi/skills/formily-linkage-effects/references/linkage-example.md +116 -0
- package/template/.pi/skills/formily-mode-slot-detail/SKILL.md +3 -81
- package/template/.pi/skills/formily-mode-slot-detail/references/mode-slot-example.md +81 -0
- package/template/.pi/skills/formily-step-flow/SKILL.md +3 -143
- package/template/.pi/skills/formily-step-flow/references/step-flow-example.md +143 -0
- package/template/.pi/skills/handoff/SKILL.md +3 -1
- package/template/.pi/skills/i-have-adhd/SKILL.md +2 -2
- package/template/.pi/skills/i-have-adhd/references/yss-adaptation.md +2 -2
- package/template/.pi/skills/i-have-adhd/tests/verify-integration.mjs +7 -2
- package/template/.pi/skills/implement/SKILL.md +2 -2
- package/template/.pi/skills/llm-wiki/references/transactions.md +2 -2
- package/template/.pi/skills/llm-wiki/scripts/core.mjs +40 -2
- package/template/.pi/skills/llm-wiki/scripts/transaction.mjs +30 -27
- package/template/.pi/skills/llm-wiki/scripts/v2.test.mjs +38 -2
- package/template/.pi/skills/lombok/SKILL.md +2 -0
- package/template/.pi/skills/mapstruct/SKILL.md +2 -0
- package/template/.pi/skills/tdd/SKILL.md +2 -2
- package/template/.pi/skills/theme-token-usage/SKILL.md +6 -5
- package/template/.pi/skills/wayfinder/references/chart-map.md +2 -2
- package/template/.pi/skills/wayfinder/references/ticket-types.md +1 -1
- package/template/.pi/skills/yss-api-integration/SKILL.md +13 -50
- package/template/.pi/skills/yss-api-integration/references/orval-list-example.md +38 -0
- package/template/.pi/skills/yss-application/SKILL.md +11 -5
- package/template/.pi/skills/yss-audit-log/SKILL.md +8 -6
- package/template/.pi/skills/yss-audit-log/references/README.md +5 -5
- package/template/.pi/skills/yss-cache/SKILL.md +4 -4
- package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +7 -8
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/USAGE_EXAMPLES.md +13 -6
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/command-examples.md +2 -0
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +28 -1
- package/template/.pi/skills/yss-design-system/SKILL.md +2 -2
- package/template/.pi/skills/yss-distributed-id/SKILL.md +4 -4
- package/template/.pi/skills/yss-dto/SKILL.md +9 -9
- package/template/.pi/skills/yss-dto/references/README.md +4 -4
- package/template/.pi/skills/yss-dto/references/wire-validation-checklist.md +4 -4
- package/template/.pi/skills/yss-excel-mvc/SKILL.md +4 -4
- package/template/.pi/skills/yss-exception/SKILL.md +42 -48
- package/template/.pi/skills/yss-formily-schema-generator/SKILL.md +26 -170
- package/template/.pi/skills/yss-formily-schema-generator/references/workflow.md +49 -193
- package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +14 -10
- package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +2 -6
- package/template/.pi/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +15 -1
- package/template/.pi/skills/yss-layered-mvc-scaffold-generator/SKILL.md +1 -1
- package/template/.pi/skills/yss-mybatis/SKILL.md +4 -4
- package/template/.pi/skills/yss-openapi-draft-review/SKILL.md +6 -4
- package/template/.pi/skills/yss-openapi-draft-review/references/review-output.md +2 -0
- package/template/.pi/skills/yss-openapi-draft-review/references/semantic-review.md +3 -3
- package/template/.pi/skills/yss-openapi-governance/SKILL.md +5 -7
- package/template/.pi/skills/yss-openapi-governance/references/governance-output.md +2 -0
- package/template/.pi/skills/yss-openapi-governance/references/governance-workflow.md +3 -3
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +23 -21
- package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
- package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +25 -5
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +100 -4
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +35 -12
- package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +3 -1
- package/template/.pi/skills/yss-product-lifecycle/references/user-decisions.md +3 -3
- package/template/.pi/skills/yss-prototype-stage/SKILL.md +1 -5
- package/template/.pi/skills/yss-repository/SKILL.md +2 -2
- package/template/.pi/skills/yss-research/SKILL.md +39 -48
- package/template/.pi/skills/yss-research/assets/competitive-evidence-template.yaml +146 -0
- package/template/.pi/skills/yss-research/references/competitive-analysis.md +76 -0
- package/template/.pi/skills/yss-research/references/competitive-analysis.schema.json +324 -0
- package/template/.pi/skills/yss-research/references/evidence-contract.md +8 -0
- package/template/.pi/skills/yss-research/scripts/lib/competitive-analysis.mjs +185 -0
- package/template/.pi/skills/yss-research/scripts/render-competitive-outputs.mjs +16 -0
- package/template/.pi/skills/yss-research/scripts/validate-research-package.mjs +6 -2
- package/template/.pi/skills/yss-research/tests/competitive-scenarios.test.mjs +270 -0
- package/template/.pi/skills/yss-resilience4j/SKILL.md +25 -31
- package/template/.pi/skills/yss-security-algorithm/SKILL.md +37 -43
- package/template/.pi/skills/yss-skill-source-index-refresh/SKILL.md +29 -36
- package/template/.pi/skills/yss-skill-source-index-refresh/references/backend-component-platform-compatibility.md +1 -1
- package/template/.pi/skills/yss-stage-decision/SKILL.md +2 -5
- package/template/.pi/skills/yss-tactical-design/SKILL.md +1 -1
- package/template/.pi/skills/yss-tactical-design/references/output-template.md +3 -3
- package/template/.pi/skills/yss-tactical-design/references/tactical-design-contract.md +1 -1
- package/template/.pi/skills/yss-technical-design/SKILL.md +6 -5
- package/template/.pi/skills/yss-ui/SKILL.md +7 -1
- package/template/.pi/skills/yss-ui/assets/docs/guide/gitlab-ci-integration.md +2 -2
- package/template/.pi/skills/yss-ui/references/checklist.md +38 -96
- package/template/.pi/skills/yss-ui/references/component-routing.md +3 -1
- package/template/.pi/skills/yss-ui/references/quick-recipes.md +17 -272
- package/template/.pi/skills/yss-ui/references/specialized-components.md +3 -3
- package/template/.pi/skills/yss-ui-business-page-generation/SKILL.md +1 -1
- package/template/.pi/skills/yss-up-springboot3/SKILL.md +19 -21
- package/template/.pi/skills/yss-userinfo/SKILL.md +27 -33
- package/template/.pi/skills/yss-validation/SKILL.md +26 -32
- package/template/.pi/skills/yss-web-controller/SKILL.md +11 -44
- package/template/.pi/skills/yss-web-controller/references/crud-generation.md +38 -0
- package/template/.pi/skills/ytable-usage/SKILL.md +2 -2
- package/template/.pi/skills/ytree-usage/SKILL.md +2 -80
- package/template/.pi/skills/ytree-usage/references/tree-and-confirmation-example.md +81 -0
- package/template/.template-spec/agents/backend-architecture-profiles.md +1 -1
- package/template/.template-spec/agents/digital-human-roles.md +5 -1
- package/template/.template-spec/agents/digital-human-roles.yaml +49 -1
- package/template/.template-spec/engineering/backend-platforms.json +1 -1
- package/template/.template-spec/plan/templates/competitive-analysis-template.md +38 -36
- package/template/.template-spec/plan/templates/competitive-matrix-template.md +37 -17
- package/template/.template-spec/process/document-writing.md +22 -3
- package/template/.template-spec/process/harness-process-tailoring.md +5 -1
- package/template/.template-spec/process/implementation-repo-integration.md +26 -8
- package/template/.template-spec/process/research-completion.md +2 -0
- package/template/.template-spec/process/runtime-storage.md +78 -0
- package/template/.template-spec/process/schemas/approval-context.schema.json +67 -0
- package/template/.template-spec/process/schemas/approval-record.schema.json +179 -16
- package/template/.template-spec/process/schemas/backend-delivery.schema.json +16 -0
- package/template/.template-spec/process/schemas/delivery-preflight-input.schema.json +4 -0
- package/template/.template-spec/process/schemas/digital-human-task-package.schema.json +236 -1
- package/template/.template-spec/process/schemas/implementation-repository-preparation-result.schema.json +335 -52
- package/template/.template-spec/process/schemas/lifecycle-checkpoint.schema.json +11 -0
- package/template/.template-spec/process/schemas/project-scaffold-contract.schema.json +3 -0
- package/template/.template-spec/process/schemas/review-bundle.schema.json +347 -35
- package/template/.template-spec/process/schemas/strategic-design-handoff-v3.schema.json +504 -0
- package/template/.template-spec/process/schemas/strategic-design-handoff-v4.schema.json +544 -8
- package/template/.template-spec/process/schemas/strategic-design-handoff-v5.schema.json +616 -0
- package/template/.template-spec/process/schemas/strategic-design-handoff.schema.json +616 -0
- package/template/.template-spec/process/schemas/strategic-handoff-domain-strategy-v3.schema.json +712 -109
- package/template/.template-spec/process/schemas/strategic-handoff-domain-strategy.schema.json +595 -90
- package/template/.template-spec/process/schemas/strategic-handoff-export-v2.schema.json +448 -0
- package/template/.template-spec/process/schemas/strategic-handoff-export.schema.json +392 -0
- package/template/.template-spec/process/schemas/strategic-handoff-stage-decision-package-v3.schema.json +556 -83
- package/template/.template-spec/process/schemas/strategic-handoff-stage-decision-package.schema.json +418 -57
- package/template/.template-spec/process/subagent-collaboration.md +7 -1
- package/template/.template-spec/templates/approval-record-template.json +7 -3
- package/template/.template-spec/templates/approval-record-template.yaml +8 -2
- package/template/.template-spec/templates/examples/lifecycle-writing-examples.md +92 -2
- package/template/.template-spec/templates/retro-report-template.md +10 -3
- package/template/.template-spec/templates/review-bundle-template.yaml +19 -10
- package/template/AGENTS.md +4 -3
- package/template/CONTEXT.md +2 -2
- package/template/README.md +2 -2
- package/template/scripts/advance-maintenance-iteration +51 -0
- package/template/scripts/lib/approval-checkpoint-discovery.mjs +26 -0
- package/template/scripts/lib/approval-consumption.mjs +35 -0
- package/template/scripts/lib/approval-current.mjs +111 -0
- package/template/scripts/lib/approval-record-io.mjs +56 -0
- package/template/scripts/lib/approval-record.mjs +79 -184
- package/template/scripts/lib/approved-execution-context.mjs +8 -6
- package/template/scripts/lib/asset-transactions.mjs +5 -1
- package/template/scripts/lib/backend-delivery.mjs +1 -1
- package/template/scripts/lib/backend-review.mjs +2 -1
- package/template/scripts/lib/backend-scaffold-prerequisites.mjs +3 -2
- package/template/scripts/lib/business-ticket-lifecycle.mjs +2 -1
- package/template/scripts/lib/checkpoint-commit.mjs +50 -0
- package/template/scripts/lib/command-runner.mjs +44 -9
- package/template/scripts/lib/content-identity.mjs +273 -0
- package/template/scripts/lib/delivery-preflight.mjs +2 -1
- package/template/scripts/lib/digital-human-roles.mjs +12 -5
- package/template/scripts/lib/drift-report.mjs +110 -0
- package/template/scripts/lib/existing-backend-architecture.mjs +4 -1
- package/template/scripts/lib/lifecycle-context-query.mjs +172 -11
- package/template/scripts/lib/lifecycle-controls.mjs +9 -19
- package/template/scripts/lib/lifecycle-presentation.mjs +5 -0
- package/template/scripts/lib/lifecycle-status.mjs +63 -12
- package/template/scripts/lib/lifecycle-transition.mjs +2 -1
- package/template/scripts/lib/maintenance-candidate.mjs +24 -30
- package/template/scripts/lib/maintenance-research.mjs +52 -8
- package/template/scripts/lib/maintenance-storage.mjs +81 -0
- package/template/scripts/lib/plan-spec-entry.mjs +2 -1
- package/template/scripts/lib/project-governance.mjs +2 -1
- package/template/scripts/lib/read-only-intake.mjs +44 -9
- package/template/scripts/lib/review-capabilities.mjs +234 -0
- package/template/scripts/lib/review-package.mjs +100 -0
- package/template/scripts/lib/runtime-store.mjs +650 -0
- package/template/scripts/lib/skill-registry.mjs +4 -4
- package/template/scripts/lib/strategic-handoff.mjs +22 -9
- package/template/scripts/lib/task-package.mjs +47 -16
- package/template/scripts/lifecycle-status +26 -1
- package/template/scripts/maintenance-path +11 -0
- package/template/scripts/prepare-review-package +8 -0
- package/template/scripts/project-ci +13 -3
- package/template/scripts/query-lifecycle-context +8 -1
- package/template/scripts/run-read-only-intake +2 -2
- package/template/scripts/runtime-store +40 -0
- package/template/scripts/verify-approval-record +21 -13
- package/template/scripts/verify-lifecycle-checkpoint +7 -3
- package/template/scripts/verify-project-instance +21 -1
- package/template/skills-lock.json +62 -61
- package/template.snapshot.json +4 -4
- package/vendor/cli-core/cli.mjs +2 -0
- package/vendor/cli-core/command-runner.mjs +44 -9
- package/vendor/cli-core/package.json +1 -1
- package/vendor/cli-core/runtime-store.mjs +650 -0
- package/vendor/cli-core/scaffold.mjs +4 -2
|
@@ -1,205 +1,100 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function fail(message) {
|
|
20
|
-
throw new TypeError(message);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function requireString(value, field) {
|
|
24
|
-
if (typeof value !== "string" || !value.trim()) fail(`${field} 不能为空`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function yamlFromFile(filePath, label) {
|
|
28
|
-
let source;
|
|
29
|
-
try {
|
|
30
|
-
source = readFileSync(filePath, "utf8");
|
|
31
|
-
} catch (error) {
|
|
32
|
-
if (error.code === "ENOENT") fail(`缺少${label}: ${filePath}`);
|
|
33
|
-
throw error;
|
|
1
|
+
import {withValidationPhase, readFileSync} from './validation-phase.mjs';
|
|
2
|
+
import {ROOT, loadRegistry} from './lifecycle-registry.mjs';
|
|
3
|
+
import {loadDigitalHumanRoles, countersignRuleForGate} from './digital-human-roles.mjs';
|
|
4
|
+
import {assertGateChecks} from './lifecycle-controls.mjs';
|
|
5
|
+
import {assertUserDecisionRequirement, assertWorkUnitUserDecision, assertImplementationDecision} from './user-decision.mjs';
|
|
6
|
+
import {validateAssetStructure} from './structured-assets.mjs';
|
|
7
|
+
import {assertCurrentApproval, approvalExpectationFromState} from './approval-current.mjs';
|
|
8
|
+
import {approvalExpectedFromTask} from './review-capabilities.mjs';
|
|
9
|
+
import {approvalIO, readApprovalDocument, reviewBundleRows, loadApprovalRecord, selectApprovalRecord, readApprovalHistory, resolveApprovalRef, approvalError} from './approval-record-io.mjs';
|
|
10
|
+
export {assertCurrentApproval, approvalExpectationFromState, approvalExpectationFromSubject} from './approval-current.mjs';
|
|
11
|
+
export {loadApprovalRecord, selectApprovalRecord, readApprovalHistory, resolveApprovalRef} from './approval-record-io.mjs';
|
|
12
|
+
|
|
13
|
+
function expectedFor(record, options) {
|
|
14
|
+
if (options.expected) return Array.isArray(options.expected) ? options.expected.find(row => row.boundary === record.gate_id) : options.expected;
|
|
15
|
+
if (options.checkpoint) {
|
|
16
|
+
const state = options.checkpoint.gates?.[record.gate_id] || options.checkpoint.checks?.[record.gate_id];
|
|
17
|
+
return approvalExpectationFromState(record.gate_id,state,options);
|
|
34
18
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return value;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function loadApprovalRecord(filePath, gateId) {
|
|
42
|
-
return selectApprovalRecord(yamlFromFile(filePath, "会签记录"), gateId);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function reviewBundleRows(bundle) {
|
|
46
|
-
if (bundle?.schema_version !== 1 || bundle.kind !== "review-bundle") fail("组合审查身份无效");
|
|
47
|
-
for (const field of ["bundle_id", "task_id", "work_unit_id", "review_session_id", "role_id", "runtime_id", "principal_ref"]) requireString(bundle[field], field);
|
|
48
|
-
if (!/^review-bundle\.[a-z0-9][a-z0-9-]*$/.test(bundle.bundle_id)) fail("组合审查 bundle_id 格式非法");
|
|
49
|
-
if (!/^work-unit\.[a-z0-9][a-z0-9-]*$/.test(bundle.work_unit_id)) fail("组合审查 work_unit_id 格式非法");
|
|
50
|
-
if (!Array.isArray(bundle.reviews) || !bundle.reviews.length) fail("组合审查不能为空");
|
|
51
|
-
if (new Set(bundle.reviews.map(row => row?.gate_id)).size !== bundle.reviews.length) fail("组合审查 gate_id 重复");
|
|
52
|
-
for (const row of bundle.reviews) {
|
|
53
|
-
if (!row || typeof row !== "object" || Array.isArray(row)) fail("组合审查结论必须是对象");
|
|
54
|
-
if (row.role_id !== bundle.role_id || row.runtime_id !== bundle.runtime_id || row.principal_ref !== bundle.principal_ref) fail("组合审查必须来自同一复核角色、运行时和实例");
|
|
55
|
-
if (row.review_session_id != null && row.review_session_id !== bundle.review_session_id) fail("组合审查 review_session_id 不一致");
|
|
19
|
+
if (record.schema_version === 2 && record.review_task_ref) {
|
|
20
|
+
const task = approvalIO(options).document(record.review_task_ref);
|
|
21
|
+
return approvalExpectedFromTask(task,{...options,read:options.read || readFileSync,boundary:record.gate_id,reviewTaskRef:record.review_task_ref,reviewTaskDigest:record.review_task_digest});
|
|
56
22
|
}
|
|
57
|
-
return
|
|
23
|
+
return undefined;
|
|
58
24
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
...selected[0],
|
|
66
|
-
review_bundle_id: record.bundle_id,
|
|
67
|
-
review_task_id: record.task_id,
|
|
68
|
-
review_work_unit_id: record.work_unit_id,
|
|
69
|
-
review_session_id: record.review_session_id
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function resolveApprovalRef(approvalRef, fromFile = ROOT) {
|
|
74
|
-
requireString(approvalRef, "approval_ref");
|
|
75
|
-
if (path.isAbsolute(approvalRef)) return approvalRef;
|
|
76
|
-
const fromRoot = path.join(ROOT, approvalRef);
|
|
77
|
-
if (existsSync(fromRoot)) return fromRoot;
|
|
78
|
-
return path.resolve(path.dirname(fromFile), approvalRef);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function validateApprovalRecord(record, { rolesDoc, requireApproved = false, ...decisionOptions } = {}) {
|
|
82
|
-
validateAssetStructure(record, 'approval-record');
|
|
83
|
-
if (!record || typeof record !== "object" || Array.isArray(record)) fail("会签记录必须是对象");
|
|
84
|
-
if (record.schema_version !== 1) fail("会签记录 schema_version 必须为 1");
|
|
85
|
-
requireString(record.gate_id, "gate_id");
|
|
86
|
-
requireString(record.decision, "decision");
|
|
87
|
-
if (!DECISIONS.has(record.decision)) fail("decision 必须是 approved、rejected 或 vetoed");
|
|
88
|
-
requireString(record.actor_kind, "actor_kind");
|
|
89
|
-
if (!ACTOR_KINDS.has(record.actor_kind)) fail("actor_kind 无效");
|
|
90
|
-
requireString(record.role_id, "role_id");
|
|
91
|
-
requireString(record.runtime_id, "runtime_id");
|
|
92
|
-
requireString(record.principal_ref, "principal_ref");
|
|
93
|
-
|
|
94
|
-
const registry = rolesDoc || loadDigitalHumanRoles();
|
|
95
|
-
const runtimeIds = new Set((registry.runtimes || []).map((runtime) => runtime.id));
|
|
96
|
-
if (!runtimeIds.has(record.runtime_id)) fail(`未知 runtime_id: ${record.runtime_id}`);
|
|
97
|
-
if (record.actor_kind === "orchestrator") fail("编排器门禁不使用会签记录关闭");
|
|
98
|
-
|
|
99
|
-
if (!requireApproved && loadRegistry().id_policy.deprecated_ids.includes(record.gate_id)) return { bucket: "historical", gate: record.gate_id };
|
|
100
|
-
let rule = countersignRuleForGate(registry.gate_policy, record.gate_id);
|
|
101
|
-
const continuationReviewers = registry.gate_policy.continuation_reviews?.[record.gate_id];
|
|
102
|
-
if (record.continuation_ref && record.actor_kind === 'digital-human' && continuationReviewers) {
|
|
103
|
-
rule = { bucket: 'digital_human_review', gate: record.gate_id, countersigners: continuationReviewers };
|
|
104
|
-
if (!record.drafter_principal_ref || record.drafter_principal_ref === record.principal_ref) fail('延续批准必须由独立审查者核验');
|
|
105
|
-
}
|
|
106
|
-
if (!rule) fail(`${record.gate_id} 不是会签门禁;evidence_only / orchestrator 门禁不写 approval-record`);
|
|
107
|
-
|
|
108
|
-
if (requireApproved && record.decision !== "approved") {
|
|
109
|
-
fail(`${record.gate_id} 会签 decision 必须为 approved 才能关闭门禁`);
|
|
25
|
+
export function validateApprovalRecord(record, options = {}) {
|
|
26
|
+
if (options.history === true || options.requireApproved === false) {
|
|
27
|
+
validateAssetStructure(record,'approval-record');
|
|
28
|
+
if (record.kind === 'review-bundle') reviewBundleRows(record);
|
|
29
|
+
return {bucket:'history-only',record,execution_authorization:'not-evaluated'};
|
|
110
30
|
}
|
|
111
|
-
|
|
112
|
-
fail(`${record.gate_id} 已被生物人否决,不能标为 approved`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (rule.bucket === "biological_human") {
|
|
116
|
-
if (record.actor_kind !== "biological-human") fail(`${record.gate_id} 必须由生物人会签`);
|
|
117
|
-
if (record.role_id !== BIOLOGICAL_ROLE_ID) fail(`${record.gate_id} 的 role_id 必须为 ${BIOLOGICAL_ROLE_ID}`);
|
|
118
|
-
if (requireApproved) assertRecordUserDecision(record, registry, decisionOptions);
|
|
119
|
-
return rule;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (record.actor_kind !== "digital-human") fail(`${record.gate_id} 必须由数字人会签`);
|
|
123
|
-
if (!rule.countersigners.includes(record.role_id)) {
|
|
124
|
-
fail(`${record.gate_id} 会签角色必须是 ${rule.countersigners.join(" / ")}`);
|
|
125
|
-
}
|
|
126
|
-
if (rule.drafter && record.role_id === rule.drafter) fail(`${record.gate_id} 起草者不得会签自己`);
|
|
127
|
-
if (Array.isArray(record.countersigner_role_ids) && rule.drafter && record.countersigner_role_ids.includes(rule.drafter)) {
|
|
128
|
-
fail(`${record.gate_id} 起草者不得出现在 countersigner_role_ids`);
|
|
129
|
-
}
|
|
130
|
-
if (rule.drafter && record.drafter_role_id && record.drafter_role_id !== rule.drafter) {
|
|
131
|
-
fail(`${record.gate_id} drafter_role_id 必须为 ${rule.drafter}`);
|
|
132
|
-
}
|
|
133
|
-
if (requireApproved) assertRecordUserDecision(record, registry, decisionOptions);
|
|
134
|
-
return rule;
|
|
31
|
+
return withValidationPhase({root:options.root || ROOT,purpose:'approval-current',readOnly:true},()=>assertCurrentApproval(record,expectedFor(record,options),options));
|
|
135
32
|
}
|
|
136
|
-
|
|
137
|
-
function assertRecordUserDecision(record, registry, options) {
|
|
138
|
-
if (!registry.user_decision_policy.gates.includes(record.gate_id)) return;
|
|
139
|
-
const result = assertApprovalUserDecision(record, registry, options);
|
|
140
|
-
if (record.actor_kind === "biological-human" && result.validated.some((item) => item.principal_ref !== record.principal_ref)) fail("user-decision-responder-mismatch: 生物人会签者与原始回复者不一致");
|
|
141
|
-
}
|
|
142
|
-
|
|
143
33
|
export function validateApprovalRecordFile(filePath, options = {}) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const io = decisionIO(options);
|
|
151
|
-
if (!row.subject_ref || decisionDigest(io.bytes(row.subject_ref)) !== `sha256:${row.subject_digest}`) fail('组合审查主体缺失或已过期');
|
|
152
|
-
}
|
|
153
|
-
return validateApprovalRecord(row, options);
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
return validateApprovalRecord(record, options);
|
|
34
|
+
if (options.history === true || options.requireApproved === false) return readApprovalHistory(filePath,options);
|
|
35
|
+
return withValidationPhase({root:options.root || ROOT,purpose:'approval-current',readOnly:true},()=>{
|
|
36
|
+
const record = readApprovalDocument(filePath,options);
|
|
37
|
+
if (record.kind !== 'review-bundle') return assertCurrentApproval(record,expectedFor(record,options),options);
|
|
38
|
+
return reviewBundleRows(record).map(row=>assertCurrentApproval(loadApprovalRecord(filePath,row.gate_id,options),expectedFor(row,options),options));
|
|
39
|
+
});
|
|
157
40
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (
|
|
163
|
-
if (!gateState
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const record = loadApprovalRecord(resolved, gateId);
|
|
171
|
-
if (record.gate_id !== gateId) fail(`${gateId} 的会签记录 gate_id 不匹配`);
|
|
172
|
-
if (!gateState.subject_ref || gateState.subject_ref !== record.subject_ref || !gateState.approval_scope?.length || JSON.stringify([...gateState.approval_scope].sort()) !== JSON.stringify([...(record.approval_scope || [])].sort())) {
|
|
173
|
-
fail(`${gateId} user-decision-subject-mismatch: 当前门禁资产与会签范围不匹配`);
|
|
174
|
-
}
|
|
175
|
-
validateApprovalRecord(record, { rolesDoc, requireApproved: true });
|
|
41
|
+
export function assertApprovedGateHasValidApproval(gateId,gateState,options = {}) {
|
|
42
|
+
const rolesDoc=options.rolesDoc || loadDigitalHumanRoles();
|
|
43
|
+
if (!countersignRuleForGate(rolesDoc.gate_policy,gateId)) return;
|
|
44
|
+
if (!gateState || typeof gateState !== 'object') approvalError('APPROVAL_CONTEXT_REQUIRED',`${gateId} 缺少门禁状态`);
|
|
45
|
+
if (gateState.status !== 'approved') return;
|
|
46
|
+
if (!gateState.approval_ref) approvalError('APPROVAL_REFERENCE_REQUIRED',`${gateId} 已 approved 但缺少 approval_ref`);
|
|
47
|
+
return withValidationPhase({root:options.root || ROOT,purpose:'approval-helper-current',readOnly:true},()=>{
|
|
48
|
+
const file=resolveApprovalRef(gateState.approval_ref,options.checkpointPath || ROOT,options);
|
|
49
|
+
// A gate assertion always consumes current authority. History options only
|
|
50
|
+
// belong to the separate history reader and cannot weaken this boundary.
|
|
51
|
+
return assertCurrentApproval(loadApprovalRecord(file,gateId,options),approvalExpectationFromState(gateId,gateState,options),{...options,rolesDoc});
|
|
52
|
+
});
|
|
176
53
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
54
|
+
export function assertCheckpointApprovals(checkpoint,checkpointPath,options = {}) {
|
|
55
|
+
const registry=options.registry || loadRegistry(),rolesDoc=options.rolesDoc || loadDigitalHumanRoles();
|
|
56
|
+
return withValidationPhase({root:options.root || ROOT,purpose:'checkpoint-approvals',readOnly:true},()=>{
|
|
57
|
+
const known=new Set(registry.gates.map(gate=>gate.id));
|
|
58
|
+
for (const [gateId,state] of Object.entries(checkpoint?.gates || {})) {
|
|
59
|
+
if (!known.has(gateId)) approvalError('APPROVAL_CURRENT_INVALID',`未知或已退役门禁: ${gateId};历史记录只读,不自动迁移批准`);
|
|
60
|
+
if (state.status === 'approved') assertGateChecks(gateId,checkpoint,{...options,registry,rolesDoc});
|
|
61
|
+
assertApprovedGateHasValidApproval(gateId,state,{...options,checkpointPath,registry,rolesDoc});
|
|
62
|
+
}
|
|
63
|
+
});
|
|
187
64
|
}
|
|
188
65
|
|
|
189
66
|
// Called on resume/transition as well as completion; drafting while waiting stays allowed.
|
|
190
|
-
export function assertCheckpointUserDecisions(checkpoint) {
|
|
67
|
+
export function assertCheckpointUserDecisions(checkpoint, options = {}) {
|
|
191
68
|
if (checkpoint.repository_mode !== "project-instance") return;
|
|
192
69
|
const review = checkpoint.human_review || {};
|
|
193
70
|
const advancing = ["running", "completed"].includes(checkpoint.status) || (checkpoint.mode === "resume" && checkpoint.status === "routing");
|
|
194
71
|
if (!advancing) return;
|
|
195
72
|
const state = { user_decisions: review.user_decisions || [], user_decision_not_applicable: review.not_applicable || [] };
|
|
196
73
|
const completedUnit = checkpoint.stage_trace?.completed_work_unit;
|
|
197
|
-
if (completedUnit) assertWorkUnitUserDecision(completedUnit, state);
|
|
198
|
-
if (checkpoint.next_work_unit === "work-unit.slice-implementation") assertImplementationDecision({ ...review.implementation, ...state });
|
|
199
|
-
for (const requirement of review.required_decisions || []) assertUserDecisionRequirement(requirement);
|
|
200
|
-
if (review.external_input) assertUserDecisionRequirement({ ...review.external_input, boundary: "external-input" });
|
|
74
|
+
if (completedUnit) assertWorkUnitUserDecision(completedUnit, state, options);
|
|
75
|
+
if (checkpoint.next_work_unit === "work-unit.slice-implementation") assertImplementationDecision({ ...review.implementation, ...state }, options);
|
|
76
|
+
for (const requirement of review.required_decisions || []) assertUserDecisionRequirement(requirement, options);
|
|
77
|
+
if (review.external_input) assertUserDecisionRequirement({ ...review.external_input, boundary: "external-input" }, options);
|
|
201
78
|
if (checkpoint.status === "completed") {
|
|
202
79
|
if (checkpoint.blockers?.length || Object.values(checkpoint.gates || {}).some(gate => !["approved", "not-applicable"].includes(gate.status))) throw new TypeError("lifecycle-control-blocked: 仍有阻塞或未通过门禁,不可完成");
|
|
203
|
-
|
|
80
|
+
const completionGate=loadRegistry().gates.some(gate=>gate.id==="gate.strategic-design-handoff-approved")?"gate.strategic-design-handoff-approved":"gate.delivery-accepted";
|
|
81
|
+
if (checkpoint.gates?.[completionGate]?.status !== "approved") throw new TypeError("lifecycle-control-blocked: 阶段完成须当前交付或战略交接验收,不等于发布授权");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Strategic profiles retain their bounded stage-transition API while using the same current kernel.
|
|
86
|
+
export function assertStrategicWorkUnitDecision(workUnit, state, options = {}) {
|
|
87
|
+
const roles=options.rolesDoc || loadDigitalHumanRoles();
|
|
88
|
+
const boundaries=workUnit==='work-unit.strategic-design-handoff' ? ['gate.strategic-design-handoff-approved'] : [...(roles.user_decision_policy.work_unit_gates?.[workUnit] || []), ...(roles.user_decision_policy.work_units?.[workUnit] ? [roles.user_decision_policy.work_units[workUnit]] : [])];
|
|
89
|
+
for(const boundary of boundaries) {
|
|
90
|
+
const gate=state.gates?.[boundary];
|
|
91
|
+
if(gate?.status==='approved') {
|
|
92
|
+
assertGateChecks(boundary,state,options);
|
|
93
|
+
assertApprovedGateHasValidApproval(boundary,gate,{...options,rolesDoc:roles});
|
|
94
|
+
} else if(workUnit==='work-unit.strategic-design-handoff') {
|
|
95
|
+
approvalError('APPROVAL_CURRENT_INVALID','strategic-gate-migration-required: '+boundary);
|
|
96
|
+
} else {
|
|
97
|
+
assertWorkUnitUserDecision(workUnit,{user_decisions:state.user_decisions || state.human_review?.user_decisions || [],user_decision_not_applicable:state.user_decision_not_applicable || state.human_review?.not_applicable || []},{...options,rolesDoc:roles});break;
|
|
98
|
+
}
|
|
204
99
|
}
|
|
205
100
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {approvalExpectationForCheckpoint,approvalExpectationForBoundAsset} from './approval-consumption.mjs';
|
|
1
2
|
import {validateJsonSchemas} from './json-schema.mjs';
|
|
2
3
|
import { assertScopeSlice, assertScopeWorkUnit } from './lifecycle-execution-scope.mjs';
|
|
3
4
|
import { selectSliceWorkUnit, normalizeSliceContract, sourceSliceContract, parseSliceYaml } from './slice-contract.mjs';
|
|
@@ -5,7 +6,7 @@ import path from 'node:path';
|
|
|
5
6
|
import { readFileSync, inValidationPhase, validationMemo, validationPhaseToken } from './validation-phase.mjs';
|
|
6
7
|
import { ROOT, read, parse, safe, hash, digest, schema } from './strategic-handoff-io.mjs';
|
|
7
8
|
import { countersignRuleForGate } from './digital-human-roles.mjs';
|
|
8
|
-
import { validateApprovalRecord } from './approval-record.mjs';
|
|
9
|
+
import { validateApprovalRecord, loadApprovalRecord } from './approval-record.mjs';
|
|
9
10
|
import { assertImplementationDecision } from './user-decision.mjs';
|
|
10
11
|
import { loadSkillRegistry } from './skill-registry.mjs';
|
|
11
12
|
|
|
@@ -52,7 +53,7 @@ export function verifySliceContractApproval(binding,{root=process.cwd(),contract
|
|
|
52
53
|
assertImplementationDecision({...review.implementation,user_decisions:review.user_decisions||[]},{...ioFor(root),rolesDoc:roles});
|
|
53
54
|
} else {
|
|
54
55
|
// Historical source profiles that declared this a countersign gate retain their policy.
|
|
55
|
-
validateApprovalRecord(approval,{...ioFor(root),rolesDoc:roles,requireApproved:true});
|
|
56
|
+
validateApprovalRecord(approval,{...ioFor(root),rolesDoc:roles,requireApproved:true,expected:approvalExpectationForBoundAsset(gateId,binding,{...ioFor(root),review_package:false})});
|
|
56
57
|
check(approval.gate_id===gateId&&approval.artifact_bindings?.some(item=>item.id===contract.contract_id&&item.version===contract.contract_version&&item.digest===binding.digest),'EXECUTION_APPROVAL_SCOPE','源会签未绑定当前 Slice 的身份、版本和字节');
|
|
57
58
|
}
|
|
58
59
|
if(contract.schema_version===3) verifySliceProfessionalReview(approval,{...binding,id:contract.contract_id,version:contract.contract_version},roles,root);
|
|
@@ -144,14 +145,15 @@ function verifySliceProfessionalReview(approval,binding,roles,root) {
|
|
|
144
145
|
if(!/\.(yaml|yml|json)$/.test(ref))continue;
|
|
145
146
|
const record=read(safe(root,ref));
|
|
146
147
|
const rows=record.kind==='review-bundle'?record.reviews:[record];
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
if(!(rows || []).some(row=>row.gate_id==='check.design-reviewed'&&row.subject_ref===binding.ref))continue;
|
|
149
|
+
// Loading the selected conclusion validates the entire container and carries
|
|
150
|
+
// its task/session identity into the same current-approval kernel.
|
|
151
|
+
const row=loadApprovalRecord(safe(root,ref),'check.design-reviewed',ioFor(root));
|
|
152
|
+
validateApprovalRecord(row,{...ioFor(root),rolesDoc:roles,requireApproved:true,expected:approvalExpectationForCheckpoint('check.design-reviewed',approval.checks?.['check.design-reviewed'],{...ioFor(root),review_package:false})});
|
|
150
153
|
check(row.drafter_principal_ref&&row.principal_ref!==row.drafter_principal_ref,'EXECUTION_REVIEW_NOT_INDEPENDENT','Slice 工程审查必须独立于起草者');
|
|
151
154
|
check(row.subject_digest===binding.digest.slice(7)&&row.artifact_bindings?.some(x=>x.id===binding.id&&x.version===binding.version&&x.digest===binding.digest),'EXECUTION_REVIEW_STALE','Slice 工程审查未绑定当前合同');
|
|
152
155
|
check(Array.isArray(row.findings)&&row.findings.every(x=>x.kind==='suggestion'?!!x.follow_up:['requirement-violation','missing-evidence','important-risk'].includes(x.kind)&&x.status==='resolved'),'EXECUTION_REVIEW_BLOCKED','Slice 工程审查有未关闭问题');
|
|
153
156
|
found=true;
|
|
154
|
-
}
|
|
155
157
|
}
|
|
156
158
|
check(found,'EXECUTION_REVIEW_REQUIRED','Slice v3 缺少当前合同的独立工程审查');
|
|
157
159
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {findApprovalCheckpoint} from './approval-checkpoint-discovery.mjs';
|
|
1
2
|
import fs from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import os from 'node:os';
|
|
@@ -72,7 +73,10 @@ export function validateAssetSemantics(root, ref, kind) {
|
|
|
72
73
|
args = [file, '--root', root];
|
|
73
74
|
} else {
|
|
74
75
|
tool = { checkpoint: 'scripts/verify-lifecycle-checkpoint', 'task-package': 'scripts/verify-digital-human-task-package', 'approval-record': 'scripts/verify-approval-record' }[kind];
|
|
75
|
-
|
|
76
|
+
if(kind==='approval-record') {
|
|
77
|
+
const current=value.decision==='approved'||value.kind==='review-bundle';
|
|
78
|
+
args=current&&value.schema_version!==2?['--require-approved','--checkpoint',findApprovalCheckpoint(root,ref),file]:[current?'--require-approved':'--history',file];
|
|
79
|
+
} else args=[file];
|
|
76
80
|
}
|
|
77
81
|
ensure(exists(safeFile(root, tool)), `ASSET_CONSUMER_MISSING: ${tool}`);
|
|
78
82
|
const result = spawnSync(process.execPath, [path.join(root, tool), ...args], { cwd: root, encoding: 'utf8', timeout: 60000, maxBuffer: 8 * 1024 * 1024 });
|
|
@@ -21,7 +21,7 @@ async function approvedFile(root, binding, gate) {
|
|
|
21
21
|
if(gate==='gate.slice-contract-approved'){verifySliceContractApproval(binding,{root});return bytes;}
|
|
22
22
|
const record=read(safe(root,binding.approval_ref));
|
|
23
23
|
const roles=sourceApprovalPolicy(read(safe(root,'.template-spec/agents/digital-human-roles.yaml')));
|
|
24
|
-
await sourceApproval(record,roles,root);
|
|
24
|
+
await sourceApproval(record,roles,root,binding);
|
|
25
25
|
ensure((Array.isArray(gate)?gate:[gate]).includes(record.gate_id),`交付资产批准门禁不匹配: ${binding.ref}`);
|
|
26
26
|
ensure(record.artifact_bindings?.some(x=>x.id===binding.id&&x.version===binding.version&&x.digest===binding.digest),`批准未绑定当前交付资产: ${binding.ref}`);
|
|
27
27
|
return bytes;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {approvalExpectationForBoundAsset} from './approval-consumption.mjs';
|
|
1
2
|
import fs from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { spawnSync } from 'node:child_process';
|
|
@@ -124,7 +125,7 @@ function validateBaselineReview(state,{root}) {
|
|
|
124
125
|
ensure(digest(fs.readFileSync(file(root,input.spec_binding.ref)))===input.spec_binding.digest.replace(/^sha256:/,''),'Spec evidence stale');
|
|
125
126
|
ensure(text(input.spec_binding.approval_ref),'Spec approval record required');
|
|
126
127
|
const approval=parseSliceYaml(fs.readFileSync(file(root,input.spec_binding.approval_ref),'utf8'));
|
|
127
|
-
validateApprovalRecord(approval,{root,requireApproved:true,rolesDoc:parseSliceYaml(fs.readFileSync(file(root,'.template-spec/agents/digital-human-roles.yaml'),'utf8'))});
|
|
128
|
+
validateApprovalRecord(approval,{root,requireApproved:true,rolesDoc:parseSliceYaml(fs.readFileSync(file(root,'.template-spec/agents/digital-human-roles.yaml'),'utf8')),expected:approvalExpectationForBoundAsset('gate.spec-baseline-approved',input.spec_binding,{root})});
|
|
128
129
|
ensure(approval.gate_id==='gate.spec-baseline-approved' && approval.artifact_bindings?.some(b=>b.digest.replace(/^sha256:/,'')===input.spec_binding.digest.replace(/^sha256:/,'')),'Spec approval does not bind current baseline');
|
|
129
130
|
ensure(Array.isArray(result.constraint_results)&&result.constraint_results.some(r=>r.axis==='Spec'&&r.status==='passed'&&text(r.evidence_ref)),'Spec acceptance evidence required');
|
|
130
131
|
for(const row of result.constraint_results.filter(r=>r.axis==='Spec')) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {approvalExpectationForBoundAsset} from './approval-consumption.mjs';
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { existsSync, readFileSync } from './validation-phase.mjs';
|
|
3
4
|
import path from "node:path";
|
|
@@ -103,7 +104,7 @@ export async function validateBackendScaffoldPrerequisites(contract, { contractF
|
|
|
103
104
|
if (approvalRef !== contract.lifecycle_approval_ref || approvalRef !== contract.approval?.approval_ref) fail("工程合同批准引用与脚手架合同不一致");
|
|
104
105
|
const approvalFile = resolveLocalRef(root, approvalRef, "工程合同批准记录");
|
|
105
106
|
const approval = loadApprovalRecord(approvalFile, 'gate.engineering-contract-approved');
|
|
106
|
-
validateApprovalRecord(approval, { requireApproved: true, root });
|
|
107
|
+
validateApprovalRecord(approval, { requireApproved: true, root, expected: approvalExpectationForBoundAsset('gate.engineering-contract-approved',prerequisites.technical_design,{root,scope:[contract.contract_id,contract.project_name]}) });
|
|
107
108
|
if (approval.gate_id !== "gate.engineering-contract-approved") fail("工程合同批准记录 gate_id 必须为 gate.engineering-contract-approved");
|
|
108
109
|
if (!Array.isArray(approval.approval_scope) || !approval.approval_scope.includes(contract.contract_id) || !approval.approval_scope.includes(contract.project_name)) fail("工程合同批准范围未覆盖当前合同和项目");
|
|
109
110
|
requireEngineeringPackage(root, approval, contract, technical, data, api, prerequisites);
|
|
@@ -115,7 +116,7 @@ export async function validateBackendScaffoldPrerequisites(contract, { contractF
|
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
return {
|
|
118
|
-
technical_design: { ref: prerequisites.technical_design.ref, version: technical.value.version, digest: prerequisites.technical_design.digest },
|
|
119
|
+
technical_design: { ref: prerequisites.technical_design.ref, version: technical.value.version, digest: prerequisites.technical_design.digest, ...(prerequisites.technical_design.approval_context ? { approval_context: structuredClone(prerequisites.technical_design.approval_context) } : {}) },
|
|
119
120
|
data_architecture_decision: { ref: prerequisites.data_architecture_decision.ref, version: data.value.decision_version, digest: prerequisites.data_architecture_decision.digest, impact: data.value.impact },
|
|
120
121
|
api_contract_decision: { ref: prerequisites.api_contract_decision.ref, version: api.decision.decision_version, digest: prerequisites.api_contract_decision.digest, impact: api.decision.impact },
|
|
121
122
|
engineering_contract_approval_ref: approvalRef,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {approvalExpectationForCheckpoint} from './approval-consumption.mjs';
|
|
1
2
|
import fs from 'node:fs';
|
|
2
3
|
import {businessAuthoringEnabled,businessPath,businessSetRef,checkBusinessTickets,assertBusinessDeferredApprovals} from './business-tickets.mjs';
|
|
3
4
|
import {yamlValue} from './plan-spec-markdown.mjs';
|
|
@@ -18,7 +19,7 @@ export function assertBusinessApprovalBasis(root,state,{required=false}={}) {
|
|
|
18
19
|
if(gate?.status!=='approved'||!gate.approval_ref)throw Error(`BUSINESS_APPROVAL_REQUIRED: ${id}`);
|
|
19
20
|
const record=loadApprovalRecord(businessPath(root,gate.approval_ref),id);
|
|
20
21
|
if(record.gate_id!==id||record.subject_ref!==gate.subject_ref||!gate.approval_scope?.length||JSON.stringify([...gate.approval_scope].sort())!==JSON.stringify([...(record.approval_scope||[])].sort()))throw Error(`BUSINESS_APPROVAL_SCOPE_MISMATCH: ${id}`);
|
|
21
|
-
validateApprovalRecord(record,{root,rolesDoc,requireApproved:true});
|
|
22
|
+
validateApprovalRecord(record,{root,rolesDoc,requireApproved:true,expected:approvalExpectationForCheckpoint(id,gate,{root})});
|
|
22
23
|
if(id==='gate.spec-baseline-approved'&&record.subject_ref!==report.spec.ref) {
|
|
23
24
|
// Existing approvals may cover a review package instead of the Spec itself.
|
|
24
25
|
// Its signed bytes, rather than a mutable checkpoint label, bind the baseline.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
// Reject ids that git cannot turn into a ref ("" .. "", trailing ".lock",
|
|
7
|
+
// path separators, unsafe characters) before anything is written.
|
|
8
|
+
const RUN_ID_PATTERN = /^(?!.*\.\.)[a-z0-9][a-z0-9._-]{0,62}$/;
|
|
9
|
+
export const CHECKPOINT_PREFIX = "refs/checkpoints/";
|
|
10
|
+
|
|
11
|
+
export function validateCheckpointRunId(root, runId, { spawn = spawnSync } = {}) {
|
|
12
|
+
if (typeof runId !== "string" || !RUN_ID_PATTERN.test(runId) || runId.endsWith(".lock")) {
|
|
13
|
+
throw new TypeError("run-id 必须安全(小写字母/数字/._-;不得含 .. 或以 .lock 结尾): " + String(runId));
|
|
14
|
+
}
|
|
15
|
+
const reference = CHECKPOINT_PREFIX + runId;
|
|
16
|
+
const checked = spawn("git", ["-C", root, "check-ref-format", reference], { encoding: "utf8" });
|
|
17
|
+
if (checked.status !== 0) throw new TypeError("非法 checkpoint 引用: " + reference);
|
|
18
|
+
return reference;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Create an immutable checkpoint commit of the current working tree without
|
|
22
|
+
// touching the user's index, working tree, branch or HEAD. A temporary index is
|
|
23
|
+
// populated from the base commit plus the working tree, written to a tree
|
|
24
|
+
// object, wrapped in a commit, and published only as a local
|
|
25
|
+
// refs/checkpoints/<run-id> ref.
|
|
26
|
+
export function commitCheckpoint({ root, runId, message, baseRef = "HEAD", dryRun = false, spawn = spawnSync } = {}) {
|
|
27
|
+
const reference = validateCheckpointRunId(root, runId, { spawn });
|
|
28
|
+
const run = (args, options) => {
|
|
29
|
+
const result = spawn("git", ["-C", root, ...args], { encoding: "utf8", maxBuffer: 128 * 1024 * 1024, ...options });
|
|
30
|
+
if (result.status !== 0) throw new TypeError((result.stderr || "").trim() || "git " + args.join(" ") + " 执行失败");
|
|
31
|
+
return result.stdout.trim();
|
|
32
|
+
};
|
|
33
|
+
const parent = run(["rev-parse", "--verify", baseRef + "^{commit}"]);
|
|
34
|
+
const existing = spawn("git", ["-C", root, "rev-parse", "--verify", "--quiet", reference], { encoding: "utf8" });
|
|
35
|
+
if (dryRun) return { ref: reference, commit: null, tree: null, parent, run_id: runId, dry_run: true, exists: existing.status === 0 };
|
|
36
|
+
if (existing.status === 0) throw new TypeError("checkpoint 已存在,拒绝覆盖: " + reference);
|
|
37
|
+
const indexDirectory = mkdtempSync(path.join(os.tmpdir(), "yss-checkpoint-index-"));
|
|
38
|
+
const indexPath = path.join(indexDirectory, "index");
|
|
39
|
+
const env = { ...process.env, GIT_INDEX_FILE: indexPath };
|
|
40
|
+
try {
|
|
41
|
+
run(["read-tree", baseRef], { env });
|
|
42
|
+
run(["add", "-A", "--", "."], { env });
|
|
43
|
+
const tree = run(["write-tree"], { env });
|
|
44
|
+
const commit = run(["commit-tree", tree, "-p", parent, "-m", message || ("checkpoint " + runId)], { env });
|
|
45
|
+
run(["update-ref", reference, commit]);
|
|
46
|
+
return { ref: reference, commit, tree, parent, run_id: runId, dry_run: false, exists: false };
|
|
47
|
+
} finally {
|
|
48
|
+
rmSync(indexDirectory, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "node:child_process";
|
|
2
2
|
import { appendFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { StringDecoder } from "node:string_decoder";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { assertNodeVersion } from "./runtime-store.mjs";
|
|
4
6
|
import { fileURLToPath } from "node:url";
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
const sessionSequences = new WeakMap();
|
|
9
|
+
function runtimeLogs(session, stdoutFile, stderrFile) {
|
|
10
|
+
if (!session) return { stdoutFile, stderrFile };
|
|
11
|
+
const sequence = sessionSequences.get(session) || 0;
|
|
12
|
+
sessionSequences.set(session, sequence + 1);
|
|
13
|
+
return { stdoutFile: stdoutFile || path.join(session.runDir, `command-${sequence}.stdout`), stderrFile: stderrFile || path.join(session.runDir, `command-${sequence}.stderr`) };
|
|
14
|
+
}
|
|
15
|
+
function recordRuntimeResult(session, result, command, args, files) {
|
|
16
|
+
if (!session) return result;
|
|
17
|
+
try { session.recordCommand({ command: JSON.stringify([command, ...args]), ...result, stdout: undefined, stderr: undefined, ...files }); }
|
|
18
|
+
catch (error) { result.storageError = [result.storageError,error.message].filter(Boolean).join("; "); }
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function killTree(child, signal) {
|
|
7
23
|
if (!child.pid) return;
|
|
8
24
|
try {
|
|
9
25
|
if (process.platform === "win32") spawnSync("taskkill", ["/PID", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
@@ -12,9 +28,10 @@ function killTree(child, signal) {
|
|
|
12
28
|
}
|
|
13
29
|
|
|
14
30
|
/** Bounded lifetime for external tools; stdout is never mixed with progress. */
|
|
15
|
-
export function runCommand(command, args, { cwd, env = process.env, timeoutMs = 0, signal, stdoutFile, stderrFile, secrets = [], progress = false } = {}) {
|
|
31
|
+
export function runCommand(command, args, { cwd, env = process.env, timeoutMs = 0, signal, stdoutFile, stderrFile, secrets = [], progress = false, runtimeSession } = {}) {
|
|
32
|
+
assertNodeVersion();
|
|
33
|
+
({ stdoutFile, stderrFile } = runtimeLogs(runtimeSession, stdoutFile, stderrFile));
|
|
16
34
|
if (!Number.isFinite(timeoutMs) || timeoutMs < 0) throw new TypeError("timeoutMs 必须是非负毫秒数");
|
|
17
|
-
if (signal?.aborted) return Promise.resolve({ status: 1, stdout: "", stderr: "command cancelled", termination: "cancelled", duration_ms: 0 });
|
|
18
35
|
return new Promise(resolve => {
|
|
19
36
|
const started = performance.now();
|
|
20
37
|
const argumentSecrets = args.flatMap(value => { try { const url = new URL(value); return url.password ? [url.password, decodeURIComponent(url.password)] : []; } catch { return []; } });
|
|
@@ -22,14 +39,15 @@ export function runCommand(command, args, { cwd, env = process.env, timeoutMs =
|
|
|
22
39
|
const replacement = secret => secretNames.has(secret) ? `[REDACTED:${secretNames.get(secret)}]` : "[REDACTED]";
|
|
23
40
|
const sensitive = [...secrets, ...argumentSecrets, ...secretNames.keys()].filter(value => typeof value === "string" && value.length > 0).sort((a, b) => b.length - a.length);
|
|
24
41
|
const redact = text => sensitive.reduce((value, secret) => value.replaceAll(secret, replacement(secret)), text);
|
|
42
|
+
if (signal?.aborted) { resolve(recordRuntimeResult(runtimeSession,{status:1,stdout:"",stderr:"command cancelled",termination:"cancelled",duration_ms:0,actual_exit_code:null,actual_exit_signal:null,actual_exit_code_observed:false},redact(command),args.map(redact),{}));return; }
|
|
25
43
|
if (progress) process.stderr.write(`[开始] ${redact(command + " " + args.join(" "))}\n`);
|
|
26
44
|
for (const file of [stdoutFile, stderrFile]) if (file) writeFileSync(file, "");
|
|
27
45
|
const child = spawn(command, args, { cwd, env, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"] });
|
|
28
|
-
let termination = null, escalation, timer, errorMessage;
|
|
46
|
+
let termination = null, escalation, timer, errorMessage, logError, spawnError = false;
|
|
29
47
|
const makeStream = file => {
|
|
30
48
|
const decoder = new StringDecoder("utf8");
|
|
31
49
|
let pending = "", captured = "";
|
|
32
|
-
const emit = text => { captured += text; if (file) appendFileSync(file, text); };
|
|
50
|
+
const emit = text => { captured += text; if (file && !logError) try { appendFileSync(file, text); } catch (error) { logError=error.message; } };
|
|
33
51
|
function consume(final = false) {
|
|
34
52
|
let output = "", cursor = 0;
|
|
35
53
|
while (cursor < pending.length) {
|
|
@@ -57,7 +75,7 @@ export function runCommand(command, args, { cwd, env = process.env, timeoutMs =
|
|
|
57
75
|
if (timeoutMs) timer = setTimeout(() => cancel("timeout"), timeoutMs);
|
|
58
76
|
child.stdout.on("data", bytes => stdout.write(bytes));
|
|
59
77
|
child.stderr.on("data", bytes => stderr.write(bytes));
|
|
60
|
-
child.on("error", error => { errorMessage = redact(error.message); });
|
|
78
|
+
child.on("error", error => { spawnError = true; errorMessage = redact(error.message); });
|
|
61
79
|
child.on("close", (code, exitSignal) => {
|
|
62
80
|
clearTimeout(timer); clearTimeout(escalation);
|
|
63
81
|
// A group leader can exit before its descendants close redirected streams.
|
|
@@ -67,7 +85,13 @@ export function runCommand(command, args, { cwd, env = process.env, timeoutMs =
|
|
|
67
85
|
const duration_ms = performance.now() - started;
|
|
68
86
|
const status = termination === "timeout" ? 124 : termination ? 1 : code ?? 1;
|
|
69
87
|
if (progress) process.stderr.write(`[${status === 0 ? "完成" : "失败"}] ${command} (${Math.round(duration_ms)}ms, exit=${status}${termination ? `, ${termination}` : ""})\n`);
|
|
70
|
-
|
|
88
|
+
const actual_exit_code_observed = !spawnError && Number.isInteger(code);
|
|
89
|
+
const result = { status, stdout: stdout.end(), stderr: stderr.end() + (errorMessage || ""), signal: exitSignal, termination, duration_ms,
|
|
90
|
+
actual_exit_code: actual_exit_code_observed ? code : null,
|
|
91
|
+
actual_exit_signal: spawnError ? null : exitSignal ?? null,
|
|
92
|
+
actual_exit_code_observed };
|
|
93
|
+
if(logError)result.storageError=logError;
|
|
94
|
+
resolve(recordRuntimeResult(runtimeSession, result, redact(command), args.map(redact), { stdoutFile, stderrFile }));
|
|
71
95
|
});
|
|
72
96
|
});
|
|
73
97
|
}
|
|
@@ -75,12 +99,23 @@ export function runCommand(command, args, { cwd, env = process.env, timeoutMs =
|
|
|
75
99
|
// Synchronous API compatibility for existing generators/cache consumers. The worker
|
|
76
100
|
// owns the process group and streams logs; it never updates project metadata.
|
|
77
101
|
export function runCommandSync(command, args, options = {}) {
|
|
102
|
+
assertNodeVersion();
|
|
103
|
+
const { runtimeSession, ...workerOptions } = options;
|
|
104
|
+
Object.assign(workerOptions, runtimeLogs(runtimeSession, options.stdoutFile, options.stderrFile));
|
|
78
105
|
const result = spawnSync(process.execPath, [fileURLToPath(import.meta.url), "--worker"], {
|
|
79
|
-
input: JSON.stringify({ command, args, options }), encoding: "utf8", maxBuffer: 64 * 1024 * 1024,
|
|
106
|
+
input: JSON.stringify({ command, args, options: workerOptions }), encoding: "utf8", maxBuffer: 64 * 1024 * 1024,
|
|
80
107
|
stdio: ["pipe", "pipe", "inherit"], env: options.env ?? process.env,
|
|
81
108
|
});
|
|
82
109
|
if (result.error || result.status !== 0) throw new TypeError(result.error?.message || "command worker failed");
|
|
83
|
-
|
|
110
|
+
const value = JSON.parse(result.stdout);
|
|
111
|
+
if (runtimeSession) {
|
|
112
|
+
// The worker already redacts output. Redact arguments before registering in the parent.
|
|
113
|
+
const env = options.env || process.env;
|
|
114
|
+
const sensitive = [...(options.secrets || []), ...Object.entries(env).filter(([key]) => /(?:PASSWORD|TOKEN|SECRET)$/.test(key) || key === "MAVEN_REPO_USERNAME").map(([, secret]) => secret), ...args.flatMap(arg => { try { const url = new URL(arg); return url.password ? [url.password, decodeURIComponent(url.password)] : []; } catch { return []; } })].filter(secret => typeof secret === "string" && secret.length).sort((a,b) => b.length - a.length);
|
|
115
|
+
const redact = text => sensitive.reduce((value, secret) => value.replaceAll(secret, "[REDACTED]"), text);
|
|
116
|
+
return recordRuntimeResult(runtimeSession, value, redact(command), args.map(redact), { stdoutFile: workerOptions.stdoutFile, stderrFile: workerOptions.stderrFile });
|
|
117
|
+
}
|
|
118
|
+
return value;
|
|
84
119
|
}
|
|
85
120
|
|
|
86
121
|
if (process.argv[1] === fileURLToPath(import.meta.url) && process.argv[2] === "--worker") {
|