bmad-module-skill-forge 2.2.0 → 3.0.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/.claude-plugin/marketplace.json +1 -1
- package/README.md +49 -49
- package/docs/404.md +10 -8
- package/docs/_data/pinned.yaml +22 -13
- package/docs/_internal/STABILITY.md +58 -35
- package/docs/agents.md +39 -53
- package/docs/architecture.md +65 -51
- package/docs/bmad-synergy.md +53 -51
- package/docs/campaign.md +127 -75
- package/docs/concepts.md +34 -28
- package/docs/examples.md +70 -68
- package/docs/forge-auto.md +34 -31
- package/docs/getting-started.md +118 -57
- package/docs/how-it-works.md +25 -21
- package/docs/index.md +15 -15
- package/docs/skill-model.md +70 -59
- package/docs/troubleshooting.md +135 -18
- package/docs/verifying-a-skill.md +83 -57
- package/docs/why-skf.md +24 -22
- package/docs/workflows.md +274 -110
- package/package.json +18 -10
- package/src/forger/preferences.yaml +8 -1
- package/src/knowledge/agentskills-spec.md +2 -0
- package/src/knowledge/ccc-bridge.md +40 -24
- package/src/knowledge/confidence-tiers.md +9 -5
- package/src/knowledge/overview.md +3 -3
- package/src/knowledge/progressive-capability.md +8 -8
- package/src/knowledge/provenance-tracking.md +9 -5
- package/src/knowledge/qmd-registry.md +2 -2
- package/src/knowledge/skf-knowledge-index.csv +2 -2
- package/src/knowledge/skill-lifecycle.md +18 -11
- package/src/knowledge/split-body-strategy.md +0 -3
- package/src/knowledge/tool-resolution.md +4 -2
- package/src/knowledge/version-paths.md +101 -15
- package/src/module-help.csv +3 -3
- package/src/module.yaml +10 -0
- package/src/shared/data/ast-grep-recipes.yaml +608 -0
- package/src/shared/data/ide-context-files.json +30 -0
- package/src/shared/health-check.md +32 -12
- package/src/shared/references/description-guard-protocol.md +12 -9
- package/src/shared/references/feasibility-report-schema.md +19 -13
- package/src/shared/references/headless-gate-convention.md +55 -3
- package/src/shared/references/output-contract-schema.md +19 -8
- package/src/shared/references/pipeline-contracts.md +94 -29
- package/src/shared/references/tessl-review.md +77 -0
- package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
- package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
- package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
- package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
- package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
- package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
- package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
- package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
- package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
- package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
- package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
- package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
- package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
- package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
- package/src/shared/scripts/skf-atomic-write.py +30 -14
- package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
- package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
- package/src/shared/scripts/skf-check-unit-records.py +184 -0
- package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
- package/src/shared/scripts/skf-classify-changed-files.py +694 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
- package/src/shared/scripts/skf-count-imports.py +1867 -0
- package/src/shared/scripts/skf-count-tokens.py +1 -1
- package/src/shared/scripts/skf-derive-assembly-shape.py +3 -2
- package/src/shared/scripts/skf-description-guard.py +99 -11
- package/src/shared/scripts/skf-detect-docs.py +694 -2
- package/src/shared/scripts/skf-detect-language.py +486 -107
- package/src/shared/scripts/skf-detect-registry.py +887 -0
- package/src/shared/scripts/skf-detect-scripts-assets.py +1 -1
- package/src/shared/scripts/skf-detect-tools.py +209 -27
- package/src/shared/scripts/skf-detect-workspaces.py +506 -30
- package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
- package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
- package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
- package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
- package/src/shared/scripts/skf-extract-public-api.py +4084 -85
- package/src/shared/scripts/skf-extraction-inventory.py +746 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +539 -0
- package/src/shared/scripts/skf-fetch-temporal.py +674 -0
- package/src/shared/scripts/skf-find-cycles.py +97 -29
- package/src/shared/scripts/skf-find-test-report.py +476 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +444 -203
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +661 -0
- package/src/shared/scripts/skf-hash-content.py +166 -12
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +159 -27
- package/src/shared/scripts/skf-manifest-ops.py +1 -1
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
- package/src/shared/scripts/skf-merge-doc-urls.py +1 -1
- package/src/shared/scripts/skf-names-present.py +221 -0
- package/src/shared/scripts/skf-pair-intersect.py +119 -28
- package/src/shared/scripts/skf-parse-gaps.py +1384 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-preflight.py +161 -27
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
- package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
- package/src/shared/scripts/skf-quick-batch.py +774 -0
- package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
- package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
- package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
- package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
- package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
- package/src/shared/scripts/skf-resolve-authoritative-files.py +128 -13
- package/src/shared/scripts/skf-resolve-package.py +523 -106
- package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
- package/src/shared/scripts/skf-run-lock.py +577 -0
- package/src/shared/scripts/skf-scan-manifests.py +998 -57
- package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
- package/src/shared/scripts/skf-severity-classify.py +712 -108
- package/src/shared/scripts/skf-shape-detect.py +298 -204
- package/src/shared/scripts/skf-shard-body.py +9 -8
- package/src/shared/scripts/skf-skill-inventory.py +2412 -89
- package/src/shared/scripts/skf-skills-module.py +472 -0
- package/src/shared/scripts/skf-source-tree.py +1796 -0
- package/src/shared/scripts/skf-structural-diff.py +670 -119
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +5 -5
- package/src/shared/scripts/skf-update-run-state.py +624 -0
- package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
- package/src/shared/scripts/skf-validate-brief-schema.py +4 -1
- package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
- package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
- package/src/shared/scripts/skf-validate-output.py +712 -64
- package/src/shared/scripts/skf-validate-pins.py +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +116 -10
- package/src/shared/scripts/skf-verify-provenance-completeness.py +2919 -54
- package/src/shared/scripts/skf-write-skill-brief.py +367 -19
- package/src/shared/tool-requirements.yaml +201 -0
- package/src/skf-analyze-source/SKILL.md +41 -36
- package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
- package/src/skf-analyze-source/customize.toml +36 -24
- package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
- package/src/skf-analyze-source/references/continue.md +2 -13
- package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
- package/src/skf-analyze-source/references/generate-briefs.md +121 -55
- package/src/skf-analyze-source/references/headless-contract.md +42 -15
- package/src/skf-analyze-source/references/identify-units.md +96 -110
- package/src/skf-analyze-source/references/init.md +73 -71
- package/src/skf-analyze-source/references/map-and-detect.md +123 -105
- package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
- package/src/skf-analyze-source/references/recommend.md +51 -70
- package/src/skf-analyze-source/references/scan-project.md +60 -84
- package/src/skf-analyze-source/references/scan-root.md +39 -0
- package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
- package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
- package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
- package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
- package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
- package/src/skf-audit-skill/SKILL.md +43 -51
- package/src/skf-audit-skill/assets/drift-report-template.md +27 -3
- package/src/skf-audit-skill/customize.toml +41 -20
- package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
- package/src/skf-audit-skill/references/doc-drift.md +141 -0
- package/src/skf-audit-skill/references/headless-contract.md +29 -0
- package/src/skf-audit-skill/references/init.md +148 -210
- package/src/skf-audit-skill/references/re-index.md +96 -108
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +27 -18
- package/src/skf-audit-skill/references/severity-classify.md +79 -65
- package/src/skf-audit-skill/references/severity-rules.md +15 -6
- package/src/skf-audit-skill/references/structural-diff.md +75 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
- package/src/skf-brief-skill/SKILL.md +36 -25
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +17 -24
- package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +142 -125
- package/src/skf-brief-skill/references/confirm-brief.md +10 -8
- package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
- package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
- package/src/skf-brief-skill/references/gather-intent.md +87 -182
- package/src/skf-brief-skill/references/headless-args.md +84 -16
- package/src/skf-brief-skill/references/health-check.md +1 -1
- package/src/skf-brief-skill/references/invocation-contract.md +18 -13
- package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
- package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
- package/src/skf-brief-skill/references/scope-definition.md +123 -47
- package/src/skf-brief-skill/references/step-auto-brief.md +24 -80
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +3 -2
- package/src/skf-brief-skill/references/write-brief.md +66 -57
- package/src/skf-campaign/SKILL.md +31 -34
- package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
- package/src/skf-campaign/customize.toml +47 -16
- package/src/skf-campaign/references/campaign-contracts.md +39 -29
- package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
- package/src/skf-campaign/references/health-check.md +7 -16
- package/src/skf-campaign/references/step-01-setup.md +46 -84
- package/src/skf-campaign/references/step-02-strategy.md +31 -30
- package/src/skf-campaign/references/step-03-pins.md +26 -18
- package/src/skf-campaign/references/step-04-provenance.md +24 -23
- package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
- package/src/skf-campaign/references/step-06-batch.md +41 -34
- package/src/skf-campaign/references/step-07-capstone.md +40 -25
- package/src/skf-campaign/references/step-08-verify.md +28 -29
- package/src/skf-campaign/references/step-09-refine.md +29 -30
- package/src/skf-campaign/references/step-10-export.md +48 -36
- package/src/skf-campaign/references/step-11-maintenance.md +31 -34
- package/src/skf-campaign/references/step-resume.md +37 -68
- package/src/skf-campaign/scripts/campaign-deps.py +57 -18
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
- package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
- package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
- package/src/skf-campaign/scripts/campaign-report.py +204 -37
- package/src/skf-campaign/scripts/campaign-state.py +1128 -0
- package/src/skf-campaign/scripts/campaign-status.py +10 -74
- package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
- package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
- package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
- package/src/skf-campaign/templates/campaign-report-template.md +5 -1
- package/src/skf-campaign/templates/kickoff-template.md +0 -14
- package/src/skf-create-skill/SKILL.md +27 -20
- package/src/skf-create-skill/assets/compile-assembly-rules.md +6 -5
- package/src/skf-create-skill/assets/skill-sections.md +15 -5
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
- package/src/skf-create-skill/references/batch-mode.md +81 -0
- package/src/skf-create-skill/references/ccc-index-check.md +27 -0
- package/src/skf-create-skill/references/compile.md +107 -29
- package/src/skf-create-skill/references/component-extraction.md +113 -91
- package/src/skf-create-skill/references/enrich.md +41 -23
- package/src/skf-create-skill/references/entry-points-by-hand.md +20 -0
- package/src/skf-create-skill/references/extract.md +200 -161
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
- package/src/skf-create-skill/references/extraction-patterns.md +584 -196
- package/src/skf-create-skill/references/generate-artifacts.md +145 -93
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +53 -36
- package/src/skf-create-skill/references/relabel-rule.md +12 -0
- package/src/skf-create-skill/references/report.md +28 -59
- package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
- package/src/skf-create-skill/references/step-auto-shard.md +20 -93
- package/src/skf-create-skill/references/step-doc-rot.md +44 -60
- package/src/skf-create-skill/references/step-doc-sources.md +28 -19
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
- package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
- package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
- package/src/skf-create-skill/references/validate.md +173 -99
- package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
- package/src/skf-create-stack-skill/SKILL.md +29 -56
- package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
- package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
- package/src/skf-create-stack-skill/customize.toml +23 -12
- package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
- package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
- package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
- package/src/skf-create-stack-skill/references/generate-output.md +138 -128
- package/src/skf-create-stack-skill/references/init.md +90 -32
- package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
- package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
- package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
- package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
- package/src/skf-create-stack-skill/references/report.md +39 -33
- package/src/skf-create-stack-skill/references/validate.md +20 -39
- package/src/skf-drop-skill/SKILL.md +28 -51
- package/src/skf-drop-skill/customize.toml +44 -30
- package/src/skf-drop-skill/references/execute.md +79 -146
- package/src/skf-drop-skill/references/invocation-contract.md +64 -0
- package/src/skf-drop-skill/references/report.md +46 -30
- package/src/skf-drop-skill/references/select.md +118 -124
- package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
- package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
- package/src/skf-export-skill/SKILL.md +40 -62
- package/src/skf-export-skill/assets/managed-section-format.md +14 -50
- package/src/skf-export-skill/assets/snippet-format.md +3 -1
- package/src/skf-export-skill/customize.toml +42 -13
- package/src/skf-export-skill/references/generate-snippet.md +54 -46
- package/src/skf-export-skill/references/health-check.md +2 -0
- package/src/skf-export-skill/references/invocation-contract.md +15 -0
- package/src/skf-export-skill/references/load-skill.md +88 -62
- package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
- package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
- package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
- package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
- package/src/skf-export-skill/references/package.md +15 -73
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
- package/src/skf-export-skill/references/result-envelope.md +31 -16
- package/src/skf-export-skill/references/summary.md +41 -17
- package/src/skf-export-skill/references/token-report.md +4 -12
- package/src/skf-export-skill/references/update-context.md +118 -237
- package/src/skf-forger/SKILL.md +61 -37
- package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
- package/src/skf-forger/customize.toml +43 -0
- package/src/skf-forger/references/pipeline-mode.md +73 -18
- package/src/skf-forger/scripts/forge-status.py +299 -0
- package/src/skf-forger/scripts/parse-pipeline.py +322 -54
- package/src/skf-forger/scripts/pipeline-gate.py +428 -0
- package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
- package/src/skf-quick-skill/SKILL.md +54 -53
- package/src/skf-quick-skill/assets/skill-template.md +4 -2
- package/src/skf-quick-skill/customize.toml +51 -20
- package/src/skf-quick-skill/references/batch-mode.md +74 -21
- package/src/skf-quick-skill/references/compile.md +30 -31
- package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
- package/src/skf-quick-skill/references/finalize.md +69 -18
- package/src/skf-quick-skill/references/halt-contract.md +41 -29
- package/src/skf-quick-skill/references/health-check.md +5 -3
- package/src/skf-quick-skill/references/quick-extract.md +114 -45
- package/src/skf-quick-skill/references/registry-resolution.md +9 -64
- package/src/skf-quick-skill/references/resolve-target.md +116 -66
- package/src/skf-quick-skill/references/write-and-validate.md +79 -40
- package/src/skf-refine-architecture/SKILL.md +43 -53
- package/src/skf-refine-architecture/customize.toml +49 -20
- package/src/skf-refine-architecture/references/compile.md +97 -54
- package/src/skf-refine-architecture/references/exit-codes.md +30 -0
- package/src/skf-refine-architecture/references/finding-storage.md +21 -0
- package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
- package/src/skf-refine-architecture/references/improvements.md +14 -20
- package/src/skf-refine-architecture/references/init.md +98 -57
- package/src/skf-refine-architecture/references/issue-detection.md +32 -39
- package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
- package/src/skf-refine-architecture/references/report.md +65 -54
- package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
- package/src/skf-rename-skill/SKILL.md +19 -54
- package/src/skf-rename-skill/customize.toml +32 -26
- package/src/skf-rename-skill/references/execute.md +230 -184
- package/src/skf-rename-skill/references/exit-codes.md +7 -7
- package/src/skf-rename-skill/references/health-check.md +1 -7
- package/src/skf-rename-skill/references/invocation-contract.md +25 -0
- package/src/skf-rename-skill/references/report.md +63 -52
- package/src/skf-rename-skill/references/select.md +197 -115
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
- package/src/skf-setup/SKILL.md +26 -26
- package/src/skf-setup/customize.toml +14 -10
- package/src/skf-setup/references/auto-index.md +50 -63
- package/src/skf-setup/references/ccc-index.md +29 -90
- package/src/skf-setup/references/detect-and-tier.md +58 -67
- package/src/skf-setup/references/health-check.md +2 -0
- package/src/skf-setup/references/invocation-contract.md +14 -0
- package/src/skf-setup/references/report.md +43 -166
- package/src/skf-setup/references/tier-rules.md +5 -5
- package/src/skf-setup/references/write-config.md +34 -57
- package/src/skf-test-skill/SKILL.md +17 -57
- package/src/skf-test-skill/assets/output-section-formats.md +33 -34
- package/src/skf-test-skill/customize.toml +27 -13
- package/src/skf-test-skill/references/coherence-check.md +134 -62
- package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
- package/src/skf-test-skill/references/coverage-check.md +217 -254
- package/src/skf-test-skill/references/detect-mode.md +5 -5
- package/src/skf-test-skill/references/external-validators.md +94 -82
- package/src/skf-test-skill/references/health-check.md +6 -7
- package/src/skf-test-skill/references/init.md +163 -88
- package/src/skf-test-skill/references/invocation-contract.md +66 -0
- package/src/skf-test-skill/references/migration-section-rules.md +5 -2
- package/src/skf-test-skill/references/report.md +162 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +41 -155
- package/src/skf-test-skill/references/source-access-protocol.md +19 -92
- package/src/skf-test-skill/references/step-hard-gate.md +51 -33
- package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
- package/src/skf-test-skill/scripts/build-result-context.py +287 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
- package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
- package/src/skf-test-skill/scripts/compute-score.py +223 -45
- package/src/skf-test-skill/scripts/gap-ledger.py +1381 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
- package/src/skf-test-skill/scripts/score-signatures.py +459 -0
- package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +127 -52
- package/src/skf-test-skill/templates/test-report-template.md +21 -15
- package/src/skf-update-skill/SKILL.md +38 -25
- package/src/skf-update-skill/customize.toml +27 -12
- package/src/skf-update-skill/references/detect-changes.md +233 -222
- package/src/skf-update-skill/references/gap-driven.md +336 -0
- package/src/skf-update-skill/references/health-check.md +31 -5
- package/src/skf-update-skill/references/init.md +250 -84
- package/src/skf-update-skill/references/invocation-contract.md +12 -0
- package/src/skf-update-skill/references/manual-section-rules.md +6 -23
- package/src/skf-update-skill/references/merge.md +180 -47
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +100 -35
- package/src/skf-update-skill/references/write.md +331 -149
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
- package/src/skf-verify-stack/SKILL.md +23 -42
- package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
- package/src/skf-verify-stack/customize.toml +55 -22
- package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
- package/src/skf-verify-stack/references/coverage.md +67 -64
- package/src/skf-verify-stack/references/exit-codes.md +21 -8
- package/src/skf-verify-stack/references/init.md +107 -62
- package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
- package/src/skf-verify-stack/references/integrations.md +106 -65
- package/src/skf-verify-stack/references/report.md +59 -42
- package/src/skf-verify-stack/references/requirements.md +32 -9
- package/src/skf-verify-stack/references/synthesize.md +53 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
- package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
- package/tools/cli/commands/install.js +11 -4
- package/tools/cli/commands/status.js +15 -3
- package/tools/cli/commands/update.js +11 -4
- package/tools/cli/lib/tool-check.js +320 -0
- package/tools/cli/lib/version-check.js +22 -9
- package/tools/cli/skf-cli.js +4 -1
- package/.gitattributes +0 -16
- package/.nvmrc +0 -1
- package/docs/_internal/RELEASING.md +0 -679
- package/release-audits/v1.0.0-launch-audit.md +0 -728
- package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
- package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
- package/src/skf-campaign/manifest.yaml +0 -15
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
- package/src/skf-create-skill/references/ecosystem-check.md +0 -74
- package/src/skf-drop-skill/references/headless-contract.md +0 -18
- package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
- package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
- package/src/skf-update-skill/references/validate.md +0 -124
- package/tools/validate-docs-drift.js +0 -233
- package/tools/validate-docs-links.js +0 -665
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
nextStepFile: 'write.md'
|
|
3
|
-
# Resolve `{hashContentHelper}` to the first existing path; HALT if neither
|
|
4
|
-
# candidate exists. Check B uses its `manual-verify` subcommand to verify the
|
|
5
|
-
# merged (on-disk) SKILL.md against the byte-exact [MANUAL] inventory captured
|
|
6
|
-
# in step 1 §5 — the deterministic replacement for the LLM byte-identity
|
|
7
|
-
# eyeball, which could silently pass a subtly truncated block.
|
|
8
|
-
hashContentProbeOrder:
|
|
9
|
-
- '{project-root}/_bmad/skf/shared/scripts/skf-hash-content.py'
|
|
10
|
-
- '{project-root}/src/shared/scripts/skf-hash-content.py'
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
<!-- Config: communicate in {communication_language}. -->
|
|
14
|
-
|
|
15
|
-
# Step 5: Validate
|
|
16
|
-
|
|
17
|
-
## STEP GOAL:
|
|
18
|
-
|
|
19
|
-
Validate the merged skill content against the agentskills.io specification, verify all [MANUAL] sections survived the merge intact, and check confidence tier consistency across all re-extracted content. This is an advisory validation — findings are warnings, not blockers.
|
|
20
|
-
|
|
21
|
-
## Rules
|
|
22
|
-
|
|
23
|
-
- Focus only on validation — do not fix issues (that's the user's choice)
|
|
24
|
-
- Validation is read-only — do not modify merged content
|
|
25
|
-
- Run the two live structural checks (B, then C) in order; Checks A, D, E, F are deferred to step 6
|
|
26
|
-
|
|
27
|
-
## Steps
|
|
28
|
-
|
|
29
|
-
### 1. Check Tool Availability and Validation Timing
|
|
30
|
-
|
|
31
|
-
Run: `npx skill-check -h`
|
|
32
|
-
|
|
33
|
-
- If succeeds: skill-check is available for Checks A, E, F below
|
|
34
|
-
- If fails: Use manual fallback paths in those checks
|
|
35
|
-
|
|
36
|
-
**Important:** Do not assume availability — empirical check required.
|
|
37
|
-
|
|
38
|
-
**Validation timing note:** Step-04 section 6b has already written SKILL.md to disk. External-tool checks against written files (skill-check Checks A, E, F) still run in **step 6 section 7** to co-locate external-tool validation with post-write verification. Check D (Provenance Completeness) is deterministic but needs both `metadata.json` and `provenance-map.json` on disk — neither exists yet at this step — so it is deferred to **step 6 section 6a**, which runs it via the completeness helper against the freshly-written artifacts. Structural checks (B, C) run here against the merged content — content on disk is byte-identical to the in-context copy.
|
|
39
|
-
|
|
40
|
-
### 2. Run Validation Checks
|
|
41
|
-
|
|
42
|
-
Per the §1 timing note, only Check B (a single deterministic `manual-verify` script) and Check C (an in-prompt tier-label consistency check) run live at this step; Checks A, D, E, F are deferred to step 6. Run B then C in order — one script plus one in-prompt comparison have nothing to fan out.
|
|
43
|
-
|
|
44
|
-
**Check A — Spec Compliance (deferred to post-write):**
|
|
45
|
-
|
|
46
|
-
Skill-check requires written files on disk. This check is deferred to step 6 section 7. Perform manual structural check only: verify merged SKILL.md has required sections (exports, usage patterns, conventions), verify export entries have name/type/signature/file:line reference, flag missing sections.
|
|
47
|
-
|
|
48
|
-
**Check B — [MANUAL] Section Integrity:**
|
|
49
|
-
|
|
50
|
-
Run the deterministic [MANUAL]-integrity verifier against the step-1 §5 inventory — do not eyeball byte-identity (a subtly truncated block reads as intact to the eye):
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
uv run {hashContentHelper} manual-verify {skill_package}/SKILL.md \
|
|
54
|
-
--inventory {manual_inventory}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Read the verdict JSON `{"preserved":[...], "modified":[...], "missing":[...], "moved":[...], "ok":bool}` (the on-disk SKILL.md is byte-identical to the merged in-context copy per the timing note above):
|
|
58
|
-
- `ok == true` → status PASS. `preserved` blocks are byte-identical in place; any `moved` blocks are byte-identical but relocated with their logical parent section (report as informational, not a finding).
|
|
59
|
-
- `modified` non-empty → FAIL: these blocks' byte-exact interiors changed (the truncation a marker-count/eyeball check would miss). List each by name.
|
|
60
|
-
- `missing` non-empty → FAIL: these blocks lost their markers entirely. List each by name.
|
|
61
|
-
|
|
62
|
-
Populate the §3 `manual_integrity` record from this verdict (`sections_verified` = inventory count, `sections_intact` = `len(preserved) + len(moved)`). This check is advisory here (findings inform, do not block); write.md §1 enforces the same `ok` verdict as a HALT gate before any derived artifact is written.
|
|
63
|
-
|
|
64
|
-
**Check C — Confidence Tier Consistency:**
|
|
65
|
-
- Verify all re-extracted exports have confidence labels (T1/T1-low/T2)
|
|
66
|
-
- Verify tier labels match forge tier: Quick=T1-low only, Forge=T1 (T1-low for degraded), Forge+=T1 (same as Forge, CCC improves coverage not confidence), Deep=T1+T2
|
|
67
|
-
- Flag mismatched or missing tier labels
|
|
68
|
-
|
|
69
|
-
**Check D — Provenance Completeness (deferred to post-write):**
|
|
70
|
-
|
|
71
|
-
The provenance map does not exist on disk until step 6 §3 writes it, and completeness is a deterministic set-diff (metadata `exports[]` vs provenance `entries[].export_name`) plus file:line citation resolution — not something to eyeball. This check is deferred to **step 6 section 6a**, which runs `skf-verify-provenance-completeness.py` against the just-written `metadata.json` and `provenance-map.json` and reads back `missing[]` / `orphaned[]` / `stale[]` findings. Do not attempt the set comparison here — there is no provenance map to compare against yet. The `Provenance` row in §5's summary is populated from §6a's result.
|
|
72
|
-
|
|
73
|
-
**Check E — Diff Comparison (via skill-check):**
|
|
74
|
-
|
|
75
|
-
**If available** and previous skill version exists: `npx skill-check diff <original-skill-dir> <updated-skill-dir>`
|
|
76
|
-
|
|
77
|
-
Shows diagnostic changes between original and updated skill. Record diff results as informational context.
|
|
78
|
-
|
|
79
|
-
**If unavailable or no previous version:** Skip with note.
|
|
80
|
-
|
|
81
|
-
**Check F — Security Scan:**
|
|
82
|
-
|
|
83
|
-
**If available**, run: `npx skill-check check <skill-dir> --format json` (security scan enabled by default).
|
|
84
|
-
|
|
85
|
-
Record security findings as advisory warnings — they do not block the update.
|
|
86
|
-
|
|
87
|
-
**If unavailable:** Skip with note: "Security scan skipped — skill-check tool unavailable"
|
|
88
|
-
|
|
89
|
-
### 3. Aggregate Validation Results
|
|
90
|
-
|
|
91
|
-
Compile results from all checks:
|
|
92
|
-
|
|
93
|
-
```
|
|
94
|
-
Validation Results:
|
|
95
|
-
spec_compliance: {status: PASS|WARN|FAIL, findings: [{severity, description, location}]}
|
|
96
|
-
manual_integrity: {status, sections_verified, sections_intact, findings}
|
|
97
|
-
confidence_consistency: {status, exports_checked, findings}
|
|
98
|
-
provenance_completeness: {status, entries_checked, findings}
|
|
99
|
-
diff_comparison: {status: PASS|SKIP, new_issues, fixed_issues, unchanged}
|
|
100
|
-
security_scan: {status: PASS|WARN|SKIP, findings}
|
|
101
|
-
quality_score: [0-100] # from skill-check, if available
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### 5. Display Validation Summary
|
|
105
|
-
|
|
106
|
-
"**Validation Results:**
|
|
107
|
-
|
|
108
|
-
| Check | Status | Findings |
|
|
109
|
-
|-------|--------|----------|
|
|
110
|
-
| Spec Compliance | {PASS/WARN/FAIL} | {count} findings (quality score: {score}/100) |
|
|
111
|
-
| [MANUAL] Integrity | {PASS/WARN/FAIL} | {count} findings |
|
|
112
|
-
| Confidence Tiers | {PASS/WARN/FAIL} | {count} findings |
|
|
113
|
-
| Provenance | {PASS/WARN/FAIL} | {count} findings |
|
|
114
|
-
| Diff Comparison | {PASS/SKIP} | {new} new, {fixed} fixed |
|
|
115
|
-
| Security Scan | {PASS/WARN/SKIP} | {count} findings |
|
|
116
|
-
|
|
117
|
-
**Overall: {ALL_PASS / WARNINGS_FOUND / FAILURES_FOUND}**"
|
|
118
|
-
|
|
119
|
-
**If findings exist:** List each with severity, description, and location. Add: "Validation is advisory. Findings do not block the update."
|
|
120
|
-
|
|
121
|
-
### 6. Route to Next Step
|
|
122
|
-
|
|
123
|
-
This step auto-proceeds — no user choices; validation is advisory and does not block, it only informs. Once all validation checks have completed and findings are displayed, display "**Proceeding to write updated files...**", then load, fully read, and execute `{nextStepFile}` to write the updated files.
|
|
124
|
-
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Documentation Drift Validator
|
|
3
|
-
*
|
|
4
|
-
* Verifies that SKF docs agree with the canonical oh-my-skills output on
|
|
5
|
-
* every version number, commit SHA, and library reference the docs cite.
|
|
6
|
-
*
|
|
7
|
-
* What it checks:
|
|
8
|
-
* - The anchor `skf_version` matches `package.json.version` (self-reference invariant
|
|
9
|
-
* declared in pinned.yaml's header; enforced here at CI/pre-commit time AND bumped
|
|
10
|
-
* by release.yaml on every release)
|
|
11
|
-
* - Every skill listed in `docs/_data/pinned.yaml` actually exists at the
|
|
12
|
-
* claimed version and commit in $OMS/skills/<name>/<version>/<name>/metadata.json
|
|
13
|
-
* - The metadata.json `version` field matches the anchor `version`
|
|
14
|
-
* - The metadata.json `source_commit` field matches the anchor `source_commit`
|
|
15
|
-
* - Every `.md` file under `docs/` is grepped for `<library> v?<x.y.z>` strings;
|
|
16
|
-
* any that don't match the currently-pinned version for that library are flagged
|
|
17
|
-
* - Known illustrative libraries (hono, drizzle-orm, ...) are whitelisted and
|
|
18
|
-
* allowed to carry any version number
|
|
19
|
-
*
|
|
20
|
-
* Usage:
|
|
21
|
-
* node tools/validate-docs-drift.js # validate, exit 1 on drift
|
|
22
|
-
* OMS=/path/to/oh-my-skills node tools/validate-docs-drift.js
|
|
23
|
-
*
|
|
24
|
-
* Exit codes:
|
|
25
|
-
* 0 — no drift detected
|
|
26
|
-
* 1 — drift found; fix the docs or update docs/_data/pinned.yaml
|
|
27
|
-
* 2 — infrastructure failure (anchors file missing, oh-my-skills path
|
|
28
|
-
* unreachable, yaml parse error)
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
const fs = require('node:fs');
|
|
32
|
-
const path = require('node:path');
|
|
33
|
-
const yaml = require('js-yaml');
|
|
34
|
-
|
|
35
|
-
const SKF_ROOT = path.resolve(__dirname, '..');
|
|
36
|
-
const DOCS_DIR = path.join(SKF_ROOT, 'docs');
|
|
37
|
-
const ANCHORS_PATH = path.join(DOCS_DIR, '_data', 'pinned.yaml');
|
|
38
|
-
const PACKAGE_JSON_PATH = path.join(SKF_ROOT, 'package.json');
|
|
39
|
-
|
|
40
|
-
function loadAnchors() {
|
|
41
|
-
if (!fs.existsSync(ANCHORS_PATH)) {
|
|
42
|
-
console.error(`error: anchors file not found at ${ANCHORS_PATH}`);
|
|
43
|
-
process.exit(2);
|
|
44
|
-
}
|
|
45
|
-
try {
|
|
46
|
-
return yaml.load(fs.readFileSync(ANCHORS_PATH, 'utf8'));
|
|
47
|
-
} catch (error) {
|
|
48
|
-
console.error(`error: could not parse ${ANCHORS_PATH}: ${error.message}`);
|
|
49
|
-
process.exit(2);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function checkSkfVersionAgainstPackageJson(anchors) {
|
|
54
|
-
const errors = [];
|
|
55
|
-
if (!fs.existsSync(PACKAGE_JSON_PATH)) {
|
|
56
|
-
errors.push(`CRITICAL: package.json not found at ${PACKAGE_JSON_PATH}`);
|
|
57
|
-
return errors;
|
|
58
|
-
}
|
|
59
|
-
let pkg;
|
|
60
|
-
try {
|
|
61
|
-
pkg = JSON.parse(fs.readFileSync(PACKAGE_JSON_PATH, 'utf8'));
|
|
62
|
-
} catch (error) {
|
|
63
|
-
errors.push(`CRITICAL: could not parse ${PACKAGE_JSON_PATH}: ${error.message}`);
|
|
64
|
-
return errors;
|
|
65
|
-
}
|
|
66
|
-
const anchorVersion = anchors.skf_version;
|
|
67
|
-
const packageVersion = pkg.version;
|
|
68
|
-
if (!anchorVersion) {
|
|
69
|
-
errors.push(`MISSING_ANCHOR: pinned.yaml has no skf_version key`);
|
|
70
|
-
return errors;
|
|
71
|
-
}
|
|
72
|
-
if (!packageVersion) {
|
|
73
|
-
errors.push(`MISSING_PKG_VERSION: package.json has no version field`);
|
|
74
|
-
return errors;
|
|
75
|
-
}
|
|
76
|
-
if (anchorVersion !== packageVersion) {
|
|
77
|
-
errors.push(
|
|
78
|
-
`SKF_VERSION_DRIFT: pinned.yaml skf_version "${anchorVersion}" !== package.json version "${packageVersion}" ` +
|
|
79
|
-
`— bump pinned.yaml or check that release.yaml's "Update pinned.yaml skf_version" step fired`,
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
return errors;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function resolveOmsPath(anchors) {
|
|
86
|
-
if (process.env.OMS) {
|
|
87
|
-
return path.resolve(process.env.OMS);
|
|
88
|
-
}
|
|
89
|
-
return path.resolve(SKF_ROOT, anchors.oh_my_skills_path);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Accept either a full SHA match or a short-SHA prefix match, per
|
|
93
|
-
// src/skf-update-skill/references/re-extract.md:36 — the pinned commit
|
|
94
|
-
// is often stored as an 8-char short hash. Both anchors and metadata are
|
|
95
|
-
// lowercased before comparison; blank / null values never match.
|
|
96
|
-
function commitsMatch(anchorCommit, metadataCommit) {
|
|
97
|
-
if (!anchorCommit || !metadataCommit) return false;
|
|
98
|
-
const a = String(anchorCommit).toLowerCase();
|
|
99
|
-
const b = String(metadataCommit).toLowerCase();
|
|
100
|
-
return a === b || a.startsWith(b) || b.startsWith(a);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function checkCanonicalFiles(anchors, omsPath) {
|
|
104
|
-
const errors = [];
|
|
105
|
-
if (!fs.existsSync(omsPath) || !fs.statSync(omsPath).isDirectory()) {
|
|
106
|
-
errors.push(
|
|
107
|
-
`CRITICAL: oh_my_skills_path does not resolve to a directory: ${omsPath}`,
|
|
108
|
-
` hint: set OMS=/path/to/oh-my-skills or edit docs/_data/pinned.yaml`,
|
|
109
|
-
);
|
|
110
|
-
return errors;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
for (const [skillName, spec] of Object.entries(anchors.skills)) {
|
|
114
|
-
const metadataPath = path.join(omsPath, 'skills', skillName, spec.version, skillName, 'metadata.json');
|
|
115
|
-
|
|
116
|
-
if (!fs.existsSync(metadataPath)) {
|
|
117
|
-
errors.push(`MISSING: ${skillName}@${spec.version} — expected ${metadataPath}`);
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
let metadata;
|
|
122
|
-
try {
|
|
123
|
-
metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
|
|
124
|
-
} catch (error) {
|
|
125
|
-
errors.push(`UNPARSEABLE: ${metadataPath} — ${error.message}`);
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (metadata.version !== spec.version) {
|
|
130
|
-
errors.push(`VERSION_DRIFT: ${skillName} — anchors say ${spec.version}, ` + `metadata.json says ${metadata.version}`);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (!commitsMatch(spec.source_commit, metadata.source_commit)) {
|
|
134
|
-
const anchorShort = (spec.source_commit || '').slice(0, 12);
|
|
135
|
-
const realShort = (metadata.source_commit || '').slice(0, 12);
|
|
136
|
-
errors.push(`COMMIT_DRIFT: ${skillName} — anchors say ${anchorShort}, ` + `metadata.json says ${realShort}`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (metadata.confidence_tier !== spec.confidence_tier) {
|
|
140
|
-
errors.push(`TIER_DRIFT: ${skillName} — anchors say ${spec.confidence_tier}, ` + `metadata.json says ${metadata.confidence_tier}`);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (metadata.source_authority !== spec.source_authority) {
|
|
144
|
-
errors.push(
|
|
145
|
-
`AUTHORITY_DRIFT: ${skillName} — anchors say ${spec.source_authority}, ` + `metadata.json says ${metadata.source_authority}`,
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return errors;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function getMarkdownFiles(dir) {
|
|
154
|
-
const files = [];
|
|
155
|
-
function walk(currentDir) {
|
|
156
|
-
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
157
|
-
for (const entry of entries) {
|
|
158
|
-
if (entry.name.startsWith('_')) continue;
|
|
159
|
-
const fullPath = path.join(currentDir, entry.name);
|
|
160
|
-
if (entry.isDirectory()) {
|
|
161
|
-
walk(fullPath);
|
|
162
|
-
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
163
|
-
files.push(fullPath);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
walk(dir);
|
|
168
|
-
return files;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function checkDocsForStaleVersions(anchors) {
|
|
172
|
-
const errors = [];
|
|
173
|
-
|
|
174
|
-
// Build map: library-name → current-version
|
|
175
|
-
const libVersions = Object.fromEntries(Object.values(anchors.skills).map((spec) => [spec.library, spec.version]));
|
|
176
|
-
const libs = Object.keys(libVersions);
|
|
177
|
-
if (libs.length === 0) return errors;
|
|
178
|
-
|
|
179
|
-
const illustrative = new Set(anchors.illustrative_libraries || []);
|
|
180
|
-
|
|
181
|
-
// Pattern: <library-name><whitespace or @>v?<semver>
|
|
182
|
-
// Word-boundary anchored to avoid partial matches inside other words.
|
|
183
|
-
const libPattern = String.raw`\b(` + libs.map((l) => l.replaceAll(/[.*+?^${}()|[\\]\\\\]/g, String.raw`\\$&`)).join('|') + ')';
|
|
184
|
-
const versionPattern = String.raw`[\s@]+v?(\d+\.\d+\.\d+)`;
|
|
185
|
-
const regex = new RegExp(libPattern + versionPattern, 'gi');
|
|
186
|
-
|
|
187
|
-
for (const mdFile of getMarkdownFiles(DOCS_DIR)) {
|
|
188
|
-
const content = fs.readFileSync(mdFile, 'utf8');
|
|
189
|
-
const lines = content.split('\n');
|
|
190
|
-
for (const [idx, line] of lines.entries()) {
|
|
191
|
-
for (const match of line.matchAll(regex)) {
|
|
192
|
-
const lib = match[1].toLowerCase();
|
|
193
|
-
if (illustrative.has(lib)) continue;
|
|
194
|
-
const found = match[2];
|
|
195
|
-
const expected = libVersions[lib];
|
|
196
|
-
if (expected && found !== expected) {
|
|
197
|
-
const relPath = path.relative(SKF_ROOT, mdFile);
|
|
198
|
-
errors.push(`STALE_VERSION: ${relPath}:${idx + 1} — ${lib} v${found} (expected v${expected})`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return errors;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function main() {
|
|
208
|
-
const anchors = loadAnchors();
|
|
209
|
-
const omsPath = resolveOmsPath(anchors);
|
|
210
|
-
|
|
211
|
-
const errors = [
|
|
212
|
-
...checkSkfVersionAgainstPackageJson(anchors),
|
|
213
|
-
...checkCanonicalFiles(anchors, omsPath),
|
|
214
|
-
...checkDocsForStaleVersions(anchors),
|
|
215
|
-
];
|
|
216
|
-
|
|
217
|
-
if (errors.length > 0) {
|
|
218
|
-
console.error('DRIFT DETECTED:\n');
|
|
219
|
-
for (const err of errors) {
|
|
220
|
-
console.error(` - ${err}`);
|
|
221
|
-
}
|
|
222
|
-
console.error(`\n${errors.length} drift finding(s). Fix the docs or update docs/_data/pinned.yaml.`);
|
|
223
|
-
console.error('\nAnchors file: docs/_data/pinned.yaml');
|
|
224
|
-
console.error(`Checked against: ${omsPath}`);
|
|
225
|
-
process.exit(1);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const skillCount = Object.keys(anchors.skills).length;
|
|
229
|
-
console.log(`OK: skf_version ${anchors.skf_version} matches package.json; ${skillCount} skills checked against ${omsPath}, no drift.`);
|
|
230
|
-
process.exit(0);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
main();
|