mustflow 1.18.16 → 1.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -8
- package/dist/cli/commands/adapters.js +90 -0
- package/dist/cli/commands/classify.js +3 -4
- package/dist/cli/commands/contract-lint.js +26 -6
- package/dist/cli/commands/dashboard.js +103 -4
- package/dist/cli/commands/explain-verify.js +213 -0
- package/dist/cli/commands/explain.js +48 -4
- package/dist/cli/commands/handoff.js +136 -0
- package/dist/cli/commands/run.js +302 -168
- package/dist/cli/commands/update.js +91 -61
- package/dist/cli/commands/upgrade.js +65 -0
- package/dist/cli/commands/verify.js +304 -139
- package/dist/cli/i18n/en.js +77 -4
- package/dist/cli/i18n/es.js +77 -4
- package/dist/cli/i18n/fr.js +77 -4
- package/dist/cli/i18n/hi.js +77 -4
- package/dist/cli/i18n/ko.js +77 -4
- package/dist/cli/i18n/zh.js +77 -4
- package/dist/cli/index.js +34 -42
- package/dist/cli/lib/command-registry.js +15 -0
- package/dist/cli/lib/dashboard-export.js +775 -0
- package/dist/cli/lib/dashboard-html.js +1 -1
- package/dist/cli/lib/local-index.js +33 -14
- package/dist/cli/lib/reporter.js +6 -0
- package/dist/cli/lib/run-plan.js +239 -0
- package/dist/cli/lib/templates.js +18 -3
- package/dist/cli/lib/update-diff-preview.js +163 -0
- package/dist/cli/lib/validation.js +132 -1
- package/dist/core/adapter-compatibility.js +235 -0
- package/dist/core/bounded-output.js +38 -0
- package/dist/core/change-classification.js +14 -1
- package/dist/core/change-verification.js +246 -5
- package/dist/core/check-issues.js +10 -0
- package/dist/core/command-contract-validation.js +34 -0
- package/dist/core/command-cwd.js +18 -6
- package/dist/core/command-effects.js +13 -0
- package/dist/core/command-env.js +91 -0
- package/dist/core/contract-lint.js +260 -4
- package/dist/core/contract-models.js +172 -0
- package/dist/core/dashboard-verification.js +10 -0
- package/dist/core/doc-review-triage.js +1 -0
- package/dist/core/handoff-record.js +376 -0
- package/dist/core/public-json-contracts.js +23 -0
- package/dist/core/run-performance-history.js +307 -0
- package/dist/core/run-profile.js +87 -0
- package/dist/core/run-receipt.js +217 -11
- package/dist/core/run-write-drift.js +196 -0
- package/dist/core/secret-redaction.js +39 -0
- package/dist/core/skill-route-alignment.js +90 -0
- package/dist/core/source-anchors.js +3 -5
- package/dist/core/test-selection.js +224 -0
- package/dist/core/verification-decision-graph.js +290 -0
- package/dist/core/verification-scheduler.js +96 -2
- package/package.json +3 -1
- package/schemas/README.md +15 -4
- package/schemas/adapter-compatibility-report.schema.json +184 -0
- package/schemas/change-verification-report.schema.json +286 -4
- package/schemas/commands.schema.json +55 -2
- package/schemas/contract-lint-report.schema.json +99 -0
- package/schemas/dashboard-export.schema.json +273 -0
- package/schemas/explain-report.schema.json +267 -2
- package/schemas/handoff-validation-report.schema.json +68 -0
- package/schemas/run-receipt.schema.json +183 -1
- package/templates/default/common/.mustflow/config/commands.toml +3 -1
- package/templates/default/i18n.toml +78 -234
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +7 -3
- package/templates/default/locales/en/.mustflow/skills/architecture-deepening-review/SKILL.md +154 -0
- package/templates/default/locales/en/.mustflow/skills/behavior-preserving-refactor/SKILL.md +8 -3
- package/templates/default/locales/en/.mustflow/skills/code-review/SKILL.md +9 -4
- package/templates/default/locales/en/.mustflow/skills/date-number-audit/SKILL.md +19 -4
- package/templates/default/locales/en/.mustflow/skills/diff-risk-review/SKILL.md +4 -2
- package/templates/default/locales/en/.mustflow/skills/external-skill-intake/SKILL.md +141 -0
- package/templates/default/locales/en/.mustflow/skills/release-notes-authoring/SKILL.md +143 -0
- package/templates/default/locales/en/.mustflow/skills/repro-first-debug/SKILL.md +22 -8
- package/templates/default/locales/en/.mustflow/skills/skill-authoring/SKILL.md +3 -3
- package/templates/default/locales/en/.mustflow/skills/source-freshness-check/SKILL.md +22 -9
- package/templates/default/locales/en/.mustflow/skills/ui-quality-gate/SKILL.md +21 -13
- package/templates/default/locales/en/.mustflow/skills/vertical-slice-tdd/SKILL.md +167 -0
- package/templates/default/manifest.toml +16 -1
- package/templates/default/locales/es/.mustflow/skills/INDEX.md +0 -75
- package/templates/default/locales/es/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
- package/templates/default/locales/es/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
- package/templates/default/locales/es/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
- package/templates/default/locales/es/.mustflow/skills/code-review/SKILL.md +0 -115
- package/templates/default/locales/es/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
- package/templates/default/locales/es/.mustflow/skills/command-pattern/SKILL.md +0 -247
- package/templates/default/locales/es/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
- package/templates/default/locales/es/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
- package/templates/default/locales/es/.mustflow/skills/database-change-safety/SKILL.md +0 -155
- package/templates/default/locales/es/.mustflow/skills/date-number-audit/SKILL.md +0 -116
- package/templates/default/locales/es/.mustflow/skills/dependency-injection/SKILL.md +0 -161
- package/templates/default/locales/es/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
- package/templates/default/locales/es/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
- package/templates/default/locales/es/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
- package/templates/default/locales/es/.mustflow/skills/docs-update/SKILL.md +0 -97
- package/templates/default/locales/es/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
- package/templates/default/locales/es/.mustflow/skills/facade-pattern/SKILL.md +0 -210
- package/templates/default/locales/es/.mustflow/skills/failure-triage/SKILL.md +0 -97
- package/templates/default/locales/es/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
- package/templates/default/locales/es/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
- package/templates/default/locales/es/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
- package/templates/default/locales/es/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -260
- package/templates/default/locales/es/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
- package/templates/default/locales/es/.mustflow/skills/pattern-scout/SKILL.md +0 -110
- package/templates/default/locales/es/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
- package/templates/default/locales/es/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
- package/templates/default/locales/es/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
- package/templates/default/locales/es/.mustflow/skills/readme-authoring/SKILL.md +0 -115
- package/templates/default/locales/es/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
- package/templates/default/locales/es/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
- package/templates/default/locales/es/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
- package/templates/default/locales/es/.mustflow/skills/result-option/SKILL.md +0 -186
- package/templates/default/locales/es/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
- package/templates/default/locales/es/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
- package/templates/default/locales/es/.mustflow/skills/skill-authoring/SKILL.md +0 -110
- package/templates/default/locales/es/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
- package/templates/default/locales/es/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
- package/templates/default/locales/es/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
- package/templates/default/locales/es/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
- package/templates/default/locales/es/.mustflow/skills/test-design-guard/SKILL.md +0 -162
- package/templates/default/locales/es/.mustflow/skills/test-maintenance/SKILL.md +0 -122
- package/templates/default/locales/es/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
- package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
- package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
- package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
- package/templates/default/locales/es/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
- package/templates/default/locales/fr/.mustflow/skills/INDEX.md +0 -75
- package/templates/default/locales/fr/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
- package/templates/default/locales/fr/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
- package/templates/default/locales/fr/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
- package/templates/default/locales/fr/.mustflow/skills/code-review/SKILL.md +0 -115
- package/templates/default/locales/fr/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
- package/templates/default/locales/fr/.mustflow/skills/command-pattern/SKILL.md +0 -247
- package/templates/default/locales/fr/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
- package/templates/default/locales/fr/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
- package/templates/default/locales/fr/.mustflow/skills/database-change-safety/SKILL.md +0 -155
- package/templates/default/locales/fr/.mustflow/skills/date-number-audit/SKILL.md +0 -116
- package/templates/default/locales/fr/.mustflow/skills/dependency-injection/SKILL.md +0 -161
- package/templates/default/locales/fr/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
- package/templates/default/locales/fr/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
- package/templates/default/locales/fr/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
- package/templates/default/locales/fr/.mustflow/skills/docs-update/SKILL.md +0 -97
- package/templates/default/locales/fr/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
- package/templates/default/locales/fr/.mustflow/skills/facade-pattern/SKILL.md +0 -210
- package/templates/default/locales/fr/.mustflow/skills/failure-triage/SKILL.md +0 -97
- package/templates/default/locales/fr/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
- package/templates/default/locales/fr/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
- package/templates/default/locales/fr/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
- package/templates/default/locales/fr/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -260
- package/templates/default/locales/fr/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
- package/templates/default/locales/fr/.mustflow/skills/pattern-scout/SKILL.md +0 -110
- package/templates/default/locales/fr/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
- package/templates/default/locales/fr/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
- package/templates/default/locales/fr/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
- package/templates/default/locales/fr/.mustflow/skills/readme-authoring/SKILL.md +0 -115
- package/templates/default/locales/fr/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
- package/templates/default/locales/fr/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
- package/templates/default/locales/fr/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
- package/templates/default/locales/fr/.mustflow/skills/result-option/SKILL.md +0 -186
- package/templates/default/locales/fr/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
- package/templates/default/locales/fr/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
- package/templates/default/locales/fr/.mustflow/skills/skill-authoring/SKILL.md +0 -110
- package/templates/default/locales/fr/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
- package/templates/default/locales/fr/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
- package/templates/default/locales/fr/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
- package/templates/default/locales/fr/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
- package/templates/default/locales/fr/.mustflow/skills/test-design-guard/SKILL.md +0 -162
- package/templates/default/locales/fr/.mustflow/skills/test-maintenance/SKILL.md +0 -122
- package/templates/default/locales/fr/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
- package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
- package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
- package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
- package/templates/default/locales/fr/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
- package/templates/default/locales/hi/.mustflow/skills/INDEX.md +0 -75
- package/templates/default/locales/hi/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
- package/templates/default/locales/hi/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
- package/templates/default/locales/hi/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
- package/templates/default/locales/hi/.mustflow/skills/code-review/SKILL.md +0 -115
- package/templates/default/locales/hi/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
- package/templates/default/locales/hi/.mustflow/skills/command-pattern/SKILL.md +0 -247
- package/templates/default/locales/hi/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
- package/templates/default/locales/hi/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
- package/templates/default/locales/hi/.mustflow/skills/database-change-safety/SKILL.md +0 -155
- package/templates/default/locales/hi/.mustflow/skills/date-number-audit/SKILL.md +0 -116
- package/templates/default/locales/hi/.mustflow/skills/dependency-injection/SKILL.md +0 -161
- package/templates/default/locales/hi/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
- package/templates/default/locales/hi/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
- package/templates/default/locales/hi/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
- package/templates/default/locales/hi/.mustflow/skills/docs-update/SKILL.md +0 -97
- package/templates/default/locales/hi/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
- package/templates/default/locales/hi/.mustflow/skills/facade-pattern/SKILL.md +0 -210
- package/templates/default/locales/hi/.mustflow/skills/failure-triage/SKILL.md +0 -97
- package/templates/default/locales/hi/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
- package/templates/default/locales/hi/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
- package/templates/default/locales/hi/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
- package/templates/default/locales/hi/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -260
- package/templates/default/locales/hi/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
- package/templates/default/locales/hi/.mustflow/skills/pattern-scout/SKILL.md +0 -110
- package/templates/default/locales/hi/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
- package/templates/default/locales/hi/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
- package/templates/default/locales/hi/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
- package/templates/default/locales/hi/.mustflow/skills/readme-authoring/SKILL.md +0 -115
- package/templates/default/locales/hi/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
- package/templates/default/locales/hi/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
- package/templates/default/locales/hi/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
- package/templates/default/locales/hi/.mustflow/skills/result-option/SKILL.md +0 -186
- package/templates/default/locales/hi/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
- package/templates/default/locales/hi/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
- package/templates/default/locales/hi/.mustflow/skills/skill-authoring/SKILL.md +0 -110
- package/templates/default/locales/hi/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
- package/templates/default/locales/hi/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
- package/templates/default/locales/hi/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
- package/templates/default/locales/hi/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
- package/templates/default/locales/hi/.mustflow/skills/test-design-guard/SKILL.md +0 -162
- package/templates/default/locales/hi/.mustflow/skills/test-maintenance/SKILL.md +0 -122
- package/templates/default/locales/hi/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
- package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
- package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
- package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
- package/templates/default/locales/hi/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
- package/templates/default/locales/ko/.mustflow/skills/INDEX.md +0 -80
- package/templates/default/locales/ko/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
- package/templates/default/locales/ko/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
- package/templates/default/locales/ko/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
- package/templates/default/locales/ko/.mustflow/skills/code-review/SKILL.md +0 -118
- package/templates/default/locales/ko/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
- package/templates/default/locales/ko/.mustflow/skills/command-pattern/SKILL.md +0 -247
- package/templates/default/locales/ko/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
- package/templates/default/locales/ko/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
- package/templates/default/locales/ko/.mustflow/skills/database-change-safety/SKILL.md +0 -155
- package/templates/default/locales/ko/.mustflow/skills/date-number-audit/SKILL.md +0 -116
- package/templates/default/locales/ko/.mustflow/skills/dependency-injection/SKILL.md +0 -161
- package/templates/default/locales/ko/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
- package/templates/default/locales/ko/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
- package/templates/default/locales/ko/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
- package/templates/default/locales/ko/.mustflow/skills/docs-update/SKILL.md +0 -107
- package/templates/default/locales/ko/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
- package/templates/default/locales/ko/.mustflow/skills/facade-pattern/SKILL.md +0 -210
- package/templates/default/locales/ko/.mustflow/skills/failure-triage/SKILL.md +0 -119
- package/templates/default/locales/ko/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
- package/templates/default/locales/ko/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
- package/templates/default/locales/ko/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
- package/templates/default/locales/ko/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -259
- package/templates/default/locales/ko/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
- package/templates/default/locales/ko/.mustflow/skills/pattern-scout/SKILL.md +0 -110
- package/templates/default/locales/ko/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
- package/templates/default/locales/ko/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
- package/templates/default/locales/ko/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
- package/templates/default/locales/ko/.mustflow/skills/readme-authoring/SKILL.md +0 -115
- package/templates/default/locales/ko/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
- package/templates/default/locales/ko/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
- package/templates/default/locales/ko/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
- package/templates/default/locales/ko/.mustflow/skills/result-option/SKILL.md +0 -186
- package/templates/default/locales/ko/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
- package/templates/default/locales/ko/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
- package/templates/default/locales/ko/.mustflow/skills/skill-authoring/SKILL.md +0 -110
- package/templates/default/locales/ko/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
- package/templates/default/locales/ko/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
- package/templates/default/locales/ko/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
- package/templates/default/locales/ko/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
- package/templates/default/locales/ko/.mustflow/skills/test-design-guard/SKILL.md +0 -162
- package/templates/default/locales/ko/.mustflow/skills/test-maintenance/SKILL.md +0 -130
- package/templates/default/locales/ko/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
- package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
- package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
- package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
- package/templates/default/locales/ko/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
- package/templates/default/locales/zh/.mustflow/skills/INDEX.md +0 -74
- package/templates/default/locales/zh/.mustflow/skills/adapter-boundary/SKILL.md +0 -193
- package/templates/default/locales/zh/.mustflow/skills/artifact-integrity-check/SKILL.md +0 -114
- package/templates/default/locales/zh/.mustflow/skills/behavior-preserving-refactor/SKILL.md +0 -182
- package/templates/default/locales/zh/.mustflow/skills/code-review/SKILL.md +0 -115
- package/templates/default/locales/zh/.mustflow/skills/codebase-orientation/SKILL.md +0 -115
- package/templates/default/locales/zh/.mustflow/skills/command-pattern/SKILL.md +0 -247
- package/templates/default/locales/zh/.mustflow/skills/composition-over-inheritance/SKILL.md +0 -176
- package/templates/default/locales/zh/.mustflow/skills/contract-sync-check/SKILL.md +0 -116
- package/templates/default/locales/zh/.mustflow/skills/database-change-safety/SKILL.md +0 -155
- package/templates/default/locales/zh/.mustflow/skills/date-number-audit/SKILL.md +0 -116
- package/templates/default/locales/zh/.mustflow/skills/dependency-injection/SKILL.md +0 -161
- package/templates/default/locales/zh/.mustflow/skills/dependency-reality-check/SKILL.md +0 -115
- package/templates/default/locales/zh/.mustflow/skills/diff-risk-review/SKILL.md +0 -136
- package/templates/default/locales/zh/.mustflow/skills/docs-prose-review/SKILL.md +0 -119
- package/templates/default/locales/zh/.mustflow/skills/docs-update/SKILL.md +0 -97
- package/templates/default/locales/zh/.mustflow/skills/external-prompt-injection-defense/SKILL.md +0 -116
- package/templates/default/locales/zh/.mustflow/skills/facade-pattern/SKILL.md +0 -210
- package/templates/default/locales/zh/.mustflow/skills/failure-triage/SKILL.md +0 -96
- package/templates/default/locales/zh/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +0 -118
- package/templates/default/locales/zh/.mustflow/skills/line-ending-hygiene/SKILL.md +0 -111
- package/templates/default/locales/zh/.mustflow/skills/migration-safety-check/SKILL.md +0 -117
- package/templates/default/locales/zh/.mustflow/skills/multi-agent-work-coordination/SKILL.md +0 -260
- package/templates/default/locales/zh/.mustflow/skills/null-object-pattern/SKILL.md +0 -196
- package/templates/default/locales/zh/.mustflow/skills/pattern-scout/SKILL.md +0 -110
- package/templates/default/locales/zh/.mustflow/skills/performance-budget-check/SKILL.md +0 -121
- package/templates/default/locales/zh/.mustflow/skills/project-context-authoring/SKILL.md +0 -107
- package/templates/default/locales/zh/.mustflow/skills/pure-core-imperative-shell/SKILL.md +0 -212
- package/templates/default/locales/zh/.mustflow/skills/readme-authoring/SKILL.md +0 -115
- package/templates/default/locales/zh/.mustflow/skills/repo-improvement-loop/SKILL.md +0 -150
- package/templates/default/locales/zh/.mustflow/skills/repro-first-debug/SKILL.md +0 -112
- package/templates/default/locales/zh/.mustflow/skills/requirement-regression-guard/SKILL.md +0 -152
- package/templates/default/locales/zh/.mustflow/skills/result-option/SKILL.md +0 -186
- package/templates/default/locales/zh/.mustflow/skills/security-privacy-review/SKILL.md +0 -116
- package/templates/default/locales/zh/.mustflow/skills/security-regression-tests/SKILL.md +0 -131
- package/templates/default/locales/zh/.mustflow/skills/skill-authoring/SKILL.md +0 -110
- package/templates/default/locales/zh/.mustflow/skills/source-freshness-check/SKILL.md +0 -111
- package/templates/default/locales/zh/.mustflow/skills/state-machine-pattern/SKILL.md +0 -214
- package/templates/default/locales/zh/.mustflow/skills/strategy-pattern/SKILL.md +0 -215
- package/templates/default/locales/zh/.mustflow/skills/structure-discovery-gate/SKILL.md +0 -159
- package/templates/default/locales/zh/.mustflow/skills/test-design-guard/SKILL.md +0 -162
- package/templates/default/locales/zh/.mustflow/skills/test-maintenance/SKILL.md +0 -122
- package/templates/default/locales/zh/.mustflow/skills/ui-quality-gate/SKILL.md +0 -117
- package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/SKILL.md +0 -127
- package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/assets/review-template.html +0 -286
- package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/resources.toml +0 -7
- package/templates/default/locales/zh/.mustflow/skills/web-asset-optimization/SKILL.md +0 -108
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { isRecord, readStringArray } from './config-loading.js';
|
|
1
2
|
import { CHANGE_CLASSIFICATION_SURFACE_AUTHORITY, createPathTarget, } from './surface-decision-model.js';
|
|
2
|
-
import { createVerificationPlan, } from './verification-plan.js';
|
|
3
|
+
import { classifyVerificationCandidate, createVerificationPlan, } from './verification-plan.js';
|
|
4
|
+
import { createVerificationDecisionGraph, } from './verification-decision-graph.js';
|
|
3
5
|
import { createVerificationSchedule, } from './verification-scheduler.js';
|
|
6
|
+
import { createProjectTestSelectionPlan, } from './test-selection.js';
|
|
4
7
|
export const CHANGE_VERIFICATION_SCHEMA_VERSION = '1';
|
|
5
8
|
function uniqueSorted(values) {
|
|
6
9
|
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
@@ -8,6 +11,21 @@ function uniqueSorted(values) {
|
|
|
8
11
|
function uniqueUpdatePolicies(values) {
|
|
9
12
|
return uniqueSorted([...values].filter((value) => value !== 'not_applicable'));
|
|
10
13
|
}
|
|
14
|
+
const DECLARED_ESCALATION_SIGNALS = [
|
|
15
|
+
'public_api',
|
|
16
|
+
'release',
|
|
17
|
+
'package',
|
|
18
|
+
'packaging',
|
|
19
|
+
'security',
|
|
20
|
+
'selector',
|
|
21
|
+
'command contract',
|
|
22
|
+
'classifier',
|
|
23
|
+
'classification',
|
|
24
|
+
'verification planner',
|
|
25
|
+
'verification planning',
|
|
26
|
+
'machine-readable output contract',
|
|
27
|
+
'JSON schema',
|
|
28
|
+
];
|
|
11
29
|
function classificationsForReason(classificationReport, reason) {
|
|
12
30
|
return classificationReport.classifications.filter((classification) => classification.surface.validationReasons.includes(reason));
|
|
13
31
|
}
|
|
@@ -39,13 +57,209 @@ function createVerificationRequirement(classificationReport, reason) {
|
|
|
39
57
|
source: 'change_classification',
|
|
40
58
|
};
|
|
41
59
|
}
|
|
42
|
-
function
|
|
60
|
+
function candidateKey(reason, intent) {
|
|
61
|
+
return `${reason}\0${intent}`;
|
|
62
|
+
}
|
|
63
|
+
function readIntentRelationList(commandContract, intent, key) {
|
|
64
|
+
const rawIntent = commandContract.intents[intent];
|
|
65
|
+
if (!isRecord(rawIntent) || !isRecord(rawIntent.relations)) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
return readStringArray(rawIntent.relations, key) ?? [];
|
|
69
|
+
}
|
|
70
|
+
function readIntentSelectionList(commandContract, intent, key) {
|
|
71
|
+
const rawIntent = commandContract.intents[intent];
|
|
72
|
+
if (!isRecord(rawIntent) || !isRecord(rawIntent.selection)) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
return readStringArray(rawIntent.selection, key) ?? [];
|
|
76
|
+
}
|
|
77
|
+
function readIntentCostExpectedSeconds(commandContract, intent) {
|
|
78
|
+
const rawIntent = commandContract.intents[intent];
|
|
79
|
+
if (!isRecord(rawIntent) || !isRecord(rawIntent.cost)) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const expectedSeconds = rawIntent.cost.expected_seconds;
|
|
83
|
+
return Number.isInteger(expectedSeconds) && Number(expectedSeconds) >= 0 ? Number(expectedSeconds) : null;
|
|
84
|
+
}
|
|
85
|
+
function intentCoverageSignature(commandContract, intent) {
|
|
86
|
+
const rawIntent = commandContract.intents[intent];
|
|
87
|
+
if (!isRecord(rawIntent) || !isRecord(rawIntent.covers)) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const signature = {
|
|
91
|
+
contracts: uniqueSorted(readStringArray(rawIntent.covers, 'contracts') ?? []),
|
|
92
|
+
paths: uniqueSorted(readStringArray(rawIntent.covers, 'paths') ?? []),
|
|
93
|
+
reasons: uniqueSorted(readStringArray(rawIntent.covers, 'reasons') ?? []),
|
|
94
|
+
surfaces: uniqueSorted(readStringArray(rawIntent.covers, 'surfaces') ?? []),
|
|
95
|
+
};
|
|
96
|
+
if (signature.contracts.length === 0 &&
|
|
97
|
+
signature.paths.length === 0 &&
|
|
98
|
+
signature.reasons.length === 0 &&
|
|
99
|
+
signature.surfaces.length === 0) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return JSON.stringify(signature);
|
|
103
|
+
}
|
|
104
|
+
function fallbackIntentsForCandidate(commandContract, candidate) {
|
|
105
|
+
if (candidate.intent.length === 0 || candidate.status === 'runnable') {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
return uniqueSorted([
|
|
109
|
+
...readIntentSelectionList(commandContract, candidate.intent, 'fallback_intents'),
|
|
110
|
+
...readIntentSelectionList(commandContract, candidate.intent, 'escalate_to'),
|
|
111
|
+
...readIntentRelationList(commandContract, candidate.intent, 'escalate_to'),
|
|
112
|
+
]);
|
|
113
|
+
}
|
|
114
|
+
function escalationIntentsForCandidate(commandContract, candidate) {
|
|
115
|
+
if (candidate.intent.length === 0) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
return uniqueSorted([
|
|
119
|
+
...readIntentSelectionList(commandContract, candidate.intent, 'escalate_to'),
|
|
120
|
+
...readIntentRelationList(commandContract, candidate.intent, 'escalate_to'),
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
123
|
+
function expandCandidatesWithDeclaredFallbacks(commandContract, candidates) {
|
|
124
|
+
const hasRunnableCandidate = candidates.some((candidate) => candidate.status === 'runnable' && candidate.intent.length > 0);
|
|
125
|
+
if (hasRunnableCandidate) {
|
|
126
|
+
return candidates;
|
|
127
|
+
}
|
|
128
|
+
const existingIntents = new Set(candidates.map((candidate) => candidate.intent).filter((intent) => intent.length > 0));
|
|
129
|
+
const fallbackIntents = uniqueSorted(candidates.flatMap((candidate) => fallbackIntentsForCandidate(commandContract, candidate))).filter((intent) => !existingIntents.has(intent));
|
|
130
|
+
if (fallbackIntents.length === 0) {
|
|
131
|
+
return candidates;
|
|
132
|
+
}
|
|
133
|
+
return [
|
|
134
|
+
...candidates,
|
|
135
|
+
...fallbackIntents.map((intent) => {
|
|
136
|
+
const fallback = classifyVerificationCandidate(intent, commandContract.intents[intent]);
|
|
137
|
+
return {
|
|
138
|
+
...fallback,
|
|
139
|
+
detail: fallback.status === 'runnable' ? 'Declared fallback for unavailable verification intent.' : fallback.detail,
|
|
140
|
+
};
|
|
141
|
+
}),
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
function requirementNeedsDeclaredEscalation(requirement) {
|
|
145
|
+
if (requirement.surfaces.length > 1) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
const signalText = [
|
|
149
|
+
requirement.reason,
|
|
150
|
+
...requirement.affectedContracts,
|
|
151
|
+
...requirement.driftChecks,
|
|
152
|
+
...requirement.surfaces,
|
|
153
|
+
].join('\n').toLowerCase();
|
|
154
|
+
return DECLARED_ESCALATION_SIGNALS.some((signal) => signalText.includes(signal.toLowerCase()));
|
|
155
|
+
}
|
|
156
|
+
function expandCandidatesWithDeclaredEscalations(commandContract, requirement, candidates) {
|
|
157
|
+
if (!requirementNeedsDeclaredEscalation(requirement)) {
|
|
158
|
+
return candidates;
|
|
159
|
+
}
|
|
160
|
+
const existingIntents = new Set(candidates.map((candidate) => candidate.intent).filter((intent) => intent.length > 0));
|
|
161
|
+
const escalationIntents = uniqueSorted(candidates.flatMap((candidate) => escalationIntentsForCandidate(commandContract, candidate))).filter((intent) => !existingIntents.has(intent));
|
|
162
|
+
if (escalationIntents.length === 0) {
|
|
163
|
+
return candidates;
|
|
164
|
+
}
|
|
165
|
+
return [
|
|
166
|
+
...candidates,
|
|
167
|
+
...escalationIntents.map((intent) => {
|
|
168
|
+
const escalation = classifyVerificationCandidate(intent, commandContract.intents[intent]);
|
|
169
|
+
return {
|
|
170
|
+
...escalation,
|
|
171
|
+
detail: escalation.status === 'runnable'
|
|
172
|
+
? 'Declared escalation for a high-risk verification requirement.'
|
|
173
|
+
: escalation.detail,
|
|
174
|
+
};
|
|
175
|
+
}),
|
|
176
|
+
];
|
|
177
|
+
}
|
|
178
|
+
function intentExplicitlySubsumes(commandContract, broaderIntent, narrowerIntent) {
|
|
179
|
+
return readIntentRelationList(commandContract, broaderIntent, 'subsumes').includes(narrowerIntent);
|
|
180
|
+
}
|
|
181
|
+
function intentExplicitlySubsumedBy(commandContract, narrowerIntent, broaderIntent) {
|
|
182
|
+
return readIntentRelationList(commandContract, narrowerIntent, 'subsumed_by').includes(broaderIntent);
|
|
183
|
+
}
|
|
184
|
+
function intentRequiresCompanion(commandContract, intent) {
|
|
185
|
+
return readIntentRelationList(commandContract, intent, 'requires_with').length > 0;
|
|
186
|
+
}
|
|
187
|
+
function intentIsExplicitlySubsumed(commandContract, narrowerIntent, broaderIntent) {
|
|
188
|
+
return (intentExplicitlySubsumedBy(commandContract, narrowerIntent, broaderIntent) ||
|
|
189
|
+
intentExplicitlySubsumes(commandContract, broaderIntent, narrowerIntent));
|
|
190
|
+
}
|
|
191
|
+
function selectVerificationCandidates(commandContract, candidates) {
|
|
192
|
+
const runnableCandidates = candidates.filter((candidate) => candidate.status === 'runnable' && candidate.intent.length > 0);
|
|
193
|
+
const selectedIntents = new Set(runnableCandidates.map((candidate) => candidate.intent));
|
|
194
|
+
for (const candidate of runnableCandidates) {
|
|
195
|
+
const isSubsumed = runnableCandidates.some((other) => other.intent !== candidate.intent && intentIsExplicitlySubsumed(commandContract, candidate.intent, other.intent));
|
|
196
|
+
if (isSubsumed) {
|
|
197
|
+
selectedIntents.delete(candidate.intent);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const costComparableCandidates = runnableCandidates.filter((candidate) => selectedIntents.has(candidate.intent) &&
|
|
201
|
+
!intentRequiresCompanion(commandContract, candidate.intent) &&
|
|
202
|
+
intentCoverageSignature(commandContract, candidate.intent) !== null &&
|
|
203
|
+
readIntentCostExpectedSeconds(commandContract, candidate.intent) !== null);
|
|
204
|
+
const costComparableGroups = new Map();
|
|
205
|
+
for (const candidate of costComparableCandidates) {
|
|
206
|
+
const signature = intentCoverageSignature(commandContract, candidate.intent);
|
|
207
|
+
if (signature === null) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
costComparableGroups.set(signature, [...(costComparableGroups.get(signature) ?? []), candidate]);
|
|
211
|
+
}
|
|
212
|
+
for (const group of costComparableGroups.values()) {
|
|
213
|
+
if (group.length < 2) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const costs = group.map((candidate) => readIntentCostExpectedSeconds(commandContract, candidate.intent));
|
|
217
|
+
if (costs.some((cost) => cost === null)) {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const minCost = Math.min(...costs);
|
|
221
|
+
const winners = group.filter((candidate) => readIntentCostExpectedSeconds(commandContract, candidate.intent) === minCost);
|
|
222
|
+
if (winners.length !== 1) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
for (const candidate of group) {
|
|
226
|
+
if (candidate.intent !== winners[0]?.intent) {
|
|
227
|
+
selectedIntents.delete(candidate.intent);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (selectedIntents.size === 0 && runnableCandidates.length > 0) {
|
|
232
|
+
return runnableCandidates;
|
|
233
|
+
}
|
|
234
|
+
return runnableCandidates.filter((candidate) => selectedIntents.has(candidate.intent));
|
|
235
|
+
}
|
|
236
|
+
function uniqueVerificationCandidates(candidates) {
|
|
237
|
+
const byIntent = new Map();
|
|
238
|
+
for (const candidate of candidates) {
|
|
239
|
+
if (candidate.intent.length === 0 || byIntent.has(candidate.intent)) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
byIntent.set(candidate.intent, candidate);
|
|
243
|
+
}
|
|
244
|
+
return [...byIntent.values()].sort((left, right) => left.intent.localeCompare(right.intent));
|
|
245
|
+
}
|
|
246
|
+
function toChangeVerificationCandidate(reason, candidate, selectedCandidateKeys) {
|
|
247
|
+
const hasIntent = candidate.intent.length > 0;
|
|
248
|
+
const isMissingIntent = !hasIntent || candidate.reason === 'no_matching_intents';
|
|
249
|
+
const isEligible = hasIntent && candidate.status === 'runnable';
|
|
43
250
|
return {
|
|
44
251
|
reason,
|
|
45
252
|
intent: candidate.intent.length > 0 ? candidate.intent : null,
|
|
46
253
|
status: candidate.status,
|
|
47
254
|
skipReason: candidate.reason,
|
|
48
255
|
detail: candidate.detail,
|
|
256
|
+
candidateState: isMissingIntent ? 'gap' : 'candidate',
|
|
257
|
+
eligibilityState: isMissingIntent ? 'missing' : isEligible ? 'eligible' : 'ineligible',
|
|
258
|
+
selectionState: isEligible
|
|
259
|
+
? selectedCandidateKeys.has(candidateKey(reason, candidate.intent))
|
|
260
|
+
? 'selected'
|
|
261
|
+
: 'not_selected'
|
|
262
|
+
: 'not_applicable',
|
|
49
263
|
};
|
|
50
264
|
}
|
|
51
265
|
function gapForRequirement(requirement, candidates) {
|
|
@@ -61,9 +275,34 @@ function gapForRequirement(requirement, candidates) {
|
|
|
61
275
|
};
|
|
62
276
|
}
|
|
63
277
|
export function createChangeVerificationReport(classificationReport, commandContract, projectRoot) {
|
|
278
|
+
const testSelectionPlan = createProjectTestSelectionPlan(projectRoot, classificationReport, commandContract);
|
|
64
279
|
const requirements = classificationReport.summary.validationReasons.map((reason) => createVerificationRequirement(classificationReport, reason));
|
|
65
|
-
const
|
|
66
|
-
|
|
280
|
+
const plans = requirements.map((requirement) => ({
|
|
281
|
+
requirement,
|
|
282
|
+
candidates: expandCandidatesWithDeclaredEscalations(commandContract, requirement, expandCandidatesWithDeclaredFallbacks(commandContract, createVerificationPlan(commandContract, requirement.reason).candidates)),
|
|
283
|
+
}));
|
|
284
|
+
const plansWithProjectTestSelection = plans.map((plan) => {
|
|
285
|
+
const additionalCandidates = testSelectionPlan.candidates
|
|
286
|
+
.filter((candidate) => candidate.reason === plan.requirement.reason)
|
|
287
|
+
.filter((candidate) => !plan.candidates.some((existing) => existing.intent === candidate.candidate.intent))
|
|
288
|
+
.map((candidate) => candidate.candidate);
|
|
289
|
+
return additionalCandidates.length > 0
|
|
290
|
+
? { ...plan, candidates: [...plan.candidates, ...additionalCandidates] }
|
|
291
|
+
: plan;
|
|
292
|
+
});
|
|
293
|
+
const selectedPlans = plansWithProjectTestSelection.map((plan) => ({
|
|
294
|
+
...plan,
|
|
295
|
+
selectedCandidates: uniqueVerificationCandidates([
|
|
296
|
+
...selectVerificationCandidates(commandContract, plan.candidates),
|
|
297
|
+
...testSelectionPlan.selectedCandidates
|
|
298
|
+
.filter((candidate) => candidate.reason === plan.requirement.reason)
|
|
299
|
+
.map((candidate) => candidate.candidate),
|
|
300
|
+
]),
|
|
301
|
+
}));
|
|
302
|
+
const selectedCandidatePlans = selectedPlans.flatMap((plan) => plan.selectedCandidates);
|
|
303
|
+
const selectedCandidateKeys = new Set(selectedPlans.flatMap((plan) => plan.selectedCandidates.map((candidate) => candidateKey(plan.requirement.reason, candidate.intent))));
|
|
304
|
+
const schedule = createVerificationSchedule(projectRoot, commandContract, selectedCandidatePlans);
|
|
305
|
+
const candidates = plansWithProjectTestSelection.flatMap((plan) => plan.candidates.map((candidate) => toChangeVerificationCandidate(plan.requirement.reason, candidate, selectedCandidateKeys)));
|
|
67
306
|
const gaps = requirements
|
|
68
307
|
.map((requirement) => gapForRequirement(requirement, candidates))
|
|
69
308
|
.filter((gap) => gap !== null);
|
|
@@ -75,6 +314,8 @@ export function createChangeVerificationReport(classificationReport, commandCont
|
|
|
75
314
|
requirements,
|
|
76
315
|
candidates,
|
|
77
316
|
gaps,
|
|
78
|
-
schedule
|
|
317
|
+
schedule,
|
|
318
|
+
decision_graph: createVerificationDecisionGraph(commandContract, requirements, candidates, gaps, schedule),
|
|
319
|
+
test_selection: testSelectionPlan.report,
|
|
79
320
|
};
|
|
80
321
|
}
|
|
@@ -20,11 +20,21 @@ const CHECK_ISSUE_ID_RULES = [
|
|
|
20
20
|
['mustflow.release.template_version_intentionally_unchanged', /^Strict warning: templates\/default\/manifest\.toml version "[^"]+" is older than package\.json version "[^"]+"; this is allowed only when the installed template surface is unchanged$/u],
|
|
21
21
|
['mustflow.preferences.release_versioning_contract_authority', /^Strict: \[preferences\.release\.versioning\]\.[a-z_]+ cannot define version sources or release authority; use \.mustflow\/config\/versioning\.toml or \.mustflow\/config\/commands\.toml$/u],
|
|
22
22
|
['mustflow.preferences.verification_selection_command_authority', /^Strict: \[preferences\.verification\.selection\]\.[a-z_]+ cannot define command authority; use \.mustflow\/config\/commands\.toml$/u],
|
|
23
|
+
['mustflow.contract_model.deferred_policy', /^Strict: \.mustflow\/config\/policy\.toml is deferred; use narrow candidate contract files instead$/u],
|
|
24
|
+
['mustflow.contract_model.command_authority_field', /^Strict: \.mustflow\/config\/(?:changes|surfaces)\.toml .+ cannot define command authority; use \.mustflow\/config\/commands\.toml$/u],
|
|
25
|
+
['mustflow.contract_model.invalid_match_kind', /^Strict: \.mustflow\/config\/(?:changes|surfaces)\.toml rules\[\d+\]\.match\.kind must be "exact", "prefix", or "glob"; regular expressions are deferred$/u],
|
|
26
|
+
['mustflow.contract_model.invalid_shape', /^Strict: \.mustflow\/config\/(?:changes|surfaces)\.toml .+(?:must be|must define|is not allowed)/u],
|
|
27
|
+
['mustflow.test_selection.command_authority_field', /^Strict: \.mustflow\/config\/test-selection\.toml .+ cannot define command authority; use \.mustflow\/config\/commands\.toml$/u],
|
|
28
|
+
['mustflow.test_selection.unknown_command_intent', /^Strict: \.mustflow\/config\/test-selection\.toml .+ references unknown command intent "[^"]+"$/u],
|
|
29
|
+
['mustflow.test_selection.invalid_shape', /^Strict: \.mustflow\/config\/test-selection\.toml .+(?:must be|must define|is not allowed|references command intent "[^"]+" that is not configured)/u],
|
|
23
30
|
['mustflow.skill.procedure_only', /^Strict: \.mustflow\/skills\/[^/]+\/SKILL\.md metadata\.mustflow_kind must be "procedure"$/u],
|
|
24
31
|
['mustflow.skill.raw_command_block', /^Strict: \.mustflow\/skills\/[^/]+\/SKILL\.md contains a raw shell command block; reference command intents instead$/u],
|
|
25
32
|
['mustflow.skill.command_permission_claim', /^Strict: \.mustflow\/skills\/[^/]+\/SKILL\.md claims command execution permission; keep permissions in \.mustflow\/config\/commands\.toml$/u],
|
|
26
33
|
['mustflow.skill.unknown_command_intent', /^Strict: \.mustflow\/skills\/[^/]+\/SKILL\.md metadata\.command_intents references unknown command intent "[^"]+"$/u],
|
|
27
34
|
['mustflow.skill.index_route_unknown_command_intent', /^Strict: \.mustflow\/skills\/INDEX\.md route \.mustflow\/skills\/[^/]+\/SKILL\.md references command intent "[^"]+" not declared by the skill frontmatter$/u],
|
|
35
|
+
['mustflow.skill.index_route_broad_catch_all', /^Strict warning: \.mustflow\/skills\/INDEX\.md \.mustflow\/skills\/[^/]+\/SKILL\.md route uses broad catch-all trigger ".+" that can shadow narrower skills$/u],
|
|
36
|
+
['mustflow.skill.index_route_identical_trigger', /^Strict warning: \.mustflow\/skills\/INDEX\.md \.mustflow\/skills\/[^/]+\/SKILL\.md and \.mustflow\/skills\/[^/]+\/SKILL\.md have identical skill route trigger text$/u],
|
|
37
|
+
['mustflow.skill.index_route_duplicate_surface', /^Strict warning: \.mustflow\/skills\/INDEX\.md \.mustflow\/skills\/[^/]+\/SKILL\.md and \.mustflow\/skills\/[^/]+\/SKILL\.md have duplicate edit scope, risk, and expected output route surface$/u],
|
|
28
38
|
['mustflow.skill.resource_unknown_command_intent', /^Strict: \.mustflow\/skills\/[^/]+\/resources\.toml script [^\s]+ references unknown command intent "[^"]+"$/u],
|
|
29
39
|
['mustflow.source_anchor.invalid_format', /^Strict: source anchor .+ has invalid format:/u],
|
|
30
40
|
['mustflow.source_anchor.duplicate_id', /^Strict: source anchor id "[^"]+" is duplicated:/u],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { COMMAND_LIFECYCLES, COMMAND_RUN_POLICIES, LONG_RUNNING_LIFECYCLES, isRecord, } from './config-loading.js';
|
|
2
|
+
import { COMMAND_ENV_POLICIES } from './command-env.js';
|
|
2
3
|
import { COMMAND_EFFECT_CONCURRENCY, COMMAND_EFFECT_MODES, COMMAND_EFFECT_TYPES, validateCommandEffectLockWarnings, validateCommandEffects, } from './command-effects.js';
|
|
3
4
|
import { commandIntentHasBlockedShellBackgroundPattern, commandIntentHasCommandSource, commandIntentNameIsSafe, } from './command-contract-rules.js';
|
|
4
5
|
function commandContractIssue(message) {
|
|
@@ -31,6 +32,15 @@ function validateStringField(table, key, label, issues) {
|
|
|
31
32
|
issues.push(commandContractIssue(`${label} must be a string`));
|
|
32
33
|
}
|
|
33
34
|
}
|
|
35
|
+
function validateStringArrayField(table, key, label, issues) {
|
|
36
|
+
if (!hasOwn(table, key)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const value = table[key];
|
|
40
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== 'string' || entry.trim().length === 0)) {
|
|
41
|
+
issues.push(commandContractIssue(`${label} must be a string array`));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
34
44
|
function validatePositiveIntegerField(table, key, label, issues) {
|
|
35
45
|
if (hasOwn(table, key) && !isPositiveInteger(table[key])) {
|
|
36
46
|
issues.push(commandContractIssue(`${label} must be a positive integer`));
|
|
@@ -57,6 +67,8 @@ function validateCommandDefaults(commandsToml, issues) {
|
|
|
57
67
|
validateStringField(defaults, 'default_cwd', '[commands.defaults].default_cwd', issues);
|
|
58
68
|
validateStringField(defaults, 'stdin', '[commands.defaults].stdin', issues);
|
|
59
69
|
validateStringField(defaults, 'on_timeout', '[commands.defaults].on_timeout', issues);
|
|
70
|
+
validateAllowedStringField(defaults, 'env_policy', '[commands.defaults].env_policy', COMMAND_ENV_POLICIES, issues);
|
|
71
|
+
validateStringArrayField(defaults, 'env_allowlist', '[commands.defaults].env_allowlist', issues);
|
|
60
72
|
validatePositiveIntegerField(defaults, 'default_timeout_seconds', '[commands.defaults].default_timeout_seconds', issues);
|
|
61
73
|
validatePositiveIntegerField(defaults, 'max_output_bytes', '[commands.defaults].max_output_bytes', issues);
|
|
62
74
|
validatePositiveIntegerField(defaults, 'kill_after_seconds', '[commands.defaults].kill_after_seconds', issues);
|
|
@@ -108,6 +120,25 @@ function validateCommandIntentEffects(intentName, intent, issues) {
|
|
|
108
120
|
}
|
|
109
121
|
}
|
|
110
122
|
}
|
|
123
|
+
function validateCommandIntentSelection(intentName, intent, issues) {
|
|
124
|
+
if (!hasOwn(intent, 'selection')) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!isRecord(intent.selection)) {
|
|
128
|
+
issues.push(commandContractIssue(`[commands.intents.${intentName}.selection] must be a TOML table`));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const selection = intent.selection;
|
|
132
|
+
validateStringField(selection, 'coverage_level', `[commands.intents.${intentName}.selection].coverage_level`, issues);
|
|
133
|
+
validateStringField(selection, 'coverage_confidence', `[commands.intents.${intentName}.selection].coverage_confidence`, issues);
|
|
134
|
+
validateStringField(selection, 'accepts_changed_files', `[commands.intents.${intentName}.selection].accepts_changed_files`, issues);
|
|
135
|
+
validateStringArrayField(selection, 'fallback_intents', `[commands.intents.${intentName}.selection].fallback_intents`, issues);
|
|
136
|
+
validateStringArrayField(selection, 'escalate_to', `[commands.intents.${intentName}.selection].escalate_to`, issues);
|
|
137
|
+
validateBooleanField(selection, 'accepts_test_targets', `[commands.intents.${intentName}.selection].accepts_test_targets`, issues);
|
|
138
|
+
if (selection.accepts_test_targets === true && intent.status === 'configured' && !Array.isArray(intent.argv)) {
|
|
139
|
+
issues.push(commandContractIssue(`[commands.intents.${intentName}.selection].accepts_test_targets requires argv command mode`));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
111
142
|
function validateCommandIntent(intentName, intent, issues) {
|
|
112
143
|
if (!commandIntentNameIsSafe(intentName)) {
|
|
113
144
|
issues.push(commandContractIssue(`Intent ${intentName} name must contain only letters, numbers, underscores, and hyphens`));
|
|
@@ -115,6 +146,9 @@ function validateCommandIntent(intentName, intent, issues) {
|
|
|
115
146
|
validateStringField(intent, 'status', `[commands.intents.${intentName}].status`, issues);
|
|
116
147
|
validateAllowedStringField(intent, 'lifecycle', `[commands.intents.${intentName}].lifecycle`, COMMAND_LIFECYCLES, issues);
|
|
117
148
|
validateAllowedStringField(intent, 'run_policy', `[commands.intents.${intentName}].run_policy`, COMMAND_RUN_POLICIES, issues);
|
|
149
|
+
validateAllowedStringField(intent, 'env_policy', `[commands.intents.${intentName}].env_policy`, COMMAND_ENV_POLICIES, issues);
|
|
150
|
+
validateStringArrayField(intent, 'env_allowlist', `[commands.intents.${intentName}].env_allowlist`, issues);
|
|
151
|
+
validateCommandIntentSelection(intentName, intent, issues);
|
|
118
152
|
if (intent.status !== 'configured') {
|
|
119
153
|
return;
|
|
120
154
|
}
|
package/dist/core/command-cwd.js
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
|
+
import { existsSync, realpathSync, statSync } from 'node:fs';
|
|
1
2
|
import path from 'node:path';
|
|
3
|
+
function normalizeForContainment(value) {
|
|
4
|
+
const normalized = path.resolve(value);
|
|
5
|
+
return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
|
|
6
|
+
}
|
|
7
|
+
function isInsideOrEqual(parent, child) {
|
|
8
|
+
const normalizedParent = normalizeForContainment(parent);
|
|
9
|
+
const normalizedChild = normalizeForContainment(child);
|
|
10
|
+
return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}${path.sep}`);
|
|
11
|
+
}
|
|
2
12
|
export function resolveSafeProjectCwd(projectRoot, rawCwd) {
|
|
3
13
|
const cwd = rawCwd ?? '.';
|
|
4
14
|
const resolved = path.resolve(projectRoot, cwd);
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
15
|
+
const rootRealPath = realpathSync.native(projectRoot);
|
|
16
|
+
if (!existsSync(resolved) || !statSync(resolved).isDirectory()) {
|
|
17
|
+
throw new Error(`Intent cwd must stay inside the current root and resolve to an existing directory: ${cwd}`);
|
|
18
|
+
}
|
|
19
|
+
const cwdRealPath = realpathSync.native(resolved);
|
|
20
|
+
if (!isInsideOrEqual(rootRealPath, cwdRealPath)) {
|
|
21
|
+
throw new Error(`Intent cwd must stay inside the current root and resolve to an existing directory: ${cwd}`);
|
|
10
22
|
}
|
|
11
|
-
return
|
|
23
|
+
return cwdRealPath;
|
|
12
24
|
}
|
|
@@ -70,6 +70,19 @@ function normalizeDeclaredEffect(projectRoot, commandContract, intentName, inten
|
|
|
70
70
|
if (!lock && paths.length === 0) {
|
|
71
71
|
throw new Error(`Command effect for intent ${intentName} must define path, paths, or lock`);
|
|
72
72
|
}
|
|
73
|
+
if (paths.length === 0) {
|
|
74
|
+
return [
|
|
75
|
+
{
|
|
76
|
+
intent: intentName,
|
|
77
|
+
source: 'effects',
|
|
78
|
+
access,
|
|
79
|
+
mode,
|
|
80
|
+
path: null,
|
|
81
|
+
lock: lock,
|
|
82
|
+
concurrency,
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
}
|
|
73
86
|
return paths.map((rawPath) => {
|
|
74
87
|
const normalizedPath = validateEffectPath(projectRoot, intent, rawPath);
|
|
75
88
|
return {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readString, readStringArray } from './config-loading.js';
|
|
3
|
+
export const COMMAND_ENV_POLICIES = new Set(['inherit', 'minimal', 'allowlist']);
|
|
4
|
+
export const DEFAULT_COMMAND_ENV_POLICY = 'inherit';
|
|
5
|
+
const BASE_MINIMAL_ENV_KEYS = [
|
|
6
|
+
'CI',
|
|
7
|
+
'COLORTERM',
|
|
8
|
+
'COMSPEC',
|
|
9
|
+
'ComSpec',
|
|
10
|
+
'FORCE_COLOR',
|
|
11
|
+
'HOME',
|
|
12
|
+
'HOMEDRIVE',
|
|
13
|
+
'HOMEPATH',
|
|
14
|
+
'LANG',
|
|
15
|
+
'LC_ALL',
|
|
16
|
+
'NO_COLOR',
|
|
17
|
+
'PATHEXT',
|
|
18
|
+
'Path',
|
|
19
|
+
'SystemRoot',
|
|
20
|
+
'TEMP',
|
|
21
|
+
'TERM',
|
|
22
|
+
'TMP',
|
|
23
|
+
'TMPDIR',
|
|
24
|
+
'USERPROFILE',
|
|
25
|
+
'WINDIR',
|
|
26
|
+
'windir',
|
|
27
|
+
];
|
|
28
|
+
function getPathEnvKey(env) {
|
|
29
|
+
return Object.keys(env).find((key) => key.toLowerCase() === 'path') ?? 'PATH';
|
|
30
|
+
}
|
|
31
|
+
function sameResolvedPath(left, right) {
|
|
32
|
+
const resolvedLeft = path.resolve(left);
|
|
33
|
+
const resolvedRight = path.resolve(right);
|
|
34
|
+
return process.platform === 'win32'
|
|
35
|
+
? resolvedLeft.toLowerCase() === resolvedRight.toLowerCase()
|
|
36
|
+
: resolvedLeft === resolvedRight;
|
|
37
|
+
}
|
|
38
|
+
function uniqueEnvNames(values) {
|
|
39
|
+
return [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))].sort((left, right) => left.localeCompare(right));
|
|
40
|
+
}
|
|
41
|
+
function readEnvPolicy(table) {
|
|
42
|
+
if (!table) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const value = readString(table, 'env_policy');
|
|
46
|
+
return value && COMMAND_ENV_POLICIES.has(value) ? value : undefined;
|
|
47
|
+
}
|
|
48
|
+
function readEnvAllowlist(table) {
|
|
49
|
+
return table ? (readStringArray(table, 'env_allowlist') ?? []) : [];
|
|
50
|
+
}
|
|
51
|
+
function pickEnv(source, names) {
|
|
52
|
+
const output = {};
|
|
53
|
+
for (const name of names) {
|
|
54
|
+
const value = source[name];
|
|
55
|
+
if (value !== undefined) {
|
|
56
|
+
output[name] = value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return output;
|
|
60
|
+
}
|
|
61
|
+
function removeProjectLocalBinFromPath(env, projectRoot) {
|
|
62
|
+
const pathKey = getPathEnvKey(env);
|
|
63
|
+
const currentPath = env[pathKey];
|
|
64
|
+
if (!currentPath) {
|
|
65
|
+
return env;
|
|
66
|
+
}
|
|
67
|
+
const localBinPath = path.join(projectRoot, 'node_modules', '.bin');
|
|
68
|
+
env[pathKey] = currentPath
|
|
69
|
+
.split(path.delimiter)
|
|
70
|
+
.filter((entry) => entry.length > 0 && !sameResolvedPath(entry, localBinPath))
|
|
71
|
+
.join(path.delimiter);
|
|
72
|
+
return env;
|
|
73
|
+
}
|
|
74
|
+
export function resolveCommandEnv(contract, intent) {
|
|
75
|
+
const policy = readEnvPolicy(intent) ?? readEnvPolicy(contract.defaults) ?? DEFAULT_COMMAND_ENV_POLICY;
|
|
76
|
+
const allowlist = policy === 'allowlist'
|
|
77
|
+
? uniqueEnvNames([...readEnvAllowlist(contract.defaults), ...readEnvAllowlist(intent)])
|
|
78
|
+
: [];
|
|
79
|
+
return {
|
|
80
|
+
policy,
|
|
81
|
+
allowlist,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function createCommandEnv(projectRoot, resolution, sourceEnv = process.env) {
|
|
85
|
+
const pathKey = getPathEnvKey(sourceEnv);
|
|
86
|
+
const minimalKeys = uniqueEnvNames([...BASE_MINIMAL_ENV_KEYS, pathKey]);
|
|
87
|
+
const env = resolution.policy === 'inherit'
|
|
88
|
+
? { ...sourceEnv }
|
|
89
|
+
: pickEnv(sourceEnv, resolution.policy === 'allowlist' ? [...minimalKeys, ...resolution.allowlist] : minimalKeys);
|
|
90
|
+
return removeProjectLocalBinFromPath(env, projectRoot);
|
|
91
|
+
}
|