create-yss-spec 3.4.8 → 3.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/template/attach-planner.js +5 -0
- package/src/template/sync-planner.js +5 -0
- package/template/.agents/skills/.strategic-design-skills-manifest.json +5 -5
- package/template/.agents/skills/alibaba-java-code-style/SKILL.md +2 -2
- package/template/.agents/skills/archify/SKILL.md +2 -19
- package/template/.agents/skills/archify/references/geometry-and-routing.md +20 -0
- package/template/.agents/skills/code-review/SKILL.md +3 -33
- package/template/.agents/skills/code-review/references/candidate-capture.md +33 -0
- package/template/.agents/skills/code-review/references/yss-review-standards.md +3 -5
- package/template/.agents/skills/codebase-design/SKILL.md +2 -2
- package/template/.agents/skills/competitive-intelligence/SKILL.md +1 -1
- package/template/.agents/skills/diagnosing-bugs/SKILL.md +6 -2
- package/template/.agents/skills/formily-foundation/SKILL.md +1 -1
- package/template/.agents/skills/formily-step-flow/SKILL.md +3 -2
- package/template/.agents/skills/frontend-commit/SKILL.md +6 -6
- package/template/.agents/skills/grilling/SKILL.md +2 -2
- package/template/.agents/skills/implement/SKILL.md +1 -1
- package/template/.agents/skills/implementation-repo-onboarding/SKILL.md +3 -3
- package/template/.agents/skills/implementation-repo-onboarding/references/write-scope.md +5 -0
- package/template/.agents/skills/improve-codebase-architecture/SKILL.md +10 -6
- package/template/.agents/skills/java-backend-commit/SKILL.md +5 -5
- package/template/.agents/skills/llm-wiki/SKILL.md +1 -1
- package/template/.agents/skills/prototype/SKILL.md +1 -1
- package/template/.agents/skills/prototype-review/SKILL.md +1 -1
- package/template/.agents/skills/resolving-merge-conflicts/SKILL.md +2 -2
- package/template/.agents/skills/tdd/SKILL.md +1 -1
- package/template/.agents/skills/to-questionnaire/SKILL.md +4 -2
- package/template/.agents/skills/to-spec/SKILL.md +3 -3
- package/template/.agents/skills/to-tickets/SKILL.md +7 -7
- package/template/.agents/skills/using-git-worktrees/SKILL.md +13 -11
- package/template/.agents/skills/wait-what/SKILL.md +1 -1
- package/template/.agents/skills/wayfinder/SKILL.md +4 -2
- package/template/.agents/skills/writing-for-agents/SKILL.md +9 -73
- package/template/.agents/skills/writing-for-agents/references/writing-principles.md +76 -0
- package/template/.agents/skills/yss-api-integration/SKILL.md +2 -2
- package/template/.agents/skills/yss-application/SKILL.md +12 -0
- package/template/.agents/skills/yss-audit-log/SKILL.md +3 -1
- package/template/.agents/skills/yss-audit-log/assets/AuditLogAspect.java +1 -0
- package/template/.agents/skills/yss-audit-log/assets/YssAuditLogPrintSubscriberImpl.java +1 -0
- package/template/.agents/skills/yss-audit-log/assets/YssAuditLogSysManagerSubscriberImpl.java +1 -0
- package/template/.agents/skills/yss-audit-log/assets/YssAuditPublishService.java +1 -0
- package/template/.agents/skills/yss-backend-spec-review/SKILL.md +6 -0
- package/template/.agents/skills/yss-backend-spec-review/references/check-inputs.md +2 -2
- package/template/.agents/skills/yss-backend-spec-review/references/standards-coverage.md +39 -0
- package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +5 -34
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/command-examples.md +32 -0
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/generator-maintenance.md +7 -0
- package/template/.agents/skills/yss-design-system/SKILL.md +2 -2
- package/template/.agents/skills/yss-domain/SKILL.md +17 -5
- package/template/.agents/skills/yss-domain/references/domain-layer-guide.md +2 -2
- package/template/.agents/skills/yss-domain/references/existing-project.md +5 -0
- package/template/.agents/skills/yss-dto/SKILL.md +13 -10
- package/template/.agents/skills/yss-dto/references/wire-validation-checklist.md +14 -0
- package/template/.agents/skills/yss-exception/SKILL.md +2 -2
- package/template/.agents/skills/yss-formily-schema-generator/SKILL.md +12 -12
- package/template/.agents/skills/yss-hook/SKILL.md +8 -44
- package/template/.agents/skills/yss-hook/references/use-request.md +42 -0
- package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +3 -5
- package/template/.agents/skills/yss-implementation-contract-compiler/references/strategic-handoff-routing.md +7 -0
- package/template/.agents/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +5 -1
- package/template/.agents/skills/yss-layered-mvc-scaffold-generator/SKILL.md +2 -2
- package/template/.agents/skills/yss-mybatis/SKILL.md +10 -0
- package/template/.agents/skills/yss-openapi-draft-review/SKILL.md +3 -1
- package/template/.agents/skills/yss-openapi-governance/SKILL.md +5 -32
- package/template/.agents/skills/yss-openapi-governance/references/governance-output.md +34 -0
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +12 -6
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +63 -1
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.agents/skills/yss-prototype-stage/SKILL.md +3 -5
- package/template/.agents/skills/yss-prototype-stage/references/existing-ui-entry.md +7 -0
- package/template/.agents/skills/yss-prototype-stage/scripts/visual-baseline-contract.mjs +2 -2
- package/template/.agents/skills/yss-repository/SKILL.md +13 -1
- package/template/.agents/skills/yss-repository/references/profiles/existing-domain-driven-maven.md +7 -0
- package/template/.agents/skills/yss-repository/references/profiles/existing-layered-mvc-maven.md +7 -0
- package/template/.agents/skills/yss-repository/tests/profile-routing.test.mjs +3 -1
- package/template/.agents/skills/yss-stage-decision/SKILL.md +3 -1
- package/template/.agents/skills/yss-stage-decision/references/strategic-handoff-routing.md +3 -0
- package/template/.agents/skills/yss-tactical-design/SKILL.md +3 -3
- package/template/.agents/skills/yss-tactical-design/references/strategic-handoff-routing.md +5 -0
- package/template/.agents/skills/yss-technical-design/SKILL.md +2 -0
- package/template/.agents/skills/yss-technical-design/scripts/engineering-design.mjs +1 -1
- package/template/.agents/skills/yss-technical-design/scripts/validate-technical-design.mjs +11 -8
- package/template/.agents/skills/yss-ui-business-page-generation/SKILL.md +5 -3
- package/template/.agents/skills/yss-validation/SKILL.md +1 -1
- package/template/.agents/skills/yss-web-controller/SKILL.md +16 -7
- package/template/.agents/skills/ytable-usage/SKILL.md +2 -2
- package/template/.codex/skills/alibaba-java-code-style/SKILL.md +2 -2
- package/template/.codex/skills/archify/SKILL.md +2 -19
- package/template/.codex/skills/archify/references/geometry-and-routing.md +20 -0
- package/template/.codex/skills/code-review/SKILL.md +3 -33
- package/template/.codex/skills/code-review/references/candidate-capture.md +33 -0
- package/template/.codex/skills/code-review/references/yss-review-standards.md +3 -5
- package/template/.codex/skills/codebase-design/SKILL.md +2 -2
- package/template/.codex/skills/competitive-intelligence/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/mcp/server.cjs +2 -1
- package/template/.codex/skills/data-analytics/skills/analyze-data-quality/SKILL.md +9 -32
- package/template/.codex/skills/data-analytics/skills/analyze-data-quality/references/quality-checks.md +29 -0
- package/template/.codex/skills/data-analytics/skills/build-dashboard/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/build-report/SKILL.md +4 -4
- package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/SKILL.md +12 -22
- package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/cli.py +5 -10
- package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/plan.py +47 -49
- package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/tests/test_delivery_plan.py +45 -0
- package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/SKILL.md +4 -5
- package/template/.codex/skills/data-analytics/skills/build-report/report-to-pdf/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/build-report/specifications/mcp-app-report.md +1 -1
- package/template/.codex/skills/data-analytics/skills/design-kpis/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/gather-business-context/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/index/SKILL.md +4 -4
- package/template/.codex/skills/data-analytics/skills/jupyter-notebooks/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/kpi-reporting/SKILL.md +2 -2
- package/template/.codex/skills/data-analytics/skills/market-sizing/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/metric-diagnostics/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/product-business-analysis/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/spreadsheets/SKILL.md +4 -4
- package/template/.codex/skills/data-analytics/skills/user-context/SKILL.md +16 -14
- package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/automation-config.md +1 -1
- package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding-examples.md +1 -1
- package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding.md +7 -7
- package/template/.codex/skills/data-analytics/skills/user-context/references/source-category-runtime.md +7 -7
- package/template/.codex/skills/data-analytics/skills/user-context/scripts/data_analytics_preflight.py +4 -2
- package/template/.codex/skills/data-analytics/skills/user-context/scripts/validate_user_context_preflight.py +5 -5
- package/template/.codex/skills/data-analytics/skills/user-context/tests/test_state_helpers.py +3 -3
- package/template/.codex/skills/data-analytics/skills/validate-data/SKILL.md +7 -71
- package/template/.codex/skills/data-analytics/skills/validate-data/references/validation-methods.md +70 -0
- package/template/.codex/skills/data-analytics/skills/visualize-data/SKILL.md +4 -4
- package/template/.codex/skills/data-analytics/src/analytics-app/App.tsx +1 -1
- package/template/.codex/skills/data-analytics/src/analytics-app-core.md +1 -1
- package/template/.codex/skills/diagnosing-bugs/SKILL.md +6 -2
- package/template/.codex/skills/formily-foundation/SKILL.md +1 -1
- package/template/.codex/skills/formily-step-flow/SKILL.md +3 -2
- package/template/.codex/skills/frontend-commit/SKILL.md +6 -6
- package/template/.codex/skills/grilling/SKILL.md +2 -2
- package/template/.codex/skills/implement/SKILL.md +1 -1
- package/template/.codex/skills/implementation-repo-onboarding/SKILL.md +3 -3
- package/template/.codex/skills/implementation-repo-onboarding/references/write-scope.md +5 -0
- package/template/.codex/skills/improve-codebase-architecture/SKILL.md +10 -6
- package/template/.codex/skills/java-backend-commit/SKILL.md +5 -5
- package/template/.codex/skills/llm-wiki/SKILL.md +1 -1
- package/template/.codex/skills/product-design/references/critical-overrides.md +3 -4
- package/template/.codex/skills/product-design/skills/audit/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/design-qa/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/get-context/SKILL.md +2 -1
- package/template/.codex/skills/product-design/skills/ideate/SKILL.md +2 -50
- package/template/.codex/skills/product-design/skills/ideate/references/image-prompt-patterns.md +51 -0
- package/template/.codex/skills/product-design/skills/image-to-code/SKILL.md +6 -6
- package/template/.codex/skills/product-design/skills/index/SKILL.md +2 -2
- package/template/.codex/skills/product-design/skills/prototype/SKILL.md +6 -6
- package/template/.codex/skills/product-design/skills/url-to-code/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/user-context/SKILL.md +1 -1
- package/template/.codex/skills/prototype/SKILL.md +1 -1
- package/template/.codex/skills/prototype-review/SKILL.md +1 -1
- package/template/.codex/skills/resolving-merge-conflicts/SKILL.md +2 -2
- package/template/.codex/skills/tdd/SKILL.md +1 -1
- package/template/.codex/skills/to-questionnaire/SKILL.md +4 -2
- package/template/.codex/skills/to-spec/SKILL.md +3 -3
- package/template/.codex/skills/to-tickets/SKILL.md +7 -7
- package/template/.codex/skills/using-git-worktrees/SKILL.md +13 -11
- package/template/.codex/skills/wait-what/SKILL.md +1 -1
- package/template/.codex/skills/wayfinder/SKILL.md +4 -2
- package/template/.codex/skills/writing-for-agents/SKILL.md +9 -73
- package/template/.codex/skills/writing-for-agents/references/writing-principles.md +76 -0
- package/template/.codex/skills/yss-api-integration/SKILL.md +2 -2
- package/template/.codex/skills/yss-application/SKILL.md +12 -0
- package/template/.codex/skills/yss-audit-log/SKILL.md +3 -1
- package/template/.codex/skills/yss-audit-log/assets/AuditLogAspect.java +1 -0
- package/template/.codex/skills/yss-audit-log/assets/YssAuditLogPrintSubscriberImpl.java +1 -0
- package/template/.codex/skills/yss-audit-log/assets/YssAuditLogSysManagerSubscriberImpl.java +1 -0
- package/template/.codex/skills/yss-audit-log/assets/YssAuditPublishService.java +1 -0
- package/template/.codex/skills/yss-backend-spec-review/SKILL.md +6 -0
- package/template/.codex/skills/yss-backend-spec-review/references/check-inputs.md +2 -2
- package/template/.codex/skills/yss-backend-spec-review/references/standards-coverage.md +39 -0
- package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +5 -34
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/command-examples.md +32 -0
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/generator-maintenance.md +7 -0
- package/template/.codex/skills/yss-design-system/SKILL.md +2 -2
- package/template/.codex/skills/yss-domain/SKILL.md +17 -5
- package/template/.codex/skills/yss-domain/references/domain-layer-guide.md +2 -2
- package/template/.codex/skills/yss-domain/references/existing-project.md +5 -0
- package/template/.codex/skills/yss-dto/SKILL.md +13 -10
- package/template/.codex/skills/yss-dto/references/wire-validation-checklist.md +14 -0
- package/template/.codex/skills/yss-exception/SKILL.md +2 -2
- package/template/.codex/skills/yss-formily-schema-generator/SKILL.md +12 -12
- package/template/.codex/skills/yss-hook/SKILL.md +8 -44
- package/template/.codex/skills/yss-hook/references/use-request.md +42 -0
- package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +3 -5
- package/template/.codex/skills/yss-implementation-contract-compiler/references/strategic-handoff-routing.md +7 -0
- package/template/.codex/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +5 -1
- package/template/.codex/skills/yss-layered-mvc-scaffold-generator/SKILL.md +2 -2
- package/template/.codex/skills/yss-mybatis/SKILL.md +10 -0
- package/template/.codex/skills/yss-openapi-draft-review/SKILL.md +3 -1
- package/template/.codex/skills/yss-openapi-governance/SKILL.md +5 -32
- package/template/.codex/skills/yss-openapi-governance/references/governance-output.md +34 -0
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +12 -6
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +63 -1
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.codex/skills/yss-prototype-stage/SKILL.md +3 -5
- package/template/.codex/skills/yss-prototype-stage/references/existing-ui-entry.md +7 -0
- package/template/.codex/skills/yss-prototype-stage/scripts/visual-baseline-contract.mjs +2 -2
- package/template/.codex/skills/yss-repository/SKILL.md +13 -1
- package/template/.codex/skills/yss-repository/references/profiles/existing-domain-driven-maven.md +7 -0
- package/template/.codex/skills/yss-repository/references/profiles/existing-layered-mvc-maven.md +7 -0
- package/template/.codex/skills/yss-repository/tests/profile-routing.test.mjs +3 -1
- package/template/.codex/skills/yss-stage-decision/SKILL.md +3 -1
- package/template/.codex/skills/yss-stage-decision/references/strategic-handoff-routing.md +3 -0
- package/template/.codex/skills/yss-tactical-design/SKILL.md +3 -3
- package/template/.codex/skills/yss-tactical-design/references/strategic-handoff-routing.md +5 -0
- package/template/.codex/skills/yss-technical-design/SKILL.md +2 -0
- package/template/.codex/skills/yss-technical-design/scripts/engineering-design.mjs +1 -1
- package/template/.codex/skills/yss-technical-design/scripts/validate-technical-design.mjs +11 -8
- package/template/.codex/skills/yss-ui-business-page-generation/SKILL.md +5 -3
- package/template/.codex/skills/yss-validation/SKILL.md +1 -1
- package/template/.codex/skills/yss-web-controller/SKILL.md +16 -7
- package/template/.codex/skills/ytable-usage/SKILL.md +2 -2
- package/template/.cursor/skills/alibaba-java-code-style/SKILL.md +2 -2
- package/template/.cursor/skills/archify/SKILL.md +2 -19
- package/template/.cursor/skills/archify/references/geometry-and-routing.md +20 -0
- package/template/.cursor/skills/code-review/SKILL.md +3 -33
- package/template/.cursor/skills/code-review/references/candidate-capture.md +33 -0
- package/template/.cursor/skills/code-review/references/yss-review-standards.md +3 -5
- package/template/.cursor/skills/codebase-design/SKILL.md +2 -2
- package/template/.cursor/skills/competitive-intelligence/SKILL.md +1 -1
- package/template/.cursor/skills/diagnosing-bugs/SKILL.md +6 -2
- package/template/.cursor/skills/formily-foundation/SKILL.md +1 -1
- package/template/.cursor/skills/formily-step-flow/SKILL.md +3 -2
- package/template/.cursor/skills/frontend-commit/SKILL.md +6 -6
- package/template/.cursor/skills/grilling/SKILL.md +2 -2
- package/template/.cursor/skills/implement/SKILL.md +1 -1
- package/template/.cursor/skills/implementation-repo-onboarding/SKILL.md +3 -3
- package/template/.cursor/skills/implementation-repo-onboarding/references/write-scope.md +5 -0
- package/template/.cursor/skills/improve-codebase-architecture/SKILL.md +10 -6
- package/template/.cursor/skills/java-backend-commit/SKILL.md +5 -5
- package/template/.cursor/skills/llm-wiki/SKILL.md +1 -1
- package/template/.cursor/skills/prototype/SKILL.md +1 -1
- package/template/.cursor/skills/prototype-review/SKILL.md +1 -1
- package/template/.cursor/skills/resolving-merge-conflicts/SKILL.md +2 -2
- package/template/.cursor/skills/tdd/SKILL.md +1 -1
- package/template/.cursor/skills/to-questionnaire/SKILL.md +4 -2
- package/template/.cursor/skills/to-spec/SKILL.md +3 -3
- package/template/.cursor/skills/to-tickets/SKILL.md +7 -7
- package/template/.cursor/skills/using-git-worktrees/SKILL.md +13 -11
- package/template/.cursor/skills/wait-what/SKILL.md +1 -1
- package/template/.cursor/skills/wayfinder/SKILL.md +4 -2
- package/template/.cursor/skills/writing-for-agents/SKILL.md +9 -73
- package/template/.cursor/skills/writing-for-agents/references/writing-principles.md +76 -0
- package/template/.cursor/skills/yss-api-integration/SKILL.md +2 -2
- package/template/.cursor/skills/yss-application/SKILL.md +12 -0
- package/template/.cursor/skills/yss-audit-log/SKILL.md +3 -1
- package/template/.cursor/skills/yss-audit-log/assets/AuditLogAspect.java +1 -0
- package/template/.cursor/skills/yss-audit-log/assets/YssAuditLogPrintSubscriberImpl.java +1 -0
- package/template/.cursor/skills/yss-audit-log/assets/YssAuditLogSysManagerSubscriberImpl.java +1 -0
- package/template/.cursor/skills/yss-audit-log/assets/YssAuditPublishService.java +1 -0
- package/template/.cursor/skills/yss-backend-spec-review/SKILL.md +6 -0
- package/template/.cursor/skills/yss-backend-spec-review/references/check-inputs.md +2 -2
- package/template/.cursor/skills/yss-backend-spec-review/references/standards-coverage.md +39 -0
- package/template/.cursor/skills/yss-ddd-scaffold-generator/SKILL.md +5 -34
- package/template/.cursor/skills/yss-ddd-scaffold-generator/references/command-examples.md +32 -0
- package/template/.cursor/skills/yss-ddd-scaffold-generator/references/generator-maintenance.md +7 -0
- package/template/.cursor/skills/yss-design-system/SKILL.md +2 -2
- package/template/.cursor/skills/yss-domain/SKILL.md +17 -5
- package/template/.cursor/skills/yss-domain/references/domain-layer-guide.md +2 -2
- package/template/.cursor/skills/yss-domain/references/existing-project.md +5 -0
- package/template/.cursor/skills/yss-dto/SKILL.md +13 -10
- package/template/.cursor/skills/yss-dto/references/wire-validation-checklist.md +14 -0
- package/template/.cursor/skills/yss-exception/SKILL.md +2 -2
- package/template/.cursor/skills/yss-formily-schema-generator/SKILL.md +12 -12
- package/template/.cursor/skills/yss-hook/SKILL.md +8 -44
- package/template/.cursor/skills/yss-hook/references/use-request.md +42 -0
- package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +3 -5
- package/template/.cursor/skills/yss-implementation-contract-compiler/references/strategic-handoff-routing.md +7 -0
- package/template/.cursor/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +5 -1
- package/template/.cursor/skills/yss-layered-mvc-scaffold-generator/SKILL.md +2 -2
- package/template/.cursor/skills/yss-mybatis/SKILL.md +10 -0
- package/template/.cursor/skills/yss-openapi-draft-review/SKILL.md +3 -1
- package/template/.cursor/skills/yss-openapi-governance/SKILL.md +5 -32
- package/template/.cursor/skills/yss-openapi-governance/references/governance-output.md +34 -0
- package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +12 -6
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +63 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.cursor/skills/yss-prototype-stage/SKILL.md +3 -5
- package/template/.cursor/skills/yss-prototype-stage/references/existing-ui-entry.md +7 -0
- package/template/.cursor/skills/yss-prototype-stage/scripts/visual-baseline-contract.mjs +2 -2
- package/template/.cursor/skills/yss-repository/SKILL.md +13 -1
- package/template/.cursor/skills/yss-repository/references/profiles/existing-domain-driven-maven.md +7 -0
- package/template/.cursor/skills/yss-repository/references/profiles/existing-layered-mvc-maven.md +7 -0
- package/template/.cursor/skills/yss-repository/tests/profile-routing.test.mjs +3 -1
- package/template/.cursor/skills/yss-stage-decision/SKILL.md +3 -1
- package/template/.cursor/skills/yss-stage-decision/references/strategic-handoff-routing.md +3 -0
- package/template/.cursor/skills/yss-tactical-design/SKILL.md +3 -3
- package/template/.cursor/skills/yss-tactical-design/references/strategic-handoff-routing.md +5 -0
- package/template/.cursor/skills/yss-technical-design/SKILL.md +2 -0
- package/template/.cursor/skills/yss-technical-design/scripts/engineering-design.mjs +1 -1
- package/template/.cursor/skills/yss-technical-design/scripts/validate-technical-design.mjs +11 -8
- package/template/.cursor/skills/yss-ui-business-page-generation/SKILL.md +5 -3
- package/template/.cursor/skills/yss-validation/SKILL.md +1 -1
- package/template/.cursor/skills/yss-web-controller/SKILL.md +16 -7
- package/template/.cursor/skills/ytable-usage/SKILL.md +2 -2
- package/template/.pi/skills/alibaba-java-code-style/SKILL.md +2 -2
- package/template/.pi/skills/archify/SKILL.md +2 -19
- package/template/.pi/skills/archify/references/geometry-and-routing.md +20 -0
- package/template/.pi/skills/code-review/SKILL.md +3 -33
- package/template/.pi/skills/code-review/references/candidate-capture.md +33 -0
- package/template/.pi/skills/code-review/references/yss-review-standards.md +3 -5
- package/template/.pi/skills/codebase-design/SKILL.md +2 -2
- package/template/.pi/skills/competitive-intelligence/SKILL.md +1 -1
- package/template/.pi/skills/diagnosing-bugs/SKILL.md +6 -2
- package/template/.pi/skills/formily-foundation/SKILL.md +1 -1
- package/template/.pi/skills/formily-step-flow/SKILL.md +3 -2
- package/template/.pi/skills/frontend-commit/SKILL.md +6 -6
- package/template/.pi/skills/grilling/SKILL.md +2 -2
- package/template/.pi/skills/implement/SKILL.md +1 -1
- package/template/.pi/skills/implementation-repo-onboarding/SKILL.md +3 -3
- package/template/.pi/skills/implementation-repo-onboarding/references/write-scope.md +5 -0
- package/template/.pi/skills/improve-codebase-architecture/SKILL.md +10 -6
- package/template/.pi/skills/java-backend-commit/SKILL.md +5 -5
- package/template/.pi/skills/llm-wiki/SKILL.md +1 -1
- package/template/.pi/skills/prototype/SKILL.md +1 -1
- package/template/.pi/skills/prototype-review/SKILL.md +1 -1
- package/template/.pi/skills/resolving-merge-conflicts/SKILL.md +2 -2
- package/template/.pi/skills/tdd/SKILL.md +1 -1
- package/template/.pi/skills/to-questionnaire/SKILL.md +4 -2
- package/template/.pi/skills/to-spec/SKILL.md +3 -3
- package/template/.pi/skills/to-tickets/SKILL.md +7 -7
- package/template/.pi/skills/using-git-worktrees/SKILL.md +13 -11
- package/template/.pi/skills/wait-what/SKILL.md +1 -1
- package/template/.pi/skills/wayfinder/SKILL.md +4 -2
- package/template/.pi/skills/writing-for-agents/SKILL.md +9 -73
- package/template/.pi/skills/writing-for-agents/references/writing-principles.md +76 -0
- package/template/.pi/skills/yss-api-integration/SKILL.md +2 -2
- package/template/.pi/skills/yss-application/SKILL.md +12 -0
- package/template/.pi/skills/yss-audit-log/SKILL.md +3 -1
- package/template/.pi/skills/yss-audit-log/assets/AuditLogAspect.java +1 -0
- package/template/.pi/skills/yss-audit-log/assets/YssAuditLogPrintSubscriberImpl.java +1 -0
- package/template/.pi/skills/yss-audit-log/assets/YssAuditLogSysManagerSubscriberImpl.java +1 -0
- package/template/.pi/skills/yss-audit-log/assets/YssAuditPublishService.java +1 -0
- package/template/.pi/skills/yss-backend-spec-review/SKILL.md +6 -0
- package/template/.pi/skills/yss-backend-spec-review/references/check-inputs.md +2 -2
- package/template/.pi/skills/yss-backend-spec-review/references/standards-coverage.md +39 -0
- package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +5 -34
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/command-examples.md +32 -0
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/generator-maintenance.md +7 -0
- package/template/.pi/skills/yss-design-system/SKILL.md +2 -2
- package/template/.pi/skills/yss-domain/SKILL.md +17 -5
- package/template/.pi/skills/yss-domain/references/domain-layer-guide.md +2 -2
- package/template/.pi/skills/yss-domain/references/existing-project.md +5 -0
- package/template/.pi/skills/yss-dto/SKILL.md +13 -10
- package/template/.pi/skills/yss-dto/references/wire-validation-checklist.md +14 -0
- package/template/.pi/skills/yss-exception/SKILL.md +2 -2
- package/template/.pi/skills/yss-formily-schema-generator/SKILL.md +12 -12
- package/template/.pi/skills/yss-hook/SKILL.md +8 -44
- package/template/.pi/skills/yss-hook/references/use-request.md +42 -0
- package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +3 -5
- package/template/.pi/skills/yss-implementation-contract-compiler/references/strategic-handoff-routing.md +7 -0
- package/template/.pi/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +5 -1
- package/template/.pi/skills/yss-layered-mvc-scaffold-generator/SKILL.md +2 -2
- package/template/.pi/skills/yss-mybatis/SKILL.md +10 -0
- package/template/.pi/skills/yss-openapi-draft-review/SKILL.md +3 -1
- package/template/.pi/skills/yss-openapi-governance/SKILL.md +5 -32
- package/template/.pi/skills/yss-openapi-governance/references/governance-output.md +34 -0
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +12 -6
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +63 -1
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +2 -2
- package/template/.pi/skills/yss-prototype-stage/SKILL.md +3 -5
- package/template/.pi/skills/yss-prototype-stage/references/existing-ui-entry.md +7 -0
- package/template/.pi/skills/yss-prototype-stage/scripts/visual-baseline-contract.mjs +2 -2
- package/template/.pi/skills/yss-repository/SKILL.md +13 -1
- package/template/.pi/skills/yss-repository/references/profiles/existing-domain-driven-maven.md +7 -0
- package/template/.pi/skills/yss-repository/references/profiles/existing-layered-mvc-maven.md +7 -0
- package/template/.pi/skills/yss-repository/tests/profile-routing.test.mjs +3 -1
- package/template/.pi/skills/yss-stage-decision/SKILL.md +3 -1
- package/template/.pi/skills/yss-stage-decision/references/strategic-handoff-routing.md +3 -0
- package/template/.pi/skills/yss-tactical-design/SKILL.md +3 -3
- package/template/.pi/skills/yss-tactical-design/references/strategic-handoff-routing.md +5 -0
- package/template/.pi/skills/yss-technical-design/SKILL.md +2 -0
- package/template/.pi/skills/yss-technical-design/scripts/engineering-design.mjs +1 -1
- package/template/.pi/skills/yss-technical-design/scripts/validate-technical-design.mjs +11 -8
- package/template/.pi/skills/yss-ui-business-page-generation/SKILL.md +5 -3
- package/template/.pi/skills/yss-validation/SKILL.md +1 -1
- package/template/.pi/skills/yss-web-controller/SKILL.md +16 -7
- package/template/.pi/skills/ytable-usage/SKILL.md +2 -2
- package/template/AGENTS.md +2 -0
- package/template/CONTEXT.md +2 -1
- package/template/README.md +1 -0
- package/template/docs/agents/issue-tracker.md +7 -0
- package/template/docs/process/contract-reading.md +46 -0
- package/template/docs/process/lifecycle-artifact-map.md +2 -2
- package/template/docs/process/lifecycle-registry-baseline.json +2 -1
- package/template/docs/process/lifecycle-registry.yaml +10 -4
- package/template/docs/process/schemas/api-contract-decision-v2.schema.json +198 -0
- package/template/docs/process/schemas/digital-human-task-package.schema.json +68 -4
- package/template/docs/process/schemas/lifecycle-checkpoint.schema.json +259 -0
- package/template/docs/process/schemas/stage-tracking.schema.json +259 -0
- package/template/docs/process/stage-tracking.md +62 -0
- package/template/docs/process/strategic-handoff-package.md +8 -0
- package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +2 -0
- package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214/347/264/242/345/274/225.md +1 -0
- package/template/docs/user-guide//351/230/266/346/256/265/346/216/245/345/205/245/344/270/216/344/272/247/347/211/251/345/244/215/347/224/250/344/275/277/347/224/250/346/211/213/345/206/214.md +243 -0
- package/template/scripts/api-contract-decision +16 -0
- package/template/scripts/backend-standards-coverage +26 -0
- package/template/scripts/complete-backend-delivery +17 -0
- package/template/scripts/contract +13 -0
- package/template/scripts/dispatch-slice-task +13 -0
- package/template/scripts/lib/api-contract-decision.mjs +45 -4
- package/template/scripts/lib/approval-record.mjs +1 -1
- package/template/scripts/lib/approved-execution-context.mjs +35 -7
- package/template/scripts/lib/backend-architecture.mjs +2 -2
- package/template/scripts/lib/backend-delivery-terminal.mjs +51 -0
- package/template/scripts/lib/backend-platform-provenance.mjs +1 -1
- package/template/scripts/lib/backend-platform.mjs +1 -1
- package/template/scripts/lib/backend-review.mjs +58 -20
- package/template/scripts/lib/backend-scaffold-prerequisites.mjs +1 -1
- package/template/scripts/lib/backend-standards-coverage.mjs +237 -0
- package/template/scripts/lib/context-contract.mjs +1 -1
- package/template/scripts/lib/context-reconciliation.mjs +1 -1
- package/template/scripts/lib/contract-source.mjs +22 -0
- package/template/scripts/lib/contract-views.mjs +109 -0
- package/template/scripts/lib/delivery-preflight.mjs +3 -2
- package/template/scripts/lib/digital-human-roles.mjs +1 -1
- package/template/scripts/lib/existing-backend-architecture.mjs +4 -3
- package/template/scripts/lib/existing-ui-baseline.mjs +4 -2
- package/template/scripts/lib/first-slice-artifacts.mjs +1 -1
- package/template/scripts/lib/frontend-delivery-boundary.mjs +1 -1
- package/template/scripts/lib/frontend-delivery.mjs +1 -1
- package/template/scripts/lib/harness-execution-scope.mjs +15 -1
- package/template/scripts/lib/implementation-contract-compiler.mjs +4 -4
- package/template/scripts/lib/json-schema.mjs +19 -4
- package/template/scripts/lib/lifecycle-context-query.mjs +5 -1
- package/template/scripts/lib/lifecycle-controls.mjs +1 -1
- package/template/scripts/lib/lifecycle-execution-scope.mjs +92 -0
- package/template/scripts/lib/lifecycle-registry.mjs +2 -1
- package/template/scripts/lib/lifecycle-transition.mjs +25 -4
- package/template/scripts/lib/openapi-draft-validation.mjs +2 -1
- package/template/scripts/lib/profile-skill-sync.mjs +46 -5
- package/template/scripts/lib/skill-registry.mjs +1 -1
- package/template/scripts/lib/slice-contract-preparation.mjs +16 -14
- package/template/scripts/lib/slice-contract-views.mjs +1 -1
- package/template/scripts/lib/slice-contract.mjs +18 -3
- package/template/scripts/lib/slice-execution-preflight.mjs +7 -3
- package/template/scripts/lib/slice-repositories.mjs +1 -1
- package/template/scripts/lib/slice-task-package.mjs +3 -2
- package/template/scripts/lib/stage-tracking-migration.mjs +176 -0
- package/template/scripts/lib/stage-tracking.mjs +184 -0
- package/template/scripts/lib/strategic-handoff-consumption.mjs +5 -4
- package/template/scripts/lib/strategic-handoff-io.mjs +5 -2
- package/template/scripts/lib/strategic-handoff-routing.mjs +31 -0
- package/template/scripts/lib/strategic-handoff.mjs +4 -2
- package/template/scripts/lib/task-package.mjs +2 -0
- package/template/scripts/lib/technical-design-boundary.mjs +4 -2
- package/template/scripts/lib/ui-baseline.mjs +1 -1
- package/template/scripts/lib/user-decision.mjs +1 -1
- package/template/scripts/lib/validation-phase.mjs +72 -0
- package/template/scripts/stage-tracking +25 -0
- package/template/scripts/strategic-consumer-entry +47 -0
- package/template/scripts/verify-context-reconciliation +4 -3
- package/template/scripts/verify-lifecycle-checkpoint +10 -0
- package/template/skills-lock.json +65 -63
- package/template.snapshot.json +4 -4
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync, unlinkSync, statSync, openSync, closeSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { parseDocument, stringify } from '../vendor/yaml.mjs';
|
|
4
|
+
import { TRACKER_REF, STAGE_WORK_UNITS, sha256, safeTrackingPath, readTracking, parseYaml, trackerConfig, isDesign, binding, assertStageTracking, refreshTracking } from './stage-tracking.mjs';
|
|
5
|
+
|
|
6
|
+
const descriptor = (root, ref) => { const p = safeTrackingPath(root, ref); return existsSync(p) ? { digest: sha256(readFileSync(p)), mode: statSync(p).mode & 0o777 } : null; };
|
|
7
|
+
const json = x => `${JSON.stringify(x, null, 2)}\n`;
|
|
8
|
+
function featureFrom(ref) {
|
|
9
|
+
const match = /^docs\/\.scratch\/([a-z0-9][a-z0-9-]*)\/[^/]+\.(yaml|json)$/.exec(ref);
|
|
10
|
+
if (!match) throw new Error('tracking-checkpoint-path-invalid');
|
|
11
|
+
return match[1];
|
|
12
|
+
}
|
|
13
|
+
function identity(root) {
|
|
14
|
+
const value = parseYaml(readTracking(root, 'yss-project.yaml'));
|
|
15
|
+
if (value?.schema_version !== 1 || value.repository_mode !== 'project-instance') throw new Error('stage-tracking-project-instance-required');
|
|
16
|
+
}
|
|
17
|
+
function enabledTracker(bytes) {
|
|
18
|
+
const match = bytes.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
19
|
+
if (!match) throw new Error('tracking-tracker-frontmatter-required');
|
|
20
|
+
const doc = parseDocument(match[1], { uniqueKeys: true });
|
|
21
|
+
doc.setIn(['tracker', 'lifecycle_tracking_version'], 1);
|
|
22
|
+
return `---\n${doc.toString()}---${bytes.slice(match[0].length)}`;
|
|
23
|
+
}
|
|
24
|
+
function definition(item, checkpointRef) {
|
|
25
|
+
const fields = { kind: item.kind, id: item.id, checkpoint_ref: checkpointRef };
|
|
26
|
+
return `---\n${stringify(fields)}---\n# ${item.title}\n\n负责人:${item.owner}\n\n${item.scope}\n\n## 验收\n\n${item.acceptance.map(x => `- ${x}`).join('\n')}\n\n当前进度、依赖与完成证据以 ${checkpointRef} 中的 ${item.id} 为准。\n`;
|
|
27
|
+
}
|
|
28
|
+
export function checkTracking(root, checkpointRef) {
|
|
29
|
+
identity(root);
|
|
30
|
+
const feature = featureFrom(checkpointRef);
|
|
31
|
+
const config = trackerConfig(root);
|
|
32
|
+
if (!existsSync(safeTrackingPath(root, checkpointRef))) return { status: 'missing-checkpoint', feature_id: feature, enabled: config.lifecycle_tracking_version === 1 };
|
|
33
|
+
const checkpoint = parseYaml(readTracking(root, checkpointRef));
|
|
34
|
+
try {
|
|
35
|
+
const result = assertStageTracking(checkpoint, { root, checkpointRef });
|
|
36
|
+
return { ...result, feature_id: checkpoint.feature_id || feature, enabled: config.lifecycle_tracking_version === 1, migration_required: !checkpoint.stage_tracking };
|
|
37
|
+
} catch (error) { return { status: 'blocked', feature_id: feature, enabled: config.lifecycle_tracking_version === 1, error: error.message, migration_required: !checkpoint.stage_tracking }; }
|
|
38
|
+
}
|
|
39
|
+
export function planTracking(root, { checkpoint_ref, items = [], refresh = false } = {}) {
|
|
40
|
+
root = path.resolve(root); identity(root);
|
|
41
|
+
const feature = featureFrom(checkpoint_ref);
|
|
42
|
+
trackerConfig(root);
|
|
43
|
+
const changes = [], observed = {}, gaps = [];
|
|
44
|
+
function watch(ref) { observed[ref] = descriptor(root, ref); }
|
|
45
|
+
function change(ref, after) {
|
|
46
|
+
watch(ref);
|
|
47
|
+
if (!observed[ref] || sha256(after) !== observed[ref].digest) changes.push({ ref, before: observed[ref], after, after_digest: sha256(after) });
|
|
48
|
+
}
|
|
49
|
+
for (const ref of ['yss-project.yaml', 'CONTEXT.md', TRACKER_REF, 'docs/process/lifecycle-registry.yaml', 'docs/process/schemas/stage-tracking.schema.json', 'docs/process/harness-profile.yaml', checkpoint_ref]) watch(ref);
|
|
50
|
+
const exists = observed[checkpoint_ref] !== null;
|
|
51
|
+
let checkpoint;
|
|
52
|
+
if (exists) checkpoint = parseYaml(readTracking(root, checkpoint_ref));
|
|
53
|
+
else {
|
|
54
|
+
const template = 'docs/process/templates/lifecycle-checkpoint-template.yaml'; watch(template);
|
|
55
|
+
checkpoint = parseYaml(readTracking(root, template));
|
|
56
|
+
checkpoint.feature_id = feature;
|
|
57
|
+
checkpoint.mode = 'orchestrate'; checkpoint.status = 'running';
|
|
58
|
+
checkpoint.stage = items[0]?.stage || 'stage.plan';
|
|
59
|
+
checkpoint.next_work_unit = items[0]?.work_unit || 'work-unit.plan-requirements';
|
|
60
|
+
}
|
|
61
|
+
checkpoint.feature_id ??= feature;
|
|
62
|
+
const design = isDesign(root);
|
|
63
|
+
checkpoint.stage_tracking ??= { schema_version: 1, feature_id: checkpoint.feature_id, checkpoint_ref, entry_stage: checkpoint.stage,
|
|
64
|
+
entry: { kind: design ? 'checkpoint' : 'parent-ticket', ref: design ? checkpoint_ref : `docs/.scratch/${feature}/parent-ticket.md` }, items: [] };
|
|
65
|
+
if (refresh) checkpoint = refreshTracking(root, checkpoint).checkpoint;
|
|
66
|
+
const tracking = checkpoint.stage_tracking;
|
|
67
|
+
const ids = new Set(tracking.items.map(x => x.id));
|
|
68
|
+
for (const seed of items) {
|
|
69
|
+
if (ids.has(seed.id)) {
|
|
70
|
+
// Resume never overwrites a live item with an older task definition.
|
|
71
|
+
const existing = tracking.items.find(x => x.id === seed.id);
|
|
72
|
+
for (const key of ['title', 'owner', 'scope', 'stage', 'work_unit', 'acceptance', 'dependencies', 'split_reasons']) if (JSON.stringify(seed[key] ?? existing[key]) !== JSON.stringify(existing[key])) throw new Error(`tracking-existing-item-conflict: ${seed.id}.${key}`);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (seed.progress && seed.progress !== 'pending') throw new Error('tracking-migration-cannot-infer-completion');
|
|
76
|
+
const item = { id: seed.id, kind: 'stage-work-item', title: seed.title, stage: seed.stage, work_unit: seed.work_unit, owner: seed.owner, scope: seed.scope,
|
|
77
|
+
acceptance: seed.acceptance, dependencies: seed.dependencies || [], source_refs: (seed.source_refs || []).map(ref => binding(root, typeof ref === 'string' ? ref : ref.ref)),
|
|
78
|
+
progress: 'pending', split_reasons: seed.split_reasons || [], completion: [] };
|
|
79
|
+
if (seed.deferred) { item.deferred = seed.deferred; if (!item.split_reasons.includes('cross-stage-deferral')) item.split_reasons.push('cross-stage-deferral'); }
|
|
80
|
+
tracking.items.push(item); ids.add(item.id);
|
|
81
|
+
}
|
|
82
|
+
for (const item of tracking.items) {
|
|
83
|
+
if (tracking.items.some(other => other.dependencies.includes(item.id)) && !item.split_reasons.includes('blocks-other-work')) item.split_reasons.push('blocks-other-work');
|
|
84
|
+
if (tracking.items[0]?.owner && item.owner !== tracking.items[0].owner && !item.split_reasons.includes('different-owner')) item.split_reasons.push('different-owner');
|
|
85
|
+
}
|
|
86
|
+
if (!tracking.items.length) gaps.push('需要明确当前阶段工作项及负责人、范围和验收条件;不从历史文件推断完成');
|
|
87
|
+
if (!tracking.items.some(i => i.stage === checkpoint.stage) && ['stage.plan', 'stage.spec-architecture', 'stage.product-design'].includes(checkpoint.stage)) gaps.push('当前阶段缺少工作项');
|
|
88
|
+
for (const item of tracking.items) {
|
|
89
|
+
for (const key of ['id', 'title', 'owner', 'scope', 'stage', 'work_unit']) if (typeof item[key] !== 'string' || !item[key].trim()) gaps.push(`${item.id || '?'} 缺少 ${key}`);
|
|
90
|
+
if (!item.acceptance?.length) gaps.push(`${item.id || '?'} 缺少验收条件`);
|
|
91
|
+
for (const source of [...item.source_refs, ...item.completion.flatMap(x => x.evidence_refs)]) watch(source.ref);
|
|
92
|
+
if (item.deferred) watch(item.deferred.decision_ref);
|
|
93
|
+
if (item.split_reasons?.length && !gaps.length) {
|
|
94
|
+
const ref = `docs/.scratch/${feature}/work-items/${item.id}.md`;
|
|
95
|
+
if (!item.definition_ref) {
|
|
96
|
+
if (descriptor(root, ref)) throw new Error(`tracking-unowned-file-conflict: ${ref}`);
|
|
97
|
+
item.definition_ref = ref;
|
|
98
|
+
const content = definition(item, checkpoint_ref);
|
|
99
|
+
item.definition_digest = sha256(content); change(ref, content);
|
|
100
|
+
} else watch(item.definition_ref);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const entryRef = tracking.entry.ref;
|
|
104
|
+
if (!design) {
|
|
105
|
+
watch(entryRef);
|
|
106
|
+
const link = `\n阶段工作进度与证据:${checkpoint_ref}\n`;
|
|
107
|
+
if (!observed[entryRef]) change(entryRef, `# ${feature}\n\nStatus: needs-triage\n${link}${trackerConfig(root).platform !== 'local-markdown' ? `\npublication: pending\npending_publication_to: ${trackerConfig(root).platform}\n` : ''}`);
|
|
108
|
+
else if (!readTracking(root, entryRef).includes(checkpoint_ref)) change(entryRef, readTracking(root, entryRef) + link);
|
|
109
|
+
}
|
|
110
|
+
const mapRef = `docs/.scratch/${feature}/map.md`; watch(mapRef);
|
|
111
|
+
if (!observed[mapRef]) change(mapRef, `---\ncheckpoint_ref: ${checkpoint_ref}\n---\n# ${feature}\n\n阶段工作与证据见 ${checkpoint_ref}。\n`);
|
|
112
|
+
else if (!readTracking(root, mapRef).includes(checkpoint_ref)) change(mapRef, readTracking(root, mapRef) + `\n阶段工作与证据:${checkpoint_ref}\n`);
|
|
113
|
+
change(checkpoint_ref, checkpoint_ref.endsWith('.json') ? json(checkpoint) : stringify(checkpoint));
|
|
114
|
+
change(TRACKER_REF, enabledTracker(readTracking(root, TRACKER_REF)));
|
|
115
|
+
const input = { checkpoint_ref, items, refresh };
|
|
116
|
+
const payload = { schema_version: 1, root, input, gaps, observed, changes };
|
|
117
|
+
return { ...payload, plan_id: sha256(JSON.stringify(payload)).slice(7) };
|
|
118
|
+
}
|
|
119
|
+
export function applyTracking(root, plan, { afterWrite } = {}) {
|
|
120
|
+
root = path.resolve(root); identity(root);
|
|
121
|
+
if (plan.root !== root || plan.schema_version !== 1 || !/^[a-f0-9]{64}$/.test(plan.plan_id)) throw new Error('tracking-plan-identity-invalid');
|
|
122
|
+
const { plan_id, ...payload } = plan;
|
|
123
|
+
if (sha256(JSON.stringify(payload)).slice(7) !== plan_id) throw new Error('tracking-plan-digest-mismatch');
|
|
124
|
+
const feature = featureFrom(plan.input.checkpoint_ref);
|
|
125
|
+
const transactionRef = `docs/.scratch/${feature}/verification/stage-tracking-migrations/${plan_id}`;
|
|
126
|
+
const receiptRef = `${transactionRef}/receipt.json`;
|
|
127
|
+
if (existsSync(safeTrackingPath(root, receiptRef))) {
|
|
128
|
+
const receipt = JSON.parse(readTracking(root, receiptRef));
|
|
129
|
+
if (receipt.plan_id !== plan_id) throw new Error('tracking-receipt-conflict');
|
|
130
|
+
return { status: 'unchanged', plan_id, receipt_ref: receiptRef };
|
|
131
|
+
}
|
|
132
|
+
if (plan.gaps.length) throw new Error(`tracking-migration-needs-info: ${plan.gaps.join('; ')}`);
|
|
133
|
+
const fresh = planTracking(root, plan.input);
|
|
134
|
+
if (JSON.stringify(fresh) !== JSON.stringify(plan)) throw new Error('tracking-plan-stale');
|
|
135
|
+
if (!plan.changes.length) return { status: 'unchanged', plan_id };
|
|
136
|
+
const transactionPath = safeTrackingPath(root, transactionRef);
|
|
137
|
+
if (existsSync(transactionPath)) throw new Error(`tracking-transaction-needs-recovery: ${transactionRef}`);
|
|
138
|
+
mkdirSync(transactionPath, { recursive: true });
|
|
139
|
+
const backups = plan.changes.map(c => ({ ref: c.ref, before: c.before, bytes: c.before ? readFileSync(safeTrackingPath(root, c.ref)).toString('base64') : null }));
|
|
140
|
+
writeFileSync(path.join(transactionPath, 'backup.json'), json(backups), { flag: 'wx' });
|
|
141
|
+
writeFileSync(path.join(transactionPath, 'plan.json'), json(plan), { flag: 'wx' });
|
|
142
|
+
const written = [], temporary = new Set();
|
|
143
|
+
try {
|
|
144
|
+
for (const [ref, before] of Object.entries(plan.observed)) if (JSON.stringify(descriptor(root, ref)) !== JSON.stringify(before)) throw new Error('tracking-concurrent-change');
|
|
145
|
+
for (const change of plan.changes) {
|
|
146
|
+
const file = safeTrackingPath(root, change.ref);
|
|
147
|
+
if (JSON.stringify(descriptor(root, change.ref)) !== JSON.stringify(change.before)) throw new Error('tracking-concurrent-change');
|
|
148
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
149
|
+
const temp = `${file}.stage-tracking-${plan_id}`;
|
|
150
|
+
const fd = openSync(temp, 'wx', change.before?.mode || 0o644);
|
|
151
|
+
temporary.add(temp);
|
|
152
|
+
try { writeFileSync(fd, change.after); } finally { closeSync(fd); }
|
|
153
|
+
renameSync(temp, file); temporary.delete(temp); written.push(change);
|
|
154
|
+
afterWrite?.(change, written.length);
|
|
155
|
+
}
|
|
156
|
+
for (const [ref, before] of Object.entries(plan.observed)) {
|
|
157
|
+
const changed = written.find(x => x.ref === ref);
|
|
158
|
+
const actual = descriptor(root, ref);
|
|
159
|
+
if (changed ? actual?.digest !== changed.after_digest : JSON.stringify(actual) !== JSON.stringify(before)) throw new Error('tracking-concurrent-change');
|
|
160
|
+
}
|
|
161
|
+
const cp = parseYaml(readTracking(root, plan.input.checkpoint_ref));
|
|
162
|
+
assertStageTracking(cp, { root, checkpointRef: plan.input.checkpoint_ref });
|
|
163
|
+
writeFileSync(safeTrackingPath(root, receiptRef), json({ plan_id, status: 'applied', changed_refs: written.map(x => x.ref) }), { flag: 'wx' });
|
|
164
|
+
return { status: 'applied', plan_id, receipt_ref: receiptRef, changed_refs: written.map(x => x.ref) };
|
|
165
|
+
} catch (error) {
|
|
166
|
+
const conflicts = [];
|
|
167
|
+
for (const temp of temporary) { try { unlinkSync(temp); } catch (cleanupError) { if (cleanupError.code !== 'ENOENT') conflicts.push(temp); } }
|
|
168
|
+
for (const change of written.reverse()) {
|
|
169
|
+
if (descriptor(root, change.ref)?.digest !== change.after_digest) { conflicts.push(change.ref); continue; }
|
|
170
|
+
const backup = backups.find(x => x.ref === change.ref), file = safeTrackingPath(root, change.ref);
|
|
171
|
+
if (backup.bytes === null) unlinkSync(file); else writeFileSync(file, Buffer.from(backup.bytes, 'base64'), { mode: backup.before.mode });
|
|
172
|
+
}
|
|
173
|
+
writeFileSync(path.join(transactionPath, 'failure.json'), json({ error: error.message, recovery_conflicts: conflicts }));
|
|
174
|
+
throw new Error(`${error.message}; tracking-rollback-${conflicts.length ? `conflict:${conflicts.join(',')}` : 'complete'}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { readFileSync, existsSync, lstatSync, realpathSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { parseDocument } from '../vendor/yaml.mjs';
|
|
5
|
+
import { validateJsonSchema } from './json-schema.mjs';
|
|
6
|
+
|
|
7
|
+
export const TRACKER_REF = 'docs/agents/issue-tracker.md';
|
|
8
|
+
export const STAGE_WORK_UNITS = Object.freeze({
|
|
9
|
+
'work-unit.plan-opportunity': 'stage.plan',
|
|
10
|
+
'work-unit.plan-requirements': 'stage.plan',
|
|
11
|
+
'work-unit.domain-strategy-design': 'stage.plan',
|
|
12
|
+
'work-unit.stage-decision': 'stage.plan',
|
|
13
|
+
'work-unit.spec-synthesis': 'stage.spec-architecture',
|
|
14
|
+
'work-unit.prototype-design': 'stage.product-design',
|
|
15
|
+
});
|
|
16
|
+
export const sha256 = bytes => `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
|
|
17
|
+
export function parseYaml(bytes) {
|
|
18
|
+
const doc = parseDocument(String(bytes), { uniqueKeys: true });
|
|
19
|
+
if (doc.errors.length) throw new Error(doc.errors[0].message);
|
|
20
|
+
return doc.toJS({ maxAliasCount: 0 });
|
|
21
|
+
}
|
|
22
|
+
export function safeTrackingPath(root, ref) {
|
|
23
|
+
if (typeof ref !== 'string' || !ref || path.isAbsolute(ref) || ref.includes('\\') || ref.split('/').some(p => !p || p === '.' || p === '..')) throw new Error(`tracking-path-invalid: ${ref}`);
|
|
24
|
+
const base = realpathSync(root);
|
|
25
|
+
let file = base;
|
|
26
|
+
for (const part of ref.split('/')) {
|
|
27
|
+
file = path.join(file, part);
|
|
28
|
+
if (existsSync(file) || (() => { try { lstatSync(file); return true; } catch { return false; } })()) {
|
|
29
|
+
if (lstatSync(file).isSymbolicLink()) throw new Error(`tracking-symlink-forbidden: ${ref}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return file;
|
|
33
|
+
}
|
|
34
|
+
export const readTracking = (root, ref) => readFileSync(safeTrackingPath(root, ref), 'utf8');
|
|
35
|
+
export const binding = (root, ref) => ({ ref, digest: sha256(readTracking(root, ref)) });
|
|
36
|
+
export function trackerConfig(root) {
|
|
37
|
+
const bytes = readTracking(root, TRACKER_REF);
|
|
38
|
+
const match = bytes.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
39
|
+
if (!match) throw new Error('tracking-tracker-frontmatter-required');
|
|
40
|
+
const config = parseYaml(match[1])?.tracker;
|
|
41
|
+
if (!config || !['local-markdown', 'github', 'gitlab'].includes(config.platform)) throw new Error('tracking-tracker-invalid');
|
|
42
|
+
if (config.lifecycle_tracking_version !== undefined && config.lifecycle_tracking_version !== 1) throw new Error('tracking-version-unsupported');
|
|
43
|
+
return config;
|
|
44
|
+
}
|
|
45
|
+
export function trackingProfile(root) {
|
|
46
|
+
const ref = 'docs/process/harness-profile.yaml';
|
|
47
|
+
return existsSync(safeTrackingPath(root, ref)) ? parseYaml(readTracking(root, ref)) : null;
|
|
48
|
+
}
|
|
49
|
+
export const isDesign = root => trackingProfile(root)?.profile_id === 'harness.business-ddd-strategy-handoff';
|
|
50
|
+
function current(root, value) {
|
|
51
|
+
try { return binding(root, value.ref).digest === value.digest; } catch { return false; }
|
|
52
|
+
}
|
|
53
|
+
export function trackingDrift(root, tracking) {
|
|
54
|
+
const changed = new Set(tracking.items.filter(item => [...item.source_refs, ...item.completion.flatMap(c => c.evidence_refs)].some(b => !current(root, b))).map(item => item.id));
|
|
55
|
+
let size;
|
|
56
|
+
do {
|
|
57
|
+
size = changed.size;
|
|
58
|
+
for (const item of tracking.items) if (item.dependencies.some(id => changed.has(id))) changed.add(item.id);
|
|
59
|
+
} while (size !== changed.size);
|
|
60
|
+
return [...changed];
|
|
61
|
+
}
|
|
62
|
+
export function refreshTracking(root, checkpoint) {
|
|
63
|
+
const next = structuredClone(checkpoint);
|
|
64
|
+
const changed = trackingDrift(root, next.stage_tracking);
|
|
65
|
+
for (const item of next.stage_tracking.items) {
|
|
66
|
+
if (changed.includes(item.id) && item.progress !== 'cancelled') {
|
|
67
|
+
item.progress = 'pending';
|
|
68
|
+
item.recheck_required = true;
|
|
69
|
+
// Old bindings and evidence remain historical; only explicit re-verification replaces them.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { checkpoint: next, stale_item_ids: changed };
|
|
73
|
+
}
|
|
74
|
+
export function assertStageTracking(checkpoint, { root, checkpointRef, currentWorkUnit, nextWorkUnit, transition = false, entering = false, now = new Date() } = {}) {
|
|
75
|
+
const identity = parseYaml(readTracking(root, 'yss-project.yaml'));
|
|
76
|
+
if (identity?.schema_version !== 1 || !['template-source', 'project-instance'].includes(identity.repository_mode)) throw new Error('tracking-repository-identity-invalid');
|
|
77
|
+
const config = trackerConfig(root);
|
|
78
|
+
const tracking = checkpoint?.stage_tracking;
|
|
79
|
+
const relevant = STAGE_WORK_UNITS[currentWorkUnit] || STAGE_WORK_UNITS[nextWorkUnit] || ['stage.plan', 'stage.spec-architecture', 'stage.product-design'].includes(checkpoint?.stage);
|
|
80
|
+
if (!tracking) {
|
|
81
|
+
if (identity.repository_mode === 'project-instance' && config.lifecycle_tracking_version === 1 && relevant) throw new Error('stage-tracking-required');
|
|
82
|
+
return { status: 'not-applicable', stale_item_ids: [] };
|
|
83
|
+
}
|
|
84
|
+
validateJsonSchema(tracking, path.join(root, 'docs/process/schemas/stage-tracking.schema.json'));
|
|
85
|
+
const feature = checkpoint.feature_id;
|
|
86
|
+
if (feature !== tracking.feature_id || typeof feature !== 'string' || !feature.trim()) throw new Error('tracking-feature-mismatch');
|
|
87
|
+
const location = /^(docs\/\.scratch\/[a-z0-9][a-z0-9-]*\/)[^/]+\.(yaml|json)$/.exec(tracking.checkpoint_ref);
|
|
88
|
+
if (!location) throw new Error('tracking-checkpoint-path-invalid');
|
|
89
|
+
const base = location[1];
|
|
90
|
+
if (!tracking.checkpoint_ref.startsWith(base) || (checkpointRef && tracking.checkpoint_ref !== checkpointRef)) throw new Error('tracking-checkpoint-mismatch');
|
|
91
|
+
safeTrackingPath(root, tracking.checkpoint_ref);
|
|
92
|
+
if (isDesign(root)) {
|
|
93
|
+
if (tracking.entry.kind !== 'checkpoint' || tracking.entry.ref !== tracking.checkpoint_ref) throw new Error('tracking-design-parent-forbidden');
|
|
94
|
+
} else if (tracking.entry.kind !== 'parent-ticket' || tracking.entry.ref !== `${base}parent-ticket.md`) throw new Error('tracking-parent-required');
|
|
95
|
+
const entry = readTracking(root, tracking.entry.ref);
|
|
96
|
+
if (tracking.entry.kind === 'parent-ticket' && !entry.includes(tracking.checkpoint_ref)) throw new Error('tracking-parent-checkpoint-link-required');
|
|
97
|
+
const registry = parseYaml(readTracking(root, 'docs/process/lifecycle-registry.yaml'));
|
|
98
|
+
const stages = new Set(registry.stages.map(x => x.id));
|
|
99
|
+
const units = new Set(registry.work_units.map(x => x.id));
|
|
100
|
+
if (!stages.has(tracking.entry_stage)) throw new Error('tracking-entry-stage-invalid');
|
|
101
|
+
const profile = trackingProfile(root);
|
|
102
|
+
const allowed = profile?.lifecycle?.allowed_work_units ?? profile?.allowed_work_units;
|
|
103
|
+
const index = new Map();
|
|
104
|
+
for (const item of tracking.items) {
|
|
105
|
+
if (index.has(item.id)) throw new Error(`tracking-duplicate-id: ${item.id}`);
|
|
106
|
+
index.set(item.id, item);
|
|
107
|
+
if (!stages.has(item.stage) || !units.has(item.work_unit) || STAGE_WORK_UNITS[item.work_unit] !== item.stage) throw new Error(`tracking-stage-work-unit-mismatch: ${item.id}`);
|
|
108
|
+
if (allowed && !allowed.includes(item.work_unit)) throw new Error(`tracking-profile-work-unit-forbidden: ${item.id}`);
|
|
109
|
+
if (item.split_reasons.length && !item.definition_ref) throw new Error(`tracking-independent-item-required: ${item.id}`);
|
|
110
|
+
if (item.definition_ref) {
|
|
111
|
+
if (item.definition_ref !== `${base}work-items/${item.id}.md`) throw new Error('tracking-definition-path-invalid');
|
|
112
|
+
const definition = readTracking(root, item.definition_ref);
|
|
113
|
+
if (!definition.includes(`kind: stage-work-item`) || !definition.includes(`id: ${item.id}\n`) || !definition.includes(tracking.checkpoint_ref) || /ready-for-agent|^Status:|^progress:/m.test(definition)) throw new Error('tracking-definition-invalid');
|
|
114
|
+
if (item.definition_digest !== sha256(definition)) throw new Error('tracking-definition-drift');
|
|
115
|
+
}
|
|
116
|
+
if (item.deferred) {
|
|
117
|
+
if (!item.split_reasons.includes('cross-stage-deferral') || !item.definition_ref) throw new Error('tracking-deferral-independent-item-required');
|
|
118
|
+
if (item.progress === 'completed' || item.progress === 'cancelled') throw new Error('tracking-deferred-not-completed');
|
|
119
|
+
if (!Number.isFinite(Date.parse(item.deferred.resolve_by)) || Date.parse(item.deferred.resolve_by) <= now.getTime()) throw new Error('tracking-deferral-expired');
|
|
120
|
+
readTracking(root, item.deferred.decision_ref);
|
|
121
|
+
}
|
|
122
|
+
if (item.progress === 'cancelled' && !item.cancellation_reason) throw new Error('tracking-cancellation-reason-required');
|
|
123
|
+
if (item.progress === 'completed') {
|
|
124
|
+
if (!item.source_refs.length) throw new Error('tracking-completion-source-required');
|
|
125
|
+
if (item.recheck_required) throw new Error('tracking-recheck-required');
|
|
126
|
+
for (const criterion of item.acceptance) if (!item.completion.some(c => c.criterion === criterion && c.evidence_refs.length)) throw new Error(`tracking-acceptance-evidence-required: ${item.id}`);
|
|
127
|
+
for (const c of item.completion) if (!item.acceptance.includes(c.criterion)) throw new Error('tracking-unknown-acceptance-criterion');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const visited = new Set(), visiting = new Set();
|
|
131
|
+
function visit(id) {
|
|
132
|
+
if (visiting.has(id)) throw new Error('tracking-dependency-cycle');
|
|
133
|
+
if (visited.has(id)) return;
|
|
134
|
+
const item = index.get(id);
|
|
135
|
+
if (!item) throw new Error(`tracking-dependency-missing: ${id}`);
|
|
136
|
+
visiting.add(id); item.dependencies.forEach(visit); visiting.delete(id); visited.add(id);
|
|
137
|
+
}
|
|
138
|
+
index.forEach((_, id) => visit(id));
|
|
139
|
+
for (const item of tracking.items) {
|
|
140
|
+
if ((item.owner !== tracking.items[0].owner || tracking.items.some(other => other.dependencies.includes(item.id))) && !item.definition_ref) throw new Error(`tracking-independent-item-required: ${item.id}`);
|
|
141
|
+
|
|
142
|
+
if (['running', 'completed'].includes(item.progress) && item.dependencies.some(id => index.get(id).progress !== 'completed')) throw new Error(`tracking-dependency-blocked: ${item.id}`);
|
|
143
|
+
}
|
|
144
|
+
const stale = trackingDrift(root, tracking);
|
|
145
|
+
if (stale.some(id => ['running', 'completed'].includes(index.get(id).progress))) throw new Error(`tracking-stale-completion: ${stale.join(',')}`);
|
|
146
|
+
if (entering && STAGE_WORK_UNITS[nextWorkUnit] && !tracking.items.some(i => i.work_unit === nextWorkUnit)) throw new Error('tracking-entry-work-item-required');
|
|
147
|
+
if (transition && STAGE_WORK_UNITS[currentWorkUnit]) {
|
|
148
|
+
const items = tracking.items.filter(i => i.work_unit === currentWorkUnit);
|
|
149
|
+
if (!items.length) throw new Error('tracking-current-work-item-required');
|
|
150
|
+
if (items.some(i => !['completed', 'cancelled'].includes(i.progress) && !i.deferred)) throw new Error('tracking-current-work-incomplete');
|
|
151
|
+
if (STAGE_WORK_UNITS[currentWorkUnit] !== STAGE_WORK_UNITS[nextWorkUnit] && tracking.items.some(i => i.stage === STAGE_WORK_UNITS[currentWorkUnit] && !['completed', 'cancelled'].includes(i.progress) && !i.deferred)) throw new Error('tracking-stage-incomplete');
|
|
152
|
+
}
|
|
153
|
+
return { status: 'valid', stale_item_ids: stale };
|
|
154
|
+
}
|
|
155
|
+
export function assertTrackingTransition(currentWorkUnit, nextWorkUnit, state, { root } = {}) {
|
|
156
|
+
// Persisted checkpoint is authoritative. Inline WER status cannot replace it.
|
|
157
|
+
if (!STAGE_WORK_UNITS[currentWorkUnit] && !STAGE_WORK_UNITS[nextWorkUnit] && !state?.stage_tracking && !state?.checkpoint_ref) return { status: 'not-applicable', stale_item_ids: [] };
|
|
158
|
+
const repository = parseYaml(readTracking(root, 'yss-project.yaml'));
|
|
159
|
+
if (repository.repository_mode === 'template-source' && !state?.stage_tracking) return { status: 'not-applicable', stale_item_ids: [] };
|
|
160
|
+
if (!state?.checkpoint_ref) {
|
|
161
|
+
const identity = parseYaml(readTracking(root, 'yss-project.yaml'));
|
|
162
|
+
if (state?.stage_tracking || (identity.repository_mode === 'project-instance' && trackerConfig(root).lifecycle_tracking_version === 1 && (STAGE_WORK_UNITS[currentWorkUnit] || STAGE_WORK_UNITS[nextWorkUnit]))) throw new Error('tracking-persisted-checkpoint-ref-required');
|
|
163
|
+
return assertStageTracking(state, { root, currentWorkUnit, nextWorkUnit, transition: true });
|
|
164
|
+
}
|
|
165
|
+
const checkpoint = parseYaml(readTracking(root, state.checkpoint_ref));
|
|
166
|
+
if (state.feature_id && checkpoint.feature_id !== state.feature_id) throw new Error('tracking-feature-mismatch');
|
|
167
|
+
return assertStageTracking(checkpoint, { root, checkpointRef: state.checkpoint_ref, currentWorkUnit, nextWorkUnit, transition: true });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function assertTrackingEntry(workUnit, state, { root } = {}) {
|
|
171
|
+
if (!STAGE_WORK_UNITS[workUnit]) return;
|
|
172
|
+
const repository = parseYaml(readTracking(root, 'yss-project.yaml'));
|
|
173
|
+
if (repository.repository_mode === 'template-source') return;
|
|
174
|
+
const enabled = trackerConfig(root).lifecycle_tracking_version === 1;
|
|
175
|
+
if (!state?.checkpoint_ref) {
|
|
176
|
+
if (enabled) throw new Error('tracking-entry-checkpoint-required');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const checkpoint = parseYaml(readTracking(root, state.checkpoint_ref));
|
|
180
|
+
assertStageTracking(checkpoint, { root, checkpointRef: state.checkpoint_ref, nextWorkUnit: workUnit, entering: true });
|
|
181
|
+
const items = checkpoint.stage_tracking?.items.filter(i => i.work_unit === workUnit) || [];
|
|
182
|
+
const stale = new Set(checkpoint.stage_tracking ? trackingDrift(root, checkpoint.stage_tracking) : []);
|
|
183
|
+
if (items.length && !items.some(i => !['blocked', 'cancelled'].includes(i.progress) && !i.deferred && !i.recheck_required && !stale.has(i.id) && i.dependencies.every(id => checkpoint.stage_tracking.items.find(d => d.id === id)?.progress === 'completed'))) throw new Error('tracking-entry-no-runnable-work');
|
|
184
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { uiBaselineSourceKeys, uiBaselineKind } from './ui-baseline.mjs';
|
|
2
|
-
import { existsSync, readdirSync } from '
|
|
2
|
+
import { existsSync, readdirSync, inValidationPhase, acceptValidationDependencies } from './validation-phase.mjs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { openBundle } from './strategic-handoff.mjs';
|
|
@@ -29,8 +29,9 @@ export async function verifyConsumption(data,{root=process.cwd(),sliceRef,consum
|
|
|
29
29
|
const route=receipt.routes.find(item=>item.capability===capability);
|
|
30
30
|
ensure(route&&route.activation!=='not-applicable'&&binding.route_id===route.route_id,`${capability} 未绑定当前 Handoff v4/v5 route_id`);
|
|
31
31
|
}
|
|
32
|
-
const result=spawnSync(process.execPath,[path.join(ROOT,'scripts/verify-context-reconciliation'),'--root',root,safe(root,binding.context_reconciliation_ref)],{encoding:'utf8'});
|
|
32
|
+
const result=spawnSync(process.execPath,[path.join(ROOT,'scripts/verify-context-reconciliation'),'--root',root,safe(root,binding.context_reconciliation_ref),...(inValidationPhase()?['--validation-dependencies']:[])],{encoding:'utf8',timeout:60000,maxBuffer:16*1024*1024});
|
|
33
33
|
ensure(result.status===0,`目标术语对账未通过: ${result.error?.message || result.stderr}`);
|
|
34
|
+
if(inValidationPhase()){let value;try{value=JSON.parse(result.stdout);}catch{throw new TypeError('VALIDATION_RECEIPT_INVALID: Context 子进程未返回依赖');}acceptValidationDependencies(value.validation_dependencies);}
|
|
34
35
|
const context=parseContextContract({root});
|
|
35
36
|
const parent=safe(root,`docs/handoffs/${receipt.bundle_id}`);
|
|
36
37
|
const versions=readdirSync(parent).filter(x=>/^v[1-9][0-9]*$/.test(x)&&existsSync(path.join(parent,x,'import-receipt.json'))).sort((a,b)=>Number(b.slice(1))-Number(a.slice(1)));
|
|
@@ -84,6 +85,6 @@ export async function verifyConsumption(data,{root=process.cwd(),sliceRef,consum
|
|
|
84
85
|
}
|
|
85
86
|
const blockedHere=all||(sliceRef?blocked.has(sliceRef):issues.length>0);
|
|
86
87
|
return {result:blockedHere?'blocked':'verified',bundle_digest:current.manifest.bundle_digest,consumed_bundle_digest:receipt.bundle_digest,...(consumer==='frontend'?{frontend_acceptance_digest:digest(data)}:{tactical_digest:digest(data), ...(data.schema_version === 2 ? {technical_design_digest:digest(data)} : {})}),scope:sliceRef||`whole-${consumer}-design`,coverage_complete:[...known.keys()].every(id=>rows.has(id)),block_all:all,blocked_slice_refs:[...blocked].sort(),issues};
|
|
87
|
-
},{readOnly});
|
|
88
|
-
},{readOnly});
|
|
88
|
+
},{readOnly:readOnly||inValidationPhase()});
|
|
89
|
+
},{readOnly:readOnly||inValidationPhase()});
|
|
89
90
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { mkdirSync, writeFileSync, realpathSync } from 'node:fs';
|
|
3
|
+
import { existsSync, lstatSync, readdirSync, readFileSync, validationMemo } from './validation-phase.mjs';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
5
6
|
import { spawnSync } from 'node:child_process';
|
|
@@ -9,6 +10,7 @@ import { parseDocument } from '../vendor/yaml.mjs';
|
|
|
9
10
|
export const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
10
11
|
// A v5 package keeps the source glossary as a snapshot, never a nested CONTEXT.md.
|
|
11
12
|
// Only this fixed alias is supported, isolated to the current asynchronous reader.
|
|
13
|
+
const parseCache=Symbol('handoff-yaml');
|
|
12
14
|
const sourceContextSnapshots = new AsyncLocalStorage();
|
|
13
15
|
export function withSourceContextSnapshot(root, action) {
|
|
14
16
|
const roots = new Set(sourceContextSnapshots.getStore() || []);
|
|
@@ -20,7 +22,8 @@ export const canonical = value => Array.isArray(value) ? value.map(canonical) :
|
|
|
20
22
|
export const hash = bytes => `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
|
|
21
23
|
export const digest = value => hash(JSON.stringify(canonical(value)));
|
|
22
24
|
export const json = value => `${JSON.stringify(canonical(value), null, 2)}\n`;
|
|
23
|
-
export function parse(bytes) {
|
|
25
|
+
export function parse(bytes) {return validationMemo(parseCache,String(bytes),()=>parseFresh(bytes));}
|
|
26
|
+
function parseFresh(bytes) {
|
|
24
27
|
const doc = parseDocument(String(bytes), { uniqueKeys: true, maxAliasCount: 0 });
|
|
25
28
|
ensure(!doc.errors.length, `YAML/JSON 无效: ${doc.errors[0]?.message}`);
|
|
26
29
|
return doc.toJS({ maxAliasCount: 0 });
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { existsSync } from './validation-phase.mjs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { read, safe, ensure } from './strategic-handoff-io.mjs';
|
|
4
|
+
|
|
5
|
+
// Wire work-unit IDs belong to the immutable source package. Only target routing is adapted.
|
|
6
|
+
export function consumerEntry(root, capability, sourceWorkUnit) {
|
|
7
|
+
const scope = existsSync(path.join(root, '.yss-execution-scope.yaml')) ? read(safe(root, '.yss-execution-scope.yaml')) : null;
|
|
8
|
+
const profile = existsSync(path.join(root, 'docs/process/harness-profile.yaml')) ? read(safe(root, 'docs/process/harness-profile.yaml')) : null;
|
|
9
|
+
const contractRef = scope || !profile ? '.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml' : '.agents/skills/harness-orchestrator/references/orchestration-contract.yaml';
|
|
10
|
+
const contract = read(safe(root, contractRef));
|
|
11
|
+
const target = scope?.scope_id || profile?.profile_id || 'yss-full-lifecycle';
|
|
12
|
+
const policy = contract.consumer_entry_routes?.[target]?.[capability];
|
|
13
|
+
ensure(policy && policy.source_work_unit === sourceWorkUnit, `consumer-entry-unmapped: ${target}/${capability}/${sourceWorkUnit}`);
|
|
14
|
+
const registry = read(safe(root, 'docs/process/lifecycle-registry.yaml'));
|
|
15
|
+
ensure(registry.work_units.some(unit => unit.id === policy.target_work_unit), 'consumer-entry-unknown-target');
|
|
16
|
+
if (scope) {
|
|
17
|
+
ensure(scope.schema_version === 1, 'consumer-entry-invalid-scope');
|
|
18
|
+
ensure(contract.execution_scopes?.[scope.scope_id]?.allowed_work_units?.includes(policy.target_work_unit), 'consumer-entry-outside-scope');
|
|
19
|
+
}
|
|
20
|
+
if (profile) ensure(profile.lifecycle.allowed_work_units.includes(policy.target_work_unit), 'consumer-entry-outside-profile');
|
|
21
|
+
return { capability, source_work_unit: sourceWorkUnit, target_work_unit: policy.target_work_unit, target_profile: target };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function scopedConsumerCapabilities(root, fallback) {
|
|
25
|
+
if (!existsSync(path.join(root, '.yss-execution-scope.yaml'))) return fallback;
|
|
26
|
+
const scope = read(safe(root, '.yss-execution-scope.yaml'));
|
|
27
|
+
const contract = read(safe(root, '.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml'));
|
|
28
|
+
const capabilities = contract.execution_scopes?.[scope.scope_id]?.consumer_capabilities;
|
|
29
|
+
ensure(scope.schema_version === 1 && Array.isArray(capabilities) && capabilities.length, 'consumer-scope-capabilities-missing');
|
|
30
|
+
return capabilities;
|
|
31
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { scopedConsumerCapabilities } from './strategic-handoff-routing.mjs';
|
|
2
|
+
import { existsSync, lstatSync, readFileSync } from './validation-phase.mjs';
|
|
3
|
+
import { mkdirSync, mkdtempSync, renameSync, rmSync, cpSync } from 'node:fs';
|
|
2
4
|
import path from 'node:path';
|
|
3
5
|
import { tmpdir } from 'node:os';
|
|
4
6
|
import { ensure, canonical, digest, hash, json, parse, read, safe, relative, files, write, project, schema, schemaBatch, archive, ROOT, sourceApprovalPolicy, withSourceContextSnapshot } from './strategic-handoff-io.mjs';
|
|
@@ -432,7 +434,7 @@ export async function importBundle({bundle,targetRoot}) {
|
|
|
432
434
|
}else{
|
|
433
435
|
const profileRef=path.join(target,'docs/process/harness-profile.yaml');
|
|
434
436
|
const profile=existsSync(profileRef)?read(profileRef):null;
|
|
435
|
-
const capabilities=profile?.handoff?.consumer_capabilities||CAPABILITIES;
|
|
437
|
+
const capabilities=scopedConsumerCapabilities(target,profile?.handoff?.consumer_capabilities||CAPABILITIES);
|
|
436
438
|
ensure(Array.isArray(capabilities)&&capabilities.length&&capabilities.every(capability=>CAPABILITIES.includes(capability)),'目标 profile 未声明受支持的消费者能力');
|
|
437
439
|
const selected=b.handoff.consumer_routes.filter(route=>capabilities.includes(route.capability));
|
|
438
440
|
ensure(selected.length===capabilities.length,'目标 profile 的消费者能力在 Handoff v4 中缺失');
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertTrackingEntry } from './stage-tracking.mjs';
|
|
1
2
|
import { normalizeSliceContract } from './slice-contract.mjs';
|
|
2
3
|
import { assertSliceV3TaskPackage } from './slice-task-package.mjs';
|
|
3
4
|
export { compileSliceTaskPackage, assertSliceV3TaskPackage } from './slice-task-package.mjs';
|
|
@@ -68,6 +69,7 @@ function validateSkillSource(value, registry) {
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
function validateCommon(value, registry, lifecycle) {
|
|
72
|
+
if (value.allowed_write_paths?.length && value.contract.kind === "lifecycle-work-unit") assertTrackingEntry(value.work_unit_id, value, { root: ROOT });
|
|
71
73
|
if (value.work_unit_id === 'work-unit.spec-synthesis') assertPlanSpecEntry(value);
|
|
72
74
|
const workUnit = lifecycle.work_units.find((item) => item.id === value.work_unit_id);
|
|
73
75
|
if (!workUnit && value.contract.kind !== "slice-implementation") fail(`未知 work_unit_id: ${value.work_unit_id}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assertApprovedExecutionContext, approvedExecutionBinding } from './approved-execution-context.mjs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { readFileSync } from '
|
|
3
|
+
import { readFileSync, inValidationPhase, acceptValidationDependencies } from './validation-phase.mjs';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { ROOT, read, safe, ensure, hash } from './strategic-handoff-io.mjs';
|
|
6
6
|
|
|
@@ -22,11 +22,13 @@ export function enforceTechnicalDesign(state = {}, { root = ROOT, execution, rea
|
|
|
22
22
|
if (binding.legacy_ddd === true) args.push('--legacy-ddd');
|
|
23
23
|
if(readOnly)args.push('--read-only');
|
|
24
24
|
if(execution){
|
|
25
|
-
assertApprovedExecutionContext(execution,{root,technicalDesign:data,architectureIdentity:state.architecture_identity,sliceId:state.slice_id});
|
|
25
|
+
assertApprovedExecutionContext(execution,{root,technicalDesign:data,architectureIdentity:state.architecture_identity,sliceId:state.slice_id,readOnly});
|
|
26
26
|
const approved=approvedExecutionBinding(execution);
|
|
27
27
|
if(approved.work_unit_id)args.push('--work-unit',approved.work_unit_id);
|
|
28
28
|
args.push('--approved-slice',approved.ref,'--approved-slice-digest',approved.digest,'--approved-slice-approval',approved.approval_ref);
|
|
29
29
|
}
|
|
30
|
+
if(inValidationPhase())args.push('--validation-dependencies');
|
|
30
31
|
const verified = spawnSync(process.execPath, args, { cwd: root, encoding: 'utf8', timeout: 60000, maxBuffer: 2 * 1024 * 1024 });
|
|
31
32
|
ensure(verified.status === 0, `技术设计不可消费: ${verified.error?.message || verified.stderr}`);
|
|
33
|
+
if(inValidationPhase()){let output;try{output=JSON.parse(verified.stdout);}catch{throw new TypeError('VALIDATION_RECEIPT_INVALID: 技术设计子进程未返回依赖');}const dependencies=output.validation_dependencies;const required=[file,...(execution?[path.resolve(root,approvedExecutionBinding(execution).ref),path.resolve(root,approvedExecutionBinding(execution).approval_ref),path.resolve(root,'docs/agents/digital-human-roles.yaml')]:[])];ensure(required.every(ref=>dependencies?.files?.some(row=>row.file===ref)),'VALIDATION_RECEIPT_INVALID: 技术设计依赖报告缺少必要原始资产');acceptValidationDependencies(dependencies);}
|
|
32
34
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from '
|
|
1
|
+
import { readFileSync } from './validation-phase.mjs';
|
|
2
2
|
import { ensure, read, safe, hash } from './strategic-handoff-io.mjs';
|
|
3
3
|
import { validateVisualBaseline } from '../../.agents/skills/yss-prototype-stage/scripts/visual-baseline-contract.mjs';
|
|
4
4
|
import { validateExistingUiBaseline } from './existing-ui-baseline.mjs';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { normalizeSliceContract } from './slice-contract.mjs';
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { readFileSync } from
|
|
3
|
+
import { readFileSync } from './validation-phase.mjs';
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { parseDocument } from "../vendor/yaml.mjs";
|
|
6
6
|
import { ROOT } from "./lifecycle-registry.mjs";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {fileURLToPath} from 'node:url';
|
|
4
|
+
import {createHash} from 'node:crypto';
|
|
5
|
+
import {AsyncLocalStorage} from 'node:async_hooks';
|
|
6
|
+
|
|
7
|
+
// Only a live local call owns these snapshots. Neither receipts nor cache data confer approval.
|
|
8
|
+
const phases=new AsyncLocalStorage();
|
|
9
|
+
const checksum=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
10
|
+
const filename=value=>path.resolve(value instanceof URL?fileURLToPath(value):value);
|
|
11
|
+
const error=(code,detail)=>Object.assign(new TypeError(`${code}: ${detail}`),{code});
|
|
12
|
+
const current=()=>{const phase=phases.getStore();if(phase&&!phase.active)throw error('VALIDATION_PHASE_EXPIRED','验证阶段已经结束');if(phase?.signal?.aborted)throw error('VALIDATION_CANCELLED','验证阶段已取消');return phase;};
|
|
13
|
+
const statShape=stat=>({type:stat.isSymbolicLink()?'link':stat.isDirectory()?'directory':stat.isFile()?'file':'other',mode:Number(stat.mode),ino:String(stat.ino),dev:String(stat.dev)});
|
|
14
|
+
function observe(file,kind,read){const phase=current();if(!phase)return read();const key=`${kind}\0${file}`;if(!phase.observations.has(key))phase.observations.set(key,{file,kind,value:read()});return phase.observations.get(key).value;}
|
|
15
|
+
function pathIdentity(file){let part=path.parse(file).root;for(const name of path.relative(part,file).split(path.sep).filter(Boolean)){part=path.join(part,name);const nameRef=part;observe(nameRef,'stat',()=>{try{return statShape(fs.lstatSync(nameRef));}catch(e){if(e.code==='ENOENT')return null;throw e;}});}}
|
|
16
|
+
export function readFileSync(file,options){
|
|
17
|
+
const phase=current();if(!phase||typeof file==='number'||(typeof options==='object'&&options?.flag&&options.flag!=='r'))return fs.readFileSync(file,options);
|
|
18
|
+
const ref=filename(file);pathIdentity(ref);
|
|
19
|
+
if(!phase.files.has(ref))phase.files.set(ref,Buffer.from(fs.readFileSync(ref)));
|
|
20
|
+
const bytes=phase.files.get(ref),encoding=typeof options==='string'?options:options?.encoding;
|
|
21
|
+
return encoding?bytes.toString(encoding):Buffer.from(bytes);
|
|
22
|
+
}
|
|
23
|
+
export async function readFile(file,options){return readFileSync(file,options);}
|
|
24
|
+
export async function readdir(file,options){return readdirSync(file,options);}
|
|
25
|
+
export function existsSync(file){const phase=current();if(!phase||typeof file==='number')return fs.existsSync(file);const ref=filename(file);pathIdentity(ref);return observe(ref,'exists',()=>fs.existsSync(ref));}
|
|
26
|
+
export function lstatSync(file,options){const result=fs.lstatSync(file,options);const phase=current();if(phase&&result){const ref=filename(file);observe(ref,'stat',()=>statShape(result));}return result;}
|
|
27
|
+
export function readdirSync(file,options){
|
|
28
|
+
const result=fs.readdirSync(file,options),phase=current();
|
|
29
|
+
if(phase){const ref=filename(file);pathIdentity(ref);
|
|
30
|
+
// Record the enumeration actually returned to the consumer, not a second read.
|
|
31
|
+
const encoding=typeof options==='string'?options:options?.encoding||'utf8';
|
|
32
|
+
const names=result.map(entry=>{const name=typeof entry==='string'||Buffer.isBuffer(entry)?entry:entry.name;return Buffer.isBuffer(name)?name.toString():Buffer.from(name,encoding==='buffer'?'utf8':encoding).toString();}).sort();
|
|
33
|
+
const recorded=observe(ref,'directory',()=>names);
|
|
34
|
+
if(JSON.stringify(recorded)!==JSON.stringify(names))throw error('VALIDATION_INPUT_CHANGED',ref);
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
function actualObservation(row){if(row.kind==='exists')return fs.existsSync(row.file);if(row.kind==='directory')return fs.readdirSync(row.file).sort();if(row.kind==='stat'){try{return statShape(fs.lstatSync(row.file));}catch(e){if(e.code==='ENOENT')return null;throw e;}}throw error('VALIDATION_RECEIPT_INVALID','未知依赖类型');}
|
|
39
|
+
function receipt(phase){return{schema_version:1,files:[...phase.files].map(([file,bytes])=>({file,digest:checksum(bytes)})),observations:[...phase.observations.values()]};}
|
|
40
|
+
function checkReceipt(value){
|
|
41
|
+
if(value?.schema_version!==1||!Array.isArray(value.files)||!Array.isArray(value.observations))throw error('VALIDATION_RECEIPT_INVALID','缺少受控校验进程的依赖');
|
|
42
|
+
for(const row of value.files){if(!path.isAbsolute(row.file)||!/^[a-f0-9]{64}$/.test(row.digest))throw error('VALIDATION_RECEIPT_INVALID','非法文件依赖');try{if(checksum(fs.readFileSync(row.file))!==row.digest)throw Error('changed');}catch{throw error('VALIDATION_INPUT_CHANGED',row.file);}}
|
|
43
|
+
for(const row of value.observations){if(!path.isAbsolute(row.file))throw error('VALIDATION_RECEIPT_INVALID','非法路径依赖');try{if(JSON.stringify(actualObservation(row))!==JSON.stringify(row.value))throw Error('changed');}catch{throw error('VALIDATION_INPUT_CHANGED',row.file);}}
|
|
44
|
+
}
|
|
45
|
+
function mergedReceipt(phase){
|
|
46
|
+
const files=new Map(),observations=new Map();
|
|
47
|
+
for(const part of [receipt(phase),...phase.children]){
|
|
48
|
+
if(part?.schema_version!==1||!Array.isArray(part.files)||!Array.isArray(part.observations))throw error('VALIDATION_RECEIPT_INVALID','缺少受控校验进程的依赖');
|
|
49
|
+
for(const row of part.files){if(typeof row.file!=='string'||!path.isAbsolute(row.file)||!/^[a-f0-9]{64}$/.test(row.digest))throw error('VALIDATION_RECEIPT_INVALID','非法文件依赖');if(files.has(row.file)&&files.get(row.file).digest!==row.digest)throw error('VALIDATION_INPUT_CHANGED',row.file);files.set(row.file,row);}
|
|
50
|
+
for(const row of part.observations){if(typeof row.file!=='string'||!path.isAbsolute(row.file)||!['stat','exists','directory'].includes(row.kind))throw error('VALIDATION_RECEIPT_INVALID','非法路径依赖');const key=`${row.kind}\0${row.file}`;if(observations.has(key)&&JSON.stringify(observations.get(key).value)!==JSON.stringify(row.value))throw error('VALIDATION_INPUT_CHANGED',row.file);observations.set(key,row);}
|
|
51
|
+
}
|
|
52
|
+
return{schema_version:1,files:[...files.values()],observations:[...observations.values()]};
|
|
53
|
+
}
|
|
54
|
+
export function acceptValidationDependencies(value){
|
|
55
|
+
const phase=current();if(!phase)throw error('VALIDATION_PHASE_REQUIRED','子进程依赖必须交回本次验证阶段');
|
|
56
|
+
// Compare parent/child observations now; verify their union against disk before returning.
|
|
57
|
+
phase.children.push(structuredClone(value));mergedReceipt(phase);
|
|
58
|
+
}
|
|
59
|
+
export function validationDependencies(){const phase=current();if(!phase)throw error('VALIDATION_PHASE_REQUIRED','没有活动阶段');return structuredClone(mergedReceipt(phase));}
|
|
60
|
+
export function validationCache(namespace,key,...values){const phase=current();if(!phase)return undefined;const cache=phase.memo.get(namespace)||new Map();phase.memo.set(namespace,cache);if(values.length)cache.set(key,structuredClone(values[0]));return structuredClone(cache.get(key));}
|
|
61
|
+
export function validationMemo(namespace,key,compute){const phase=current();if(!phase)return compute();const cache=phase.memo.get(namespace)||new Map();phase.memo.set(namespace,cache);if(!cache.has(key))cache.set(key,structuredClone(compute()));return structuredClone(cache.get(key));}
|
|
62
|
+
export function validationPhaseToken(){return current()?.token;}
|
|
63
|
+
export function inValidationPhase(){return !!current();}
|
|
64
|
+
export function withValidationPhase(binding,action){
|
|
65
|
+
const parent=current(),identity=JSON.stringify({root:path.resolve(binding.root||process.cwd()),purpose:binding.purpose,unit:binding.work_unit_id||null,slice:binding.slice_id||null,readOnly:binding.readOnly===true});
|
|
66
|
+
if(binding.signal?.aborted)throw error('VALIDATION_CANCELLED','验证阶段已取消');
|
|
67
|
+
if(parent?.identity===identity&&(!binding.signal||binding.signal===parent.signal))return action();
|
|
68
|
+
const phase={identity,token:Object.freeze({}),active:true,files:new Map(),observations:new Map(),memo:new Map(),children:[],signal:binding.signal};
|
|
69
|
+
const finish=value=>{try{current();const dependencies=mergedReceipt(phase);checkReceipt(dependencies);if(parent){parent.children.push(dependencies);mergedReceipt(parent);}return value;}finally{phase.active=false;}};
|
|
70
|
+
return phases.run(phase,()=>{try{const value=action();if(value&&typeof value.then==='function')return value.then(finish,error=>{phase.active=false;throw error;});return finish(value);}catch(error){phase.active=false;throw error;}});
|
|
71
|
+
}
|
|
72
|
+
export default {...fs,readFileSync,existsSync,lstatSync,readdirSync};
|