create-yss-spec 3.5.5 → 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/README.md +2 -0
- package/bin/create-yss-spec.js +3 -1
- package/cli-core.lock.json +11 -7
- 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 +7 -2
- package/src/template/instance-runtime.js +27 -9
- 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
- package/vendor/cli-core/tests/package-contract.mjs +14 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { loadExecutionScope, assertScopeWorkUnit, scopedNextRoutes } from './lifecycle-execution-scope.mjs';
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { readFileSync, withValidationPhase, validationDependencies } from "./validation-phase.mjs";
|
|
3
|
+
import { readFileSync, existsSync, lstatSync, readdirSync, withValidationPhase, validationDependencies } from "./validation-phase.mjs";
|
|
4
|
+
import { realpathSync } from "node:fs";
|
|
5
|
+
import { OBSOLETE } from "./skill-supply-chain.mjs";
|
|
4
6
|
import path from "node:path";
|
|
5
7
|
import { parseDocument } from "../vendor/yaml.mjs";
|
|
6
8
|
import { ROOT, loadRegistry, semanticDigest, validateRegistry } from "./lifecycle-registry.mjs";
|
|
@@ -10,6 +12,8 @@ import { loadLifecyclePresenter } from './lifecycle-presentation.mjs';
|
|
|
10
12
|
const LIFECYCLE_REGISTRY_REF = ".template-spec/process/lifecycle-registry.yaml";
|
|
11
13
|
const ORCHESTRATION_CONTRACT_REF = ".agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml";
|
|
12
14
|
const SKILL_REGISTRY_REF = ".template-spec/agents/yss-skill-registry.yaml";
|
|
15
|
+
// Governed projections retain the specialist query's existing output contract.
|
|
16
|
+
const QUERY_PROFILE = 'lifecycle';
|
|
13
17
|
|
|
14
18
|
function read(relativePath) {
|
|
15
19
|
return readFileSync(path.join(ROOT, relativePath), "utf8");
|
|
@@ -68,7 +72,157 @@ export function queryLifecycleContext(options = {}) {
|
|
|
68
72
|
return withValidationPhase({ root: ROOT, purpose: "lifecycle-context-query", readOnly: true }, () => querySnapshot(options));
|
|
69
73
|
}
|
|
70
74
|
|
|
71
|
-
|
|
75
|
+
// Availability is an observation, not permission to install, invoke or approve.
|
|
76
|
+
export function inspectWorkUnitSkills({ root = ROOT, registry, route, agentRuntime, when = [] }) {
|
|
77
|
+
const issues = [], missing = [], required = new Set();
|
|
78
|
+
const report = (code, skill, ref, message) => issues.push({ code, skill: skill ?? null, ref, message });
|
|
79
|
+
const definitions = [...(registry.skills ?? []), ...(registry.external_skills ?? [])];
|
|
80
|
+
const externalIds = new Set((registry.external_skills ?? []).map(skill => skill.id));
|
|
81
|
+
const aliases = new Map(definitions.flatMap(skill => (skill.aliases ?? []).map(alias => [alias, skill.id])));
|
|
82
|
+
const roots = registry.agent_runtime_roots ?? registry.instance_distribution?.projection_roots ?? {};
|
|
83
|
+
const dependencies = registry.skill_dependencies ?? {};
|
|
84
|
+
function visit(requested) {
|
|
85
|
+
const id = aliases.get(requested) ?? requested;
|
|
86
|
+
if (required.has(id)) return;
|
|
87
|
+
required.add(id);
|
|
88
|
+
const definition = definitions.find(skill => skill.id === id);
|
|
89
|
+
if (OBSOLETE.has(id) || definition?.maturity === 'deprecated') {
|
|
90
|
+
report('skill-retired', id, '.template-spec/agents/skill-migrations.md',
|
|
91
|
+
definition?.replacement_skill ? '技能已停止新用法;请使用 ' + definition.replacement_skill : '技能已退役;按迁移说明重新路由');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!definition || (!externalIds.has(id) && !/^[a-z][a-z0-9-]+$/.test(id))) {
|
|
95
|
+
report('skill-unknown', id, SKILL_REGISTRY_REF, '路由使用未登记的技能');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (externalIds.has(id)) {
|
|
99
|
+
report('external-skill-required', id, SKILL_REGISTRY_REF, '外部技能须核验实际运行时能力,不能通过共享技能补装代替');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
for (const dependency of dependencies[id] ?? []) {
|
|
103
|
+
if (dependency.type === 'context-required' ||
|
|
104
|
+
(dependency.type === 'context-conditional' && when.includes(dependency.when))) visit(dependency.skill);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
[
|
|
108
|
+
route?.primary_skill,
|
|
109
|
+
route?.native?.invocation_mode === 'reference' ? null : route?.native?.skill,
|
|
110
|
+
...(route?.supporting_skills ?? []), ...(route?.skills ?? []),
|
|
111
|
+
].filter(Boolean).forEach(visit);
|
|
112
|
+
function readJson(ref) {
|
|
113
|
+
const file = path.join(root, ref);
|
|
114
|
+
if (!existsSync(file)) return null;
|
|
115
|
+
const value = JSON.parse(readFileSync(file, 'utf8'));
|
|
116
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new TypeError(ref + ' 必须是 JSON 对象');
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
const lock = readJson('skills-lock.json');
|
|
120
|
+
const metadata = readJson('.yss-template.json');
|
|
121
|
+
const selected = metadata?.distribution?.mode === 'selected' ? metadata.distribution : null;
|
|
122
|
+
const registeredRuntimes = selected?.runtimes ??
|
|
123
|
+
Object.keys(roots).filter(runtime => lock?.projectionRoots?.includes(roots[runtime]));
|
|
124
|
+
if (!agentRuntime && registeredRuntimes.length === 1) agentRuntime = registeredRuntimes[0];
|
|
125
|
+
if (agentRuntime && !Object.hasOwn(roots, agentRuntime)) throw new TypeError('未知 Agent 运行时: ' + agentRuntime);
|
|
126
|
+
if (!agentRuntime) report('runtime-required', null, '.yss-template.json', '请用 --agent-runtime 明确指定运行时;只在登记了唯一运行时时自动选择');
|
|
127
|
+
else if (!registeredRuntimes.includes(agentRuntime)) report('runtime-not-installed', null, '.yss-template.json', '所选运行时未登记;先核对运行时安装范围');
|
|
128
|
+
if (!lock?.skills?.shared || !Array.isArray(lock.projectionRoots)) report('skill-lock-invalid', null, 'skills-lock.json', '技能锁缺失或结构不支持;先恢复锁文件或规划迁移');
|
|
129
|
+
if (selected && (!Array.isArray(selected.installedSkills) || !Array.isArray(selected.runtimes) ||
|
|
130
|
+
JSON.stringify([...selected.runtimes.map(runtime => roots[runtime])].sort()) !== JSON.stringify([...(lock?.projectionRoots ?? [])].sort()))) {
|
|
131
|
+
report('distribution-lock-drift', null, '.yss-template.json', '实例元数据与技能锁的运行时或安装清单不一致');
|
|
132
|
+
}
|
|
133
|
+
const inside = (file, directory) => file === directory || file.startsWith(directory + path.sep);
|
|
134
|
+
const realRoot = realpathSync(root);
|
|
135
|
+
function stat(file) {
|
|
136
|
+
// existsSync observes absence; lstat also identifies occupied dangling links.
|
|
137
|
+
existsSync(file);
|
|
138
|
+
return lstatSync(file, { throwIfNoEntry: false });
|
|
139
|
+
}
|
|
140
|
+
function checkedTreeHash(directory, canonical, projection = false) {
|
|
141
|
+
const info = stat(directory);
|
|
142
|
+
if (!info) return null;
|
|
143
|
+
const resolved = realpathSync(directory);
|
|
144
|
+
if (!inside(resolved, realRoot) || (projection && info.isSymbolicLink() && resolved !== realpathSync(canonical)) ||
|
|
145
|
+
(!projection && info.isSymbolicLink()) || (!info.isDirectory() && !info.isSymbolicLink())) {
|
|
146
|
+
throw new TypeError('技能目录或投影链接无效: ' + directory);
|
|
147
|
+
}
|
|
148
|
+
const files = [];
|
|
149
|
+
function walk(current, prefix = '') {
|
|
150
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
151
|
+
if (entry.name === '.DS_Store' || entry.name === '__pycache__' || /\.(iml|pyc|pyo)$/.test(entry.name)) continue;
|
|
152
|
+
const file = path.join(current, entry.name), ref = prefix ? prefix + '/' + entry.name : entry.name;
|
|
153
|
+
const entryInfo = stat(file), real = realpathSync(file);
|
|
154
|
+
if (!inside(real, resolved)) throw new TypeError('技能文件链接越界: ' + ref);
|
|
155
|
+
if (entryInfo.isDirectory()) walk(file, ref);
|
|
156
|
+
else if (entryInfo.isFile() || entryInfo.isSymbolicLink()) files.push([ref, file]);
|
|
157
|
+
else throw new TypeError('技能包含不支持的文件类型: ' + ref);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
walk(directory);
|
|
161
|
+
const digest = createHash('sha256');
|
|
162
|
+
for (const [ref, file] of files.sort(([left], [right]) => left.localeCompare(right))) {
|
|
163
|
+
const bytes = readFileSync(file);
|
|
164
|
+
const normalized = bytes.includes(0) ? bytes : Buffer.from(bytes.toString('utf8').replaceAll('\r\n', '\n'));
|
|
165
|
+
digest.update(ref).update('\0').update(normalized).update('\0');
|
|
166
|
+
}
|
|
167
|
+
return digest.digest('hex');
|
|
168
|
+
}
|
|
169
|
+
for (const id of [...required].sort()) {
|
|
170
|
+
if (issues.some(issue => issue.skill === id)) continue;
|
|
171
|
+
const canonicalRef = '.agents/skills/' + id;
|
|
172
|
+
const canonical = path.join(root, canonicalRef);
|
|
173
|
+
const record = lock?.skills?.shared?.[id];
|
|
174
|
+
const declared = selected?.installedSkills?.includes(id);
|
|
175
|
+
if (!stat(canonical)) {
|
|
176
|
+
const managed = Object.keys(metadata?.managedFiles ?? {}).some(ref => ref.startsWith(canonicalRef + '/'));
|
|
177
|
+
if (record || declared || managed) report('managed-skill-missing', id, canonicalRef, '已登记或受管技能文件丢失;先核对 sync 计划,不能当作未安装补装');
|
|
178
|
+
else {
|
|
179
|
+
const occupied = Object.entries(roots).find(([runtime, ref]) => registeredRuntimes.includes(runtime) && stat(path.join(root, ref, id)));
|
|
180
|
+
if (occupied) report('skill-path-conflict', id, occupied[1] + '/' + id, '同名投影路径已存在但未登记,拒绝覆盖');
|
|
181
|
+
else missing.push(id);
|
|
182
|
+
}
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (!record) {
|
|
186
|
+
report('skill-path-conflict', id, canonicalRef, '同名技能路径存在但未登记,拒绝覆盖');
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (selected && !declared) report('distribution-lock-drift', id, '.yss-template.json', '技能锁与实例安装清单不一致');
|
|
190
|
+
try {
|
|
191
|
+
const hash = checkedTreeHash(canonical, canonical);
|
|
192
|
+
if (!existsSync(path.join(canonical, 'SKILL.md'))) report('managed-skill-missing', id, canonicalRef + '/SKILL.md', '已登记技能缺少入口文件');
|
|
193
|
+
if (hash !== record.effectiveHash) report('skill-hash-drift', id, canonicalRef, 'canonical 技能内容与锁定有效哈希不一致');
|
|
194
|
+
const projectionRef = agentRuntime && roots[agentRuntime];
|
|
195
|
+
if (projectionRef) {
|
|
196
|
+
if (!lock.projectionRoots.includes(projectionRef) || !record.targets?.includes(projectionRef) || !record.targets?.includes('.agents/skills')) {
|
|
197
|
+
report('projection-lock-drift', id, 'skills-lock.json', '所选运行时投影目标与技能锁不一致');
|
|
198
|
+
}
|
|
199
|
+
const projection = path.join(root, projectionRef, id);
|
|
200
|
+
if (checkedTreeHash(projection, canonical, true) !== hash) report('projection-drift', id, projectionRef + '/' + id, '运行时投影缺失或与 canonical 内容不一致');
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
report('skill-path-invalid', id, canonicalRef, error.message);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const canEnsure = metadata?.metadataSchemaVersion === 3 && selected && metadata.templateName === 'create-yss-spec';
|
|
207
|
+
const commandArgs = ['create-yss-spec', 'skills', 'ensure', ...missing.sort(), ...when.flatMap(trigger => ['--when', trigger]), '--target-dir', root];
|
|
208
|
+
const quote = value => /^[a-zA-Z0-9_./:-]+$/.test(value) ? value : "'" + value.replaceAll("'", "'\\''") + "'";
|
|
209
|
+
const command = mode => [...commandArgs, mode].map(quote).join(' ');
|
|
210
|
+
return {
|
|
211
|
+
read_only: true, execution_allowed: false, agent_runtime: agentRuntime ?? null,
|
|
212
|
+
required_skills: [...required].sort(), missing_skills: missing,
|
|
213
|
+
status: issues.length ? 'blocked' : missing.length ? 'missing' : 'ready',
|
|
214
|
+
issues,
|
|
215
|
+
remediation: missing.length && !issues.length ? canEnsure
|
|
216
|
+
? { plan_command: command('--plan'), apply_command: command('--apply'), authorization: 'existing-task-scope-required', recheck_required: true }
|
|
217
|
+
: { plan_command: null, apply_command: null, message: '此实例没有可用的 v3 按需补装元数据;按本家族 CLI 规划同步或迁移,保持现有分发模式' }
|
|
218
|
+
: null,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function querySnapshot({ mode, stageId, workUnitId, include = [], checkSkills = false, agentRuntime, when = [] } = {}) {
|
|
223
|
+
if (checkSkills && !workUnitId) throw new TypeError('--check-skills 必须指定 --work-unit');
|
|
224
|
+
if (!checkSkills && (agentRuntime !== undefined || when.length)) throw new TypeError('--agent-runtime 和 --when 必须与 --check-skills 一起使用');
|
|
225
|
+
if (!Array.isArray(when) || when.some(trigger => typeof trigger !== 'string' || !/^[a-z][a-z0-9-]+$/.test(trigger))) throw new TypeError('--when 必须是有效的条件触发项');
|
|
72
226
|
if (!mode && !stageId && !workUnitId && include.length === 0) {
|
|
73
227
|
throw new TypeError("至少提供 --mode、--stage、--work-unit 或 --include 之一");
|
|
74
228
|
}
|
|
@@ -77,15 +231,15 @@ function querySnapshot({ mode, stageId, workUnitId, include = [] } = {}) {
|
|
|
77
231
|
if (identity.schema_version !== 1 || !["template-source", "project-instance"].includes(identity.repository_mode)) {
|
|
78
232
|
throw new TypeError("仓库身份或版本无效");
|
|
79
233
|
}
|
|
80
|
-
const scope = loadExecutionScope();
|
|
81
|
-
if (workUnitId) assertScopeWorkUnit(workUnitId, { readOnly: true });
|
|
234
|
+
const scope = QUERY_PROFILE === 'lifecycle' ? loadExecutionScope() : null;
|
|
235
|
+
if (workUnitId && QUERY_PROFILE === 'lifecycle') assertScopeWorkUnit(workUnitId, { readOnly: true });
|
|
82
236
|
const lifecycle = validateRegistry(loadRegistry());
|
|
83
237
|
const orchestration = loadYaml(ORCHESTRATION_CONTRACT_REF, "生命周期编排合同");
|
|
84
238
|
const skillRegistry = loadSkillRegistry();
|
|
85
239
|
const planUnit = ['work-unit.plan-opportunity', 'work-unit.plan-requirements', 'work-unit.domain-strategy-design', 'work-unit.stage-decision', 'work-unit.spec-synthesis'].includes(workUnitId);
|
|
86
240
|
const loadPlan = ['stage.plan', 'stage.spec-architecture'].includes(stageId) || planUnit;
|
|
87
241
|
stageId ??= planUnit ? 'stage.plan' : undefined;
|
|
88
|
-
include = [...include, 'gate_consolidation'];
|
|
242
|
+
if (QUERY_PROFILE === 'lifecycle') include = [...include, 'gate_consolidation'];
|
|
89
243
|
if (loadPlan) include = [...include, 'planning', 'grill_exit'];
|
|
90
244
|
const stage = selectById(lifecycle.stages, stageId, "阶段");
|
|
91
245
|
const workUnit = selectById(lifecycle.work_units, workUnitId, "工作单元");
|
|
@@ -97,19 +251,19 @@ function querySnapshot({ mode, stageId, workUnitId, include = [] } = {}) {
|
|
|
97
251
|
}
|
|
98
252
|
|
|
99
253
|
const route = workUnitId ? orchestration.work_unit_routes?.[workUnitId] ?? null : null;
|
|
100
|
-
if (workUnit?.scope === "project-instance" && workUnit.id !== "work-unit.entry-triage" && !route) {
|
|
254
|
+
if (QUERY_PROFILE === 'lifecycle' && workUnit?.scope === "project-instance" && workUnit.id !== "work-unit.entry-triage" && !route) {
|
|
101
255
|
throw new TypeError(`项目工作单元缺少执行路由: ${workUnit.id}`);
|
|
102
256
|
}
|
|
103
|
-
if (workUnit?.scope === "project-instance" && workUnit.id !== "work-unit.entry-triage" && !Object.hasOwn(orchestration.transition_graph?.routes ?? {}, workUnit.id)) {
|
|
257
|
+
if (QUERY_PROFILE === 'lifecycle' && workUnit?.scope === "project-instance" && workUnit.id !== "work-unit.entry-triage" && !Object.hasOwn(orchestration.transition_graph?.routes ?? {}, workUnit.id)) {
|
|
104
258
|
throw new TypeError(`项目工作单元缺少流转路由: ${workUnit.id}`);
|
|
105
259
|
}
|
|
106
260
|
const gates = lifecycle.gates.filter((gate) => gate.stage === stageId || (loadPlan && gate.stage === 'stage.plan'));
|
|
107
|
-
const checks = lifecycle.checks.filter(check => check.stage === stageId || gates.some(gate => gate.requires_checks?.includes(check.id)));
|
|
261
|
+
const checks = QUERY_PROFILE === 'lifecycle' ? lifecycle.checks.filter(check => check.stage === stageId || gates.some(gate => gate.requires_checks?.includes(check.id))) : [];
|
|
108
262
|
const artifacts = lifecycle.artifacts.filter((artifact) => artifact.stage === stageId || (loadPlan && artifact.stage === 'stage.plan'));
|
|
109
263
|
const evidenceIds = new Set([...gates, ...checks].flatMap((gate) => gate.evidence ?? []));
|
|
110
264
|
const selected = Object.fromEntries(normalizedIncludes.map((key) => [key, orchestration[key]]));
|
|
111
265
|
const transition = workUnitId ? {
|
|
112
|
-
next: scopedNextRoutes(workUnitId, orchestration.transition_graph?.routes?.[workUnitId] ?? []),
|
|
266
|
+
next: QUERY_PROFILE === 'lifecycle' ? scopedNextRoutes(workUnitId, orchestration.transition_graph?.routes?.[workUnitId] ?? []) : orchestration.transition_graph?.routes?.[workUnitId] ?? [],
|
|
113
267
|
forbidden_shortcuts: (orchestration.transition_graph?.forbidden_shortcuts ?? [])
|
|
114
268
|
.filter((edge) => edge.from === workUnitId || edge.to === workUnitId),
|
|
115
269
|
} : null;
|
|
@@ -143,10 +297,10 @@ function querySnapshot({ mode, stageId, workUnitId, include = [] } = {}) {
|
|
|
143
297
|
lifecycle: {
|
|
144
298
|
artifacts,
|
|
145
299
|
evidence: lifecycle.evidence.filter((item) => evidenceIds.has(item.id)).map(({ public_description, ...item }) => ({
|
|
146
|
-
...item, description: public_description ?? item.description
|
|
300
|
+
...item, ...(QUERY_PROFILE === 'lifecycle' ? { description: public_description ?? item.description } : public_description ? { public_description } : {})
|
|
147
301
|
})),
|
|
148
302
|
gates,
|
|
149
|
-
checks,
|
|
303
|
+
...(QUERY_PROFILE === 'lifecycle' ? { checks } : {}),
|
|
150
304
|
stage,
|
|
151
305
|
work_unit: workUnit,
|
|
152
306
|
},
|
|
@@ -160,12 +314,19 @@ function querySnapshot({ mode, stageId, workUnitId, include = [] } = {}) {
|
|
|
160
314
|
},
|
|
161
315
|
skills: selectedSkills(route, skillRegistry),
|
|
162
316
|
};
|
|
317
|
+
if (checkSkills) {
|
|
318
|
+
result.query.check_skills = true;
|
|
319
|
+
result.query.when = [...new Set(when)].sort();
|
|
320
|
+
result.skill_readiness = inspectWorkUnitSkills({ registry: skillRegistry, route, agentRuntime, when: result.query.when });
|
|
321
|
+
}
|
|
322
|
+
if (QUERY_PROFILE === 'lifecycle') {
|
|
163
323
|
const presenter = loadLifecyclePresenter(ROOT);
|
|
164
324
|
result.presentation = { read_only: true, execution_allowed: false, approval_validity: 'not-checked',
|
|
165
325
|
names: presenter.catalog(result.lifecycle), sources: presenter.sources, warnings: presenter.warnings };
|
|
166
326
|
// Include role and transition references from the requested contract subtrees as well.
|
|
167
327
|
Object.assign(result.presentation.names, presenter.catalog(result.execution));
|
|
168
328
|
Object.assign(result.presentation.names, presenter.catalog(presenter.roleIds));
|
|
329
|
+
}
|
|
169
330
|
result.references = [...collectPathReferences(result), LIFECYCLE_REGISTRY_REF, ORCHESTRATION_CONTRACT_REF, SKILL_REGISTRY_REF]
|
|
170
331
|
.filter((value, index, all) => all.indexOf(value) === index)
|
|
171
332
|
.sort();
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import { readFileSync } from './validation-phase.mjs';
|
|
1
|
+
import { readFileSync, withValidationPhase } from './validation-phase.mjs';
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { parseDocument } from '../vendor/yaml.mjs';
|
|
5
5
|
import { loadRegistry, ROOT } from './lifecycle-registry.mjs';
|
|
6
6
|
import { loadDigitalHumanRoles, countersignRuleForGate } from './digital-human-roles.mjs';
|
|
7
|
-
import {
|
|
7
|
+
import {loadApprovalRecord} from './approval-record-io.mjs';
|
|
8
|
+
import {assertCurrentApproval, approvalExpectationFromState} from './approval-current.mjs';
|
|
8
9
|
|
|
9
10
|
const fail = message => { throw new TypeError(`lifecycle-control-blocked: ${message}`); };
|
|
10
11
|
|
|
11
12
|
// Checks retain their own evidence and independent review; only the aggregate requests a user decision.
|
|
12
|
-
export function assertGateChecks(gateId, state,
|
|
13
|
+
export function assertGateChecks(gateId, state, options = {}) {
|
|
14
|
+
return withValidationPhase({root:options.root || ROOT,purpose:'current-gate-checks',readOnly:true},()=>validateGateChecks(gateId,state,options));
|
|
15
|
+
}
|
|
16
|
+
function validateGateChecks(gateId, state, { root = ROOT, registry = loadRegistry(), rolesDoc = loadDigitalHumanRoles() } = {}) {
|
|
13
17
|
const gate = registry.gates.find(item => item.id === gateId);
|
|
14
18
|
if (!gate) fail(`未知或已退役门禁: ${gateId}`);
|
|
15
19
|
const controls = new Map(registry.checks.map(item => [item.id, item]));
|
|
@@ -47,12 +51,7 @@ export function assertGateChecks(gateId, state, { root = ROOT, registry = loadRe
|
|
|
47
51
|
if (rule) {
|
|
48
52
|
if (!refs.has(item.approval_ref) || !refs.has(item.subject_ref)) fail(`${id} 未绑定审查与资产`);
|
|
49
53
|
const record = loadApprovalRecord(path.resolve(root, item.approval_ref), id);
|
|
50
|
-
|
|
51
|
-
if (!item.approval_scope?.length || JSON.stringify([...item.approval_scope].sort()) !== JSON.stringify([...(record.approval_scope || [])].sort())) fail(`${id} 审查范围不匹配`);
|
|
52
|
-
const subjectDigest = createHash('sha256').update(readFileSync(path.resolve(root, item.subject_ref))).digest('hex');
|
|
53
|
-
if (record.subject_digest !== subjectDigest) fail(`${id} 审查资产摘要不匹配`);
|
|
54
|
-
validateApprovalRecord(record, { rolesDoc, root, requireApproved: true });
|
|
55
|
-
if (!record.drafter_principal_ref || record.drafter_principal_ref === record.principal_ref) fail(`${id} 缺少独立审查身份或起草者自签`);
|
|
54
|
+
assertCurrentApproval(record,approvalExpectationFromState(id,item,{root}),{rolesDoc,registry,root});
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
for (const id of gate.requires_checks || []) check(id);
|
|
@@ -66,16 +65,7 @@ export function assertGateChecks(gateId, state, { root = ROOT, registry = loadRe
|
|
|
66
65
|
if (approvalRequired) {
|
|
67
66
|
if (!refs.has(item.approval_ref) || !refs.has(item.subject_ref)) fail(`${gateId} 缺少已绑定批准记录和审阅包`);
|
|
68
67
|
const record = loadApprovalRecord(path.resolve(root, item.approval_ref), gateId);
|
|
69
|
-
|
|
70
|
-
const bytes = readFileSync(path.resolve(root, item.subject_ref));
|
|
71
|
-
if (record.subject_ref !== item.subject_ref || record.subject_digest !== createHash('sha256').update(bytes).digest('hex')) fail(`${gateId} 批准依据过期`);
|
|
72
|
-
const document = parseDocument(bytes.toString(), { uniqueKeys: true, maxAliasCount: 0 });
|
|
73
|
-
if (document.errors.length) fail(`${gateId} 审阅包不可解析`);
|
|
74
|
-
const review = document.toJS({ maxAliasCount: 0 });
|
|
75
|
-
if (review?.gate_id !== gateId || !Array.isArray(review.basis)) fail(`${gateId} 审阅包身份或依据缺失`);
|
|
76
|
-
for (const asset of item.basis.filter(asset => ![item.approval_ref, item.subject_ref].includes(asset.ref))) {
|
|
77
|
-
if (!review.basis.some(bound => bound.ref === asset.ref && bound.digest === asset.digest)) fail(`${gateId} 批准范围未覆盖证据: ${asset.ref}`);
|
|
78
|
-
}
|
|
68
|
+
assertCurrentApproval(record,approvalExpectationFromState(gateId,item,{root}),{rolesDoc,registry,root});
|
|
79
69
|
}
|
|
80
70
|
// Bind the aggregate approval to the exact check evidence it covers.
|
|
81
71
|
for (const id of seen) for (const asset of state.checks[id].basis) {
|
|
@@ -64,13 +64,18 @@ export function loadLifecyclePresenter(root) {
|
|
|
64
64
|
export function renderLifecycleStatus(result) {
|
|
65
65
|
const view = result.presentation;
|
|
66
66
|
if (!view) throw Error('缺少状态阅读信息');
|
|
67
|
+
const ownerNote = issue => ({'work-unit': '(工作单元负责人;问题责任方待确认)', 'checkpoint-pause': '(暂停记录责任方;问题责任方待确认)'}[issue.owner_scope] ?? '');
|
|
67
68
|
return [
|
|
68
69
|
`当前阶段:${view.stage}。登记状态:${view.checkpoint_status}。`,
|
|
70
|
+
`下一阶段(路由目标):${view.next_stage ?? '待核验'}。${view.next_stage_reason ?? '阶段归属未核验;不代表已批准或可进入'}。`,
|
|
69
71
|
`当前阻塞:${view.blockers.length ? view.blockers.join(';') : '未登记阻塞;完整就绪与批准仍待核验'}。`,
|
|
72
|
+
...(view.issues ?? []).map((issue, index) => `${index + 1}. ${issue.severity === 'error' ? '阻塞' : '待核验问题'}:${issue.message}\n 负责人:${issue.owner}${ownerNote(issue)};来源:${issue.source_ref ?? '未登记'}\n 处理:${issue.recovery}`),
|
|
70
73
|
`负责人:${view.owner}。`,
|
|
71
74
|
`下一项工作:${view.work_unit}。`,
|
|
72
75
|
...(view.expected_output ? [`预期产出:${view.expected_output}`] : []),
|
|
73
76
|
`下一动作:${view.next_action}。`,
|
|
77
|
+
...(view.pending_verification?.length ? [`待核验:${view.pending_verification.map(item => item.reason).join(';')}。`] : []),
|
|
78
|
+
...(view.continue_conditions?.length ? [`继续条件:${view.continue_conditions.join(';')}。`] : []),
|
|
74
79
|
...view.warnings,
|
|
75
80
|
'本次为只读查询,未核验完整批准或执行授权。',
|
|
76
81
|
].join('\n') + '\n';
|
|
@@ -15,50 +15,97 @@ function parse(bytes) {
|
|
|
15
15
|
return document.toJS({ maxAliasCount: 0 });
|
|
16
16
|
}
|
|
17
17
|
function source(root, ref) {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
try {
|
|
19
|
+
const bytes = readFileSync(safeTrackingPath(root, ref));
|
|
20
|
+
return { value: parse(bytes), digest: sha(bytes) };
|
|
21
|
+
} catch (error) {
|
|
22
|
+
error.lifecycle_input_ref ??= ref;
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
/** Read-only projection; checkpoint, registry and orchestration remain authoritative. */
|
|
23
28
|
export function lifecycleStatus({ root, checkpointRef, taskPackageRef }) {
|
|
24
29
|
if (!root || !checkpointRef) throw new TypeError('root and checkpoint are required');
|
|
25
30
|
root = path.resolve(root);
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
let identity;
|
|
32
|
+
try {
|
|
33
|
+
identity = source(root, 'yss-project.yaml').value;
|
|
34
|
+
if (identity.schema_version !== 1 || identity.repository_mode !== 'project-instance') throw new TypeError('生命周期状态仅适用于 project-instance');
|
|
35
|
+
} catch (error) {
|
|
36
|
+
error.lifecycle_input_ref ??= 'yss-project.yaml';
|
|
37
|
+
error.lifecycle_input_kind = identity?.schema_version === 1 && identity?.repository_mode === 'template-source' ? 'template-source' : 'manifest';
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
28
40
|
const registryRef = '.template-spec/process/lifecycle-registry.yaml';
|
|
29
41
|
const contractRef = orchestrationRef(root);
|
|
30
42
|
const checkpoint = source(root, checkpointRef), registry = source(root, registryRef), contract = source(root, contractRef);
|
|
31
43
|
const value = checkpoint.value;
|
|
44
|
+
const registeredText = value => typeof value === 'string' && value.trim() ? value : null;
|
|
32
45
|
if (value.schema_version !== 1 || value.repository_mode !== 'project-instance') throw new TypeError('checkpoint 身份或版本无效');
|
|
33
46
|
const items = value.stage_tracking?.items ?? [];
|
|
34
47
|
if (!Array.isArray(items)) throw new TypeError('阶段追踪 items 必须为数组');
|
|
35
48
|
const activeItems = items.filter(item => item.work_unit === value.next_work_unit && item.progress !== 'cancelled');
|
|
36
|
-
const
|
|
49
|
+
const pauseOwner = registeredText(value.pause?.owner_or_authority);
|
|
50
|
+
const workUnitOwner = registeredText(activeItems.find(item => item.progress !== 'completed')?.owner);
|
|
51
|
+
const owner = pauseOwner ?? workUnitOwner ?? '未登记';
|
|
52
|
+
const defaultOwnerScope = pauseOwner ? 'checkpoint-pause' : workUnitOwner ? 'work-unit' : 'not-recorded';
|
|
37
53
|
const diagnostics = [], verification_scope = [];
|
|
38
54
|
const check = (id, status, refs, reason) => verification_scope.push({ id, status, refs, reason });
|
|
39
|
-
const issue = (code, message, source_ref, recovery, severity = 'error') => diagnostics.push({ code, message, source_ref, owner, recovery, severity });
|
|
55
|
+
const issue = (code, message, source_ref, recovery, severity = 'error', issueOwner = owner, ownerScope = defaultOwnerScope) => diagnostics.push({ code, message, source_ref, owner: issueOwner, owner_scope: issueOwner === '未登记' ? 'not-recorded' : ownerScope, recovery, severity });
|
|
40
56
|
if (!Object.hasOwn(value, 'blockers')) {
|
|
41
57
|
issue('registered-blockers-missing', 'checkpoint 缺少 blockers;不能据此判定无已登记阻塞', checkpointRef, '核对原始状态并补齐真实阻塞记录后重验');
|
|
42
58
|
} else if (!Array.isArray(value.blockers)) {
|
|
43
59
|
issue('registered-blockers-invalid', 'checkpoint.blockers 必须为数组;当前登记不可核验', checkpointRef, '修复阻塞记录类型,保留原有阻塞内容后重验');
|
|
44
60
|
} else {
|
|
45
61
|
for (const item of value.blockers) {
|
|
46
|
-
|
|
62
|
+
const record = item && typeof item === 'object' && !Array.isArray(item) ? item : {};
|
|
63
|
+
issue('registered-blocker', registeredText(item) ?? registeredText(record.message) ?? registeredText(record.reason) ?? '已登记阻塞,具体问题尚未说明', registeredText(record.source_ref) ?? checkpointRef, registeredText(record.recovery) ?? '核对原阻塞记录、责任方和证据,明确处理动作后复验', 'error', registeredText(record.owner) ?? owner, registeredText(record.owner) ? 'issue' : defaultOwnerScope);
|
|
47
64
|
}
|
|
48
65
|
}
|
|
49
66
|
check('registered-blockers', diagnostics.length ? 'failed' : 'passed', [checkpointRef], '仅读取已登记阻塞,不代表完整就绪');
|
|
50
67
|
const stage = registry.value.stages?.find(item => item.id === value.stage);
|
|
51
68
|
const workUnit = registry.value.work_units?.find(item => item.id === value.next_work_unit);
|
|
69
|
+
// Only explicit recorded associations identify a target stage. Stage order is not a route.
|
|
70
|
+
const stageAssociations = workUnit ? [
|
|
71
|
+
...(registeredText(workUnit?.stage) ? [{stage: workUnit.stage, ref: registryRef}] : []),
|
|
72
|
+
...activeItems.filter(item => registeredText(item.stage)).map(item => ({stage: item.stage, ref: checkpointRef})),
|
|
73
|
+
] : [];
|
|
74
|
+
const stageIds = [...new Set(stageAssociations.map(item => item.stage))];
|
|
75
|
+
const nextStage = stageIds.length === 1 && registry.value.stages?.some(item => item.id === stageIds[0]) ? stageIds[0] : null;
|
|
76
|
+
const nextStageReason = !value.next_work_unit ? '未登记下一工作单元;需核验当前阶段验收与终点,不能据此判定完成'
|
|
77
|
+
: stageIds.length > 1 ? '下一工作单元的已登记阶段归属存在冲突;核对权威记录后重验'
|
|
78
|
+
: stageIds.length === 1 && !nextStage ? '下一工作单元的阶段归属未在注册表中识别;核对当前来源后重验'
|
|
79
|
+
: !nextStage ? '下一工作单元尚未登记阶段归属;核验当前路由与阶段追踪后确认'
|
|
80
|
+
: nextStage === value.stage ? '下一工作单元仍在当前阶段,先完成当前单元并验收,再核验后续流转;不代表已批准或可进入'
|
|
81
|
+
: '来自下一工作单元的已登记阶段归属,仅为路由目标,不代表已批准或可进入';
|
|
82
|
+
check('next-stage-association', nextStage ? 'passed' : 'not-checked', [...new Set(stageAssociations.map(item => item.ref))], nextStageReason);
|
|
83
|
+
if (stageIds.length > 1 || (stageIds.length === 1 && !nextStage)) issue('next-stage-unverifiable', nextStageReason, checkpointRef, '核对下一工作单元的已登记阶段归属并执行适用预检,不按阶段顺序猜目标', 'warning');
|
|
52
84
|
if (!stage) issue('unknown-stage', `未知阶段: ${value.stage}`, registryRef, '按注册表核对当前阶段');
|
|
53
85
|
if (value.next_work_unit && !workUnit) issue('unknown-work-unit', `未知下一工作单元: ${value.next_work_unit}`, registryRef, '按注册表核对下一工作单元');
|
|
54
86
|
if (workUnit && workUnit.id !== 'work-unit.entry-triage' && !contract.value.work_unit_routes?.[workUnit.id]) issue('missing-route', `缺少执行路由: ${workUnit.id}`, contractRef, '修复当前合同路由后重验');
|
|
55
87
|
check('stage-and-route', diagnostics.some(x => ['unknown-stage', 'unknown-work-unit', 'missing-route'].includes(x.code)) ? 'failed' : 'passed', [registryRef, contractRef], '仅检查身份与路由存在,不计算完整 frontier');
|
|
56
88
|
if (value.context_reconciliation?.status === 'blocked') issue('context-blocked', '术语对账受阻', checkpointRef, '修复词汇对账并执行适用校验');
|
|
57
89
|
check('context-reconciliation', value.context_reconciliation?.status === 'blocked' ? 'failed' : 'not-checked', [value.context_reconciliation?.ref].filter(Boolean), '读取登记状态;当前对账内容和摘要仍须由原验证器核验');
|
|
58
|
-
|
|
59
|
-
|
|
90
|
+
const gateNames = {blocked: '受阻', stale: '依据已过期', pending: '等待处理', failed: '未通过', 'ready-for-human': '等待会签', 'not-evaluated': '尚未评估'};
|
|
91
|
+
const gates = value.gates && typeof value.gates === 'object' && !Array.isArray(value.gates) ? Object.entries(value.gates) : [];
|
|
92
|
+
if (!Object.hasOwn(value, 'gates') || !value.gates || typeof value.gates !== 'object' || Array.isArray(value.gates)) issue('gates-unverifiable', '门禁登记缺失或格式不可核验', checkpointRef, '核对原始门禁记录并执行正式预检', 'warning');
|
|
93
|
+
for (const [id, gate] of gates) {
|
|
94
|
+
const status = gateNames[gate?.status];
|
|
95
|
+
const hardBlocked = ['blocked', 'stale'].includes(gate?.status);
|
|
96
|
+
const failed = hardBlocked || (['pending', 'failed', 'ready-for-human', 'not-evaluated'].includes(gate?.status) && gate?.applicable === true);
|
|
97
|
+
if (status) {
|
|
98
|
+
const blocked = hardBlocked || (failed && gate?.applicable !== false);
|
|
99
|
+
const reason = registeredText(gate?.reason);
|
|
100
|
+
const applicability = hardBlocked && gate?.applicable === false ? ';登记状态与适用性标记冲突,需正式预检' : blocked ? '' : ';适用性与当前处理要求待核验';
|
|
101
|
+
const recovery = registeredText(gate?.recovery) ?? (['pending', 'ready-for-human'].includes(gate?.status) ? '核对适用范围、当前资产和已登记责任方;取得所需真实决定或有效延续后复验' : '核对适用范围、失败原因或过期依据,修复并重验受影响检查与批准');
|
|
102
|
+
issue(blocked ? 'gate-blocked' : 'gate-unverified', `${id}:${status}${reason ? `;${reason}` : ''}${applicability}`, checkpointRef, hardBlocked && gate?.applicable === false ? `${recovery};保留阻断状态,核对冲突登记并执行正式预检` : recovery, blocked ? 'error' : 'warning', registeredText(gate?.owner) ?? owner, registeredText(gate?.owner) ? 'issue' : defaultOwnerScope);
|
|
103
|
+
} else if (!['approved', 'not-applicable'].includes(gate?.status)) {
|
|
104
|
+
issue('gate-unverified', `${id}:登记状态未识别,适用性与处理要求待核验`, checkpointRef, '保留原记录,核对门禁状态与适用性后执行正式预检', 'warning', registeredText(gate?.owner) ?? owner, registeredText(gate?.owner) ? 'issue' : defaultOwnerScope);
|
|
105
|
+
}
|
|
60
106
|
}
|
|
61
|
-
|
|
107
|
+
const gateDiagnostics = diagnostics.filter(x => ['gate-blocked', 'gate-unverified', 'gates-unverifiable'].includes(x.code));
|
|
108
|
+
check('registered-gates', gateDiagnostics.some(x => x.severity === 'error') ? 'failed' : gateDiagnostics.length || !gates.length ? 'not-checked' : 'passed', [checkpointRef], '仅读取已登记状态;适用性未登记、待处理或记录缺失时不能判定门禁通过;不核验完整批准');
|
|
62
109
|
const evidenceRefs = [value.context_reconciliation?.ref, ...Object.values(value.artifacts ?? {}).filter(item => item?.status === 'approved').map(item => item.ref)].filter(Boolean);
|
|
63
110
|
for (const ref of evidenceRefs) {
|
|
64
111
|
try { readFileSync(safeTrackingPath(root, ref)); }
|
|
@@ -149,17 +196,21 @@ export function lifecycleStatus({ root, checkpointRef, taskPackageRef }) {
|
|
|
149
196
|
const presentation = {
|
|
150
197
|
read_only: true, execution_allowed: false, approval_validity: 'not-checked',
|
|
151
198
|
stage: value.stage ? presenter.label(value.stage, {trace: false}) : '未登记',
|
|
199
|
+
next_stage: nextStage ? presenter.label(nextStage, {trace: false}) : '待核验', next_stage_reason: readable(nextStageReason),
|
|
152
200
|
checkpoint_status: Object.hasOwn(statusNames, value.status) ? statusNames[value.status] : `未识别状态(${value.status ?? '未登记'})`,
|
|
153
201
|
work_unit: value.next_work_unit ? presenter.label(value.next_work_unit, {trace: false}) : '未登记',
|
|
154
202
|
owner: presenter.text(owner, {trace: false}), blockers: blockers.map(readable),
|
|
203
|
+
issues: diagnostics.map(item => ({code: item.code, severity: item.severity, message: readable(item.message), source_ref: item.source_ref, owner: presenter.text(item.owner, {trace: false}), owner_scope: item.owner_scope, recovery: readable(item.recovery)})),
|
|
204
|
+
pending_verification: verification_scope.filter(item => !['passed', 'failed'].includes(item.status)).map(item => ({id: item.id, reason: readable(item.reason), refs: item.refs})),
|
|
205
|
+
continue_conditions: [...(registeredText(value.pause?.resume_condition) ? [readable(value.pause.resume_condition)] : []), ...next_step.prerequisites.map(readable), ...(blockers.length ? ['逐项处理当前阻塞,并由适用验证器确认恢复条件满足'] : []), '由主控验收当前证据并核验授权后决定继续或重新路由'],
|
|
155
206
|
expected_output: workUnit ? readable(workUnit.public_output ?? workUnit.output ?? '产出说明未登记') : null,
|
|
156
207
|
next_action: readable(next_action), sources: presenter.sources, warnings: presenter.warnings,
|
|
157
|
-
names: presenter.catalog({stage: value.stage, work_unit: value.next_work_unit, owner, gates: value.gates, artifacts: value.artifacts}),
|
|
208
|
+
names: presenter.catalog({stage: value.stage, next_stage: nextStage, work_unit: value.next_work_unit, owner, gates: value.gates, artifacts: value.artifacts}),
|
|
158
209
|
};
|
|
159
210
|
return {
|
|
160
211
|
presentation,
|
|
161
212
|
decomposition: {business, implementation: {status:implementationArtifact?'recorded':'not-recorded',recorded_status:implementationArtifact?.status??null,ref:implementationArtifact?.ref??null,coverage:implementationCoverage}, readiness:{status:'not-evaluated',reason:'阶段工作完成不替代批准与实现就绪校验'}},
|
|
162
|
-
schema_version: 1, read_only: true, stage: value.stage, checkpoint_status: value.status,
|
|
213
|
+
schema_version: 1, read_only: true, stage: value.stage, next_stage: nextStage, next_stage_reason: nextStageReason, next_stage_source_refs: [...new Set(stageAssociations.map(item => item.ref))], checkpoint_status: value.status,
|
|
163
214
|
work_unit: value.next_work_unit ?? null, owner, blockers, next_action,
|
|
164
215
|
execution_authorization: 'not-evaluated', verification_scope, diagnostics, next_step, recovery,
|
|
165
216
|
reading_views: checkReadingViews(root,checkpointRef),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {approvalExpectationForBoundAsset} from './approval-consumption.mjs';
|
|
1
2
|
import { assertBusinessApprovalBasis } from './business-ticket-lifecycle.mjs';
|
|
2
3
|
import { assertBusinessTicketTransition, assertImplementationTicket } from './business-tickets.mjs';
|
|
3
4
|
import {assertReadingTransition} from './reading-view-bundle.mjs';
|
|
@@ -233,7 +234,7 @@ function backendDesignPrerequisitesReady(prerequisites, exists, root, projectId)
|
|
|
233
234
|
? prerequisites.engineering_contract_approval_ref
|
|
234
235
|
: path.resolve(root, prerequisites.engineering_contract_approval_ref);
|
|
235
236
|
const approval = loadApprovalRecord(approvalFile, 'gate.engineering-contract-approved');
|
|
236
|
-
validateApprovalRecord(approval, { requireApproved: true, root });
|
|
237
|
+
validateApprovalRecord(approval, { requireApproved: true, root, expected: approvalExpectationForBoundAsset('gate.engineering-contract-approved',prerequisites.technical_design,{root}) });
|
|
237
238
|
if (approval.gate_id !== "gate.engineering-contract-approved" || !approval.approval_scope?.includes(projectId)) return false;
|
|
238
239
|
if (!approvalHasBinding(approval, technical.expected) || !approvalHasBinding(approval, data.expected)) return false;
|
|
239
240
|
if (!approvalHasBinding(approval, { id: api.decision.decision_id, version: api.decision.decision_version, digest: prerequisites.api_contract_decision.digest })) return false;
|
|
@@ -2,11 +2,11 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { resolveMaintenanceOutput, resolveMaintenanceLocation, maintenanceReference, resolveMaintenanceReference, resolveMaintenanceBundleFile } from './maintenance-storage.mjs';
|
|
5
6
|
import { parseDocument, stringify } from "../vendor/yaml.mjs";
|
|
6
7
|
|
|
7
8
|
const MAGIC = Buffer.from("YSS-WORKTREE-CANDIDATE-V1\0", "ascii");
|
|
8
9
|
const MAX_BUFFER = 512 * 1024 * 1024;
|
|
9
|
-
const MAINTENANCE_EVIDENCE_ROOT = ".template-source/evidence/maintenance";
|
|
10
10
|
const CANDIDATE_FILES = ["candidate-manifest.yaml", "candidate.bin", "tracked.diff"];
|
|
11
11
|
|
|
12
12
|
function fail(message) { throw new TypeError(message); }
|
|
@@ -25,15 +25,6 @@ function splitNull(buffer) {
|
|
|
25
25
|
if (start < buffer.length) result.push(buffer.subarray(start));
|
|
26
26
|
return result;
|
|
27
27
|
}
|
|
28
|
-
function normalizeRelative(value, label) {
|
|
29
|
-
ensure(typeof value === "string" && value.trim(), `${label} 不能为空`);
|
|
30
|
-
const normalized = value.replaceAll("\\", "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
31
|
-
ensure(normalized && !path.posix.isAbsolute(normalized) && path.posix.normalize(normalized) === normalized && normalized !== ".." && !normalized.startsWith("../"), `${label} 必须是规范的仓库内相对路径`);
|
|
32
|
-
return normalized;
|
|
33
|
-
}
|
|
34
|
-
function isMaintenanceEvidencePath(value) {
|
|
35
|
-
return value === MAINTENANCE_EVIDENCE_ROOT || value.startsWith(`${MAINTENANCE_EVIDENCE_ROOT}/`);
|
|
36
|
-
}
|
|
37
28
|
function readLength(buffer, offset, bytes, label) {
|
|
38
29
|
ensure(offset + bytes <= buffer.length, `packed candidate 缺少 ${label}`);
|
|
39
30
|
const value = bytes === 8 ? buffer.readBigUInt64BE(offset) : BigInt(buffer.readUInt32BE(offset));
|
|
@@ -43,21 +34,14 @@ function readLength(buffer, offset, bytes, label) {
|
|
|
43
34
|
|
|
44
35
|
export function captureMaintenanceCandidate({ root, outputDir, baseRef = "HEAD", excludePaths = [] }) {
|
|
45
36
|
const repositoryRoot = path.resolve(root);
|
|
46
|
-
const outputPath =
|
|
47
|
-
const outputRelative =
|
|
48
|
-
ensure(isMaintenanceEvidencePath(outputRelative), `outputDir 必须位于 ${MAINTENANCE_EVIDENCE_ROOT}`);
|
|
37
|
+
const outputPath = resolveMaintenanceOutput(outputDir, { root: repositoryRoot });
|
|
38
|
+
const outputRelative = maintenanceReference(outputPath, { root: repositoryRoot });
|
|
49
39
|
ensure(!existsSync(outputPath), "outputDir 必须不存在,禁止复用可能含残留文件的候选目录");
|
|
50
40
|
ensure(Array.isArray(excludePaths), "excludePaths 必须是数组");
|
|
51
|
-
|
|
52
|
-
for (const exclusion of explicitExclusions) ensure(isMaintenanceEvidencePath(exclusion), `excludePaths 只允许 ${MAINTENANCE_EVIDENCE_ROOT} 下的维护证据`);
|
|
53
|
-
const exclusions = [...new Set([outputRelative, ...explicitExclusions])];
|
|
41
|
+
ensure(excludePaths.length === 0, "excludePaths 已退役;新候选必须完整捕获,维护材料请保存到仓外");
|
|
54
42
|
const mergeBase = git(["merge-base", baseRef, "HEAD"], repositoryRoot).trim();
|
|
55
43
|
const trackedDiff = git(["diff", "--no-ext-diff", "--binary", "--full-index", mergeBase], repositoryRoot, null);
|
|
56
44
|
const rawPaths = splitNull(git(["ls-files", "-z", "--others", "--exclude-standard"], repositoryRoot, null))
|
|
57
|
-
.filter((rawPath) => {
|
|
58
|
-
const value = rawPath.toString();
|
|
59
|
-
return !exclusions.some((exclusion) => value === exclusion || value.startsWith(`${exclusion}/`));
|
|
60
|
-
})
|
|
61
45
|
.sort(Buffer.compare);
|
|
62
46
|
ensure(trackedDiff.length > 0 || rawPaths.length > 0, "维护候选不能为空");
|
|
63
47
|
|
|
@@ -81,11 +65,13 @@ export function captureMaintenanceCandidate({ root, outputDir, baseRef = "HEAD",
|
|
|
81
65
|
}
|
|
82
66
|
const stream = Buffer.concat(parts);
|
|
83
67
|
const digest = createHash("sha256").update(stream).digest("hex");
|
|
84
|
-
const streamRef =
|
|
85
|
-
const diffRef =
|
|
68
|
+
const streamRef = 'candidate.bin';
|
|
69
|
+
const diffRef = 'tracked.diff';
|
|
86
70
|
const manifestRef = `${outputRelative}/candidate-manifest.yaml`;
|
|
87
71
|
const manifest = {
|
|
88
|
-
schema_version:
|
|
72
|
+
schema_version: 2,
|
|
73
|
+
reference_base: 'bundle',
|
|
74
|
+
workspace_id: resolveMaintenanceLocation({ root: repositoryRoot }).workspaceId,
|
|
89
75
|
candidate_kind: "yss-worktree-candidate-v1",
|
|
90
76
|
storage: "packed-stream",
|
|
91
77
|
review_mode: "worktree",
|
|
@@ -99,7 +85,7 @@ export function captureMaintenanceCandidate({ root, outputDir, baseRef = "HEAD",
|
|
|
99
85
|
untracked_diff_command: "packed in candidate.bin",
|
|
100
86
|
untracked_files: untrackedFiles,
|
|
101
87
|
untracked_path_bytes: untrackedPathBytes,
|
|
102
|
-
excluded_paths:
|
|
88
|
+
excluded_paths: [],
|
|
103
89
|
snapshot_stream_ref: streamRef,
|
|
104
90
|
tracked_diff_ref: diffRef,
|
|
105
91
|
commit_list_command: `git log ${baseRef}..HEAD --oneline`
|
|
@@ -115,10 +101,10 @@ export function captureMaintenanceCandidate({ root, outputDir, baseRef = "HEAD",
|
|
|
115
101
|
} finally {
|
|
116
102
|
if (existsSync(stagingPath)) rmSync(stagingPath, { recursive: true, force: true });
|
|
117
103
|
}
|
|
118
|
-
return { candidate_digest: digest, manifest, manifest_ref: manifestRef, files: [manifestRef, streamRef
|
|
104
|
+
return { candidate_digest: digest, manifest, manifest_ref: manifestRef, files: [manifestRef, `${outputRelative}/${streamRef}`, `${outputRelative}/${diffRef}`] };
|
|
119
105
|
}
|
|
120
106
|
|
|
121
|
-
export function inspectMaintenanceCandidate({ manifestPath }) {
|
|
107
|
+
export function inspectMaintenanceCandidate({ manifestPath, root: repositoryRoot = process.cwd() }) {
|
|
122
108
|
const absoluteManifest = path.resolve(manifestPath);
|
|
123
109
|
const document = parseDocument(readFileSync(absoluteManifest, "utf8"), { uniqueKeys: true });
|
|
124
110
|
ensure(document.errors.length === 0, document.errors[0]?.message || "candidate manifest 无法解析");
|
|
@@ -126,10 +112,18 @@ export function inspectMaintenanceCandidate({ manifestPath }) {
|
|
|
126
112
|
ensure(manifest.storage === "packed-stream", "只支持 packed-stream candidate");
|
|
127
113
|
const candidateDir = path.dirname(absoluteManifest);
|
|
128
114
|
ensure(JSON.stringify(readdirSync(candidateDir).sort()) === JSON.stringify([...CANDIDATE_FILES].sort()), `packed candidate 目录必须恰好包含 ${CANDIDATE_FILES.join("、")}`);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
115
|
+
ensure([1, 2].includes(manifest.schema_version), 'candidate manifest schema 不支持');
|
|
116
|
+
const external = manifest.schema_version === 2;
|
|
117
|
+
if (external) {
|
|
118
|
+
ensure(Array.isArray(manifest.excluded_paths) && manifest.excluded_paths.length === 0, 'v2 候选不允许旧档案排除白名单');
|
|
119
|
+
ensure(manifest.reference_base === 'bundle', 'candidate reference_base 必须为 bundle');
|
|
120
|
+
ensure(manifest.workspace_id === resolveMaintenanceLocation({ root: repositoryRoot }).workspaceId, '候选不属于当前工作区');
|
|
121
|
+
ensure(resolveMaintenanceReference(manifest.candidate_snapshot_ref, { root: repositoryRoot }) === absoluteManifest, 'candidate_snapshot_ref 未绑定当前 manifest');
|
|
122
|
+
}
|
|
123
|
+
const root = external ? candidateDir : path.resolve(candidateDir, ...Array(manifest.candidate_snapshot_ref.split('/').length - 1).fill('..'));
|
|
124
|
+
if (!external) ensure(path.resolve(root, manifest.candidate_snapshot_ref) === absoluteManifest, 'candidate_snapshot_ref 未绑定当前 manifest');
|
|
125
|
+
const streamPath = external ? resolveMaintenanceBundleFile(candidateDir, manifest.snapshot_stream_ref) : path.resolve(root, manifest.snapshot_stream_ref);
|
|
126
|
+
const diffPath = external ? resolveMaintenanceBundleFile(candidateDir, manifest.tracked_diff_ref) : path.resolve(root, manifest.tracked_diff_ref);
|
|
133
127
|
ensure(streamPath === path.join(candidateDir, "candidate.bin") && diffPath === path.join(candidateDir, "tracked.diff"), "packed candidate 引用必须绑定同目录规范文件");
|
|
134
128
|
const stream = readFileSync(streamPath);
|
|
135
129
|
ensure(createHash("sha256").update(stream).digest("hex") === manifest.candidate_digest.replace(/^sha256:/, ""), "candidate_digest 与 packed stream 不一致");
|