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,27 +1,32 @@
|
|
|
1
1
|
# /// script
|
|
2
|
-
# requires-python = ">=3.
|
|
2
|
+
# requires-python = ">=3.11"
|
|
3
3
|
# dependencies = []
|
|
4
4
|
# ///
|
|
5
5
|
"""SKF Update Active Symlink — atomic + idempotent + verified flip of
|
|
6
6
|
{skill_group}/active to point at a target version directory.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
update-skill's `write.md` (its active-link step) previously asked the LLM to
|
|
9
9
|
"create or update the active symlink at {skill_group}/active pointing
|
|
10
10
|
to the new {version}; if the symlink already exists, remove it first
|
|
11
11
|
and recreate". That two-step (`rm` then `ln`) leaves a brief window
|
|
12
12
|
where the symlink doesn't exist — readers that resolve `active`
|
|
13
|
-
mid-update see a `FileNotFoundError`.
|
|
13
|
+
mid-update see a `FileNotFoundError`. A second check then re-reads the symlink
|
|
14
14
|
to verify it points where expected and halts on divergence.
|
|
15
15
|
|
|
16
16
|
This helper consolidates the two steps into one workflow-specific
|
|
17
17
|
invocation:
|
|
18
18
|
|
|
19
|
+
- holds {skill-group}/active.skf-lock, the lock skf-atomic-write.py
|
|
20
|
+
flip-link takes, from the read through the re-read, so one flip of
|
|
21
|
+
the link runs at a time; while another flip holds it, waits up to
|
|
22
|
+
FLIP_LOCK_WAIT_SECONDS, then returns busy without touching the link
|
|
19
23
|
- detects whether a flip is required (idempotent: already pointing
|
|
20
24
|
at the target → no-op)
|
|
21
|
-
- performs the flip
|
|
22
|
-
|
|
25
|
+
- performs the flip through skf-atomic-write.py's replace_link, the
|
|
26
|
+
code flip-link runs (link at a temp name → os.replace), so on POSIX
|
|
27
|
+
concurrent readers never see a missing symlink
|
|
23
28
|
- verifies the post-state and surfaces ok / flipped / mismatch
|
|
24
|
-
/ missing-target
|
|
29
|
+
/ missing-target / busy
|
|
25
30
|
|
|
26
31
|
Two subcommands:
|
|
27
32
|
|
|
@@ -41,7 +46,7 @@ silently breaks downstream consumers that expect it to resolve.
|
|
|
41
46
|
|
|
42
47
|
Output JSON (stdout):
|
|
43
48
|
{
|
|
44
|
-
"status": "ok" | "flipped" | "mismatch" | "missing-target",
|
|
49
|
+
"status": "ok" | "flipped" | "mismatch" | "missing-target" | "busy",
|
|
45
50
|
"skill_group": "<abs path>",
|
|
46
51
|
"active_link": "<abs path to active>",
|
|
47
52
|
"expected_target": "<version>",
|
|
@@ -52,19 +57,28 @@ Output JSON (stdout):
|
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
Exit codes:
|
|
55
|
-
0
|
|
56
|
-
1
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
0: ok (already correct) or flipped (just updated)
|
|
61
|
+
1: script error, one `error:` line on stderr and nothing on stdout
|
|
62
|
+
(group path invalid, a real folder or file at {skill-group}/active,
|
|
63
|
+
skf-atomic-write.py not loadable from this script's folder, or the
|
|
64
|
+
link could not be moved); argparse exits 2 on bad arguments
|
|
65
|
+
2: mismatch (verify mode and target diverges), missing-target
|
|
66
|
+
(the {version} directory doesn't exist; caller must halt), or
|
|
67
|
+
busy (update: another flip held the link's lock for the whole
|
|
68
|
+
wait; the link is unchanged, caller must halt)
|
|
69
|
+
|
|
70
|
+
Platform: Linux, macOS and native Windows, as skf-atomic-write.py's
|
|
71
|
+
flip-link. On Windows the flip removes the old link first whenever the
|
|
72
|
+
rename over it is refused, which it always is over a directory link, so
|
|
73
|
+
it is not atomic there; without symlink privilege the new link is a
|
|
74
|
+
directory junction. A junction reads back as the name of the version folder it
|
|
75
|
+
resolves to, so `ok` means the link names {version} whichever kind it is.
|
|
63
76
|
"""
|
|
64
77
|
|
|
65
78
|
from __future__ import annotations
|
|
66
79
|
|
|
67
80
|
import argparse
|
|
81
|
+
import importlib.util
|
|
68
82
|
import json
|
|
69
83
|
import os
|
|
70
84
|
import sys
|
|
@@ -72,6 +86,23 @@ from pathlib import Path
|
|
|
72
86
|
|
|
73
87
|
|
|
74
88
|
ACTIVE_NAME = "active"
|
|
89
|
+
ATOMIC_WRITE_HELPER = Path(__file__).resolve().parent / "skf-atomic-write.py"
|
|
90
|
+
# A flip holds <link>.skf-lock for well under a millisecond, so update waits
|
|
91
|
+
# this long for another flip to let it go before it returns busy.
|
|
92
|
+
FLIP_LOCK_WAIT_SECONDS = 5.0
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _load_atomic_write():
|
|
96
|
+
"""Load skf-atomic-write.py, which installs into the same folder as this script."""
|
|
97
|
+
try:
|
|
98
|
+
spec = importlib.util.spec_from_file_location("skf_atomic_write", ATOMIC_WRITE_HELPER)
|
|
99
|
+
if spec is None or spec.loader is None:
|
|
100
|
+
raise ImportError("no import spec")
|
|
101
|
+
module = importlib.util.module_from_spec(spec)
|
|
102
|
+
spec.loader.exec_module(module)
|
|
103
|
+
except (OSError, ImportError, SyntaxError) as e:
|
|
104
|
+
raise OSError(f"cannot load the flip-lock helper {ATOMIC_WRITE_HELPER}: {e}") from e
|
|
105
|
+
return module
|
|
75
106
|
|
|
76
107
|
|
|
77
108
|
# --------------------------------------------------------------------------
|
|
@@ -80,46 +111,51 @@ ACTIVE_NAME = "active"
|
|
|
80
111
|
|
|
81
112
|
|
|
82
113
|
def read_link_target(link_path: Path) -> str | None:
|
|
83
|
-
"""Return the
|
|
84
|
-
|
|
85
|
-
(
|
|
86
|
-
|
|
114
|
+
"""Return what the link at `link_path` names, or None if nothing is there.
|
|
115
|
+
|
|
116
|
+
A symlink gives its stored target (`1.6.2` for the links SKF makes). A
|
|
117
|
+
Windows junction, which Path.is_symlink() does not report and whose
|
|
118
|
+
os.readlink is an absolute `\\\\?\\` path, gives the name of the folder it
|
|
119
|
+
resolves to when that folder sits beside it, else its stored path (a
|
|
120
|
+
junction whose folder is gone, one that leads elsewhere, or a loop). Raises
|
|
121
|
+
ValueError if `link_path` exists but is not a link (someone replaced it
|
|
122
|
+
with a regular dir/file)."""
|
|
123
|
+
if not os.path.lexists(link_path):
|
|
87
124
|
return None
|
|
88
|
-
if
|
|
125
|
+
if link_path.is_symlink():
|
|
126
|
+
return os.readlink(link_path)
|
|
127
|
+
try:
|
|
128
|
+
stored = os.readlink(link_path)
|
|
129
|
+
except (OSError, ValueError):
|
|
89
130
|
raise ValueError(
|
|
90
131
|
f"{link_path} exists but is not a symlink — refusing to overwrite "
|
|
91
132
|
"(manual recovery required)"
|
|
92
|
-
)
|
|
93
|
-
|
|
133
|
+
) from None
|
|
134
|
+
try:
|
|
135
|
+
resolved = link_path.resolve(strict=True)
|
|
136
|
+
except (OSError, RuntimeError): # Python 3.11 and 3.12 raise RuntimeError on a loop
|
|
137
|
+
return stored
|
|
138
|
+
if resolved.parent == link_path.parent.resolve():
|
|
139
|
+
return resolved.name
|
|
140
|
+
return stored
|
|
94
141
|
|
|
95
142
|
|
|
96
143
|
def atomic_flip_symlink(link_path: Path, target_name: str) -> None:
|
|
97
|
-
"""
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
rename is atomic for symlinks, so concurrent
|
|
105
|
-
the old target or the new one, never a missing file.
|
|
144
|
+
"""Point `link_path` at `target_name` using the create-temp + rename
|
|
145
|
+
pattern. `target_name` is a relative path interpreted in the parent of
|
|
146
|
+
`link_path` (same convention as {skill_group}/active → version-dir-sibling).
|
|
147
|
+
|
|
148
|
+
Implementation: skf-atomic-write.py's replace_link, the code flip-link
|
|
149
|
+
runs, with `.{name}.skf-symlink.tmp` as the temp name: it removes a stale
|
|
150
|
+
temp from a prior crash, writes the new link there and os.replace renames
|
|
151
|
+
it over link_path. POSIX rename is atomic for symlinks, so concurrent
|
|
152
|
+
readers either see the old target or the new one, never a missing file.
|
|
153
|
+
On Windows the old link is removed first whenever the rename over it is
|
|
154
|
+
refused, which it always is over a directory link; without symlink
|
|
155
|
+
privilege the new link is a junction.
|
|
106
156
|
"""
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
# Clean up a stale temp from a prior crash, if any.
|
|
110
|
-
if tmp.is_symlink() or tmp.exists():
|
|
111
|
-
os.unlink(tmp)
|
|
112
|
-
try:
|
|
113
|
-
os.symlink(target_name, tmp)
|
|
114
|
-
os.replace(tmp, link_path)
|
|
115
|
-
except OSError:
|
|
116
|
-
# Best-effort cleanup; raise the original error.
|
|
117
|
-
try:
|
|
118
|
-
if tmp.is_symlink() or tmp.exists():
|
|
119
|
-
os.unlink(tmp)
|
|
120
|
-
except OSError:
|
|
121
|
-
pass
|
|
122
|
-
raise
|
|
157
|
+
tmp = link_path.parent / f".{link_path.name}.skf-symlink.tmp"
|
|
158
|
+
_load_atomic_write().replace_link(link_path, target_name, tmp)
|
|
123
159
|
|
|
124
160
|
|
|
125
161
|
# --------------------------------------------------------------------------
|
|
@@ -142,7 +178,7 @@ def _envelope_missing_target(skill_group: Path, version: str) -> dict:
|
|
|
142
178
|
"halt_message": (
|
|
143
179
|
f"Cannot point {skill_group / ACTIVE_NAME} at `{version}` — "
|
|
144
180
|
f"target directory `{skill_group / version}` does not exist on "
|
|
145
|
-
"disk. Verify the version directory was written before
|
|
181
|
+
"disk. Verify the version directory was written before the flip runs."
|
|
146
182
|
),
|
|
147
183
|
}
|
|
148
184
|
|
|
@@ -190,9 +226,26 @@ def _envelope_mismatch(skill_group: Path, version: str, current: str | None) ->
|
|
|
190
226
|
"halt_message": (
|
|
191
227
|
f"Active symlink divergence. `{skill_group / ACTIVE_NAME}` "
|
|
192
228
|
f"resolves to `{cur}` but metadata.json reports `version: "
|
|
193
|
-
f"{version}`.
|
|
194
|
-
f"(`
|
|
195
|
-
"update-skill, then re-verify."
|
|
229
|
+
f"{version}`. The flip did not apply. Re-point the symlink manually "
|
|
230
|
+
f"(`uv run \"{ATOMIC_WRITE_HELPER}\" flip-link --link \"{skill_group / ACTIVE_NAME}\" "
|
|
231
|
+
f"--target \"{version}\"`) or re-run update-skill, then re-verify."
|
|
232
|
+
),
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _envelope_busy(skill_group: Path, version: str, message: str) -> dict:
|
|
237
|
+
return {
|
|
238
|
+
"status": "busy",
|
|
239
|
+
"skill_group": str(skill_group),
|
|
240
|
+
"active_link": str(skill_group / ACTIVE_NAME),
|
|
241
|
+
"expected_target": version,
|
|
242
|
+
"current_target": None,
|
|
243
|
+
"action_taken": "halt",
|
|
244
|
+
"log_message": f"active_symlink_update: busy ({message})",
|
|
245
|
+
"halt_message": (
|
|
246
|
+
f"Another flip of `{skill_group / ACTIVE_NAME}` held its lock for "
|
|
247
|
+
f"{FLIP_LOCK_WAIT_SECONDS:g} s, so the link is unchanged. "
|
|
248
|
+
"Re-run once the other run ends."
|
|
196
249
|
),
|
|
197
250
|
}
|
|
198
251
|
|
|
@@ -204,16 +257,24 @@ def update(skill_group: Path, version: str) -> dict:
|
|
|
204
257
|
return _envelope_missing_target(skill_group, version)
|
|
205
258
|
|
|
206
259
|
link_path = skill_group / ACTIVE_NAME
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
260
|
+
atomic_write = _load_atomic_write()
|
|
261
|
+
try:
|
|
262
|
+
lock_fd = atomic_write.take_flip_lock(link_path, wait=FLIP_LOCK_WAIT_SECONDS)
|
|
263
|
+
except atomic_write.FlipLockHeld as exc:
|
|
264
|
+
return _envelope_busy(skill_group, version, str(exc))
|
|
265
|
+
try:
|
|
266
|
+
current = read_link_target(link_path)
|
|
267
|
+
if current == version:
|
|
268
|
+
return _envelope_ok(skill_group, version, current)
|
|
210
269
|
|
|
211
|
-
|
|
270
|
+
atomic_flip_symlink(link_path, version)
|
|
212
271
|
|
|
213
|
-
|
|
214
|
-
|
|
272
|
+
# Re-read to confirm
|
|
273
|
+
post = read_link_target(link_path)
|
|
274
|
+
finally:
|
|
275
|
+
atomic_write.release_flip_lock(link_path, lock_fd)
|
|
215
276
|
if post != version:
|
|
216
|
-
#
|
|
277
|
+
# Only a writer that skips the lock, such as a hand-run `ln -sfn`, gets here.
|
|
217
278
|
return _envelope_mismatch(skill_group, version, post)
|
|
218
279
|
return _envelope_flipped(skill_group, version, current)
|
|
219
280
|
|
|
@@ -235,7 +296,7 @@ def verify(skill_group: Path, version: str) -> dict:
|
|
|
235
296
|
def _exit_code_for_status(status: str) -> int:
|
|
236
297
|
if status in ("ok", "flipped"):
|
|
237
298
|
return 0
|
|
238
|
-
if status in ("mismatch", "missing-target"):
|
|
299
|
+
if status in ("mismatch", "missing-target", "busy"):
|
|
239
300
|
return 2
|
|
240
301
|
return 1
|
|
241
302
|
|
|
@@ -298,14 +359,6 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
298
359
|
|
|
299
360
|
|
|
300
361
|
def main(argv: list[str] | None = None) -> int:
|
|
301
|
-
if sys.platform.startswith("win"):
|
|
302
|
-
print(
|
|
303
|
-
"error: native Windows symlinks require admin/developer mode; "
|
|
304
|
-
"use WSL2 to run update-skill (same constraint as "
|
|
305
|
-
"skf-atomic-write.py flip-link)",
|
|
306
|
-
file=sys.stderr,
|
|
307
|
-
)
|
|
308
|
-
return 1
|
|
309
362
|
parser = _build_parser()
|
|
310
363
|
args = parser.parse_args(argv)
|
|
311
364
|
return args.func(args)
|