mustflow 1.15.97
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/LICENSE +16 -0
- package/README.md +422 -0
- package/dist/cli/commands/check.js +73 -0
- package/dist/cli/commands/classify.js +104 -0
- package/dist/cli/commands/context.js +95 -0
- package/dist/cli/commands/contract-lint.js +74 -0
- package/dist/cli/commands/dashboard.js +654 -0
- package/dist/cli/commands/docs.js +382 -0
- package/dist/cli/commands/doctor.js +232 -0
- package/dist/cli/commands/explain.js +293 -0
- package/dist/cli/commands/help.js +148 -0
- package/dist/cli/commands/impact.js +120 -0
- package/dist/cli/commands/index.js +70 -0
- package/dist/cli/commands/init.js +986 -0
- package/dist/cli/commands/line-endings.js +102 -0
- package/dist/cli/commands/map.js +95 -0
- package/dist/cli/commands/run.js +442 -0
- package/dist/cli/commands/search.js +166 -0
- package/dist/cli/commands/status.js +65 -0
- package/dist/cli/commands/update.js +443 -0
- package/dist/cli/commands/verify.js +448 -0
- package/dist/cli/commands/version-sources.js +79 -0
- package/dist/cli/commands/version.js +57 -0
- package/dist/cli/i18n/en.js +702 -0
- package/dist/cli/i18n/es.js +702 -0
- package/dist/cli/i18n/fr.js +702 -0
- package/dist/cli/i18n/hi.js +702 -0
- package/dist/cli/i18n/ko.js +702 -0
- package/dist/cli/i18n/zh.js +702 -0
- package/dist/cli/index.js +218 -0
- package/dist/cli/lib/agent-context.js +342 -0
- package/dist/cli/lib/browser-open.js +58 -0
- package/dist/cli/lib/cli-output.js +36 -0
- package/dist/cli/lib/command-contract.js +1 -0
- package/dist/cli/lib/command-registry.js +107 -0
- package/dist/cli/lib/dashboard-html.js +1866 -0
- package/dist/cli/lib/dashboard-locale.js +309 -0
- package/dist/cli/lib/dashboard-preferences.js +405 -0
- package/dist/cli/lib/doc-review-ledger.js +226 -0
- package/dist/cli/lib/filesystem.js +125 -0
- package/dist/cli/lib/git-changes.js +13 -0
- package/dist/cli/lib/i18n.js +55 -0
- package/dist/cli/lib/local-index.js +1014 -0
- package/dist/cli/lib/locale-tags.js +4 -0
- package/dist/cli/lib/manifest-lock.js +131 -0
- package/dist/cli/lib/npm-version-check.js +97 -0
- package/dist/cli/lib/package-info.js +13 -0
- package/dist/cli/lib/preferences-options.js +8 -0
- package/dist/cli/lib/project-root.js +23 -0
- package/dist/cli/lib/repo-map.js +635 -0
- package/dist/cli/lib/reporter.js +8 -0
- package/dist/cli/lib/run-receipt.js +1 -0
- package/dist/cli/lib/template-i18n.js +265 -0
- package/dist/cli/lib/templates.js +188 -0
- package/dist/cli/lib/toml.js +1 -0
- package/dist/cli/lib/validation.js +1639 -0
- package/dist/cli/lib/version-sources.js +1 -0
- package/dist/core/authority-resolution.js +155 -0
- package/dist/core/change-classification.js +122 -0
- package/dist/core/change-verification.js +80 -0
- package/dist/core/check-issues.js +67 -0
- package/dist/core/command-classification.js +22 -0
- package/dist/core/command-contract-rules.js +27 -0
- package/dist/core/command-contract-validation.js +197 -0
- package/dist/core/command-cwd.js +12 -0
- package/dist/core/command-effects.js +182 -0
- package/dist/core/command-explanation.js +135 -0
- package/dist/core/command-intent-eligibility.js +76 -0
- package/dist/core/config-loading.js +54 -0
- package/dist/core/contract-lint.js +110 -0
- package/dist/core/contract-models.js +53 -0
- package/dist/core/dashboard-verification.js +132 -0
- package/dist/core/doc-review-triage.js +92 -0
- package/dist/core/line-endings.js +144 -0
- package/dist/core/public-json-contracts.js +112 -0
- package/dist/core/public-surface-explanation.js +49 -0
- package/dist/core/release-version-validation.js +53 -0
- package/dist/core/retention-explanation.js +74 -0
- package/dist/core/retention-policy.js +57 -0
- package/dist/core/run-receipt.js +77 -0
- package/dist/core/skill-route-alignment.js +100 -0
- package/dist/core/skill-route-explanation.js +117 -0
- package/dist/core/source-anchor-explanation.js +33 -0
- package/dist/core/source-anchor-status.js +269 -0
- package/dist/core/source-anchor-symbols.js +181 -0
- package/dist/core/source-anchor-validation.js +158 -0
- package/dist/core/source-anchors.js +194 -0
- package/dist/core/surface-decision-model.js +18 -0
- package/dist/core/toml.js +11 -0
- package/dist/core/verification-plan.js +41 -0
- package/dist/core/verification-scheduler.js +92 -0
- package/dist/core/version-impact.js +54 -0
- package/dist/core/version-sources.js +235 -0
- package/dist/core/version-sync-policy.js +85 -0
- package/examples/README.md +13 -0
- package/examples/docs-only/README.md +72 -0
- package/examples/host-instruction-conflicts/README.md +47 -0
- package/examples/minimal-js/README.md +98 -0
- package/examples/missing-command-contracts/README.md +70 -0
- package/examples/nested-repos/README.md +62 -0
- package/package.json +80 -0
- package/schemas/README.md +32 -0
- package/schemas/change-verification-report.schema.json +319 -0
- package/schemas/classify-report.schema.json +113 -0
- package/schemas/commands.schema.json +116 -0
- package/schemas/context-report.schema.json +341 -0
- package/schemas/contract-lint-report.schema.json +61 -0
- package/schemas/docs-review-list.schema.json +72 -0
- package/schemas/doctor-report.schema.json +175 -0
- package/schemas/explain-report.schema.json +471 -0
- package/schemas/impact-report.schema.json +121 -0
- package/schemas/line-endings-report.schema.json +63 -0
- package/schemas/run-receipt.schema.json +75 -0
- package/schemas/verify-report.schema.json +67 -0
- package/schemas/version-sources-report.schema.json +42 -0
- package/templates/default/common/.mustflow/config/commands.toml +251 -0
- package/templates/default/common/.mustflow/config/mustflow.toml +424 -0
- package/templates/default/common/.mustflow/config/preferences.toml +125 -0
- package/templates/default/common/gitignore.mustflow +9 -0
- package/templates/default/i18n.toml +483 -0
- package/templates/default/locales/en/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/en/.mustflow/context/PROJECT.md +66 -0
- package/templates/default/locales/en/.mustflow/docs/agent-workflow.md +345 -0
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/en/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/en/.mustflow/skills/artifact-integrity-check/SKILL.md +121 -0
- package/templates/default/locales/en/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/en/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/en/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/en/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/en/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/en/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/en/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/en/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/en/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/en/.mustflow/skills/diff-risk-review/SKILL.md +143 -0
- package/templates/default/locales/en/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/en/.mustflow/skills/docs-update/SKILL.md +100 -0
- package/templates/default/locales/en/.mustflow/skills/external-prompt-injection-defense/SKILL.md +124 -0
- package/templates/default/locales/en/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/en/.mustflow/skills/failure-triage/SKILL.md +97 -0
- package/templates/default/locales/en/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/en/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/en/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/en/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/en/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/en/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/en/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/en/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/en/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/en/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/en/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/en/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/en/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/en/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/en/.mustflow/skills/security-privacy-review/SKILL.md +130 -0
- package/templates/default/locales/en/.mustflow/skills/security-regression-tests/SKILL.md +157 -0
- package/templates/default/locales/en/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/en/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/en/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/en/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/en/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/en/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/en/.mustflow/skills/ui-quality-gate/SKILL.md +119 -0
- package/templates/default/locales/en/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/en/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/en/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/en/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/en/AGENTS.md +114 -0
- package/templates/default/locales/es/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/es/.mustflow/context/PROJECT.md +63 -0
- package/templates/default/locales/es/.mustflow/docs/agent-workflow.md +365 -0
- package/templates/default/locales/es/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/es/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/es/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/es/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/es/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/es/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/es/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/es/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/es/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/es/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/es/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/es/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/es/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/es/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/es/.mustflow/skills/docs-update/SKILL.md +97 -0
- package/templates/default/locales/es/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/es/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/es/.mustflow/skills/failure-triage/SKILL.md +97 -0
- package/templates/default/locales/es/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/es/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/es/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/es/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/es/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/es/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/es/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/es/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/es/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/es/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/es/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/es/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/es/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/es/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/es/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/es/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/es/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/es/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/es/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/es/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/es/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/es/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/es/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/es/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/es/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/es/AGENTS.md +83 -0
- package/templates/default/locales/fr/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/fr/.mustflow/context/PROJECT.md +63 -0
- package/templates/default/locales/fr/.mustflow/docs/agent-workflow.md +368 -0
- package/templates/default/locales/fr/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/fr/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/fr/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/fr/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/fr/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/fr/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/fr/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/fr/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/fr/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/fr/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/fr/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/fr/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/fr/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/fr/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/fr/.mustflow/skills/docs-update/SKILL.md +97 -0
- package/templates/default/locales/fr/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/fr/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/fr/.mustflow/skills/failure-triage/SKILL.md +97 -0
- package/templates/default/locales/fr/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/fr/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/fr/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/fr/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/fr/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/fr/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/fr/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/fr/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/fr/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/fr/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/fr/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/fr/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/fr/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/fr/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/fr/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/fr/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/fr/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/fr/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/fr/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/fr/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/fr/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/fr/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/fr/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/fr/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/fr/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/fr/AGENTS.md +84 -0
- package/templates/default/locales/hi/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/hi/.mustflow/context/PROJECT.md +65 -0
- package/templates/default/locales/hi/.mustflow/docs/agent-workflow.md +359 -0
- package/templates/default/locales/hi/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/hi/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/hi/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/hi/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/hi/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/hi/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/hi/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/hi/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/hi/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/hi/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/hi/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/hi/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/hi/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/hi/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/hi/.mustflow/skills/docs-update/SKILL.md +97 -0
- package/templates/default/locales/hi/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/hi/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/hi/.mustflow/skills/failure-triage/SKILL.md +97 -0
- package/templates/default/locales/hi/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/hi/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/hi/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/hi/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/hi/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/hi/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/hi/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/hi/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/hi/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/hi/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/hi/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/hi/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/hi/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/hi/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/hi/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/hi/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/hi/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/hi/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/hi/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/hi/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/hi/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/hi/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/hi/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/hi/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/hi/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/hi/AGENTS.md +83 -0
- package/templates/default/locales/ko/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/ko/.mustflow/context/PROJECT.md +66 -0
- package/templates/default/locales/ko/.mustflow/docs/agent-workflow.md +506 -0
- package/templates/default/locales/ko/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/ko/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/ko/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/ko/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/ko/.mustflow/skills/code-review/SKILL.md +118 -0
- package/templates/default/locales/ko/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/ko/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/ko/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/ko/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/ko/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/ko/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/ko/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/ko/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/ko/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/ko/.mustflow/skills/docs-update/SKILL.md +107 -0
- package/templates/default/locales/ko/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/ko/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/ko/.mustflow/skills/failure-triage/SKILL.md +119 -0
- package/templates/default/locales/ko/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/ko/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/ko/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/ko/.mustflow/skills/multi-agent-work-coordination/SKILL.md +259 -0
- package/templates/default/locales/ko/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/ko/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/ko/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/ko/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/ko/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/ko/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/ko/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/ko/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/ko/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/ko/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/ko/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/ko/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/ko/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/ko/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/ko/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/ko/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/ko/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/ko/.mustflow/skills/test-maintenance/SKILL.md +130 -0
- package/templates/default/locales/ko/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/ko/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/ko/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/ko/AGENTS.md +85 -0
- package/templates/default/locales/zh/.mustflow/context/INDEX.md +39 -0
- package/templates/default/locales/zh/.mustflow/context/PROJECT.md +64 -0
- package/templates/default/locales/zh/.mustflow/docs/agent-workflow.md +310 -0
- package/templates/default/locales/zh/.mustflow/skills/INDEX.md +78 -0
- package/templates/default/locales/zh/.mustflow/skills/adapter-boundary/SKILL.md +193 -0
- package/templates/default/locales/zh/.mustflow/skills/artifact-integrity-check/SKILL.md +114 -0
- package/templates/default/locales/zh/.mustflow/skills/behavior-preserving-refactor/SKILL.md +182 -0
- package/templates/default/locales/zh/.mustflow/skills/code-review/SKILL.md +115 -0
- package/templates/default/locales/zh/.mustflow/skills/codebase-orientation/SKILL.md +115 -0
- package/templates/default/locales/zh/.mustflow/skills/command-pattern/SKILL.md +247 -0
- package/templates/default/locales/zh/.mustflow/skills/composition-over-inheritance/SKILL.md +176 -0
- package/templates/default/locales/zh/.mustflow/skills/contract-sync-check/SKILL.md +116 -0
- package/templates/default/locales/zh/.mustflow/skills/date-number-audit/SKILL.md +116 -0
- package/templates/default/locales/zh/.mustflow/skills/dependency-injection/SKILL.md +161 -0
- package/templates/default/locales/zh/.mustflow/skills/dependency-reality-check/SKILL.md +115 -0
- package/templates/default/locales/zh/.mustflow/skills/diff-risk-review/SKILL.md +136 -0
- package/templates/default/locales/zh/.mustflow/skills/docs-prose-review/SKILL.md +119 -0
- package/templates/default/locales/zh/.mustflow/skills/docs-update/SKILL.md +97 -0
- package/templates/default/locales/zh/.mustflow/skills/external-prompt-injection-defense/SKILL.md +116 -0
- package/templates/default/locales/zh/.mustflow/skills/facade-pattern/SKILL.md +210 -0
- package/templates/default/locales/zh/.mustflow/skills/failure-triage/SKILL.md +96 -0
- package/templates/default/locales/zh/.mustflow/skills/instruction-conflict-scope-check/SKILL.md +118 -0
- package/templates/default/locales/zh/.mustflow/skills/line-ending-hygiene/SKILL.md +111 -0
- package/templates/default/locales/zh/.mustflow/skills/migration-safety-check/SKILL.md +117 -0
- package/templates/default/locales/zh/.mustflow/skills/multi-agent-work-coordination/SKILL.md +260 -0
- package/templates/default/locales/zh/.mustflow/skills/null-object-pattern/SKILL.md +196 -0
- package/templates/default/locales/zh/.mustflow/skills/pattern-scout/SKILL.md +110 -0
- package/templates/default/locales/zh/.mustflow/skills/performance-budget-check/SKILL.md +121 -0
- package/templates/default/locales/zh/.mustflow/skills/project-context-authoring/SKILL.md +107 -0
- package/templates/default/locales/zh/.mustflow/skills/pure-core-imperative-shell/SKILL.md +212 -0
- package/templates/default/locales/zh/.mustflow/skills/readme-authoring/SKILL.md +115 -0
- package/templates/default/locales/zh/.mustflow/skills/repo-improvement-loop/SKILL.md +150 -0
- package/templates/default/locales/zh/.mustflow/skills/repro-first-debug/SKILL.md +112 -0
- package/templates/default/locales/zh/.mustflow/skills/requirement-regression-guard/SKILL.md +152 -0
- package/templates/default/locales/zh/.mustflow/skills/result-option/SKILL.md +186 -0
- package/templates/default/locales/zh/.mustflow/skills/security-privacy-review/SKILL.md +116 -0
- package/templates/default/locales/zh/.mustflow/skills/security-regression-tests/SKILL.md +131 -0
- package/templates/default/locales/zh/.mustflow/skills/skill-authoring/SKILL.md +110 -0
- package/templates/default/locales/zh/.mustflow/skills/source-freshness-check/SKILL.md +111 -0
- package/templates/default/locales/zh/.mustflow/skills/state-machine-pattern/SKILL.md +214 -0
- package/templates/default/locales/zh/.mustflow/skills/strategy-pattern/SKILL.md +215 -0
- package/templates/default/locales/zh/.mustflow/skills/structure-discovery-gate/SKILL.md +159 -0
- package/templates/default/locales/zh/.mustflow/skills/test-maintenance/SKILL.md +122 -0
- package/templates/default/locales/zh/.mustflow/skills/ui-quality-gate/SKILL.md +117 -0
- package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/SKILL.md +127 -0
- package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/assets/review-template.html +286 -0
- package/templates/default/locales/zh/.mustflow/skills/visual-review-artifact/resources.toml +7 -0
- package/templates/default/locales/zh/.mustflow/skills/web-asset-optimization/SKILL.md +108 -0
- package/templates/default/locales/zh/AGENTS.md +86 -0
- package/templates/default/manifest.toml +339 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { listSourceAnchorFiles, parseSourceAnchorsInContent, splitSourceAnchorList, } from './source-anchors.js';
|
|
5
|
+
import { extractSourceAnchorSymbol, } from './source-anchor-symbols.js';
|
|
6
|
+
const HIGH_RISK_SOURCE_ANCHOR_TAGS = new Set([
|
|
7
|
+
'authn',
|
|
8
|
+
'authz',
|
|
9
|
+
'authorization',
|
|
10
|
+
'data_loss',
|
|
11
|
+
'file_upload',
|
|
12
|
+
'injection',
|
|
13
|
+
'migration',
|
|
14
|
+
'payment',
|
|
15
|
+
'pii',
|
|
16
|
+
'privacy',
|
|
17
|
+
'secrets',
|
|
18
|
+
'security',
|
|
19
|
+
'ssrf',
|
|
20
|
+
'xss',
|
|
21
|
+
]);
|
|
22
|
+
function sha256(value) {
|
|
23
|
+
return `sha256:${createHash('sha256').update(value).digest('hex')}`;
|
|
24
|
+
}
|
|
25
|
+
function hashStringList(values) {
|
|
26
|
+
return values.length > 0 ? sha256(values.join('\n')) : null;
|
|
27
|
+
}
|
|
28
|
+
function contextForAnchor(content, lineStart) {
|
|
29
|
+
const lines = content.split(/\r?\n/u);
|
|
30
|
+
const anchorIndex = Math.max(0, lineStart - 1);
|
|
31
|
+
const from = Math.max(0, anchorIndex - 3);
|
|
32
|
+
const to = Math.min(lines.length, anchorIndex + 4);
|
|
33
|
+
return lines.slice(from, to).join('\n');
|
|
34
|
+
}
|
|
35
|
+
function createFingerprint(content, anchor, search, risk) {
|
|
36
|
+
const invariant = anchor.fields.get('invariant') ?? null;
|
|
37
|
+
const metadata = {
|
|
38
|
+
purpose: anchor.fields.get('purpose') ?? null,
|
|
39
|
+
search,
|
|
40
|
+
invariant,
|
|
41
|
+
risk,
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
anchorMetadataHash: sha256(JSON.stringify(metadata)),
|
|
45
|
+
anchorTextHash: sha256(anchor.rawText),
|
|
46
|
+
contextHash: sha256(contextForAnchor(content, anchor.lineStart)),
|
|
47
|
+
searchTermsHash: hashStringList(search),
|
|
48
|
+
invariantHash: invariant ? sha256(invariant) : null,
|
|
49
|
+
riskHash: sha256(risk.join('\n')),
|
|
50
|
+
symbol: extractSourceAnchorSymbol(content, anchor.lineStart),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function currentAnchorSignals(risk) {
|
|
54
|
+
return {
|
|
55
|
+
identity: 'current_anchor_id_valid',
|
|
56
|
+
location: 'current_file_and_line_indexed',
|
|
57
|
+
symbol: 'current_symbol_fingerprinted',
|
|
58
|
+
body: 'current_body_fingerprinted',
|
|
59
|
+
metadata: 'current_anchor_metadata_fingerprinted',
|
|
60
|
+
semantic: 'search_terms_and_invariant_fingerprinted',
|
|
61
|
+
risk: risk.length > 0 ? 'risk_tags_fingerprinted' : 'no_risk_tags',
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function hasHighRisk(risk) {
|
|
65
|
+
return risk.some((tag) => HIGH_RISK_SOURCE_ANCHOR_TAGS.has(tag));
|
|
66
|
+
}
|
|
67
|
+
function sameSymbolIdentity(left, right) {
|
|
68
|
+
return left.kind === right.kind && left.name !== null && left.name === right.name;
|
|
69
|
+
}
|
|
70
|
+
function sameSymbolTarget(left, right) {
|
|
71
|
+
if (!sameSymbolIdentity(left, right)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
if (left.signatureHash && right.signatureHash && left.signatureHash !== right.signatureHash) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (left.bodyHash && right.bodyHash && left.bodyHash !== right.bodyHash) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
function sourceAnchorSignals(current, previous) {
|
|
83
|
+
if (!previous) {
|
|
84
|
+
return currentAnchorSignals(current.risk);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
identity: current.id === previous.id ? 'anchor_id_matched_previous_snapshot' : 'anchor_id_from_previous_snapshot',
|
|
88
|
+
location: current.path === previous.path && current.lineStart === previous.lineStart
|
|
89
|
+
? 'same_path_and_line'
|
|
90
|
+
: current.path === previous.path
|
|
91
|
+
? 'same_path_line_changed'
|
|
92
|
+
: 'path_changed',
|
|
93
|
+
symbol: current.fingerprint.symbol.kind === 'unknown'
|
|
94
|
+
? 'current_symbol_unknown'
|
|
95
|
+
: sameSymbolIdentity(current.fingerprint.symbol, previous.fingerprint.symbol)
|
|
96
|
+
? 'symbol_identity_matched'
|
|
97
|
+
: 'symbol_identity_changed',
|
|
98
|
+
body: current.fingerprint.symbol.bodyHash && current.fingerprint.symbol.bodyHash === previous.fingerprint.symbol.bodyHash
|
|
99
|
+
? 'symbol_body_hash_matched'
|
|
100
|
+
: current.fingerprint.symbol.signatureHash && current.fingerprint.symbol.signatureHash === previous.fingerprint.symbol.signatureHash
|
|
101
|
+
? 'signature_hash_matched_body_changed_or_unknown'
|
|
102
|
+
: 'symbol_body_or_signature_changed',
|
|
103
|
+
metadata: current.fingerprint.anchorMetadataHash === previous.fingerprint.anchorMetadataHash
|
|
104
|
+
? 'anchor_metadata_hash_matched'
|
|
105
|
+
: 'anchor_metadata_hash_changed',
|
|
106
|
+
semantic: current.fingerprint.searchTermsHash === previous.fingerprint.searchTermsHash &&
|
|
107
|
+
current.fingerprint.invariantHash === previous.fingerprint.invariantHash
|
|
108
|
+
? 'search_terms_and_invariant_matched'
|
|
109
|
+
: 'search_terms_or_invariant_changed',
|
|
110
|
+
risk: current.fingerprint.riskHash === previous.fingerprint.riskHash
|
|
111
|
+
? hasHighRisk(current.risk)
|
|
112
|
+
? 'high_risk_tags_matched'
|
|
113
|
+
: current.risk.length > 0
|
|
114
|
+
? 'risk_tags_matched'
|
|
115
|
+
: 'no_risk_tags'
|
|
116
|
+
: 'risk_tags_changed',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function compareSourceAnchorStatus(current, previous) {
|
|
120
|
+
if (!previous) {
|
|
121
|
+
return {
|
|
122
|
+
status: 'valid',
|
|
123
|
+
confidence: 1,
|
|
124
|
+
signals: currentAnchorSignals(current.risk),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const signals = sourceAnchorSignals(current, previous);
|
|
128
|
+
const locationChanged = current.path !== previous.path || current.lineStart !== previous.lineStart;
|
|
129
|
+
const metadataChanged = current.fingerprint.anchorMetadataHash !== previous.fingerprint.anchorMetadataHash;
|
|
130
|
+
const semanticChanged = current.fingerprint.searchTermsHash !== previous.fingerprint.searchTermsHash ||
|
|
131
|
+
current.fingerprint.invariantHash !== previous.fingerprint.invariantHash;
|
|
132
|
+
const signatureChanged = current.fingerprint.symbol.signatureHash !== previous.fingerprint.symbol.signatureHash &&
|
|
133
|
+
(current.fingerprint.symbol.signatureHash !== null || previous.fingerprint.symbol.signatureHash !== null);
|
|
134
|
+
const bodyChanged = current.fingerprint.symbol.bodyHash !== previous.fingerprint.symbol.bodyHash &&
|
|
135
|
+
(current.fingerprint.symbol.bodyHash !== null || previous.fingerprint.symbol.bodyHash !== null);
|
|
136
|
+
const contextChanged = current.fingerprint.contextHash !== previous.fingerprint.contextHash;
|
|
137
|
+
const symbolIdentityChanged = !sameSymbolIdentity(current.fingerprint.symbol, previous.fingerprint.symbol);
|
|
138
|
+
if (hasHighRisk(current.risk) && (bodyChanged || signatureChanged || semanticChanged || metadataChanged)) {
|
|
139
|
+
return {
|
|
140
|
+
status: 'review',
|
|
141
|
+
confidence: 0.55,
|
|
142
|
+
signals: {
|
|
143
|
+
...signals,
|
|
144
|
+
risk: signals.risk.startsWith('high_risk') ? 'high_risk_anchor_requires_review_after_change' : signals.risk,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (symbolIdentityChanged && previous.fingerprint.symbol.kind !== 'unknown') {
|
|
149
|
+
return {
|
|
150
|
+
status: 'review',
|
|
151
|
+
confidence: 0.5,
|
|
152
|
+
signals,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (locationChanged && sameSymbolTarget(current.fingerprint.symbol, previous.fingerprint.symbol)) {
|
|
156
|
+
return {
|
|
157
|
+
status: 'moved',
|
|
158
|
+
confidence: 0.85,
|
|
159
|
+
signals,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (bodyChanged || signatureChanged || contextChanged || metadataChanged || semanticChanged) {
|
|
163
|
+
return {
|
|
164
|
+
status: 'changed',
|
|
165
|
+
confidence: signatureChanged ? 0.65 : 0.75,
|
|
166
|
+
signals,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
status: 'valid',
|
|
171
|
+
confidence: 1,
|
|
172
|
+
signals,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function staleAnchorSignals(previous, replacement) {
|
|
176
|
+
if (replacement) {
|
|
177
|
+
return {
|
|
178
|
+
identity: 'previous_anchor_id_missing_unique_symbol_candidate_found',
|
|
179
|
+
location: replacement.path === previous.path ? 'same_path_candidate' : 'path_changed_candidate',
|
|
180
|
+
symbol: 'symbol_identity_candidate_matched',
|
|
181
|
+
body: sameSymbolTarget(replacement.fingerprint.symbol, previous.fingerprint.symbol)
|
|
182
|
+
? 'symbol_body_hash_matched'
|
|
183
|
+
: 'symbol_body_or_signature_changed',
|
|
184
|
+
metadata: 'previous_anchor_metadata_only',
|
|
185
|
+
semantic: 'previous_anchor_semantic_metadata_only',
|
|
186
|
+
risk: hasHighRisk(previous.risk) ? 'high_risk_previous_anchor_requires_review' : 'previous_risk_tags_only',
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
identity: 'previous_anchor_id_missing',
|
|
191
|
+
location: 'previous_location_missing',
|
|
192
|
+
symbol: 'no_unique_symbol_candidate',
|
|
193
|
+
body: 'previous_body_fingerprint_only',
|
|
194
|
+
metadata: 'previous_anchor_metadata_only',
|
|
195
|
+
semantic: 'previous_anchor_semantic_metadata_only',
|
|
196
|
+
risk: hasHighRisk(previous.risk) ? 'high_risk_previous_anchor_stale' : 'previous_risk_tags_only',
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function findUniqueSymbolCandidate(previous, currentRecords) {
|
|
200
|
+
if (previous.fingerprint.symbol.kind === 'unknown' || previous.fingerprint.symbol.name === null) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
const matches = currentRecords.filter((record) => sameSymbolTarget(record.fingerprint.symbol, previous.fingerprint.symbol));
|
|
204
|
+
return matches.length === 1 ? matches[0] ?? null : null;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* mf:anchor core.source-anchor-status.index-records
|
|
208
|
+
* purpose: Build source anchor index records with fingerprints and navigation-only status metadata.
|
|
209
|
+
* search: source anchor status, fingerprint, sqlite, navigation only
|
|
210
|
+
* invariant: Status records are derived search metadata and do not grant command or verification authority.
|
|
211
|
+
* risk: cache, config
|
|
212
|
+
*/
|
|
213
|
+
export function collectSourceAnchorIndexRecords(projectRoot, previousSnapshots = []) {
|
|
214
|
+
const currentRecords = [];
|
|
215
|
+
for (const relativePath of listSourceAnchorFiles(projectRoot)) {
|
|
216
|
+
const filePath = path.join(projectRoot, ...relativePath.split('/'));
|
|
217
|
+
if (!existsSync(filePath) || !statSync(filePath).isFile()) {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const content = readFileSync(filePath, 'utf8');
|
|
221
|
+
for (const anchor of parseSourceAnchorsInContent(relativePath, content)) {
|
|
222
|
+
if (!anchor.idValid) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
const search = splitSourceAnchorList(anchor.fields.get('search'));
|
|
226
|
+
const risk = splitSourceAnchorList(anchor.fields.get('risk'));
|
|
227
|
+
currentRecords.push({
|
|
228
|
+
id: anchor.rawId,
|
|
229
|
+
path: relativePath,
|
|
230
|
+
lineStart: anchor.lineStart,
|
|
231
|
+
purpose: anchor.fields.get('purpose') ?? null,
|
|
232
|
+
search,
|
|
233
|
+
invariant: anchor.fields.get('invariant') ?? null,
|
|
234
|
+
risk,
|
|
235
|
+
navigationOnly: true,
|
|
236
|
+
canInstructAgent: false,
|
|
237
|
+
fingerprint: createFingerprint(content, anchor, search, risk),
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const previousById = new Map(previousSnapshots.map((snapshot) => [snapshot.id, snapshot]));
|
|
242
|
+
const currentById = new Set(currentRecords.map((record) => record.id));
|
|
243
|
+
const records = currentRecords.map((record) => ({
|
|
244
|
+
...record,
|
|
245
|
+
...compareSourceAnchorStatus(record, previousById.get(record.id) ?? null),
|
|
246
|
+
}));
|
|
247
|
+
for (const previous of previousSnapshots) {
|
|
248
|
+
if (currentById.has(previous.id)) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const replacement = findUniqueSymbolCandidate(previous, currentRecords);
|
|
252
|
+
const status = replacement ? (hasHighRisk(previous.risk) ? 'review' : 'moved') : 'stale';
|
|
253
|
+
records.push({
|
|
254
|
+
...(replacement ?? previous),
|
|
255
|
+
id: previous.id,
|
|
256
|
+
purpose: previous.purpose,
|
|
257
|
+
search: previous.search,
|
|
258
|
+
invariant: previous.invariant,
|
|
259
|
+
risk: previous.risk,
|
|
260
|
+
navigationOnly: true,
|
|
261
|
+
canInstructAgent: false,
|
|
262
|
+
fingerprint: replacement?.fingerprint ?? previous.fingerprint,
|
|
263
|
+
status,
|
|
264
|
+
confidence: replacement ? (status === 'review' ? 0.45 : 0.65) : 0.2,
|
|
265
|
+
signals: staleAnchorSignals(previous, replacement),
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
return records.sort((left, right) => left.id.localeCompare(right.id) || left.path.localeCompare(right.path));
|
|
269
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
function sha256(value) {
|
|
3
|
+
return `sha256:${createHash('sha256').update(value).digest('hex')}`;
|
|
4
|
+
}
|
|
5
|
+
function countBraceDelta(line) {
|
|
6
|
+
let delta = 0;
|
|
7
|
+
let quote = null;
|
|
8
|
+
let escaped = false;
|
|
9
|
+
for (const char of line) {
|
|
10
|
+
if (escaped) {
|
|
11
|
+
escaped = false;
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
if (char === '\\') {
|
|
15
|
+
escaped = true;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (quote) {
|
|
19
|
+
if (char === quote) {
|
|
20
|
+
quote = null;
|
|
21
|
+
}
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
25
|
+
quote = char;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (char === '{') {
|
|
29
|
+
delta += 1;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (char === '}') {
|
|
33
|
+
delta -= 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return delta;
|
|
37
|
+
}
|
|
38
|
+
function findBracedBodyEndLine(lines, startIndex) {
|
|
39
|
+
let depth = 0;
|
|
40
|
+
let hasBodyStart = false;
|
|
41
|
+
for (let index = startIndex; index < lines.length; index += 1) {
|
|
42
|
+
const delta = countBraceDelta(lines[index] ?? '');
|
|
43
|
+
depth += delta;
|
|
44
|
+
if (delta > 0) {
|
|
45
|
+
hasBodyStart = true;
|
|
46
|
+
}
|
|
47
|
+
if (hasBodyStart && depth <= 0) {
|
|
48
|
+
return index + 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return hasBodyStart ? lines.length : null;
|
|
52
|
+
}
|
|
53
|
+
function indentationWidth(line) {
|
|
54
|
+
return line.match(/^\s*/u)?.[0].length ?? 0;
|
|
55
|
+
}
|
|
56
|
+
function findIndentedBodyEndLine(lines, startIndex) {
|
|
57
|
+
const declarationIndent = indentationWidth(lines[startIndex] ?? '');
|
|
58
|
+
for (let index = startIndex + 1; index < lines.length; index += 1) {
|
|
59
|
+
const line = lines[index] ?? '';
|
|
60
|
+
if (line.trim().length === 0) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (indentationWidth(line) <= declarationIndent) {
|
|
64
|
+
return index;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return lines.length;
|
|
68
|
+
}
|
|
69
|
+
function normalizeSignature(line) {
|
|
70
|
+
return line.trim().replace(/\s+/gu, ' ');
|
|
71
|
+
}
|
|
72
|
+
function extractSymbolFromLine(line) {
|
|
73
|
+
const trimmed = line.trim();
|
|
74
|
+
const functionMatch = trimmed.match(/^(export\s+)?(?:default\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/u);
|
|
75
|
+
if (functionMatch) {
|
|
76
|
+
return {
|
|
77
|
+
kind: 'function',
|
|
78
|
+
name: functionMatch[2],
|
|
79
|
+
exported: Boolean(functionMatch[1]),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const classMatch = trimmed.match(/^(export\s+)?(?:default\s+)?class\s+([A-Za-z_$][\w$]*)\b/u);
|
|
83
|
+
if (classMatch) {
|
|
84
|
+
return {
|
|
85
|
+
kind: 'class',
|
|
86
|
+
name: classMatch[2],
|
|
87
|
+
exported: Boolean(classMatch[1]),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const constMatch = trimmed.match(/^(export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\b/u);
|
|
91
|
+
if (constMatch) {
|
|
92
|
+
return {
|
|
93
|
+
kind: 'const',
|
|
94
|
+
name: constMatch[2],
|
|
95
|
+
exported: Boolean(constMatch[1]),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const rustFunctionMatch = trimmed.match(/^(pub(?:\([^)]*\))?\s+)?(?:async\s+)?fn\s+([A-Za-z_][\w]*)\s*[<(]/u);
|
|
99
|
+
if (rustFunctionMatch) {
|
|
100
|
+
return {
|
|
101
|
+
kind: 'function',
|
|
102
|
+
name: rustFunctionMatch[2],
|
|
103
|
+
exported: Boolean(rustFunctionMatch[1]),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const goFunctionMatch = trimmed.match(/^func\s+(?:\([^)]*\)\s*)?([A-Za-z_][\w]*)\s*\(/u);
|
|
107
|
+
if (goFunctionMatch) {
|
|
108
|
+
return {
|
|
109
|
+
kind: trimmed.startsWith('func (') ? 'method' : 'function',
|
|
110
|
+
name: goFunctionMatch[1],
|
|
111
|
+
exported: /^[A-Z]/u.test(goFunctionMatch[1] ?? ''),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const pythonFunctionMatch = trimmed.match(/^(?:async\s+)?def\s+([A-Za-z_][\w]*)\s*\(/u);
|
|
115
|
+
if (pythonFunctionMatch) {
|
|
116
|
+
return {
|
|
117
|
+
kind: 'function',
|
|
118
|
+
name: pythonFunctionMatch[1],
|
|
119
|
+
exported: !pythonFunctionMatch[1]?.startsWith('_'),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const pythonClassMatch = trimmed.match(/^class\s+([A-Za-z_][\w]*)\b/u);
|
|
123
|
+
if (pythonClassMatch) {
|
|
124
|
+
return {
|
|
125
|
+
kind: 'class',
|
|
126
|
+
name: pythonClassMatch[1],
|
|
127
|
+
exported: !pythonClassMatch[1]?.startsWith('_'),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const methodMatch = trimmed.match(/^(?:public\s+|private\s+|protected\s+|static\s+|async\s+|get\s+|set\s+)*([A-Za-z_$][\w$]*)\s*\([^)]*\)\s*(?::\s*[^={]+)?\s*\{/u);
|
|
131
|
+
if (methodMatch && !['if', 'for', 'while', 'switch', 'catch', 'function'].includes(methodMatch[1] ?? '')) {
|
|
132
|
+
return {
|
|
133
|
+
kind: 'method',
|
|
134
|
+
name: methodMatch[1],
|
|
135
|
+
exported: !trimmed.startsWith('private ') && !trimmed.startsWith('protected '),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
export function unknownSourceAnchorSymbol() {
|
|
141
|
+
return {
|
|
142
|
+
kind: 'unknown',
|
|
143
|
+
name: null,
|
|
144
|
+
exported: false,
|
|
145
|
+
signatureHash: null,
|
|
146
|
+
bodyHash: null,
|
|
147
|
+
startLine: null,
|
|
148
|
+
endLine: null,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
export function extractSourceAnchorSymbol(content, anchorLineStart) {
|
|
152
|
+
const lines = content.split(/\r?\n/u);
|
|
153
|
+
const scanStart = Math.max(0, anchorLineStart);
|
|
154
|
+
const scanEnd = Math.min(lines.length, scanStart + 24);
|
|
155
|
+
for (let index = scanStart; index < scanEnd; index += 1) {
|
|
156
|
+
const line = lines[index] ?? '';
|
|
157
|
+
const trimmed = line.trim();
|
|
158
|
+
if (trimmed.length === 0 ||
|
|
159
|
+
trimmed.startsWith('*') ||
|
|
160
|
+
trimmed.startsWith('//') ||
|
|
161
|
+
trimmed.startsWith('#') ||
|
|
162
|
+
trimmed.startsWith('@') ||
|
|
163
|
+
trimmed === '*/') {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const symbol = extractSymbolFromLine(line);
|
|
167
|
+
if (!symbol) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const endLine = line.includes('{') ? findBracedBodyEndLine(lines, index) : findIndentedBodyEndLine(lines, index);
|
|
171
|
+
const body = endLine ? lines.slice(index, endLine).join('\n') : null;
|
|
172
|
+
return {
|
|
173
|
+
...symbol,
|
|
174
|
+
signatureHash: sha256(normalizeSignature(line)),
|
|
175
|
+
bodyHash: body ? sha256(body) : null,
|
|
176
|
+
startLine: index + 1,
|
|
177
|
+
endLine,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return unknownSourceAnchorSymbol();
|
|
181
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { SOURCE_ANCHOR_ALLOWED_RISKS, listSourceAnchorFiles, parseSourceAnchorsInContent, sourceAnchorPathIsGeneratedOrVendor, splitSourceAnchorList, } from './source-anchors.js';
|
|
4
|
+
export const SOURCE_ANCHOR_IGNORED_DIRECTORIES = new Set([
|
|
5
|
+
'.git',
|
|
6
|
+
'.mustflow',
|
|
7
|
+
'coverage',
|
|
8
|
+
'dist',
|
|
9
|
+
'build',
|
|
10
|
+
'node_modules',
|
|
11
|
+
'tests',
|
|
12
|
+
'.next',
|
|
13
|
+
'.nuxt',
|
|
14
|
+
]);
|
|
15
|
+
const SOURCE_ANCHOR_PURPOSE_WARNING_MAX_CHARS = 180;
|
|
16
|
+
const SOURCE_ANCHOR_SEARCH_WARNING_MAX_TERMS = 12;
|
|
17
|
+
const SOURCE_ANCHOR_DENSITY_WARNING_MAX_PER_FILE = 5;
|
|
18
|
+
const SOURCE_ANCHOR_DENSITY_WARNING_MIN_LINES_PER_ANCHOR = 120;
|
|
19
|
+
const SOURCE_ANCHOR_HIGH_RISK_PURPOSE_REVIEW_MAX_CHARS = 120;
|
|
20
|
+
const SOURCE_ANCHOR_HIGH_RISK_SEARCH_REVIEW_MAX_TERMS = 8;
|
|
21
|
+
const SOURCE_ANCHOR_HIGH_RISK_TAGS = new Set([
|
|
22
|
+
'authz',
|
|
23
|
+
'authorization',
|
|
24
|
+
'data_loss',
|
|
25
|
+
'migration',
|
|
26
|
+
'payment',
|
|
27
|
+
'pii',
|
|
28
|
+
'privacy',
|
|
29
|
+
'secrets',
|
|
30
|
+
'security',
|
|
31
|
+
]);
|
|
32
|
+
const SOURCE_ANCHOR_FORBIDDEN_INSTRUCTION_PATTERNS = [
|
|
33
|
+
/\b(?:agent|agents|llm|model|assistant)\s+(?:must|should|may|can)\s+(?:not\s+)?(?:run|execute|skip|ignore|bypass|override)\b/iu,
|
|
34
|
+
/\b(?:do\s+not|don't|never|skip)\s+(?:run|execute)\s+(?:tests?|checks?|validation|mf\s+run)\b/iu,
|
|
35
|
+
/\b(?:ignore|bypass|override)\s+(?:AGENTS\.md|mustflow|command\s+contract|commands\.toml|workflow\s+rules?)\b/iu,
|
|
36
|
+
/\b(?:run|execute)\s+(?:this\s+)?(?:shell\s+)?command\b/iu,
|
|
37
|
+
/\bmf\s+run\s+[a-z0-9_.-]+\b/iu,
|
|
38
|
+
/\bthis\s+anchor\s+(?:authorizes|grants|allows)\b.*\b(?:agents?|commands?|validation|verification)\b/iu,
|
|
39
|
+
/\b(?:command_intents?|required_after|run_policy|argv|cmd|permissions?|allowed_edits|skip_validation|agent_action)\s*[:=]/iu,
|
|
40
|
+
];
|
|
41
|
+
const SOURCE_ANCHOR_SECRET_LIKE_PATTERNS = [
|
|
42
|
+
/\b(?:api[_-]?key|api[_-]?token|access[_-]?token|auth[_-]?token|secret|password|passwd|private[_-]?key)\b\s*[:=]\s*["']?[A-Za-z0-9_./+=:-]{8,}/iu,
|
|
43
|
+
/\b(?:sk-[A-Za-z0-9]{16,}|ghp_[A-Za-z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}|AKIA[0-9A-Z]{16})\b/u,
|
|
44
|
+
];
|
|
45
|
+
function sourceAnchorIssue(message) {
|
|
46
|
+
return { severity: 'error', message };
|
|
47
|
+
}
|
|
48
|
+
function sourceAnchorWarning(message) {
|
|
49
|
+
return { severity: 'warning', message };
|
|
50
|
+
}
|
|
51
|
+
function sourceAnchorLabel(anchor) {
|
|
52
|
+
return `${anchor.rawId} in ${anchor.path}:${anchor.lineStart}`;
|
|
53
|
+
}
|
|
54
|
+
function validateSourceAnchor(anchor) {
|
|
55
|
+
const issues = [];
|
|
56
|
+
if (!anchor.idValid) {
|
|
57
|
+
return [
|
|
58
|
+
sourceAnchorIssue(`source anchor ${anchor.path}:${anchor.lineStart} has invalid format: anchor id must be lowercase letters, numbers, dots, or hyphens`),
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
const label = sourceAnchorLabel(anchor);
|
|
62
|
+
if (sourceAnchorPathIsGeneratedOrVendor(anchor.path)) {
|
|
63
|
+
issues.push(sourceAnchorIssue(`source anchor ${anchor.rawId} is in generated or vendor path ${anchor.path}`));
|
|
64
|
+
}
|
|
65
|
+
if (SOURCE_ANCHOR_FORBIDDEN_INSTRUCTION_PATTERNS.some((pattern) => pattern.test(anchor.rawText))) {
|
|
66
|
+
issues.push(sourceAnchorIssue(`source anchor ${label} contains agent command or policy instructions`));
|
|
67
|
+
}
|
|
68
|
+
if (SOURCE_ANCHOR_SECRET_LIKE_PATTERNS.some((pattern) => pattern.test(anchor.rawText))) {
|
|
69
|
+
issues.push(sourceAnchorIssue(`source anchor ${label} contains secret-like text`));
|
|
70
|
+
}
|
|
71
|
+
for (const field of anchor.unsupportedFields) {
|
|
72
|
+
issues.push(sourceAnchorIssue(`source anchor ${anchor.rawId} in ${anchor.path}:${anchor.lineStart} has invalid format: unsupported field "${field}"`));
|
|
73
|
+
}
|
|
74
|
+
const riskTags = splitSourceAnchorList(anchor.fields.get('risk'));
|
|
75
|
+
for (const risk of riskTags) {
|
|
76
|
+
if (!SOURCE_ANCHOR_ALLOWED_RISKS.has(risk)) {
|
|
77
|
+
issues.push(sourceAnchorIssue(`source anchor ${label} uses unknown risk tag "${risk}"`));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const purpose = anchor.fields.get('purpose');
|
|
81
|
+
if (purpose && purpose.length > SOURCE_ANCHOR_PURPOSE_WARNING_MAX_CHARS) {
|
|
82
|
+
issues.push(sourceAnchorWarning(`source anchor ${label} purpose is long (${purpose.length} characters > ${SOURCE_ANCHOR_PURPOSE_WARNING_MAX_CHARS})`));
|
|
83
|
+
}
|
|
84
|
+
const searchTerms = splitSourceAnchorList(anchor.fields.get('search'));
|
|
85
|
+
if (searchTerms.length > SOURCE_ANCHOR_SEARCH_WARNING_MAX_TERMS) {
|
|
86
|
+
issues.push(sourceAnchorWarning(`source anchor ${label} has too many search terms (${searchTerms.length} > ${SOURCE_ANCHOR_SEARCH_WARNING_MAX_TERMS})`));
|
|
87
|
+
}
|
|
88
|
+
const highRiskTags = riskTags.filter((risk) => SOURCE_ANCHOR_HIGH_RISK_TAGS.has(risk));
|
|
89
|
+
if (highRiskTags.length === 0) {
|
|
90
|
+
return issues;
|
|
91
|
+
}
|
|
92
|
+
const reviewReasons = [];
|
|
93
|
+
if (!anchor.fields.has('invariant')) {
|
|
94
|
+
reviewReasons.push('missing invariant');
|
|
95
|
+
}
|
|
96
|
+
if (purpose && purpose.length > SOURCE_ANCHOR_HIGH_RISK_PURPOSE_REVIEW_MAX_CHARS) {
|
|
97
|
+
reviewReasons.push(`purpose ${purpose.length} characters > ${SOURCE_ANCHOR_HIGH_RISK_PURPOSE_REVIEW_MAX_CHARS}`);
|
|
98
|
+
}
|
|
99
|
+
if (searchTerms.length > SOURCE_ANCHOR_HIGH_RISK_SEARCH_REVIEW_MAX_TERMS) {
|
|
100
|
+
reviewReasons.push(`search terms ${searchTerms.length} > ${SOURCE_ANCHOR_HIGH_RISK_SEARCH_REVIEW_MAX_TERMS}`);
|
|
101
|
+
}
|
|
102
|
+
if (reviewReasons.length > 0) {
|
|
103
|
+
issues.push(sourceAnchorWarning(`source anchor ${label} uses high-risk tags and needs review: ${highRiskTags.join(', ')}; ${reviewReasons.join('; ')}`));
|
|
104
|
+
}
|
|
105
|
+
return issues;
|
|
106
|
+
}
|
|
107
|
+
function countNonEmptyLines(content) {
|
|
108
|
+
return content.split(/\r?\n/u).filter((line) => line.trim().length > 0).length;
|
|
109
|
+
}
|
|
110
|
+
function validateSourceAnchorDensity(relativePath, content, anchors) {
|
|
111
|
+
if (anchors.length <= SOURCE_ANCHOR_DENSITY_WARNING_MAX_PER_FILE) {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
const nonEmptyLines = countNonEmptyLines(content);
|
|
115
|
+
const linesPerAnchor = nonEmptyLines / anchors.length;
|
|
116
|
+
if (linesPerAnchor >= SOURCE_ANCHOR_DENSITY_WARNING_MIN_LINES_PER_ANCHOR) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
return [
|
|
120
|
+
sourceAnchorWarning(`${relativePath} has high source anchor density (${anchors.length} anchors across ${nonEmptyLines} non-empty lines)`),
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* mf:anchor core.source-anchor-validation
|
|
125
|
+
* purpose: Validate source anchors as navigation-only metadata without command, verification, or policy authority.
|
|
126
|
+
* search: source anchor validation, forbidden instruction, duplicate id, high risk review
|
|
127
|
+
* invariant: Source anchor validation reports issues but never grants command permission or verification authority.
|
|
128
|
+
* risk: config, security
|
|
129
|
+
*/
|
|
130
|
+
export function validateSourceAnchorsInProject(projectRoot) {
|
|
131
|
+
const sourceFiles = listSourceAnchorFiles(projectRoot, {
|
|
132
|
+
ignoredDirectoryNames: SOURCE_ANCHOR_IGNORED_DIRECTORIES,
|
|
133
|
+
});
|
|
134
|
+
const issues = [];
|
|
135
|
+
const anchorsById = new Map();
|
|
136
|
+
for (const relativePath of sourceFiles) {
|
|
137
|
+
const absolutePath = path.join(projectRoot, ...relativePath.split('/'));
|
|
138
|
+
const content = readFileSync(absolutePath, 'utf8');
|
|
139
|
+
const anchors = parseSourceAnchorsInContent(relativePath, content);
|
|
140
|
+
issues.push(...validateSourceAnchorDensity(relativePath, content, anchors));
|
|
141
|
+
for (const anchor of anchors) {
|
|
142
|
+
issues.push(...validateSourceAnchor(anchor));
|
|
143
|
+
if (!anchor.idValid) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const anchorsForId = anchorsById.get(anchor.rawId) ?? [];
|
|
147
|
+
anchorsForId.push(anchor);
|
|
148
|
+
anchorsById.set(anchor.rawId, anchorsForId);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
for (const [id, anchors] of anchorsById) {
|
|
152
|
+
if (anchors.length <= 1) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
issues.push(sourceAnchorIssue(`source anchor id "${id}" is duplicated: ${anchors.map((anchor) => `${anchor.path}:${anchor.lineStart}`).join(', ')}`));
|
|
156
|
+
}
|
|
157
|
+
return issues;
|
|
158
|
+
}
|