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,24 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# /// script
|
|
3
|
-
# requires-python = ">=3.
|
|
3
|
+
# requires-python = ">=3.11"
|
|
4
4
|
# dependencies = []
|
|
5
5
|
# ///
|
|
6
6
|
"""Deterministic numerator ground-truth verifier.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
"Numerator ground
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
Lookup-and-count helper for the SKF test-skill workflow (coverage-check.md
|
|
9
|
+
§2b, its "Numerator ground truth" paragraph; §4b records the gap). It fires
|
|
10
|
+
only on the inflation signature
|
|
11
|
+
(`stats.exports_documented == effective_denominator` exactly, or, for a
|
|
12
|
+
provenance map with no `::` entry, its distinct entry names number
|
|
13
|
+
`effective_denominator`): the numerator equals the denominator, the tell of a
|
|
14
|
+
documented count padded to force 100% coverage. On that signature the declared
|
|
15
|
+
count is not trusted: every declared export name is looked up in the skill's
|
|
16
|
+
documentation surface and only the names that actually appear count toward
|
|
17
|
+
coverage.
|
|
18
|
+
|
|
19
|
+
Distinct from reconcile-coverage.py (whose scalar/stack branches look up the §1
|
|
20
|
+
inventory names and return only a residual missing *count*): this script looks
|
|
21
|
+
up the full declared metadata/provenance set and enumerates the *absent* names so
|
|
22
|
+
§4b can list them in a High-severity gap. Both scripts read the same text and
|
|
23
|
+
match names the same way, through validate-inventory.py beside them (SKILL.md ∪
|
|
24
|
+
sorted references/*.md, UTF-8; the name as a fixed string, case-sensitive, never
|
|
25
|
+
inside a longer identifier, so `get` is not found in `target` or `getAll`), so
|
|
26
|
+
their numerators agree.
|
|
22
27
|
|
|
23
28
|
Input schema (one JSON object):
|
|
24
29
|
{
|
|
@@ -26,59 +31,71 @@ Input schema (one JSON object):
|
|
|
26
31
|
"skillPackagePath": "/path/to/skill" # SKILL.md ∪ references/*.md
|
|
27
32
|
}
|
|
28
33
|
|
|
34
|
+
or the files: --inputs <coverage-inputs.json> --skill-dir <skill package>.
|
|
35
|
+
--inputs reads load-coverage-inputs.py metadata's output: its `declaredNames`
|
|
36
|
+
and `inflationSignature`. Without the signature there is nothing to verify,
|
|
37
|
+
so the result is `skipped` and `inflated` is false; a caller can run the
|
|
38
|
+
command on every skill.
|
|
39
|
+
|
|
29
40
|
Output (stdout, one object):
|
|
30
41
|
{
|
|
42
|
+
"skipped": <bool>, # --inputs only: true when there is no inflation signature
|
|
31
43
|
"declared": <int>, # de-duplicated declared name count
|
|
32
44
|
"verified": <int>, # declared names present in the doc surface
|
|
33
45
|
"present": [names], # sorted
|
|
34
|
-
"absent": [names], # sorted (declared − verified)
|
|
46
|
+
"absent": [names], # sorted (declared − verified): the gap list
|
|
35
47
|
"inflated": <bool> # verified < declared (numerator was padded)
|
|
36
48
|
}
|
|
37
49
|
or {"error": ..., "code": "INVALID_INPUT"} on a schema violation.
|
|
38
50
|
|
|
39
|
-
`verified` is the numerator §
|
|
40
|
-
declared count when `inflated` is true).
|
|
51
|
+
`verified` is the numerator §2c's reconcile-coverage.py call uses (it
|
|
52
|
+
overrides the declared count when `inflated` is true): reconcile-coverage.py
|
|
53
|
+
--verified reads this result. --output also writes it to a file.
|
|
41
54
|
|
|
42
55
|
CLI usage (mirrors reconcile-coverage.py):
|
|
56
|
+
uv run verify-declared-numerator.py --inputs <file> --skill-dir <dir> [--output <file>]
|
|
43
57
|
uv run verify-declared-numerator.py '<JSON>' # positional
|
|
44
58
|
uv run verify-declared-numerator.py --json-input '<JSON>' # explicit flag
|
|
45
59
|
cat input.json | uv run verify-declared-numerator.py --stdin # piped input
|
|
46
60
|
|
|
47
61
|
Exit codes:
|
|
48
|
-
0
|
|
49
|
-
1
|
|
50
|
-
2
|
|
62
|
+
0 verification emitted successfully
|
|
63
|
+
1 no input, input that does not parse as JSON, or an --inputs file that cannot be read
|
|
64
|
+
2 input parsed but schema/semantics invalid (error object emitted as JSON)
|
|
51
65
|
"""
|
|
52
66
|
|
|
53
67
|
from __future__ import annotations
|
|
54
68
|
|
|
55
69
|
import argparse
|
|
70
|
+
import importlib.util
|
|
56
71
|
import json
|
|
57
72
|
import sys
|
|
58
73
|
from pathlib import Path
|
|
59
74
|
|
|
75
|
+
_INVENTORY_MODULE = None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _inventory():
|
|
79
|
+
"""validate-inventory.py beside this script: the name match lives there."""
|
|
80
|
+
global _INVENTORY_MODULE
|
|
81
|
+
if _INVENTORY_MODULE is None:
|
|
82
|
+
sibling = Path(__file__).resolve().parent / "validate-inventory.py"
|
|
83
|
+
spec = importlib.util.spec_from_file_location("skf_validate_inventory", sibling)
|
|
84
|
+
if spec is None or spec.loader is None or not sibling.is_file():
|
|
85
|
+
raise ImportError(f"validate-inventory.py not found beside {Path(__file__).name}")
|
|
86
|
+
module = importlib.util.module_from_spec(spec)
|
|
87
|
+
spec.loader.exec_module(module)
|
|
88
|
+
_INVENTORY_MODULE = module
|
|
89
|
+
return _INVENTORY_MODULE
|
|
90
|
+
|
|
60
91
|
|
|
61
92
|
def make_error(message):
|
|
62
93
|
return {"error": message, "code": "INVALID_INPUT"}
|
|
63
94
|
|
|
64
95
|
|
|
65
96
|
def load_doc_text(skill_package_path):
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
Deterministic: references are read in sorted order. Reads as UTF-8 so
|
|
69
|
-
non-ASCII exports do not mojibake on Windows (cp1252 default). Mirrors
|
|
70
|
-
reconcile-coverage.py.load_doc_text so the two numerators agree.
|
|
71
|
-
"""
|
|
72
|
-
root = Path(skill_package_path)
|
|
73
|
-
parts = []
|
|
74
|
-
skill_md = root / "SKILL.md"
|
|
75
|
-
if skill_md.is_file():
|
|
76
|
-
parts.append(skill_md.read_text(encoding="utf-8"))
|
|
77
|
-
refs_dir = root / "references"
|
|
78
|
-
if refs_dir.is_dir():
|
|
79
|
-
for ref in sorted(refs_dir.glob("*.md")):
|
|
80
|
-
parts.append(ref.read_text(encoding="utf-8"))
|
|
81
|
-
return "\n".join(parts)
|
|
97
|
+
"""SKILL.md ∪ references/*.md text, as validate-inventory.py reads it."""
|
|
98
|
+
return _inventory().load_doc_text(skill_package_path)
|
|
82
99
|
|
|
83
100
|
|
|
84
101
|
def _validate(inp):
|
|
@@ -102,8 +119,8 @@ def verify(inp, doc_text=None):
|
|
|
102
119
|
if doc_text is None:
|
|
103
120
|
doc_text = load_doc_text(inp["skillPackagePath"])
|
|
104
121
|
|
|
105
|
-
present =
|
|
106
|
-
absent = sorted(
|
|
122
|
+
present = _inventory().names_present(declared_set, doc_text)
|
|
123
|
+
absent = sorted(set(declared_set) - set(present))
|
|
107
124
|
|
|
108
125
|
return {
|
|
109
126
|
"declared": len(declared_set),
|
|
@@ -122,7 +139,7 @@ def _build_parser():
|
|
|
122
139
|
prog="verify-declared-numerator",
|
|
123
140
|
description=(
|
|
124
141
|
"Deterministic numerator ground-truth verifier (coverage-check.md "
|
|
125
|
-
"§
|
|
142
|
+
"§2b). Greps the full declared export set against SKILL.md ∪ "
|
|
126
143
|
"references/*.md and enumerates the present/absent names so a padded "
|
|
127
144
|
"numerator is caught and the verified count replaces it."
|
|
128
145
|
),
|
|
@@ -150,9 +167,32 @@ def _build_parser():
|
|
|
150
167
|
action="store_true",
|
|
151
168
|
help="Read the JSON object from stdin.",
|
|
152
169
|
)
|
|
170
|
+
src.add_argument(
|
|
171
|
+
"--inputs",
|
|
172
|
+
metavar="PATH",
|
|
173
|
+
help="load-coverage-inputs.py metadata output: declaredNames and inflationSignature.",
|
|
174
|
+
)
|
|
175
|
+
parser.add_argument("--skill-dir", metavar="DIR",
|
|
176
|
+
help="the skill package (with --inputs): SKILL.md and references/")
|
|
177
|
+
parser.add_argument("--output", metavar="PATH", help="also write the result to this file")
|
|
153
178
|
return parser
|
|
154
179
|
|
|
155
180
|
|
|
181
|
+
def verify_from_inputs(inputs, skill_dir, doc_text=None):
|
|
182
|
+
"""Verify the declared set of a load-coverage-inputs.py metadata result."""
|
|
183
|
+
if not isinstance(inputs, dict):
|
|
184
|
+
return make_error("--inputs must hold a JSON object")
|
|
185
|
+
names = inputs.get("declaredNames")
|
|
186
|
+
if inputs.get("inflationSignature") is not True:
|
|
187
|
+
declared = len({n for n in names if isinstance(n, str) and n}) if isinstance(names, list) else 0
|
|
188
|
+
return {"skipped": True, "declared": declared, "verified": None, "present": [], "absent": [],
|
|
189
|
+
"inflated": False}
|
|
190
|
+
result = verify({"declaredNames": names, "skillPackagePath": skill_dir}, doc_text=doc_text)
|
|
191
|
+
if result.get("code") != "INVALID_INPUT":
|
|
192
|
+
result = {"skipped": False, **result}
|
|
193
|
+
return result
|
|
194
|
+
|
|
195
|
+
|
|
156
196
|
def _resolve_input(args):
|
|
157
197
|
if args.stdin:
|
|
158
198
|
return sys.stdin.read()
|
|
@@ -163,30 +203,67 @@ def _resolve_input(args):
|
|
|
163
203
|
return ""
|
|
164
204
|
|
|
165
205
|
|
|
206
|
+
def _write_output(path, result):
|
|
207
|
+
target = Path(path)
|
|
208
|
+
if result.get("code") == "INVALID_INPUT":
|
|
209
|
+
target.unlink(missing_ok=True)
|
|
210
|
+
return
|
|
211
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
212
|
+
target.write_bytes((json.dumps(result, indent=2, ensure_ascii=False) + "\n").encode("utf-8"))
|
|
213
|
+
|
|
214
|
+
|
|
166
215
|
def main(argv=None):
|
|
167
216
|
parser = _build_parser()
|
|
168
217
|
args = parser.parse_args(argv)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
218
|
+
if args.inputs is not None:
|
|
219
|
+
if not args.skill_dir:
|
|
220
|
+
parser.error("--inputs needs --skill-dir")
|
|
221
|
+
try:
|
|
222
|
+
inputs = json.loads(Path(args.inputs).read_bytes().decode("utf-8-sig"))
|
|
223
|
+
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as exc:
|
|
224
|
+
print(f"error: cannot read --inputs {args.inputs}: {exc}", file=sys.stderr)
|
|
225
|
+
return 1
|
|
226
|
+
result = verify_from_inputs(inputs, args.skill_dir)
|
|
227
|
+
else:
|
|
228
|
+
raw = _resolve_input(args)
|
|
229
|
+
if not raw.strip():
|
|
230
|
+
parser.print_usage(file=sys.stderr)
|
|
231
|
+
print(
|
|
232
|
+
"error: no input provided (positional arg, --json-input, --stdin or --inputs)",
|
|
233
|
+
file=sys.stderr,
|
|
234
|
+
)
|
|
235
|
+
return 1
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
data = json.loads(raw)
|
|
239
|
+
except json.JSONDecodeError as exc:
|
|
240
|
+
print(json.dumps(make_error(f"Invalid JSON: {exc.msg}"), indent=2))
|
|
241
|
+
return 1
|
|
242
|
+
|
|
243
|
+
result = verify(data)
|
|
244
|
+
if args.output:
|
|
245
|
+
_write_output(args.output, result)
|
|
185
246
|
print(json.dumps(result, indent=2))
|
|
186
247
|
if isinstance(result, dict) and result.get("code") == "INVALID_INPUT":
|
|
187
248
|
return 2
|
|
188
249
|
return 0
|
|
189
250
|
|
|
190
251
|
|
|
252
|
+
def _force_utf8(*streams) -> None:
|
|
253
|
+
"""Reconfigure stdout and stderr to UTF-8, keeping each stream's error handler.
|
|
254
|
+
|
|
255
|
+
A Windows console pipes them as cp1252, which cannot print every character
|
|
256
|
+
of the --help text, so --help would stop with UnicodeEncodeError.
|
|
257
|
+
"""
|
|
258
|
+
for stream in streams:
|
|
259
|
+
if hasattr(stream, "reconfigure"):
|
|
260
|
+
errors = getattr(stream, "errors", None)
|
|
261
|
+
if errors is None:
|
|
262
|
+
stream.reconfigure(encoding="utf-8")
|
|
263
|
+
else:
|
|
264
|
+
stream.reconfigure(encoding="utf-8", errors=errors)
|
|
265
|
+
|
|
266
|
+
|
|
191
267
|
if __name__ == "__main__":
|
|
268
|
+
_force_utf8(sys.stdout, sys.stderr)
|
|
192
269
|
raise SystemExit(main())
|
|
@@ -5,6 +5,7 @@ skillDir: ''
|
|
|
5
5
|
runId: ''
|
|
6
6
|
testMode: ''
|
|
7
7
|
forgeTier: ''
|
|
8
|
+
hardGate: ''
|
|
8
9
|
testResult: ''
|
|
9
10
|
score: ''
|
|
10
11
|
threshold: ''
|
|
@@ -20,22 +21,28 @@ nextWorkflow: ''
|
|
|
20
21
|
# Test Report: {{skillName}}
|
|
21
22
|
|
|
22
23
|
<!--
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
Each stage writes its section in place of the heading below that it owns and
|
|
25
|
+
the placeholder comment under that heading, so every heading occurs once.
|
|
26
|
+
Before the result files are written, report.md §4c checks that each heading
|
|
27
|
+
occurs exactly once and that no placeholder comment is left: a stage that
|
|
28
|
+
skipped its section stops the run there. Do not reorder or delete the
|
|
29
|
+
headings or their placeholder comments.
|
|
30
|
+
|
|
31
|
+
Heading / owning step:
|
|
32
|
+
Test Summary → detect-mode §2
|
|
33
|
+
Coverage Analysis → coverage-check §5
|
|
34
|
+
Coherence Analysis → coherence-check §6
|
|
35
|
+
External Validation → external-validators §5
|
|
36
|
+
(hard gate) → step-hard-gate reads the gap ledger; it writes the
|
|
37
|
+
Completeness Score section only when it blocks the run
|
|
38
|
+
Completeness Score → score §6, or step-hard-gate §3 on a blocked run
|
|
39
|
+
Gap Report → report §4c, rendered from the gap ledger (with the
|
|
40
|
+
Discovery Quality subsection)
|
|
34
41
|
-->
|
|
35
42
|
|
|
36
43
|
## Test Summary
|
|
37
44
|
|
|
38
|
-
<!-- Populated by detect-mode §
|
|
45
|
+
<!-- Populated by detect-mode §2 -->
|
|
39
46
|
|
|
40
47
|
## Coverage Analysis
|
|
41
48
|
|
|
@@ -51,9 +58,8 @@ Anchor / Step mapping:
|
|
|
51
58
|
|
|
52
59
|
## Completeness Score
|
|
53
60
|
|
|
54
|
-
<!-- Populated by score §6 -->
|
|
61
|
+
<!-- Populated by score §6, or by step-hard-gate §3 when the hard gate blocks the run -->
|
|
55
62
|
|
|
56
63
|
## Gap Report
|
|
57
64
|
|
|
58
|
-
<!-- Populated by report §
|
|
59
|
-
|
|
65
|
+
<!-- Populated by report §4c from the gap ledger (includes the Discovery Quality subsection) -->
|
|
@@ -7,17 +7,18 @@ description: Smart regeneration preserving [MANUAL] sections after source change
|
|
|
7
7
|
|
|
8
8
|
## Overview
|
|
9
9
|
|
|
10
|
-
Surgically updates existing skills when source code changes, preserving all [MANUAL] developer content while re-extracting only affected exports with full provenance tracking
|
|
10
|
+
Surgically updates existing skills when source code changes, preserving all [MANUAL] developer content while re-extracting only affected exports with full provenance tracking; unchanged content is never touched, and each regenerated instruction cites code by file:line. Stack skills (`skill_type: "stack"` in metadata.json) are not updated here: this workflow redirects them to `skf-create-stack-skill`, which re-composes them from updated constituents.
|
|
11
11
|
|
|
12
12
|
## Conventions
|
|
13
13
|
|
|
14
14
|
- Bare paths (e.g. `references/<name>.md`) resolve from the skill root.
|
|
15
|
-
- **Module-level path exception:** bare paths beginning with `knowledge/` or `shared/` resolve from the SKF module root (`{project-root}/_bmad/skf/` installed, `src/` in dev), not the skill root
|
|
16
|
-
-
|
|
15
|
+
- **Module-level path exception:** bare paths beginning with `knowledge/` or `shared/` resolve from the SKF module root (`{project-root}/_bmad/skf/` installed, `src/` in dev), not the skill root; stage files reference `knowledge/version-paths.md` and `knowledge/tool-resolution.md`, and the terminal step chains to `shared/health-check.md`.
|
|
16
|
+
- **Sibling skills:** a path that names another SKF skill's folder (`skf-<name>/...`) resolves from the SKF module root, and that skill must be installed with this one.
|
|
17
|
+
- `references/` holds the workflow stages, chained by each file's frontmatter `nextStepFile` (init.md §8 loads `gap-driven.md` through `gapDrivenStepFile` instead when `update_mode` is `gap-driven`), the [MANUAL] rules file merge.md loads, and the invocation contract; `scripts/` holds this skill's own helper.
|
|
17
18
|
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives, if present).
|
|
18
19
|
- `{project-root}`-prefixed paths resolve from the project working directory.
|
|
19
20
|
- `{skill-name}` resolves to the skill directory's basename.
|
|
20
|
-
- **Cross-skill data coupling:** stages
|
|
21
|
+
- **Cross-skill data coupling:** stages load shared assets from `skf-create-skill`, so create and update extract alike: `re-extract.md` pulls `extraction-patterns.md`, `extraction-patterns-tracing.md` and `tier-degradation-rules.md` from `skf-create-skill/references/`, `detect-changes.md` pulls `extraction-patterns.md`, and `gap-driven.md` pulls `extraction-patterns.md` and `tier-degradation-rules.md`; `init.md` §6c reads the version files the Version Reconciliation section of `skf-create-skill/references/source-resolution-protocols.md` lists, and `skf-source-tree.py` (init.md §6b) computes a remote skill's clone path with its workspace rule; `write.md` reads `skill-sections.md` from `skf-create-skill/assets/`, and `extraction-patterns.md` and, for §2's by-hand public API count, `entry-points-by-hand.md` from `skf-create-skill/references/`.
|
|
21
22
|
|
|
22
23
|
## Role
|
|
23
24
|
|
|
@@ -32,30 +33,26 @@ These rules apply to every step in this workflow:
|
|
|
32
33
|
- Only load one step file at a time — never preload future steps
|
|
33
34
|
- Always communicate in `{communication_language}`
|
|
34
35
|
- If `{headless_mode}` is true, auto-proceed through confirmation gates with their default action and log each auto-decision
|
|
36
|
+
- Every HALT, ABORT or other exit before step 7 runs the **Halt procedure** of the step file it fires in: one `{runStateHelper}` `halt` call that undoes this run's writes, removes the private source tree, releases the run lock and, headless, prints the halt's line. A halt never falls through to step 6.
|
|
37
|
+
- While `{source_tree}` is bound, a step that finds `{source_root}` missing HALTs with status `blocked` (`error.phase` `<step>:source-tree-missing`) instead of reading its files as deleted.
|
|
38
|
+
- **Run log.** Warnings and gate decisions live in the run folder, never only in context: a step records each warning the moment it raises it, and each gate its decision, with the `record` call that step names.
|
|
35
39
|
|
|
36
40
|
## Stages
|
|
37
41
|
|
|
38
42
|
| # | Step | File | Auto-proceed |
|
|
39
43
|
|---|------|------|--------------|
|
|
40
44
|
| 1 | Initialize & Load | references/init.md | No (confirm) |
|
|
41
|
-
| 2 | Detect Changes | references/detect-changes.md |
|
|
45
|
+
| 2 | Detect Changes | references/detect-changes.md | Conditional (§1b, §1c and §2.2 ask when triggered) |
|
|
46
|
+
| 2g | Gap-Driven Repair (only when `update_mode` is gap-driven: in place of steps 2 and 3) | references/gap-driven.md | Conditional (§1 rule R1 asks [D]/[R] when a gap's remediation names removal) |
|
|
42
47
|
| 3 | Re-Extract | references/re-extract.md | Yes |
|
|
43
|
-
| 4 | Merge | references/merge.md |
|
|
44
|
-
| 5 |
|
|
45
|
-
| 6 |
|
|
46
|
-
| 7 |
|
|
47
|
-
| 8 | Workflow Health Check | references/health-check.md | Yes |
|
|
48
|
+
| 4 | Merge | references/merge.md | Conditional ([C] after resolved [MANUAL] conflicts) |
|
|
49
|
+
| 5 | Write | references/write.md | Yes |
|
|
50
|
+
| 6 | Report | references/report.md | Yes |
|
|
51
|
+
| 7 | Workflow Health Check | references/health-check.md | Yes |
|
|
48
52
|
|
|
49
53
|
## Invocation Contract
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|--------|--------|
|
|
53
|
-
| **Inputs** | skill_name [required] |
|
|
54
|
-
| **Flags** | `--headless` / `-H` (auto-resolve all gates); `--from-test-report` (gap-driven mode); `--allow-workspace-drift` (gap-driven only — bypass §0.a pinning guard); `--allow-degraded` (headless only — pre-authorize the lossy degraded full re-extraction when the provenance map is missing, instead of halting `blocked`; init.md §4); `--detect-only` (run detect-changes only, exit before re-extract; envelope `status="detect-only"`); `--dry-run` (run detect-changes + re-extract, exit before merge/write; envelope `status="dry-run"` describes what would change). If both `--detect-only` and `--dry-run` are passed, `--detect-only` wins. |
|
|
55
|
-
| **Gates** | step 1: Confirm Gate [C] | step 4: Confirm Gate [C if clean merge, HALT if conflicts] |
|
|
56
|
-
| **Outputs** | Updated SKILL.md, metadata.json, provenance-map.json, evidence-report.md (none when `--detect-only` or `--dry-run` is set — those modes are read-only inspection paths) |
|
|
57
|
-
| **Concurrency** | Two simultaneous real-update runs against the same skill would corrupt provenance. init.md §1b acquires a PID-file lock at `{forge_data_folder}/{skill_name}/.skf-update.lock` before any artifact read; live-PID collisions halt with `status: "halted-for-concurrent-run"`. Stale locks (dead PID) are cleared silently with a warning. The lock is released by the terminal health-check step (step 8) on the normal path and by the two init-stage headless halts (§4/§6); mid-workflow halts leave it for the next run's stale-lock self-heal (see init.md §1b Release contract). Read-only modes (`--detect-only`, `--dry-run`) skip the lock entirely — they're safe alongside a concurrent real update. |
|
|
58
|
-
| **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true. Each auto-resolved gate appends a `{gate, default_action, taken_action, reason, evidence?}` entry to `headless_decisions[]`, surfaced in step 7's `SKF_UPDATE_RESULT_JSON` envelope so non-interactive runs can be audited post-hoc. A HALT reached in headless mode emits its own `SKF_UPDATE_RESULT_JSON` at the halt site (the site's `status` code plus an `error: {phase, path?, reason}` object) and exits — halts do not fall through to step 7. Pipeline branches on the envelope's top-level `status` field (`success`, `no-changes`, `detect-only`, `dry-run`, or one of the documented `halted-for-*`/`blocked` codes). The first four are successful exits — pipelines treating non-success as failure must include them in the success set. The status enum is defined once in `src/shared/scripts/schemas/skf-update-result-envelope.v1.json`. |
|
|
55
|
+
Headless callers: the inputs, flags, gate map, outputs and the `SKF_UPDATE_RESULT_JSON` line live in `references/invocation-contract.md`. Interactive runs do not need it.
|
|
59
56
|
|
|
60
57
|
## On Activation
|
|
61
58
|
|
|
@@ -63,17 +60,33 @@ These rules apply to every step in this workflow:
|
|
|
63
60
|
- `project_name`, `output_folder`, `user_name`, `communication_language`, `document_output_language`
|
|
64
61
|
- `skills_output_folder`, `forge_data_folder`, `sidecar_path`
|
|
65
62
|
|
|
66
|
-
2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in preferences.yaml
|
|
63
|
+
2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in `{sidecar_path}/preferences.yaml`. Default: false. Bind `{requested_skill}` ← the skill name or folder path the invocation passes (its argument that is neither a flag nor a flag's value), else empty: `references/init.md` §1 takes it as the skill without asking.
|
|
67
64
|
|
|
68
|
-
3. **Resolve
|
|
65
|
+
3. **Resolve the shared helpers and create the run folder**, before anything can halt. Resolve `{emitEnvelopeHelper}` ← the first that exists of `{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py` and `{project-root}/src/shared/scripts/skf-emit-result-envelope.py`.
|
|
66
|
+
Resolve `{runStateHelper}` ← the first that exists of `{project-root}/_bmad/skf/shared/scripts/skf-update-run-state.py` and `{project-root}/src/shared/scripts/skf-update-run-state.py`. Then, from `{project-root}`, run:
|
|
69
67
|
|
|
70
68
|
```bash
|
|
71
|
-
|
|
72
|
-
--skill {skill-root} --key workflow
|
|
69
|
+
mkdir -p "{project-root}/_bmad-output/.skf-run" && mktemp -d "{project-root}/_bmad-output/.skf-run/skf-update-skill-XXXXXXXX"
|
|
73
70
|
```
|
|
74
71
|
|
|
75
|
-
|
|
72
|
+
Bind `{run_dir}` ← the path it prints and `{run_id}` ← its folder name less `skf-update-skill-`.
|
|
76
73
|
|
|
77
|
-
|
|
74
|
+
If a helper is missing or the folder cannot be created, HALT: display "**SKF cannot start this update:** {the missing helper (re-install SKF), or the command's first stderr line}. Nothing was changed." Headless, when the emitter resolved, print the halt's line with no run folder, from `{project-root}`:
|
|
78
75
|
|
|
79
|
-
|
|
76
|
+
```bash
|
|
77
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-update-skill <<'SKF_JSON'
|
|
78
|
+
{"status": "blocked", "phase": "on-activation:run-folder", "path": "{project-root}/_bmad-output/.skf-run", "reason": "<which helper is missing, or that stderr line>", "skill_name": "unknown", "version": "unknown", "previous_version": "unknown", "update_mode": "normal"}
|
|
79
|
+
SKF_JSON
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
4. **Resolve workflow customization.** Run:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
It merges the bundled `{skill-root}/customize.toml` with `{project-root}/_bmad/custom/skf-update-skill.toml` (team overrides, committed) and `.user.toml` (personal overrides, gitignored). When it exits non-zero, prints no JSON or is missing, print one line, `[activation/warn] customization_resolver_unavailable: <reason>` (`<reason>`: its first stderr line, `not found` when the script is missing, `no JSON` when it printed none). If the resolver cannot run, read `{skill-root}/customize.toml` alone and use its bundled defaults: the `{project-root}/_bmad/custom/` overrides do not apply to this run. Record the warning in the run log at once: write `customization_resolver_unavailable: <reason>` to `{run_dir}/resolver-warning.txt` with a file write (a resolver error can hold quotes or `$( )`, so never echo it or type it into an argument), then run `uv run {emitEnvelopeHelper} record --run-dir "{run_dir}" --warning "$(cat "{run_dir}/resolver-warning.txt")"` from `{project-root}`.
|
|
89
|
+
|
|
90
|
+
Apply the resolved values so no surface is a silent no-op: execute each entry in `workflow.activation_steps_prepend` in order now; treat every entry in `workflow.persistent_facts` as standing context for the whole run (entries prefixed `file:` are paths or globs whose contents load as facts: the bundled default loads every `project-context.md` under `{project-root}`; an entry prefixed `!` drops each earlier entry it names and loads nothing itself, so an override's `"!file:{project-root}/**/project-context.md"` turns that default off); resolve `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty string, and stash it in workflow context (`references/report.md` §5b runs it after a finished run's result files, never in `--detect-only`, `--dry-run` or a halt; empty = no-op). After activation completes, execute each entry in `workflow.activation_steps_append` in order before `init.md` runs.
|
|
91
|
+
|
|
92
|
+
5. Load, read the full file, and then execute `references/init.md` to begin the workflow.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# DO NOT EDIT -- overwritten on every update.
|
|
2
2
|
#
|
|
3
3
|
# Workflow customization surface for skf-update-skill.
|
|
4
|
-
# Team overrides: _bmad/custom/skf-update-skill.toml
|
|
5
|
-
# Personal overrides: _bmad/custom/skf-update-skill.user.toml
|
|
4
|
+
# Team overrides: {project-root}/_bmad/custom/skf-update-skill.toml
|
|
5
|
+
# Personal overrides: {project-root}/_bmad/custom/skf-update-skill.user.toml
|
|
6
6
|
|
|
7
7
|
[workflow]
|
|
8
8
|
|
|
@@ -10,15 +10,17 @@
|
|
|
10
10
|
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
|
|
11
11
|
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
|
|
12
12
|
|
|
13
|
-
# Steps
|
|
14
|
-
#
|
|
15
|
-
#
|
|
13
|
+
# Steps SKILL.md On Activation step 4 runs once this file resolves: after
|
|
14
|
+
# the config load, the headless flag and the run folder, before
|
|
15
|
+
# activation_steps_append and references/init.md. Overrides append. Use for
|
|
16
|
+
# org-wide pre-flight checks (auth, network, compliance) that must precede
|
|
17
|
+
# any skill update work.
|
|
16
18
|
|
|
17
19
|
activation_steps_prepend = []
|
|
18
20
|
|
|
19
|
-
# Steps to run after activation
|
|
20
|
-
# Overrides append. Use for context loads or banner
|
|
21
|
-
# should run once activation completes successfully.
|
|
21
|
+
# Steps to run after activation, before references/init.md (the first
|
|
22
|
+
# stage) runs. Overrides append. Use for context loads or banner
|
|
23
|
+
# customization that should run once activation completes successfully.
|
|
22
24
|
|
|
23
25
|
activation_steps_append = []
|
|
24
26
|
|
|
@@ -26,23 +28,36 @@ activation_steps_append = []
|
|
|
26
28
|
# (drift policies, manual-section preservation rules, compliance
|
|
27
29
|
# guardrails). Overrides append.
|
|
28
30
|
#
|
|
29
|
-
# Each entry is
|
|
31
|
+
# Each entry is one of:
|
|
30
32
|
# - a literal sentence, e.g. "Updates must preserve [MANUAL] sections verbatim."
|
|
31
33
|
# - a file reference prefixed with `file:`, e.g.
|
|
32
34
|
# "file:{project-root}/docs/update-policy.md" (globs supported; file
|
|
33
35
|
# contents are loaded and treated as facts).
|
|
36
|
+
# - an entry prefixed with `!`, which loads nothing and drops each earlier
|
|
37
|
+
# entry it names.
|
|
38
|
+
#
|
|
39
|
+
# The default below loads every project-context.md under {project-root}.
|
|
40
|
+
# Overrides append, so they cannot delete it; to stop loading those files,
|
|
41
|
+
# set in {project-root}/_bmad/custom/skf-update-skill.toml:
|
|
42
|
+
# persistent_facts = ["!file:{project-root}/**/project-context.md"]
|
|
34
43
|
|
|
35
44
|
persistent_facts = [
|
|
36
45
|
"file:{project-root}/**/project-context.md",
|
|
37
46
|
]
|
|
38
47
|
|
|
39
48
|
# Pipeline-integration hook invoked after report.md §5b writes the result
|
|
40
|
-
# contract (the per-run record plus update-skill-result-latest.json)
|
|
49
|
+
# contract (the per-run record plus update-skill-result-latest.json) of a
|
|
50
|
+
# finished run: an update that wrote a version, or a run that found no
|
|
51
|
+
# change (its result files go in the current version's forge folder). The
|
|
41
52
|
# command is called as:
|
|
42
53
|
# <on_complete> --result-path=<{forge_version}/update-skill-result-latest.json>
|
|
54
|
+
# It is not called for --detect-only or --dry-run, which write no result
|
|
55
|
+
# file, nor when a run halts.
|
|
43
56
|
# Useful for Slack notifications, dashboard ingest, CI hooks, or chaining a
|
|
44
|
-
# downstream skill (audit, export, test).
|
|
45
|
-
#
|
|
57
|
+
# downstream skill (audit, export, test). A failure is reported to the user
|
|
58
|
+
# in one line and never fails the workflow; it does not reach the result
|
|
59
|
+
# files or the SKF_UPDATE_RESULT_JSON line, which are written before the
|
|
60
|
+
# hook runs.
|
|
46
61
|
#
|
|
47
62
|
# Empty string = no-op (default).
|
|
48
63
|
|