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
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.11"
|
|
4
|
+
# dependencies = []
|
|
5
|
+
# ///
|
|
6
|
+
"""Where each skill stands in the lifecycle, and the next code for it (WS).
|
|
7
|
+
|
|
8
|
+
Ferris's WS action (SKILL.md, Inline Actions) runs this once instead of
|
|
9
|
+
globbing the briefs, reading each skill's test result and working out each
|
|
10
|
+
stage and next code in the prompt. Which stage a skill reached and which code
|
|
11
|
+
comes next has one correct answer per state on disk, so it runs here.
|
|
12
|
+
|
|
13
|
+
Sources, read again on every call:
|
|
14
|
+
|
|
15
|
+
briefs {forge_data_folder}/<name>/skill-brief.yaml
|
|
16
|
+
skills skf-skill-inventory.py, the first existing of
|
|
17
|
+
{project-root}/_bmad/skf/shared/scripts/ (installed) and
|
|
18
|
+
{project-root}/src/shared/scripts/ (dev), or the path
|
|
19
|
+
--inventory names, run through its CLI: the skills SKF
|
|
20
|
+
generated (`skf_skill`), each with its `active_version`, and
|
|
21
|
+
the export manifest
|
|
22
|
+
verdicts `summary.result` of skf-test-skill-result-latest.json in
|
|
23
|
+
{forge_data_folder}/<name>/<active_version>/ (in
|
|
24
|
+
{forge_data_folder}/<name>/ for a skill in the flat layout)
|
|
25
|
+
pipeline the resume or repair offer a stopped chain left: the `resume`
|
|
26
|
+
of pipeline-journal.py (beside this script), as On Activation
|
|
27
|
+
reads it
|
|
28
|
+
|
|
29
|
+
Stage, the furthest each skill reached:
|
|
30
|
+
|
|
31
|
+
briefed a brief and no skill of that name
|
|
32
|
+
compiled a skill with no verdict for its active version
|
|
33
|
+
tested a verdict for its active version, which is not the exported one
|
|
34
|
+
exported its active version is the manifest's `active_version` for it
|
|
35
|
+
|
|
36
|
+
Next code, one per skill (null: up to date):
|
|
37
|
+
|
|
38
|
+
briefed CS <name>
|
|
39
|
+
no verdict, INCONCLUSIVE, PASS_WITH_DRIFT TS <name>
|
|
40
|
+
FAIL US <name> --from-test-report
|
|
41
|
+
PASS, active version not exported EX <name>
|
|
42
|
+
PASS, active version exported null
|
|
43
|
+
|
|
44
|
+
The skill a stopped chain's offer names (its `skill_name`) takes the offer's
|
|
45
|
+
`route` instead. An offer whose skill is not listed (a chain that stopped
|
|
46
|
+
before a workflow handed a skill name on names none) adds its route as the
|
|
47
|
+
last of the `recommended` actions. `pipeline` is the offer either way.
|
|
48
|
+
|
|
49
|
+
When the inventory cannot run, each brief is listed by name with no stage
|
|
50
|
+
and no next code, and a warning says why: the briefs alone cannot tell a
|
|
51
|
+
compiled skill from a briefed one. A skills folder that does not exist yet
|
|
52
|
+
holds no skill, with no warning.
|
|
53
|
+
|
|
54
|
+
CLI usage (from the skf-forger skill root):
|
|
55
|
+
uv run scripts/forge-status.py --project-root <dir> \\
|
|
56
|
+
--skills-output-folder <dir> --forge-data-folder <dir> \\
|
|
57
|
+
--run-root <dir> --result-dir <dir> [--inventory <skf-skill-inventory.py>]
|
|
58
|
+
|
|
59
|
+
Output (stdout, one object):
|
|
60
|
+
{
|
|
61
|
+
"status": "ok",
|
|
62
|
+
"skills": [{"name", "stage", "active_version", "verdict",
|
|
63
|
+
"exported_version", "next"}, ...], # sorted by name
|
|
64
|
+
"pipeline": null | {"offer", "route", "skill_name", "journal"},
|
|
65
|
+
"recommended": ["CS hono", "US cognee --from-test-report", ...],
|
|
66
|
+
"warnings": [] # e.g. "inventory_unavailable: not found"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Exit codes:
|
|
70
|
+
0 printed the status
|
|
71
|
+
2 usage error (argparse: usage on stderr, no JSON)
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
from __future__ import annotations
|
|
75
|
+
|
|
76
|
+
import argparse
|
|
77
|
+
import importlib.util
|
|
78
|
+
import json
|
|
79
|
+
import subprocess
|
|
80
|
+
import sys
|
|
81
|
+
from pathlib import Path
|
|
82
|
+
|
|
83
|
+
# Shipped scripts are consumer files, not a place for interpreter caches.
|
|
84
|
+
sys.dont_write_bytecode = True
|
|
85
|
+
|
|
86
|
+
JOURNAL_SCRIPT = Path(__file__).resolve().parent / "pipeline-journal.py"
|
|
87
|
+
BRIEF = "skill-brief.yaml"
|
|
88
|
+
TEST_RESULT = "skf-test-skill-result-latest.json"
|
|
89
|
+
INVENTORY_TIMEOUT = 120
|
|
90
|
+
# Where the shared inventory script sits under the project root, in probe order.
|
|
91
|
+
INVENTORY_PROBES = ("_bmad/skf/shared/scripts/skf-skill-inventory.py", "src/shared/scripts/skf-skill-inventory.py")
|
|
92
|
+
|
|
93
|
+
# `summary.result` spellings, as the next-code table names them.
|
|
94
|
+
VERDICTS = frozenset({"PASS", "FAIL", "INCONCLUSIVE", "PASS_WITH_DRIFT"})
|
|
95
|
+
RETEST = frozenset({None, "INCONCLUSIVE", "PASS_WITH_DRIFT"})
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _read_json(path: Path):
|
|
99
|
+
try:
|
|
100
|
+
return json.loads(path.read_text(encoding="utf-8-sig"))
|
|
101
|
+
except FileNotFoundError:
|
|
102
|
+
return None
|
|
103
|
+
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as e:
|
|
104
|
+
raise ValueError(f"{path.as_posix()}: {e}") from None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def brief_names(forge_data_folder: Path) -> list[str]:
|
|
108
|
+
"""The names with a skill-brief.yaml in their forge folder."""
|
|
109
|
+
try:
|
|
110
|
+
return sorted(p.parent.name for p in forge_data_folder.glob(f"*/{BRIEF}") if p.is_file())
|
|
111
|
+
except OSError:
|
|
112
|
+
return []
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def find_inventory(project_root: Path) -> Path | None:
|
|
116
|
+
"""The first inventory script of INVENTORY_PROBES under the project root, or None."""
|
|
117
|
+
return next((project_root / probe for probe in INVENTORY_PROBES if (project_root / probe).is_file()), None)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def run_inventory(inventory: Path | None, skills_output_folder: Path, forge_data_folder: Path) -> dict:
|
|
121
|
+
"""skf-skill-inventory.py's scan, through its CLI; ValueError when it cannot give one."""
|
|
122
|
+
if inventory is None:
|
|
123
|
+
raise ValueError("not found")
|
|
124
|
+
if not inventory.is_file():
|
|
125
|
+
raise ValueError(f"{inventory.as_posix()} not found")
|
|
126
|
+
try:
|
|
127
|
+
done = subprocess.run(
|
|
128
|
+
[sys.executable, str(inventory), str(skills_output_folder), "--forge-data-folder",
|
|
129
|
+
str(forge_data_folder)],
|
|
130
|
+
capture_output=True, text=True, encoding="utf-8", timeout=INVENTORY_TIMEOUT,
|
|
131
|
+
)
|
|
132
|
+
except (OSError, subprocess.TimeoutExpired) as e:
|
|
133
|
+
raise ValueError(f"{inventory.name} did not run: {e}") from None
|
|
134
|
+
try:
|
|
135
|
+
result = json.loads(done.stdout)
|
|
136
|
+
except json.JSONDecodeError:
|
|
137
|
+
first = (done.stderr.strip().splitlines() or ["no JSON"])[0]
|
|
138
|
+
raise ValueError(f"{inventory.name} printed no JSON: {first}") from None
|
|
139
|
+
if not isinstance(result, dict):
|
|
140
|
+
raise ValueError(f"{inventory.name} printed no JSON object")
|
|
141
|
+
if result.get("code") == "DIR_NOT_FOUND":
|
|
142
|
+
return {"skills": [], "manifest": None} # no skill exists yet
|
|
143
|
+
if result.get("status") != "ok":
|
|
144
|
+
raise ValueError(f"{inventory.name}: {result.get('error') or result.get('code') or 'status not ok'}")
|
|
145
|
+
return result
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def read_verdict(forge_data_folder: Path, name: str, active_version: str) -> str | None:
|
|
149
|
+
"""The settled verdict for the active version, upper case, or None; ValueError on an unreadable file."""
|
|
150
|
+
folder = forge_data_folder / name
|
|
151
|
+
record = _read_json((folder if active_version == "flat" else folder / active_version) / TEST_RESULT)
|
|
152
|
+
summary = record.get("summary") if isinstance(record, dict) else None
|
|
153
|
+
result = summary.get("result") if isinstance(summary, dict) else None
|
|
154
|
+
if not isinstance(result, str):
|
|
155
|
+
return None
|
|
156
|
+
verdict = result.strip().upper().replace("-", "_")
|
|
157
|
+
return verdict if verdict in VERDICTS else None
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def exported_version(manifest, name: str) -> str | None:
|
|
161
|
+
exports = manifest.get("exports") if isinstance(manifest, dict) else None
|
|
162
|
+
entry = exports.get(name) if isinstance(exports, dict) else None
|
|
163
|
+
version = entry.get("active_version") if isinstance(entry, dict) else None
|
|
164
|
+
return version if isinstance(version, str) and version else None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def skill_status(name: str, active_version: str | None, verdict: str | None, exported: str | None) -> dict:
|
|
168
|
+
"""One skill's stage and next code, by the tables in the module docstring."""
|
|
169
|
+
if verdict == "FAIL":
|
|
170
|
+
nxt = f"US {name} --from-test-report"
|
|
171
|
+
elif verdict in RETEST:
|
|
172
|
+
nxt = f"TS {name}"
|
|
173
|
+
elif exported != active_version:
|
|
174
|
+
nxt = f"EX {name}"
|
|
175
|
+
else:
|
|
176
|
+
nxt = None
|
|
177
|
+
if exported is not None and exported == active_version:
|
|
178
|
+
stage = "exported"
|
|
179
|
+
else:
|
|
180
|
+
stage = "compiled" if verdict is None else "tested"
|
|
181
|
+
return {"name": name, "stage": stage, "active_version": active_version, "verdict": verdict,
|
|
182
|
+
"exported_version": exported, "next": nxt}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _brief_status(name: str) -> dict:
|
|
186
|
+
return {"name": name, "stage": "briefed", "active_version": None, "verdict": None,
|
|
187
|
+
"exported_version": None, "next": f"CS {name}"}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _unknown_status(name: str) -> dict:
|
|
191
|
+
return {"name": name, "stage": None, "active_version": None, "verdict": None,
|
|
192
|
+
"exported_version": None, "next": None}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _load_journal():
|
|
196
|
+
spec = importlib.util.spec_from_file_location("skf_pipeline_journal", JOURNAL_SCRIPT)
|
|
197
|
+
if spec is None or spec.loader is None:
|
|
198
|
+
raise ImportError("no import spec")
|
|
199
|
+
module = importlib.util.module_from_spec(spec)
|
|
200
|
+
spec.loader.exec_module(module)
|
|
201
|
+
return module
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def pipeline_offer(run_root: Path, result_dir: Path, forge_data_folder: Path, skills_output_folder: Path,
|
|
205
|
+
warnings: list) -> dict | None:
|
|
206
|
+
"""The offer On Activation's `pipeline-journal.py resume` call makes, or None."""
|
|
207
|
+
try:
|
|
208
|
+
journal = _load_journal()
|
|
209
|
+
except (ImportError, OSError, SyntaxError) as e:
|
|
210
|
+
warnings.append(f"pipeline_offer_unavailable: pipeline-journal.py cannot be loaded: {e}")
|
|
211
|
+
return None
|
|
212
|
+
found = journal.cmd_resume(argparse.Namespace(
|
|
213
|
+
run_root=str(run_root), result_dir=str(result_dir), forge_data_folder=str(forge_data_folder),
|
|
214
|
+
skills_output_folder=str(skills_output_folder)))
|
|
215
|
+
warnings.extend(found.get("warnings", []))
|
|
216
|
+
if found.get("status") != "offer":
|
|
217
|
+
return None
|
|
218
|
+
return {key: found.get(key) for key in ("offer", "route", "skill_name", "journal")}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def forge_status(skills_output_folder: Path, forge_data_folder: Path, inventory: Path | None, run_root: Path,
|
|
222
|
+
result_dir: Path) -> dict:
|
|
223
|
+
warnings: list = []
|
|
224
|
+
briefs = brief_names(forge_data_folder)
|
|
225
|
+
entries: dict[str, dict] = {}
|
|
226
|
+
try:
|
|
227
|
+
scan = run_inventory(inventory, skills_output_folder, forge_data_folder)
|
|
228
|
+
except ValueError as e:
|
|
229
|
+
warnings.append(f"inventory_unavailable: {e}")
|
|
230
|
+
entries = {name: _unknown_status(name) for name in briefs}
|
|
231
|
+
else:
|
|
232
|
+
for skill in scan.get("skills") or []:
|
|
233
|
+
if not (isinstance(skill, dict) and skill.get("skf_skill") and isinstance(skill.get("name"), str)):
|
|
234
|
+
continue
|
|
235
|
+
name, active = skill["name"], skill.get("active_version")
|
|
236
|
+
verdict = None
|
|
237
|
+
if isinstance(active, str) and active:
|
|
238
|
+
try:
|
|
239
|
+
verdict = read_verdict(forge_data_folder, name, active)
|
|
240
|
+
except ValueError as e:
|
|
241
|
+
warnings.append(f"test_result_unreadable: {e}")
|
|
242
|
+
entries[name] = skill_status(name, active, verdict, exported_version(scan.get("manifest"), name))
|
|
243
|
+
for name in briefs:
|
|
244
|
+
entries.setdefault(name, _brief_status(name))
|
|
245
|
+
offer = pipeline_offer(run_root, result_dir, forge_data_folder, skills_output_folder, warnings)
|
|
246
|
+
named = offer is not None and offer.get("skill_name") in entries
|
|
247
|
+
if named:
|
|
248
|
+
entries[offer["skill_name"]]["next"] = offer["route"]
|
|
249
|
+
skills = [entries[name] for name in sorted(entries)]
|
|
250
|
+
recommended = [s["next"] for s in skills if s["next"]]
|
|
251
|
+
if offer is not None and not named and offer.get("route"):
|
|
252
|
+
recommended.append(offer["route"])
|
|
253
|
+
return {"status": "ok", "skills": skills, "pipeline": offer, "recommended": recommended,
|
|
254
|
+
"warnings": warnings}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
258
|
+
parser = argparse.ArgumentParser(
|
|
259
|
+
prog="forge-status",
|
|
260
|
+
description=(
|
|
261
|
+
"Ferris's WS status: each skill's lifecycle stage (briefed, compiled, tested or exported) "
|
|
262
|
+
"and the next code to run for it, from the briefs, the skill inventory, the test verdicts, "
|
|
263
|
+
"the export manifest and a stopped pipeline's offer."
|
|
264
|
+
),
|
|
265
|
+
)
|
|
266
|
+
parser.add_argument("--skills-output-folder", required=True, help="The skills output folder.")
|
|
267
|
+
parser.add_argument("--forge-data-folder", required=True, help="The forge data folder (briefs, test results).")
|
|
268
|
+
parser.add_argument("--project-root", required=True,
|
|
269
|
+
help="The project root, under which the shared skf-skill-inventory.py is found.")
|
|
270
|
+
parser.add_argument("--inventory",
|
|
271
|
+
help="The path of skf-skill-inventory.py, in place of the one found under the project root.")
|
|
272
|
+
parser.add_argument("--run-root", required=True, help="The folder that holds the pipeline runs' folders.")
|
|
273
|
+
parser.add_argument("--result-dir", required=True, help="The folder of the pipeline result files (the sidecar).")
|
|
274
|
+
return parser
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _force_utf8(*streams) -> None:
|
|
278
|
+
"""Reconfigure the output streams to UTF-8 (a Windows console uses cp1252)."""
|
|
279
|
+
for stream in streams:
|
|
280
|
+
if hasattr(stream, "reconfigure"):
|
|
281
|
+
errors = getattr(stream, "errors", None)
|
|
282
|
+
if errors is None:
|
|
283
|
+
stream.reconfigure(encoding="utf-8")
|
|
284
|
+
else:
|
|
285
|
+
stream.reconfigure(encoding="utf-8", errors=errors)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def main(argv: list[str] | None = None) -> int:
|
|
289
|
+
args = _build_parser().parse_args(argv)
|
|
290
|
+
inventory = Path(args.inventory) if args.inventory else find_inventory(Path(args.project_root))
|
|
291
|
+
result = forge_status(Path(args.skills_output_folder), Path(args.forge_data_folder), inventory,
|
|
292
|
+
Path(args.run_root), Path(args.result_dir))
|
|
293
|
+
print(json.dumps(result, indent=2))
|
|
294
|
+
return 0
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
if __name__ == "__main__":
|
|
298
|
+
_force_utf8(sys.stdout, sys.stderr)
|
|
299
|
+
sys.exit(main())
|