bmad-module-skill-forge 2.1.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 +51 -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 +14 -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 +117 -9
- package/src/shared/scripts/skf-detect-docs.py +892 -4
- 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 +215 -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 +17 -6
- 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 +55 -18
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -57
- 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 -89
- package/src/skf-setup/references/detect-and-tier.md +58 -66
- 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 -645
- 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,11 +1,13 @@
|
|
|
1
1
|
# /// script
|
|
2
|
-
# requires-python = ">=3.
|
|
2
|
+
# requires-python = ">=3.11"
|
|
3
3
|
# dependencies = ["pyyaml"]
|
|
4
4
|
# ///
|
|
5
5
|
"""SKF Preflight — Config and sidecar loader for all SKF skills.
|
|
6
6
|
|
|
7
7
|
Loads config.yaml, validates sidecar_path, loads preferences.yaml and
|
|
8
8
|
forge-tier.yaml, and outputs a unified JSON blob for step consumption.
|
|
9
|
+
Ferris (skf-forger) runs it at activation and again for WS, with
|
|
10
|
+
--allow-missing-sidecar.
|
|
9
11
|
|
|
10
12
|
CLI — invoke via `uv run` so the PEP 723 PyYAML dependency declared
|
|
11
13
|
above is auto-resolved on first call and cached. `docs/getting-started.md`
|
|
@@ -16,14 +18,40 @@ on stdout — that fallback is the safety net, not the canonical path:
|
|
|
16
18
|
|
|
17
19
|
uv run skf-preflight.py <project-root>
|
|
18
20
|
uv run skf-preflight.py <project-root> --config-path <alt-config>
|
|
21
|
+
uv run skf-preflight.py <project-root> --allow-missing-sidecar
|
|
22
|
+
|
|
23
|
+
--allow-missing-sidecar: a sidecar folder that does not exist yet (a first
|
|
24
|
+
run, before skf-setup writes it) is not a halt. The run goes on with empty
|
|
25
|
+
preferences and forge tier, and `sidecar.missing` is true.
|
|
26
|
+
|
|
27
|
+
Folder values: the BMAD Method installer writes each folder in config.yaml
|
|
28
|
+
as `{project-root}/<value>`, and the standalone installer writes it relative
|
|
29
|
+
to the project root. `config` keeps each raw value and adds its absolute
|
|
30
|
+
path: `output_folder_resolved`, `skills_output_folder_resolved`,
|
|
31
|
+
`forge_data_folder_resolved` ("" for an empty value) and
|
|
32
|
+
`sidecar_path_resolved`. A sidecar_path that still holds a placeholder once
|
|
33
|
+
`{project-root}` is expanded, such as `{sidecar_path}` or the `{value}` of
|
|
34
|
+
`{project-root}/{value}`, halts with SIDECAR_UNDEFINED, flag or not.
|
|
19
35
|
|
|
20
36
|
Output: JSON to stdout with all resolved config variables and sidecar state.
|
|
21
|
-
|
|
37
|
+
`sidecar.preferences` and `sidecar.forge_tier` are {} for a file that is
|
|
38
|
+
not there yet, and `sidecar.preferences_error` or
|
|
39
|
+
`sidecar.forge_tier_error` appears only for a file that is there but did not
|
|
40
|
+
load. `derived` holds what a greeting needs: `tier`, `tier_source`,
|
|
41
|
+
`compact_greeting`, `headless_mode` (true only for `headless_mode: true` in
|
|
42
|
+
preferences.yaml) and `is_first_run`.
|
|
43
|
+
Exit 0 on success, exit 1 on a hard halt, whose `code` is CONFIG_MISSING
|
|
44
|
+
(no config.yaml: SKF is not installed, so the error names the installer),
|
|
45
|
+
CONFIG_MALFORMED (config.yaml is there but cannot be read or is not a YAML
|
|
46
|
+
mapping), SIDECAR_UNDEFINED or, without --allow-missing-sidecar,
|
|
47
|
+
SIDECAR_MISSING.
|
|
22
48
|
"""
|
|
23
49
|
|
|
24
50
|
from __future__ import annotations
|
|
25
51
|
|
|
26
52
|
import json
|
|
53
|
+
import re
|
|
54
|
+
import stat
|
|
27
55
|
import sys
|
|
28
56
|
from pathlib import Path
|
|
29
57
|
|
|
@@ -39,20 +67,98 @@ except ImportError:
|
|
|
39
67
|
sys.exit(1)
|
|
40
68
|
|
|
41
69
|
|
|
70
|
+
# skf-setup halts on a missing config.yaml and never writes one: only the
|
|
71
|
+
# installer does. Ferris's config guard and skf-setup's
|
|
72
|
+
# on-activation:config-missing reason name the same two commands.
|
|
73
|
+
INSTALL_REMEDY = (
|
|
74
|
+
"From the project root, run npx bmad-module-skill-forge install "
|
|
75
|
+
"(or npx bmad-method install and add SKF), then run the skf-setup skill."
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# The BMAD Method installer writes folder values as `{project-root}/<value>`
|
|
79
|
+
# (module.yaml's `result`). Only a whole leading segment is the placeholder.
|
|
80
|
+
PROJECT_ROOT_RE = re.compile(r"\A\{project-root\}(?:[/\\]+|\Z)")
|
|
81
|
+
PLACEHOLDER_RE = re.compile(r"\{[^{}]*\}")
|
|
82
|
+
FOLDER_KEYS = ("output_folder", "skills_output_folder", "forge_data_folder")
|
|
83
|
+
|
|
84
|
+
|
|
42
85
|
def load_yaml_file(path):
|
|
43
|
-
"""Load a YAML
|
|
86
|
+
"""Load a YAML mapping, returning (data, None) or (None, error_string).
|
|
87
|
+
|
|
88
|
+
An empty file reads as an empty mapping. A file that is not there raises
|
|
89
|
+
FileNotFoundError, which each caller reads its own way: CONFIG_MISSING
|
|
90
|
+
for config.yaml, empty defaults for a sidecar file. Every file this
|
|
91
|
+
script loads is a mapping of keys, so a file that is there but cannot be
|
|
92
|
+
read, or whose top level is a list or a scalar, is an error instead of a
|
|
93
|
+
crash.
|
|
94
|
+
"""
|
|
44
95
|
try:
|
|
45
96
|
with open(path, encoding="utf-8") as f:
|
|
46
97
|
data = yaml.safe_load(f)
|
|
47
|
-
return data or {}, None
|
|
48
98
|
except FileNotFoundError:
|
|
49
|
-
|
|
99
|
+
raise
|
|
50
100
|
except yaml.YAMLError as e:
|
|
51
101
|
return None, f"YAML parse error in {path}: {e}"
|
|
102
|
+
except (OSError, ValueError) as e:
|
|
103
|
+
# A folder named like the file, a parent folder that cannot be
|
|
104
|
+
# searched, no read permission, or bytes that are not UTF-8.
|
|
105
|
+
return None, f"Cannot read {path}: {e}"
|
|
106
|
+
if data is None:
|
|
107
|
+
return {}, None
|
|
108
|
+
if not isinstance(data, dict):
|
|
109
|
+
return None, f"Not a YAML mapping: {path} holds a {type(data).__name__}"
|
|
110
|
+
return data, None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def load_sidecar_file(path):
|
|
114
|
+
"""Load a sidecar file. One that is not there yet reads as {}."""
|
|
115
|
+
try:
|
|
116
|
+
return load_yaml_file(path)
|
|
117
|
+
except FileNotFoundError:
|
|
118
|
+
return {}, None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def resolve_folder(value, project_root):
|
|
122
|
+
"""Return (absolute path, placeholder) for a folder value from config.yaml.
|
|
123
|
+
|
|
124
|
+
A leading `{project-root}` segment becomes the project root, and a
|
|
125
|
+
relative path is joined to it. `placeholder` is the first `{...}` token
|
|
126
|
+
left after that, or None. An empty value gives ("", None).
|
|
127
|
+
"""
|
|
128
|
+
if not value:
|
|
129
|
+
return "", None
|
|
130
|
+
value = str(value)
|
|
131
|
+
anchored = PROJECT_ROOT_RE.match(value)
|
|
132
|
+
rest = value[anchored.end():] if anchored else value
|
|
133
|
+
placeholder = PLACEHOLDER_RE.search(rest)
|
|
134
|
+
path = Path(rest)
|
|
135
|
+
if not path.is_absolute():
|
|
136
|
+
path = project_root / path
|
|
137
|
+
return str(path), placeholder.group(0) if placeholder else None
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def folder_missing(path):
|
|
141
|
+
"""True when no folder is at `path`.
|
|
142
|
+
|
|
143
|
+
A folder that cannot be checked, such as one under a parent folder that
|
|
144
|
+
cannot be searched, counts as there, so the reads that follow report why
|
|
145
|
+
its files did not load. Path.is_dir() raises for that on Python 3.12 and
|
|
146
|
+
returns False on 3.14.
|
|
147
|
+
"""
|
|
148
|
+
try:
|
|
149
|
+
return not stat.S_ISDIR(path.stat().st_mode)
|
|
150
|
+
except (FileNotFoundError, NotADirectoryError):
|
|
151
|
+
return True
|
|
152
|
+
except (OSError, ValueError):
|
|
153
|
+
return False
|
|
154
|
+
|
|
52
155
|
|
|
156
|
+
def run_preflight(project_root, config_path=None, allow_missing_sidecar=False):
|
|
157
|
+
"""Run preflight checks and return a result dict.
|
|
53
158
|
|
|
54
|
-
|
|
55
|
-
|
|
159
|
+
`allow_missing_sidecar` turns a missing sidecar folder into empty
|
|
160
|
+
defaults instead of the SIDECAR_MISSING halt.
|
|
161
|
+
"""
|
|
56
162
|
project_root = Path(project_root).resolve()
|
|
57
163
|
|
|
58
164
|
# 1. Load config.yaml
|
|
@@ -61,13 +167,25 @@ def run_preflight(project_root, config_path=None):
|
|
|
61
167
|
else:
|
|
62
168
|
cfg_path = project_root / "_bmad" / "skf" / "config.yaml"
|
|
63
169
|
|
|
64
|
-
|
|
65
|
-
|
|
170
|
+
try:
|
|
171
|
+
config, err = load_yaml_file(cfg_path)
|
|
172
|
+
except FileNotFoundError:
|
|
66
173
|
return {
|
|
67
174
|
"status": "hard-halt",
|
|
68
|
-
"error": f"Cannot initialize. SKF
|
|
175
|
+
"error": f"Cannot initialize. SKF is not installed in this project ({cfg_path} not found). {INSTALL_REMEDY}",
|
|
69
176
|
"code": "CONFIG_MISSING",
|
|
70
177
|
}
|
|
178
|
+
if err:
|
|
179
|
+
# An update install restores an existing config.yaml as it is, so
|
|
180
|
+
# this error names the file to repair instead of the installer.
|
|
181
|
+
return {
|
|
182
|
+
"status": "hard-halt",
|
|
183
|
+
"error": (
|
|
184
|
+
f"Cannot initialize. {' '.join(err.split())}. "
|
|
185
|
+
"Repair the file, or restore it from version control, and retry."
|
|
186
|
+
),
|
|
187
|
+
"code": "CONFIG_MALFORMED",
|
|
188
|
+
}
|
|
71
189
|
|
|
72
190
|
# 2. Resolve config variables
|
|
73
191
|
resolved = {
|
|
@@ -82,26 +200,30 @@ def run_preflight(project_root, config_path=None):
|
|
|
82
200
|
"skills_output_folder": config.get("skills_output_folder", ""),
|
|
83
201
|
"forge_data_folder": config.get("forge_data_folder", ""),
|
|
84
202
|
}
|
|
203
|
+
for key in FOLDER_KEYS:
|
|
204
|
+
resolved[f"{key}_resolved"] = resolve_folder(resolved[key], project_root)[0]
|
|
85
205
|
|
|
86
|
-
# 3. Validate sidecar_path
|
|
87
|
-
|
|
88
|
-
|
|
206
|
+
# 3. Validate sidecar_path, before the folder check, so that
|
|
207
|
+
# --allow-missing-sidecar never reads an unresolved path as a first run.
|
|
208
|
+
# The advice is the standalone installer's relative value: unquoted, a
|
|
209
|
+
# value that starts with {project-root} would be a YAML flow mapping.
|
|
210
|
+
sidecar_path, placeholder = resolve_folder(resolved["sidecar_path"], project_root)
|
|
211
|
+
if not sidecar_path or placeholder:
|
|
212
|
+
found = f"holds the placeholder {placeholder}" if placeholder else "is not defined"
|
|
89
213
|
return {
|
|
90
214
|
"status": "hard-halt",
|
|
91
215
|
"error": (
|
|
92
|
-
"Cannot initialize. sidecar_path
|
|
93
|
-
|
|
94
|
-
"
|
|
216
|
+
f"Cannot initialize. sidecar_path {found} in {cfg_path}. "
|
|
217
|
+
"Set sidecar_path to _bmad/_memory/forger-sidecar, a path from the project root, and retry. "
|
|
218
|
+
"This is a known installer issue with prompt: false config variables."
|
|
95
219
|
),
|
|
96
220
|
"code": "SIDECAR_UNDEFINED",
|
|
97
221
|
"config": resolved,
|
|
98
222
|
}
|
|
99
223
|
|
|
100
224
|
sidecar_dir = Path(sidecar_path)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if not sidecar_dir.is_dir():
|
|
225
|
+
sidecar_missing = folder_missing(sidecar_dir)
|
|
226
|
+
if sidecar_missing and not allow_missing_sidecar:
|
|
105
227
|
return {
|
|
106
228
|
"status": "hard-halt",
|
|
107
229
|
"error": f"Sidecar directory not found: {sidecar_dir}. Run skf-setup to initialize.",
|
|
@@ -111,11 +233,15 @@ def run_preflight(project_root, config_path=None):
|
|
|
111
233
|
|
|
112
234
|
resolved["sidecar_path_resolved"] = str(sidecar_dir)
|
|
113
235
|
|
|
114
|
-
# 4. Load sidecar files
|
|
115
|
-
|
|
236
|
+
# 4. Load sidecar files. A missing folder (allowed above) or a file not
|
|
237
|
+
# written yet reads as empty defaults with no error: the installer writes
|
|
238
|
+
# preferences.yaml, and skf-setup creates the folder and forge-tier.yaml
|
|
239
|
+
# on its first run. An `*_error` field is left for a file that is there
|
|
240
|
+
# but did not load.
|
|
241
|
+
sidecar = {"missing": sidecar_missing}
|
|
116
242
|
|
|
117
243
|
prefs_path = sidecar_dir / "preferences.yaml"
|
|
118
|
-
prefs, prefs_err =
|
|
244
|
+
prefs, prefs_err = ({}, None) if sidecar_missing else load_sidecar_file(prefs_path)
|
|
119
245
|
if prefs_err:
|
|
120
246
|
sidecar["preferences"] = None
|
|
121
247
|
sidecar["preferences_error"] = prefs_err
|
|
@@ -123,7 +249,7 @@ def run_preflight(project_root, config_path=None):
|
|
|
123
249
|
sidecar["preferences"] = prefs
|
|
124
250
|
|
|
125
251
|
tier_path = sidecar_dir / "forge-tier.yaml"
|
|
126
|
-
tier, tier_err =
|
|
252
|
+
tier, tier_err = ({}, None) if sidecar_missing else load_sidecar_file(tier_path)
|
|
127
253
|
if tier_err:
|
|
128
254
|
sidecar["forge_tier"] = None
|
|
129
255
|
sidecar["forge_tier_error"] = tier_err
|
|
@@ -139,6 +265,10 @@ def run_preflight(project_root, config_path=None):
|
|
|
139
265
|
if prefs:
|
|
140
266
|
compact_greeting = prefs.get("compact_greeting", False) is True
|
|
141
267
|
|
|
268
|
+
headless_mode = False
|
|
269
|
+
if prefs:
|
|
270
|
+
headless_mode = prefs.get("headless_mode", False) is True
|
|
271
|
+
|
|
142
272
|
tier_override = None
|
|
143
273
|
if prefs:
|
|
144
274
|
tier_override = prefs.get("tier_override")
|
|
@@ -151,14 +281,18 @@ def run_preflight(project_root, config_path=None):
|
|
|
151
281
|
"tier": tier_override or tier_value,
|
|
152
282
|
"tier_source": "override" if tier_override else ("detected" if tier_value else None),
|
|
153
283
|
"compact_greeting": compact_greeting,
|
|
284
|
+
"headless_mode": headless_mode,
|
|
154
285
|
"is_first_run": tier_value is None,
|
|
155
286
|
},
|
|
156
287
|
}
|
|
157
288
|
|
|
158
289
|
|
|
290
|
+
USAGE = "Usage: uv run skf-preflight.py <project-root> [--config-path <path>] [--allow-missing-sidecar]"
|
|
291
|
+
|
|
292
|
+
|
|
159
293
|
if __name__ == "__main__":
|
|
160
|
-
if len(sys.argv) < 2:
|
|
161
|
-
print(
|
|
294
|
+
if len(sys.argv) < 2 or sys.argv[1].startswith("--"):
|
|
295
|
+
print(USAGE, file=sys.stderr)
|
|
162
296
|
sys.exit(1)
|
|
163
297
|
|
|
164
298
|
proj_root = sys.argv[1]
|
|
@@ -169,6 +303,6 @@ if __name__ == "__main__":
|
|
|
169
303
|
if idx + 1 < len(sys.argv):
|
|
170
304
|
cfg_path = sys.argv[idx + 1]
|
|
171
305
|
|
|
172
|
-
result = run_preflight(proj_root, cfg_path)
|
|
306
|
+
result = run_preflight(proj_root, cfg_path, allow_missing_sidecar="--allow-missing-sidecar" in sys.argv)
|
|
173
307
|
print(json.dumps(result, indent=2))
|
|
174
308
|
sys.exit(1 if result["status"] == "hard-halt" else 0)
|