bmad-module-skill-forge 2.2.0 → 4.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 +143 -18
- package/docs/verifying-a-skill.md +87 -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 +3 -3
- 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 +31 -59
- 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 +233 -64
- package/src/shared/scripts/skf-build-change-manifest.py +2753 -28
- 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 +772 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +267 -105
- 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 +21 -3
- 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 +197 -55
- 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 +5247 -96
- package/src/shared/scripts/skf-extraction-inventory.py +1280 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +664 -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 +469 -205
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +700 -0
- package/src/shared/scripts/skf-hash-content.py +180 -20
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +161 -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 +143 -20
- 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 +176 -28
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +64 -8
- 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 +155 -14
- 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 +787 -121
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +120 -67
- 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 +23 -2
- 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 +3945 -152
- package/src/shared/scripts/skf-write-skill-brief.py +406 -25
- 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 +28 -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/health-check.md +2 -0
- package/src/skf-audit-skill/references/init.md +149 -210
- package/src/skf-audit-skill/references/re-index.md +103 -110
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +34 -25
- 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 +80 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +712 -0
- package/src/skf-brief-skill/SKILL.md +37 -26
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +18 -25
- package/src/skf-brief-skill/assets/skill-brief-schema.md +30 -23
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +144 -127
- package/src/skf-brief-skill/references/confirm-brief.md +11 -9
- 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 +26 -100
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +7 -10
- 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 +11 -8
- package/src/skf-create-skill/assets/skill-sections.md +21 -11
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +36 -58
- 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 +119 -70
- 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 +37 -0
- package/src/skf-create-skill/references/extract.md +204 -162
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +11 -11
- package/src/skf-create-skill/references/extraction-patterns.md +588 -201
- 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 +37 -57
- package/src/skf-create-skill/references/source-resolution-protocols.md +58 -169
- 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 +83 -146
- package/src/skf-drop-skill/references/health-check.md +2 -0
- 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 +122 -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 +209 -264
- 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 +164 -91
- 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 +164 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +42 -155
- package/src/skf-test-skill/references/source-access-protocol.md +18 -94
- 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 +380 -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 +1666 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +1198 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +547 -79
- package/src/skf-test-skill/scripts/score-signatures.py +479 -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 +133 -56
- 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 +253 -223
- 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 +254 -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 +182 -49
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +102 -35
- package/src/skf-update-skill/references/write.md +357 -155
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +183 -46
- 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,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,41 @@ 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
|
|
|
52
|
+
import datetime
|
|
26
53
|
import json
|
|
54
|
+
import re
|
|
55
|
+
import stat
|
|
27
56
|
import sys
|
|
28
57
|
from pathlib import Path
|
|
29
58
|
|
|
@@ -39,20 +68,111 @@ except ImportError:
|
|
|
39
68
|
sys.exit(1)
|
|
40
69
|
|
|
41
70
|
|
|
71
|
+
# skf-setup halts on a missing config.yaml and never writes one: only the
|
|
72
|
+
# installer does. Ferris's config guard and skf-setup's
|
|
73
|
+
# on-activation:config-missing reason name the same two commands.
|
|
74
|
+
INSTALL_REMEDY = (
|
|
75
|
+
"From the project root, run npx bmad-module-skill-forge install "
|
|
76
|
+
"(or npx bmad-method install and add SKF), then run the skf-setup skill."
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# The BMAD Method installer writes folder values as `{project-root}/<value>`
|
|
80
|
+
# (module.yaml's `result`). Only a whole leading segment is the placeholder.
|
|
81
|
+
PROJECT_ROOT_RE = re.compile(r"\A\{project-root\}(?:[/\\]+|\Z)")
|
|
82
|
+
PLACEHOLDER_RE = re.compile(r"\{[^{}]*\}")
|
|
83
|
+
FOLDER_KEYS = ("output_folder", "skills_output_folder", "forge_data_folder")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _json_default(value):
|
|
87
|
+
"""Print a date or time as ISO 8601.
|
|
88
|
+
|
|
89
|
+
YAML reads an unquoted timestamp as a date or datetime object. SKF 1.x
|
|
90
|
+
wrote ``tier_detected_at`` and ``ccc_index.last_indexed`` in
|
|
91
|
+
forge-tier.yaml unquoted, so a sidecar from before 2.0.0 holds them; any
|
|
92
|
+
other value json cannot print is still an error.
|
|
93
|
+
"""
|
|
94
|
+
if isinstance(value, (datetime.date, datetime.time)):
|
|
95
|
+
return value.isoformat()
|
|
96
|
+
raise TypeError(f"Object of type {type(value).__name__} is not JSON serializable")
|
|
97
|
+
|
|
98
|
+
|
|
42
99
|
def load_yaml_file(path):
|
|
43
|
-
"""Load a YAML
|
|
100
|
+
"""Load a YAML mapping, returning (data, None) or (None, error_string).
|
|
101
|
+
|
|
102
|
+
An empty file reads as an empty mapping. A file that is not there raises
|
|
103
|
+
FileNotFoundError, which each caller reads its own way: CONFIG_MISSING
|
|
104
|
+
for config.yaml, empty defaults for a sidecar file. Every file this
|
|
105
|
+
script loads is a mapping of keys, so a file that is there but cannot be
|
|
106
|
+
read, or whose top level is a list or a scalar, is an error instead of a
|
|
107
|
+
crash.
|
|
108
|
+
"""
|
|
44
109
|
try:
|
|
45
110
|
with open(path, encoding="utf-8") as f:
|
|
46
111
|
data = yaml.safe_load(f)
|
|
47
|
-
return data or {}, None
|
|
48
112
|
except FileNotFoundError:
|
|
49
|
-
|
|
113
|
+
raise
|
|
50
114
|
except yaml.YAMLError as e:
|
|
51
115
|
return None, f"YAML parse error in {path}: {e}"
|
|
116
|
+
except (OSError, ValueError) as e:
|
|
117
|
+
# A folder named like the file, a parent folder that cannot be
|
|
118
|
+
# searched, no read permission, or bytes that are not UTF-8.
|
|
119
|
+
return None, f"Cannot read {path}: {e}"
|
|
120
|
+
if data is None:
|
|
121
|
+
return {}, None
|
|
122
|
+
if not isinstance(data, dict):
|
|
123
|
+
return None, f"Not a YAML mapping: {path} holds a {type(data).__name__}"
|
|
124
|
+
return data, None
|
|
52
125
|
|
|
53
126
|
|
|
54
|
-
def
|
|
55
|
-
"""
|
|
127
|
+
def load_sidecar_file(path):
|
|
128
|
+
"""Load a sidecar file. One that is not there yet reads as {}."""
|
|
129
|
+
try:
|
|
130
|
+
return load_yaml_file(path)
|
|
131
|
+
except FileNotFoundError:
|
|
132
|
+
return {}, None
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def resolve_folder(value, project_root):
|
|
136
|
+
"""Return (absolute path, placeholder) for a folder value from config.yaml.
|
|
137
|
+
|
|
138
|
+
A leading `{project-root}` segment becomes the project root, and a
|
|
139
|
+
relative path is joined to it. `placeholder` is the first `{...}` token
|
|
140
|
+
left after that, or None. An empty value gives ("", None).
|
|
141
|
+
"""
|
|
142
|
+
if not value:
|
|
143
|
+
return "", None
|
|
144
|
+
value = str(value)
|
|
145
|
+
anchored = PROJECT_ROOT_RE.match(value)
|
|
146
|
+
rest = value[anchored.end():] if anchored else value
|
|
147
|
+
placeholder = PLACEHOLDER_RE.search(rest)
|
|
148
|
+
path = Path(rest)
|
|
149
|
+
if not path.is_absolute():
|
|
150
|
+
path = project_root / path
|
|
151
|
+
return str(path), placeholder.group(0) if placeholder else None
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def folder_missing(path):
|
|
155
|
+
"""True when no folder is at `path`.
|
|
156
|
+
|
|
157
|
+
A folder that cannot be checked, such as one under a parent folder that
|
|
158
|
+
cannot be searched, counts as there, so the reads that follow report why
|
|
159
|
+
its files did not load. Path.is_dir() raises for that on Python 3.12 and
|
|
160
|
+
returns False on 3.14.
|
|
161
|
+
"""
|
|
162
|
+
try:
|
|
163
|
+
return not stat.S_ISDIR(path.stat().st_mode)
|
|
164
|
+
except (FileNotFoundError, NotADirectoryError):
|
|
165
|
+
return True
|
|
166
|
+
except (OSError, ValueError):
|
|
167
|
+
return False
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def run_preflight(project_root, config_path=None, allow_missing_sidecar=False):
|
|
171
|
+
"""Run preflight checks and return a result dict.
|
|
172
|
+
|
|
173
|
+
`allow_missing_sidecar` turns a missing sidecar folder into empty
|
|
174
|
+
defaults instead of the SIDECAR_MISSING halt.
|
|
175
|
+
"""
|
|
56
176
|
project_root = Path(project_root).resolve()
|
|
57
177
|
|
|
58
178
|
# 1. Load config.yaml
|
|
@@ -61,13 +181,25 @@ def run_preflight(project_root, config_path=None):
|
|
|
61
181
|
else:
|
|
62
182
|
cfg_path = project_root / "_bmad" / "skf" / "config.yaml"
|
|
63
183
|
|
|
64
|
-
|
|
65
|
-
|
|
184
|
+
try:
|
|
185
|
+
config, err = load_yaml_file(cfg_path)
|
|
186
|
+
except FileNotFoundError:
|
|
66
187
|
return {
|
|
67
188
|
"status": "hard-halt",
|
|
68
|
-
"error": f"Cannot initialize. SKF
|
|
189
|
+
"error": f"Cannot initialize. SKF is not installed in this project ({cfg_path} not found). {INSTALL_REMEDY}",
|
|
69
190
|
"code": "CONFIG_MISSING",
|
|
70
191
|
}
|
|
192
|
+
if err:
|
|
193
|
+
# An update install restores an existing config.yaml as it is, so
|
|
194
|
+
# this error names the file to repair instead of the installer.
|
|
195
|
+
return {
|
|
196
|
+
"status": "hard-halt",
|
|
197
|
+
"error": (
|
|
198
|
+
f"Cannot initialize. {' '.join(err.split())}. "
|
|
199
|
+
"Repair the file, or restore it from version control, and retry."
|
|
200
|
+
),
|
|
201
|
+
"code": "CONFIG_MALFORMED",
|
|
202
|
+
}
|
|
71
203
|
|
|
72
204
|
# 2. Resolve config variables
|
|
73
205
|
resolved = {
|
|
@@ -82,26 +214,30 @@ def run_preflight(project_root, config_path=None):
|
|
|
82
214
|
"skills_output_folder": config.get("skills_output_folder", ""),
|
|
83
215
|
"forge_data_folder": config.get("forge_data_folder", ""),
|
|
84
216
|
}
|
|
217
|
+
for key in FOLDER_KEYS:
|
|
218
|
+
resolved[f"{key}_resolved"] = resolve_folder(resolved[key], project_root)[0]
|
|
85
219
|
|
|
86
|
-
# 3. Validate sidecar_path
|
|
87
|
-
|
|
88
|
-
|
|
220
|
+
# 3. Validate sidecar_path, before the folder check, so that
|
|
221
|
+
# --allow-missing-sidecar never reads an unresolved path as a first run.
|
|
222
|
+
# The advice is the standalone installer's relative value: unquoted, a
|
|
223
|
+
# value that starts with {project-root} would be a YAML flow mapping.
|
|
224
|
+
sidecar_path, placeholder = resolve_folder(resolved["sidecar_path"], project_root)
|
|
225
|
+
if not sidecar_path or placeholder:
|
|
226
|
+
found = f"holds the placeholder {placeholder}" if placeholder else "is not defined"
|
|
89
227
|
return {
|
|
90
228
|
"status": "hard-halt",
|
|
91
229
|
"error": (
|
|
92
|
-
"Cannot initialize. sidecar_path
|
|
93
|
-
|
|
94
|
-
"
|
|
230
|
+
f"Cannot initialize. sidecar_path {found} in {cfg_path}. "
|
|
231
|
+
"Set sidecar_path to _bmad/_memory/forger-sidecar, a path from the project root, and retry. "
|
|
232
|
+
"This is a known installer issue with prompt: false config variables."
|
|
95
233
|
),
|
|
96
234
|
"code": "SIDECAR_UNDEFINED",
|
|
97
235
|
"config": resolved,
|
|
98
236
|
}
|
|
99
237
|
|
|
100
238
|
sidecar_dir = Path(sidecar_path)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if not sidecar_dir.is_dir():
|
|
239
|
+
sidecar_missing = folder_missing(sidecar_dir)
|
|
240
|
+
if sidecar_missing and not allow_missing_sidecar:
|
|
105
241
|
return {
|
|
106
242
|
"status": "hard-halt",
|
|
107
243
|
"error": f"Sidecar directory not found: {sidecar_dir}. Run skf-setup to initialize.",
|
|
@@ -111,11 +247,15 @@ def run_preflight(project_root, config_path=None):
|
|
|
111
247
|
|
|
112
248
|
resolved["sidecar_path_resolved"] = str(sidecar_dir)
|
|
113
249
|
|
|
114
|
-
# 4. Load sidecar files
|
|
115
|
-
|
|
250
|
+
# 4. Load sidecar files. A missing folder (allowed above) or a file not
|
|
251
|
+
# written yet reads as empty defaults with no error: the installer writes
|
|
252
|
+
# preferences.yaml, and skf-setup creates the folder and forge-tier.yaml
|
|
253
|
+
# on its first run. An `*_error` field is left for a file that is there
|
|
254
|
+
# but did not load.
|
|
255
|
+
sidecar = {"missing": sidecar_missing}
|
|
116
256
|
|
|
117
257
|
prefs_path = sidecar_dir / "preferences.yaml"
|
|
118
|
-
prefs, prefs_err =
|
|
258
|
+
prefs, prefs_err = ({}, None) if sidecar_missing else load_sidecar_file(prefs_path)
|
|
119
259
|
if prefs_err:
|
|
120
260
|
sidecar["preferences"] = None
|
|
121
261
|
sidecar["preferences_error"] = prefs_err
|
|
@@ -123,7 +263,7 @@ def run_preflight(project_root, config_path=None):
|
|
|
123
263
|
sidecar["preferences"] = prefs
|
|
124
264
|
|
|
125
265
|
tier_path = sidecar_dir / "forge-tier.yaml"
|
|
126
|
-
tier, tier_err =
|
|
266
|
+
tier, tier_err = ({}, None) if sidecar_missing else load_sidecar_file(tier_path)
|
|
127
267
|
if tier_err:
|
|
128
268
|
sidecar["forge_tier"] = None
|
|
129
269
|
sidecar["forge_tier_error"] = tier_err
|
|
@@ -139,6 +279,10 @@ def run_preflight(project_root, config_path=None):
|
|
|
139
279
|
if prefs:
|
|
140
280
|
compact_greeting = prefs.get("compact_greeting", False) is True
|
|
141
281
|
|
|
282
|
+
headless_mode = False
|
|
283
|
+
if prefs:
|
|
284
|
+
headless_mode = prefs.get("headless_mode", False) is True
|
|
285
|
+
|
|
142
286
|
tier_override = None
|
|
143
287
|
if prefs:
|
|
144
288
|
tier_override = prefs.get("tier_override")
|
|
@@ -151,14 +295,18 @@ def run_preflight(project_root, config_path=None):
|
|
|
151
295
|
"tier": tier_override or tier_value,
|
|
152
296
|
"tier_source": "override" if tier_override else ("detected" if tier_value else None),
|
|
153
297
|
"compact_greeting": compact_greeting,
|
|
298
|
+
"headless_mode": headless_mode,
|
|
154
299
|
"is_first_run": tier_value is None,
|
|
155
300
|
},
|
|
156
301
|
}
|
|
157
302
|
|
|
158
303
|
|
|
304
|
+
USAGE = "Usage: uv run skf-preflight.py <project-root> [--config-path <path>] [--allow-missing-sidecar]"
|
|
305
|
+
|
|
306
|
+
|
|
159
307
|
if __name__ == "__main__":
|
|
160
|
-
if len(sys.argv) < 2:
|
|
161
|
-
print(
|
|
308
|
+
if len(sys.argv) < 2 or sys.argv[1].startswith("--"):
|
|
309
|
+
print(USAGE, file=sys.stderr)
|
|
162
310
|
sys.exit(1)
|
|
163
311
|
|
|
164
312
|
proj_root = sys.argv[1]
|
|
@@ -169,6 +317,6 @@ if __name__ == "__main__":
|
|
|
169
317
|
if idx + 1 < len(sys.argv):
|
|
170
318
|
cfg_path = sys.argv[idx + 1]
|
|
171
319
|
|
|
172
|
-
result = run_preflight(proj_root, cfg_path)
|
|
173
|
-
print(json.dumps(result, indent=2))
|
|
320
|
+
result = run_preflight(proj_root, cfg_path, allow_missing_sidecar="--allow-missing-sidecar" in sys.argv)
|
|
321
|
+
print(json.dumps(result, indent=2, default=_json_default))
|
|
174
322
|
sys.exit(1 if result["status"] == "hard-halt" else 0)
|