bmad-module-skill-forge 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +51 -49
- package/docs/404.md +10 -8
- package/docs/_data/pinned.yaml +22 -13
- package/docs/_internal/STABILITY.md +58 -35
- package/docs/agents.md +39 -53
- package/docs/architecture.md +65 -51
- package/docs/bmad-synergy.md +53 -51
- package/docs/campaign.md +127 -75
- package/docs/concepts.md +34 -28
- package/docs/examples.md +70 -68
- package/docs/forge-auto.md +34 -31
- package/docs/getting-started.md +118 -57
- package/docs/how-it-works.md +25 -21
- package/docs/index.md +15 -15
- package/docs/skill-model.md +70 -59
- package/docs/troubleshooting.md +135 -18
- package/docs/verifying-a-skill.md +83 -57
- package/docs/why-skf.md +24 -22
- package/docs/workflows.md +274 -110
- package/package.json +18 -10
- package/src/forger/preferences.yaml +8 -1
- package/src/knowledge/agentskills-spec.md +2 -0
- package/src/knowledge/ccc-bridge.md +40 -24
- package/src/knowledge/confidence-tiers.md +9 -5
- package/src/knowledge/overview.md +3 -3
- package/src/knowledge/progressive-capability.md +8 -8
- package/src/knowledge/provenance-tracking.md +9 -5
- package/src/knowledge/qmd-registry.md +2 -2
- package/src/knowledge/skf-knowledge-index.csv +2 -2
- package/src/knowledge/skill-lifecycle.md +18 -11
- package/src/knowledge/split-body-strategy.md +0 -3
- package/src/knowledge/tool-resolution.md +4 -2
- package/src/knowledge/version-paths.md +101 -15
- package/src/module-help.csv +3 -3
- package/src/module.yaml +10 -0
- package/src/shared/data/ast-grep-recipes.yaml +608 -0
- package/src/shared/data/ide-context-files.json +30 -0
- package/src/shared/health-check.md +32 -12
- package/src/shared/references/description-guard-protocol.md +14 -9
- package/src/shared/references/feasibility-report-schema.md +19 -13
- package/src/shared/references/headless-gate-convention.md +55 -3
- package/src/shared/references/output-contract-schema.md +19 -8
- package/src/shared/references/pipeline-contracts.md +94 -29
- package/src/shared/references/tessl-review.md +77 -0
- package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
- package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
- package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
- package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
- package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
- package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
- package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
- package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
- package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
- package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
- package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
- package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
- package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
- package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
- package/src/shared/scripts/skf-atomic-write.py +30 -14
- package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
- package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
- package/src/shared/scripts/skf-check-unit-records.py +184 -0
- package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
- package/src/shared/scripts/skf-classify-changed-files.py +694 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
- package/src/shared/scripts/skf-count-imports.py +1867 -0
- package/src/shared/scripts/skf-count-tokens.py +1 -1
- package/src/shared/scripts/skf-derive-assembly-shape.py +3 -2
- package/src/shared/scripts/skf-description-guard.py +117 -9
- package/src/shared/scripts/skf-detect-docs.py +892 -4
- package/src/shared/scripts/skf-detect-language.py +486 -107
- package/src/shared/scripts/skf-detect-registry.py +887 -0
- package/src/shared/scripts/skf-detect-scripts-assets.py +1 -1
- package/src/shared/scripts/skf-detect-tools.py +215 -27
- package/src/shared/scripts/skf-detect-workspaces.py +506 -30
- package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
- package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
- package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
- package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
- package/src/shared/scripts/skf-extract-public-api.py +4084 -85
- package/src/shared/scripts/skf-extraction-inventory.py +746 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +539 -0
- package/src/shared/scripts/skf-fetch-temporal.py +674 -0
- package/src/shared/scripts/skf-find-cycles.py +97 -29
- package/src/shared/scripts/skf-find-test-report.py +476 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +444 -203
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +661 -0
- package/src/shared/scripts/skf-hash-content.py +166 -12
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +159 -27
- package/src/shared/scripts/skf-manifest-ops.py +1 -1
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
- package/src/shared/scripts/skf-merge-doc-urls.py +1 -1
- package/src/shared/scripts/skf-names-present.py +221 -0
- package/src/shared/scripts/skf-pair-intersect.py +119 -28
- package/src/shared/scripts/skf-parse-gaps.py +1384 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-preflight.py +161 -27
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
- package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
- package/src/shared/scripts/skf-quick-batch.py +774 -0
- package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
- package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
- package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
- package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
- package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
- package/src/shared/scripts/skf-resolve-authoritative-files.py +128 -13
- package/src/shared/scripts/skf-resolve-package.py +523 -106
- package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
- package/src/shared/scripts/skf-run-lock.py +577 -0
- package/src/shared/scripts/skf-scan-manifests.py +998 -57
- package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
- package/src/shared/scripts/skf-severity-classify.py +712 -108
- package/src/shared/scripts/skf-shape-detect.py +298 -204
- package/src/shared/scripts/skf-shard-body.py +9 -8
- package/src/shared/scripts/skf-skill-inventory.py +2412 -89
- package/src/shared/scripts/skf-skills-module.py +472 -0
- package/src/shared/scripts/skf-source-tree.py +1796 -0
- package/src/shared/scripts/skf-structural-diff.py +670 -119
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +5 -5
- package/src/shared/scripts/skf-update-run-state.py +624 -0
- package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
- package/src/shared/scripts/skf-validate-brief-schema.py +4 -1
- package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
- package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
- package/src/shared/scripts/skf-validate-output.py +712 -64
- package/src/shared/scripts/skf-validate-pins.py +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +116 -10
- package/src/shared/scripts/skf-verify-provenance-completeness.py +2919 -54
- package/src/shared/scripts/skf-write-skill-brief.py +367 -19
- package/src/shared/tool-requirements.yaml +201 -0
- package/src/skf-analyze-source/SKILL.md +41 -36
- package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
- package/src/skf-analyze-source/customize.toml +36 -24
- package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
- package/src/skf-analyze-source/references/continue.md +2 -13
- package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
- package/src/skf-analyze-source/references/generate-briefs.md +121 -55
- package/src/skf-analyze-source/references/headless-contract.md +42 -15
- package/src/skf-analyze-source/references/identify-units.md +96 -110
- package/src/skf-analyze-source/references/init.md +73 -71
- package/src/skf-analyze-source/references/map-and-detect.md +123 -105
- package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
- package/src/skf-analyze-source/references/recommend.md +51 -70
- package/src/skf-analyze-source/references/scan-project.md +60 -84
- package/src/skf-analyze-source/references/scan-root.md +39 -0
- package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
- package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
- package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
- package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
- package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
- package/src/skf-audit-skill/SKILL.md +43 -51
- package/src/skf-audit-skill/assets/drift-report-template.md +27 -3
- package/src/skf-audit-skill/customize.toml +41 -20
- package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
- package/src/skf-audit-skill/references/doc-drift.md +141 -0
- package/src/skf-audit-skill/references/headless-contract.md +29 -0
- package/src/skf-audit-skill/references/init.md +148 -210
- package/src/skf-audit-skill/references/re-index.md +96 -108
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +27 -18
- package/src/skf-audit-skill/references/severity-classify.md +79 -65
- package/src/skf-audit-skill/references/severity-rules.md +15 -6
- package/src/skf-audit-skill/references/structural-diff.md +75 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
- package/src/skf-brief-skill/SKILL.md +36 -25
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +17 -24
- package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +142 -125
- package/src/skf-brief-skill/references/confirm-brief.md +10 -8
- package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
- package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
- package/src/skf-brief-skill/references/gather-intent.md +87 -182
- package/src/skf-brief-skill/references/headless-args.md +84 -16
- package/src/skf-brief-skill/references/health-check.md +1 -1
- package/src/skf-brief-skill/references/invocation-contract.md +18 -13
- package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
- package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
- package/src/skf-brief-skill/references/scope-definition.md +123 -47
- package/src/skf-brief-skill/references/step-auto-brief.md +24 -80
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +3 -2
- package/src/skf-brief-skill/references/write-brief.md +66 -57
- package/src/skf-campaign/SKILL.md +31 -34
- package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
- package/src/skf-campaign/customize.toml +47 -16
- package/src/skf-campaign/references/campaign-contracts.md +39 -29
- package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
- package/src/skf-campaign/references/health-check.md +7 -16
- package/src/skf-campaign/references/step-01-setup.md +46 -84
- package/src/skf-campaign/references/step-02-strategy.md +31 -30
- package/src/skf-campaign/references/step-03-pins.md +26 -18
- package/src/skf-campaign/references/step-04-provenance.md +24 -23
- package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
- package/src/skf-campaign/references/step-06-batch.md +41 -34
- package/src/skf-campaign/references/step-07-capstone.md +40 -25
- package/src/skf-campaign/references/step-08-verify.md +28 -29
- package/src/skf-campaign/references/step-09-refine.md +29 -30
- package/src/skf-campaign/references/step-10-export.md +48 -36
- package/src/skf-campaign/references/step-11-maintenance.md +31 -34
- package/src/skf-campaign/references/step-resume.md +37 -68
- package/src/skf-campaign/scripts/campaign-deps.py +57 -18
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
- package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
- package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
- package/src/skf-campaign/scripts/campaign-report.py +204 -37
- package/src/skf-campaign/scripts/campaign-state.py +1128 -0
- package/src/skf-campaign/scripts/campaign-status.py +10 -74
- package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
- package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
- package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
- package/src/skf-campaign/templates/campaign-report-template.md +5 -1
- package/src/skf-campaign/templates/kickoff-template.md +0 -14
- package/src/skf-create-skill/SKILL.md +27 -20
- package/src/skf-create-skill/assets/compile-assembly-rules.md +6 -5
- package/src/skf-create-skill/assets/skill-sections.md +17 -6
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
- package/src/skf-create-skill/references/batch-mode.md +81 -0
- package/src/skf-create-skill/references/ccc-index-check.md +27 -0
- package/src/skf-create-skill/references/compile.md +107 -29
- package/src/skf-create-skill/references/component-extraction.md +113 -91
- package/src/skf-create-skill/references/enrich.md +41 -23
- package/src/skf-create-skill/references/entry-points-by-hand.md +20 -0
- package/src/skf-create-skill/references/extract.md +200 -161
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
- package/src/skf-create-skill/references/extraction-patterns.md +584 -196
- package/src/skf-create-skill/references/generate-artifacts.md +145 -93
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +53 -36
- package/src/skf-create-skill/references/relabel-rule.md +12 -0
- package/src/skf-create-skill/references/report.md +28 -59
- package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
- package/src/skf-create-skill/references/step-auto-shard.md +20 -93
- package/src/skf-create-skill/references/step-doc-rot.md +44 -60
- package/src/skf-create-skill/references/step-doc-sources.md +55 -18
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -57
- package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
- package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
- package/src/skf-create-skill/references/validate.md +173 -99
- package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
- package/src/skf-create-stack-skill/SKILL.md +29 -56
- package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
- package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
- package/src/skf-create-stack-skill/customize.toml +23 -12
- package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
- package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
- package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
- package/src/skf-create-stack-skill/references/generate-output.md +138 -128
- package/src/skf-create-stack-skill/references/init.md +90 -32
- package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
- package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
- package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
- package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
- package/src/skf-create-stack-skill/references/report.md +39 -33
- package/src/skf-create-stack-skill/references/validate.md +20 -39
- package/src/skf-drop-skill/SKILL.md +28 -51
- package/src/skf-drop-skill/customize.toml +44 -30
- package/src/skf-drop-skill/references/execute.md +79 -146
- package/src/skf-drop-skill/references/invocation-contract.md +64 -0
- package/src/skf-drop-skill/references/report.md +46 -30
- package/src/skf-drop-skill/references/select.md +118 -124
- package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
- package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
- package/src/skf-export-skill/SKILL.md +40 -62
- package/src/skf-export-skill/assets/managed-section-format.md +14 -50
- package/src/skf-export-skill/assets/snippet-format.md +3 -1
- package/src/skf-export-skill/customize.toml +42 -13
- package/src/skf-export-skill/references/generate-snippet.md +54 -46
- package/src/skf-export-skill/references/health-check.md +2 -0
- package/src/skf-export-skill/references/invocation-contract.md +15 -0
- package/src/skf-export-skill/references/load-skill.md +88 -62
- package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
- package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
- package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
- package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
- package/src/skf-export-skill/references/package.md +15 -73
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
- package/src/skf-export-skill/references/result-envelope.md +31 -16
- package/src/skf-export-skill/references/summary.md +41 -17
- package/src/skf-export-skill/references/token-report.md +4 -12
- package/src/skf-export-skill/references/update-context.md +118 -237
- package/src/skf-forger/SKILL.md +61 -37
- package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
- package/src/skf-forger/customize.toml +43 -0
- package/src/skf-forger/references/pipeline-mode.md +73 -18
- package/src/skf-forger/scripts/forge-status.py +299 -0
- package/src/skf-forger/scripts/parse-pipeline.py +322 -54
- package/src/skf-forger/scripts/pipeline-gate.py +428 -0
- package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
- package/src/skf-quick-skill/SKILL.md +54 -53
- package/src/skf-quick-skill/assets/skill-template.md +4 -2
- package/src/skf-quick-skill/customize.toml +51 -20
- package/src/skf-quick-skill/references/batch-mode.md +74 -21
- package/src/skf-quick-skill/references/compile.md +30 -31
- package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
- package/src/skf-quick-skill/references/finalize.md +69 -18
- package/src/skf-quick-skill/references/halt-contract.md +41 -29
- package/src/skf-quick-skill/references/health-check.md +5 -3
- package/src/skf-quick-skill/references/quick-extract.md +114 -45
- package/src/skf-quick-skill/references/registry-resolution.md +9 -64
- package/src/skf-quick-skill/references/resolve-target.md +116 -66
- package/src/skf-quick-skill/references/write-and-validate.md +79 -40
- package/src/skf-refine-architecture/SKILL.md +43 -53
- package/src/skf-refine-architecture/customize.toml +49 -20
- package/src/skf-refine-architecture/references/compile.md +97 -54
- package/src/skf-refine-architecture/references/exit-codes.md +30 -0
- package/src/skf-refine-architecture/references/finding-storage.md +21 -0
- package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
- package/src/skf-refine-architecture/references/improvements.md +14 -20
- package/src/skf-refine-architecture/references/init.md +98 -57
- package/src/skf-refine-architecture/references/issue-detection.md +32 -39
- package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
- package/src/skf-refine-architecture/references/report.md +65 -54
- package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
- package/src/skf-rename-skill/SKILL.md +19 -54
- package/src/skf-rename-skill/customize.toml +32 -26
- package/src/skf-rename-skill/references/execute.md +230 -184
- package/src/skf-rename-skill/references/exit-codes.md +7 -7
- package/src/skf-rename-skill/references/health-check.md +1 -7
- package/src/skf-rename-skill/references/invocation-contract.md +25 -0
- package/src/skf-rename-skill/references/report.md +63 -52
- package/src/skf-rename-skill/references/select.md +197 -115
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
- package/src/skf-setup/SKILL.md +26 -26
- package/src/skf-setup/customize.toml +14 -10
- package/src/skf-setup/references/auto-index.md +50 -63
- package/src/skf-setup/references/ccc-index.md +29 -89
- package/src/skf-setup/references/detect-and-tier.md +58 -66
- package/src/skf-setup/references/health-check.md +2 -0
- package/src/skf-setup/references/invocation-contract.md +14 -0
- package/src/skf-setup/references/report.md +43 -166
- package/src/skf-setup/references/tier-rules.md +5 -5
- package/src/skf-setup/references/write-config.md +34 -57
- package/src/skf-test-skill/SKILL.md +17 -57
- package/src/skf-test-skill/assets/output-section-formats.md +33 -34
- package/src/skf-test-skill/customize.toml +27 -13
- package/src/skf-test-skill/references/coherence-check.md +134 -62
- package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
- package/src/skf-test-skill/references/coverage-check.md +217 -254
- package/src/skf-test-skill/references/detect-mode.md +5 -5
- package/src/skf-test-skill/references/external-validators.md +94 -82
- package/src/skf-test-skill/references/health-check.md +6 -7
- package/src/skf-test-skill/references/init.md +163 -88
- package/src/skf-test-skill/references/invocation-contract.md +66 -0
- package/src/skf-test-skill/references/migration-section-rules.md +5 -2
- package/src/skf-test-skill/references/report.md +162 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +41 -155
- package/src/skf-test-skill/references/source-access-protocol.md +19 -92
- package/src/skf-test-skill/references/step-hard-gate.md +51 -33
- package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
- package/src/skf-test-skill/scripts/build-result-context.py +287 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
- package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
- package/src/skf-test-skill/scripts/compute-score.py +223 -45
- package/src/skf-test-skill/scripts/gap-ledger.py +1381 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
- package/src/skf-test-skill/scripts/score-signatures.py +459 -0
- package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +127 -52
- package/src/skf-test-skill/templates/test-report-template.md +21 -15
- package/src/skf-update-skill/SKILL.md +38 -25
- package/src/skf-update-skill/customize.toml +27 -12
- package/src/skf-update-skill/references/detect-changes.md +233 -222
- package/src/skf-update-skill/references/gap-driven.md +336 -0
- package/src/skf-update-skill/references/health-check.md +31 -5
- package/src/skf-update-skill/references/init.md +250 -84
- package/src/skf-update-skill/references/invocation-contract.md +12 -0
- package/src/skf-update-skill/references/manual-section-rules.md +6 -23
- package/src/skf-update-skill/references/merge.md +180 -47
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +100 -35
- package/src/skf-update-skill/references/write.md +331 -149
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
- package/src/skf-verify-stack/SKILL.md +23 -42
- package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
- package/src/skf-verify-stack/customize.toml +55 -22
- package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
- package/src/skf-verify-stack/references/coverage.md +67 -64
- package/src/skf-verify-stack/references/exit-codes.md +21 -8
- package/src/skf-verify-stack/references/init.md +107 -62
- package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
- package/src/skf-verify-stack/references/integrations.md +106 -65
- package/src/skf-verify-stack/references/report.md +59 -42
- package/src/skf-verify-stack/references/requirements.md +32 -9
- package/src/skf-verify-stack/references/synthesize.md +53 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
- package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
- package/tools/cli/commands/install.js +11 -4
- package/tools/cli/commands/status.js +15 -3
- package/tools/cli/commands/update.js +11 -4
- package/tools/cli/lib/tool-check.js +320 -0
- package/tools/cli/lib/version-check.js +22 -9
- package/tools/cli/skf-cli.js +4 -1
- package/.gitattributes +0 -16
- package/.nvmrc +0 -1
- package/docs/_internal/RELEASING.md +0 -645
- package/release-audits/v1.0.0-launch-audit.md +0 -728
- package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
- package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
- package/src/skf-campaign/manifest.yaml +0 -15
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
- package/src/skf-create-skill/references/ecosystem-check.md +0 -74
- package/src/skf-drop-skill/references/headless-contract.md +0 -18
- package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
- package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
- package/src/skf-update-skill/references/validate.md +0 -124
- package/tools/validate-docs-drift.js +0 -233
- package/tools/validate-docs-links.js +0 -665
|
@@ -1,51 +1,38 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'report.md'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
# order (installed SKF module path first, src/ dev-checkout fallback);
|
|
7
|
-
# first existing path wins. §3 + §6 use it for crash-safe file rewrites
|
|
8
|
-
# (stage to .skf-tmp, fsync, rename) — letting the LLM write directly
|
|
9
|
-
# risks half-written artifacts on process kill or disk-full mid-write.
|
|
10
|
-
# HALT if neither candidate exists.
|
|
3
|
+
# §0 resolves each helper below from its probe order (installed SKF module
|
|
4
|
+
# path first, src/ dev-checkout fallback; the first existing path wins).
|
|
5
|
+
# {atomicWriteHelper}: the §4 `flip-link` and the §6 manifest restore.
|
|
11
6
|
atomicWriteProbeOrder:
|
|
12
7
|
- '{project-root}/_bmad/skf/shared/scripts/skf-atomic-write.py'
|
|
13
8
|
- '{project-root}/src/shared/scripts/skf-atomic-write.py'
|
|
14
|
-
#
|
|
15
|
-
# atomically repair the `active` symlink with `flock` and the Windows
|
|
16
|
-
# junction fallback — `rm + ln -s` would race against concurrent readers
|
|
17
|
-
# and silently break on Windows.
|
|
18
|
-
updateActiveSymlinkProbeOrder:
|
|
19
|
-
- '{project-root}/_bmad/skf/shared/scripts/skf-update-active-symlink.py'
|
|
20
|
-
- '{project-root}/src/shared/scripts/skf-update-active-symlink.py'
|
|
21
|
-
# Resolve `{manifestOpsHelper}` similarly. §6 uses the `rename` action
|
|
22
|
-
# for atomic re-key (preserves `active_version`, `versions` map, all
|
|
23
|
-
# fields, then writes via temp + rename).
|
|
9
|
+
# {manifestOpsHelper}: the §6 re-key.
|
|
24
10
|
manifestOpsProbeOrder:
|
|
25
11
|
- '{project-root}/_bmad/skf/shared/scripts/skf-manifest-ops.py'
|
|
26
12
|
- '{project-root}/src/shared/scripts/skf-manifest-ops.py'
|
|
27
|
-
#
|
|
28
|
-
# `replace` action for the surgical between-marker rewrite.
|
|
13
|
+
# {rebuildManagedSectionsHelper}: the §7 context-file rebuild.
|
|
29
14
|
rebuildManagedSectionsProbeOrder:
|
|
30
15
|
- '{project-root}/_bmad/skf/shared/scripts/skf-rebuild-managed-sections.py'
|
|
31
16
|
- '{project-root}/src/shared/scripts/skf-rebuild-managed-sections.py'
|
|
32
|
-
#
|
|
33
|
-
# field-scoped in-file rename transforms (SKILL.md frontmatter `name`,
|
|
34
|
-
# metadata.json `name`, provenance-map.json `skill_name`, context-snippet
|
|
35
|
-
# header + `root:` paths) — each a JSON round-trip or anchored-region edit
|
|
36
|
-
# plus the atomic write in one call, so the LLM never hand-edits JSON (which
|
|
37
|
-
# risks key reorder/drop) or eyeballs "only within the frontmatter" (which
|
|
38
|
-
# mis-fires when {old_name} is a substring, e.g. rename -> renamer).
|
|
17
|
+
# {rewriteSkillNameHelper}: the §2 package rename and in-file rewrite, one call.
|
|
39
18
|
rewriteSkillNameProbeOrder:
|
|
40
19
|
- '{project-root}/_bmad/skf/shared/scripts/skf-rewrite-skill-name.py'
|
|
41
20
|
- '{project-root}/src/shared/scripts/skf-rewrite-skill-name.py'
|
|
42
|
-
#
|
|
43
|
-
# no-trace gate: a fixed-file-set, name-token scan over affected_versions with
|
|
44
|
-
# the SKILL.md frontmatter/body region split (frontmatter = hard failure, body
|
|
45
|
-
# = advisory warning) and the directory-listing check, returned as JSON.
|
|
21
|
+
# {verifyNoTraceHelper}: the §5 no-trace commit gate.
|
|
46
22
|
verifyNoTraceProbeOrder:
|
|
47
23
|
- '{project-root}/_bmad/skf/shared/scripts/skf-verify-no-trace.py'
|
|
48
24
|
- '{project-root}/src/shared/scripts/skf-verify-no-trace.py'
|
|
25
|
+
# {skillInventoryHelper}: the §8 guarded delete.
|
|
26
|
+
skillInventoryProbeOrder:
|
|
27
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-skill-inventory.py'
|
|
28
|
+
- '{project-root}/src/shared/scripts/skf-skill-inventory.py'
|
|
29
|
+
# {runLockHelper} and {emitEnvelopeHelper}: bound since step 1 §1.
|
|
30
|
+
runLockProbeOrder:
|
|
31
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-run-lock.py'
|
|
32
|
+
- '{project-root}/src/shared/scripts/skf-run-lock.py'
|
|
33
|
+
emitEnvelopeProbeOrder:
|
|
34
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
|
|
35
|
+
- '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
|
|
49
36
|
---
|
|
50
37
|
|
|
51
38
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -54,7 +41,7 @@ verifyNoTraceProbeOrder:
|
|
|
54
41
|
|
|
55
42
|
## STEP GOAL:
|
|
56
43
|
|
|
57
|
-
Execute the rename decisions recorded in step 1 as a transaction. Copy the old `{skill_group}` and `{forge_group}` to the new name, rename inner directories, rewrite every in-file reference, verify no trace of the old name remains inside the new location, update the export manifest, rebuild platform context files, and only then delete the old directories.
|
|
44
|
+
Execute the rename decisions recorded in step 1 as a transaction. Copy the old `{skill_group}` and, when step 1 set `{forge_move}`, `{forge_group}` to the new name, rename inner directories, rewrite every in-file reference, verify no trace of the old name remains inside the new location, update the export manifest, rebuild platform context files, and only then delete the old directories. A failure in sections 1 to 6 rolls back by removing the new directories, so the old skill remains intact; the context-file rebuild in section 7 is best-effort and never rolls back.
|
|
58
45
|
|
|
59
46
|
## Rules
|
|
60
47
|
|
|
@@ -64,222 +51,265 @@ Execute the rename decisions recorded in step 1 as a transaction. Copy the old `
|
|
|
64
51
|
- Do not proceed past a verification failure in section 5
|
|
65
52
|
- Report each section's outcome as it completes
|
|
66
53
|
|
|
67
|
-
**
|
|
54
|
+
**Halt procedure.** Every HALT below names, in parentheses, its exit code, its `halt_reason` and the phase its `emit-halt` reports (see `references/exit-codes.md`). After its rollback, when it has one, it runs these, in order, before it stops:
|
|
68
55
|
|
|
69
|
-
|
|
70
|
-
SKF_RENAME_SKILL_RESULT_JSON: {"status":"error","old_name":"{old_name}","new_name":"{new_name}","versions_renamed":[],"manifest_rekeyed":false,"context_files_updated":[],"exit_code":<code>,"halt_reason":"<reason>","headless_decisions":{headless_decisions}}
|
|
71
|
-
```
|
|
56
|
+
1. Release the run lock step 1 §4b took (a release never removes a lock another run holds). From `{project-root}`:
|
|
72
57
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
58
|
+
```bash
|
|
59
|
+
uv run {runLockHelper} release --lock "{forge_data_folder}/.skf-rename-{old_name}.lock" --owner "{lock_owner}"
|
|
60
|
+
```
|
|
76
61
|
|
|
77
|
-
|
|
62
|
+
When it exits non-zero or prints no JSON, tell the user in one line that the lock file stays, and add `"warnings": ["run-lock-not-released: {forge_data_folder}/.skf-rename-{old_name}.lock"]` to the payload below.
|
|
78
63
|
|
|
79
|
-
|
|
64
|
+
2. In `{headless_mode}`, pass the halt to the shared emitter, which prints its envelope on **stderr** with the decisions and warnings the run recorded, step 1's included. Write each string as JSON (escape `"`, `\` and control characters, and write every path with `/`):
|
|
80
65
|
|
|
81
|
-
|
|
66
|
+
```bash
|
|
67
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-rename-skill --run-dir "{run_dir}" --target stderr <<'SKF_HALT'
|
|
68
|
+
{"phase": "<phase>", "halt_reason": "<halt_reason>", "reason": "<the message the halt displays>", "path": "<the path the halt names; leave the key out when it names none>", "old_name": "{old_name}", "new_name": "{new_name}"}
|
|
69
|
+
SKF_HALT
|
|
70
|
+
```
|
|
82
71
|
|
|
83
|
-
|
|
72
|
+
Display the `SKF_RENAME_SKILL_RESULT_JSON:` line it prints verbatim. When it exits non-zero and its `message` names the payload, fix the payload once and run it again. Only when `{emitEnvelopeHelper}` is missing, or the emitter still fails or prints no line, display the halt's message alone.
|
|
84
73
|
|
|
85
|
-
|
|
86
|
-
- `{rewriteSkillNameHelper}` ← first existing path in `{rewriteSkillNameProbeOrder}` (used in §3 for the field-scoped in-file rename transforms + atomic write)
|
|
87
|
-
- `{updateActiveSymlinkHelper}` ← first existing path in `{updateActiveSymlinkProbeOrder}` (used in §4 for atomic symlink repair)
|
|
88
|
-
- `{verifyNoTraceHelper}` ← first existing path in `{verifyNoTraceProbeOrder}` (used in §5 for the deterministic no-trace commit gate)
|
|
89
|
-
- `{manifestOpsHelper}` ← first existing path in `{manifestOpsProbeOrder}` (used in §6 for the manifest re-key)
|
|
90
|
-
- `{rebuildManagedSectionsHelper}` ← first existing path in `{rebuildManagedSectionsProbeOrder}` (used in §7 for between-marker swap)
|
|
74
|
+
The halt leaves `{run_dir}` in place.
|
|
91
75
|
|
|
92
|
-
|
|
76
|
+
## MANDATORY SEQUENCE
|
|
93
77
|
|
|
94
|
-
**
|
|
78
|
+
**Transactional boundary.** After section 1 (copy), the old skill is untouched; a failure in any of sections 2-6 deletes the new skill folder and, when `{forge_move}` is true, the new forge folder, reports, and halts with the old skill intact. Section 7 (context-file rebuild) is best-effort and never rolls back: by then the manifest and the skill folders are consistent under the new name, so a context file that fails to rebuild is recorded in `context_files_failed`, `{new_skill_group}` stays, and the rename goes on. Section 8 (delete old) is the only irreversible point.
|
|
95
79
|
|
|
96
|
-
###
|
|
80
|
+
### 0. Resolve Helpers
|
|
97
81
|
|
|
98
|
-
**
|
|
82
|
+
**Resolve helpers** in parallel: these are independent file-existence checks that batch into one tool-call message.
|
|
99
83
|
|
|
100
|
-
|
|
84
|
+
- `{atomicWriteHelper}` ← first existing path in `{atomicWriteProbeOrder}` (used in §4 and §6)
|
|
85
|
+
- `{rewriteSkillNameHelper}` ← first existing path in `{rewriteSkillNameProbeOrder}` (used in §2)
|
|
86
|
+
- `{verifyNoTraceHelper}` ← first existing path in `{verifyNoTraceProbeOrder}` (used in §5)
|
|
87
|
+
- `{manifestOpsHelper}` ← first existing path in `{manifestOpsProbeOrder}` (used in §6)
|
|
88
|
+
- `{rebuildManagedSectionsHelper}` ← first existing path in `{rebuildManagedSectionsProbeOrder}` (used in §7)
|
|
89
|
+
- `{skillInventoryHelper}` ← first existing path in `{skillInventoryProbeOrder}` (used in §8)
|
|
90
|
+
- `{runLockHelper}` and `{emitEnvelopeHelper}`: bound since step 1 §1 (when a binding was lost, ← first existing path in `{runLockProbeOrder}` and `{emitEnvelopeProbeOrder}`)
|
|
101
91
|
|
|
102
|
-
|
|
103
|
-
- Preserve file permissions, timestamps, and symlinks
|
|
104
|
-
- Equivalent to `cp -a {old_skill_group} {new_skill_group}` (preserves symlinks) or `cp -r` followed by explicit symlink re-creation in section 4
|
|
105
|
-
- If the copy fails: release the lock (`rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`) and halt with "**Copy failed:** `{old_skill_group}` → `{new_skill_group}`: {error}. No files were modified. Old skill is intact." HALT (exit code 4, `halt_reason: "copy-failed"`). In headless, emit the error envelope.
|
|
92
|
+
If any helper has no existing candidate, HALT (exit code 4, `halt_reason: "write-failed"`, `emit-halt` phase `execute:resolve-helpers`) before anything is copied: no section does a helper's write, transform or check by hand.
|
|
106
93
|
|
|
107
|
-
|
|
108
|
-
- If the copy fails: **rollback** by deleting `{new_skill_group}` (just created in step 2), release the lock (`rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`), then halt with "**Copy failed:** `{old_forge_group}` → `{new_forge_group}`: {error}. Rolled back new skill_group. Old skill is intact." HALT (exit code 4, `halt_reason: "copy-failed"`). In headless, emit the error envelope.
|
|
94
|
+
### 1. Copy skill_group and forge_group
|
|
109
95
|
|
|
110
|
-
**
|
|
96
|
+
**Renew the run lock first.** A run that waited at a step 1 gate past 60 minutes may have lost it to another rename; an acquire by its owner renews it. From `{project-root}`, run:
|
|
111
97
|
|
|
112
|
-
|
|
98
|
+
```bash
|
|
99
|
+
uv run {runLockHelper} acquire \
|
|
100
|
+
--lock "{forge_data_folder}/.skf-rename-{old_name}.lock" \
|
|
101
|
+
--owner "{lock_owner}" \
|
|
102
|
+
--stale-after 60
|
|
103
|
+
```
|
|
113
104
|
|
|
114
|
-
|
|
105
|
+
- **Exit 0 with `refreshed` true:** the lock is still this run's, now renewed; continue.
|
|
106
|
+
- **Exit 0 with `refreshed` false, or exit 3:** this run's lock lapsed while it waited, so another rename of `{old_name}` may have run since step 1 checked the names. Display "**This rename of `{old_name}` lost its run lock while it waited.** Nothing was changed. Run the rename again{on exit 3: ' once the other run ends. {message}', with the helper's `message`}." and HALT (exit code 5, `halt_reason: "halted-for-concurrent-run"`, `emit-halt` phase `execute:run-lock`, with the lock file as `path`) before anything is copied.
|
|
107
|
+
- **Any other exit, or no JSON:** HALT (exit code 4, `halt_reason: "write-failed"`, `emit-halt` phase `execute:run-lock`, with the lock file as `path`) before anything is copied: "**The run lock could not be renewed:** {the `message` the helper printed on stderr}. Nothing was changed."
|
|
115
108
|
|
|
116
|
-
|
|
109
|
+
**Precondition:** Both `{new_skill_group}` and `{new_forge_group}` must NOT exist (step 1 validated this in the collision check, but verify again before copying).
|
|
117
110
|
|
|
118
|
-
1.
|
|
119
|
-
2. Resolve the new inner directory: `{new_skill_group}/{v}/{new_name}/`
|
|
120
|
-
3. Rename the directory (move within the same parent): `mv {new_skill_group}/{v}/{old_name} {new_skill_group}/{v}/{new_name}`
|
|
121
|
-
4. If the old inner directory does not exist (orphaned version with no skill package), skip with a warning recorded in `section2_warnings`
|
|
111
|
+
1. If `{new_skill_group}` or `{new_forge_group}` exists on disk (a file or link counts): halt with "**Collision detected at execution time.** `{new_skill_group}` or `{new_forge_group}` now exists on disk; it did not exist during step 1 selection. Aborting before any files are touched." HALT (exit code 4, `halt_reason: "copy-failed"`, `emit-halt` phase `execute:copy`).
|
|
122
112
|
|
|
123
|
-
|
|
113
|
+
2. Copy `{old_skill_group}` to `{new_skill_group}`, naming both without a trailing `/`, as `cp -a {old_skill_group} {new_skill_group}` does. §4a refused a linked skill folder and one holding a linked version, so the only link the copy can meet is `active`. The copy carries it as a link, or as a copy of the folder it points to in a shell that cannot create links; §4 creates `{new_skill_group}/active` again either way.
|
|
114
|
+
- If the copy fails: halt with "**Copy failed:** `{old_skill_group}` → `{new_skill_group}`: {error}. No files were modified. Old skill is intact." HALT (exit code 4, `halt_reason: "copy-failed"`, `emit-halt` phase `execute:copy`).
|
|
124
115
|
|
|
125
|
-
|
|
126
|
-
- Release the lock: `rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`
|
|
127
|
-
- Halt with: "**Inner directory rename failed** at `{v}/{old_name}`: {error}. Rolled back both new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "write-failed"`). In headless, emit the error envelope.
|
|
116
|
+
3. Only when `{forge_move}` is true, copy `{old_forge_group}` to `{new_forge_group}` the same way. If the copy fails: **rollback** by deleting `{new_skill_group}` and whatever the copy created at `{new_forge_group}` (§1.1 confirmed nothing was there), then halt with "**Copy failed:** `{old_forge_group}` → `{new_forge_group}`: {error}. Rolled back the new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "copy-failed"`, `emit-halt` phase `execute:copy`). When `{forge_move}` is false, skip this copy: the forge folder is absent, left in place (`{forge_left_in_place}`), or, with `{same_folder}`, already copied with the skill folder.
|
|
128
117
|
|
|
129
|
-
|
|
118
|
+
**Rollback procedure for this section:** `rm -rf {new_skill_group}`, plus `rm -rf {new_forge_group}` when `{forge_move}` is true (this run created it), each without a trailing `/`. Old skill is untouched.
|
|
130
119
|
|
|
131
|
-
|
|
120
|
+
Report: "**Copied** `{old_skill_group}` → `{new_skill_group}`{if forge_move: ' and `{old_forge_group}` → `{new_forge_group}`'}." Name only what was copied.
|
|
132
121
|
|
|
133
|
-
|
|
122
|
+
### 2. Rename the Packages and Rewrite the Name
|
|
134
123
|
|
|
135
|
-
|
|
124
|
+
`{rewriteSkillNameHelper}` does this in one call, inside the new location only. For each version in `affected_versions` it moves `{new_skill_group}/{v}/{old_name}/` to `{new_skill_group}/{v}/{new_name}/` when that package is there, then rewrites the name in each moved package's files, writing each one atomically. Never move a package or compute file content in the prompt: a hand edit can reorder JSON keys, or rewrite the wrong place when `{old_name}` is part of a longer name (`rename` in `renamer`). From `{project-root}`:
|
|
136
125
|
|
|
137
126
|
```bash
|
|
138
|
-
|
|
139
|
-
--
|
|
140
|
-
--old-name {old_name} --new-name {new_name}
|
|
127
|
+
uv run {rewriteSkillNameHelper} --skill-group "{new_skill_group}" \
|
|
128
|
+
--versions {comma-separated affected_versions} \
|
|
129
|
+
--old-name {old_name} --new-name {new_name} --moved-folder "{skills_output_folder}" \
|
|
130
|
+
[--forge-group "{new_forge_group}" --moved-folder "{forge_data_folder}"] \
|
|
131
|
+
--result-to "{run_dir}/rename-rewrite.json"
|
|
141
132
|
```
|
|
142
133
|
|
|
143
|
-
|
|
134
|
+
Pass the bracketed group only when `{forge_move}` or `{same_folder}` is true: then this rename moves `{old_name}/` out of `{forge_data_folder}` too, and the helper also rewrites each version's provenance map. A forge folder left in place keeps its name, so paths into it stay as they are.
|
|
144
135
|
|
|
145
|
-
|
|
136
|
+
What each file keeps:
|
|
146
137
|
|
|
147
|
-
**
|
|
138
|
+
- **SKILL.md**: the frontmatter `name` only; a mention of `{old_name}` in the body stays.
|
|
139
|
+
- **metadata.json**: `name`, and the paths into the moved folders point at `{new_name}`; the values that name the upstream source stay.
|
|
140
|
+
- **context-snippet.md**: the name where SKF's snippet template writes it: the header, the `|IMPORTANT:` line and each `root:` path. Nothing else in the snippet changes: a name anywhere else stays, §5 reports it and the rename rolls back rather than commit a changed snippet.
|
|
141
|
+
- **provenance-map.json** (`{new_forge_group}/{v}/` of every version, with the bracketed group only): `skill_name`, and the paths into the moved folders, as in metadata.json.
|
|
148
142
|
|
|
149
|
-
|
|
143
|
+
It prints its result as JSON on stdout and writes the same to `{run_dir}/rename-rewrite.json`, the record step 3 reads back. A version with no package to move (a manifest version with no folder, or a version folder an interrupted run left without a package) and a file that is not there are not failures: the helper names them in `package_warnings` and `missing_files` and goes on. Only a move, a rewrite or the record write that fails stops it, with exit 2 and an `error` that names its `stage`, `path` and `message`.
|
|
150
144
|
|
|
151
|
-
**
|
|
145
|
+
**Rollback on any other exit than 0:**
|
|
152
146
|
|
|
153
|
-
|
|
147
|
+
- `rm -rf {new_skill_group}`, plus `rm -rf {new_forge_group}` when `{forge_move}` is true (this run created it), each without a trailing `/`
|
|
148
|
+
- When `error.stage` is `inner-rename`, halt with: "**Inner directory rename failed** at `{error.path}`: {error.message}. Rolled back the new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "write-failed"`, `emit-halt` phase `execute:inner-rename`).
|
|
149
|
+
- Otherwise halt with: "**File update failed** at `{error.path}`: {error.message}. Rolled back the new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "write-failed"`, `emit-halt` phase `execute:rewrite`).
|
|
154
150
|
|
|
155
|
-
|
|
156
|
-
- Release the lock: `rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`
|
|
157
|
-
- Halt with: "**File update failed** at `{path}`: {error}. Rolled back both new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "write-failed"`). In headless, emit the error envelope.
|
|
151
|
+
When stdout holds no JSON (a usage error or a traceback), `{error.path}` is `{new_skill_group}` and `{error.message}` the helper's stderr.
|
|
158
152
|
|
|
159
|
-
|
|
153
|
+
### 3. Record the Rewrite
|
|
154
|
+
|
|
155
|
+
On exit 0, bind from its result `renamed_versions` ← `renamed_versions` (the versions whose package it moved: §4 and §5 read only these) and `rewrite_counts` ← `counts` (`files_rewritten` tallied by kind). Its `files_rewritten` (the `{kind, path}` of each file it wrote), `package_warnings` and `missing_files` stay in `{run_dir}/rename-rewrite.json` for step 3.
|
|
156
|
+
|
|
157
|
+
Report: "**Renamed {the number of renamed_versions} inner directories** to `{new_name}/`. **Updated file contents:** {each kind whose `rewrite_counts` entry is above 0, as its file name and count, for example 'SKILL.md ×3, metadata.json ×3'}." Name only the kinds whose `rewrite_counts` entry is above 0, never a count taken from the version count.
|
|
160
158
|
|
|
161
159
|
### 4. Fix the `active` Symlink in the New Location
|
|
162
160
|
|
|
163
|
-
|
|
161
|
+
The §1 copy carries `{old_skill_group}/active` into `{new_skill_group}` as it found it: an absolute link, or a relative one that climbs out of the skill folder, still points into `{old_skill_group}`, which §8 deletes, and a shell that cannot create links may have copied the folder. So this section removes whatever the copy made at `{new_skill_group}/active` and creates the link again with the `flip-link` action of `{atomicWriteHelper}`, the call create-skill, quick-skill and create-stack-skill use; it refuses to replace an `active` that is a real folder, so remove the copied entry first. Never create the link with `ln -s`: Git Bash on Windows without symlink rights writes a copy of the folder instead. `{new_skill_group}` is this run's own copy, which no manifest entry or context file names until §6 and §7, so removing the copied entry before the flip is safe.
|
|
162
|
+
|
|
163
|
+
1. If nothing is at `{old_skill_group}/active`, not even a broken link (`[ ! -e "{old_skill_group}/active" ] && [ ! -L "{old_skill_group}/active" ]`), skip to the report at the end of this section: there is no link to carry over.
|
|
164
|
+
2. If `{old_skill_group}/active` is not a link (`[ ! -L "{old_skill_group}/active" ]`), take the rollback below with the reason: "`{old_skill_group}/active` is a real folder or file, not a link. Check that it only copies a version folder, remove it and re-run the rename, then point the renamed skill's link at a version with `uv run {atomicWriteHelper} flip-link --link "{new_skill_group}/active" --target <version>`."
|
|
165
|
+
3. Read the link. Set `{old_active_link}` to what the first line prints, the link text as stored, and `{target_version}` to what the second line prints, its last path component:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
readlink "{old_skill_group}/active"
|
|
169
|
+
basename "$(readlink "{old_skill_group}/active")"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
For an `{old_active_link}` of `0.6.0`, of `{old_skill_group}/0.6.0`, or of a relative path that climbs out of the skill folder and back into its `0.6.0` folder, `{target_version}` is `0.6.0`.
|
|
173
|
+
4. If `{target_version}` is not one of `renamed_versions` (§2), the link does not name a version folder holding the package this rename moved: it is broken, or it names a folder §2 skipped. Take the rollback below with the reason: "`{old_skill_group}/active` points at `{old_active_link}`, which is not one of the versions this rename moved ({renamed_versions}). Point it at one of them with `uv run {atomicWriteHelper} flip-link --link "{old_skill_group}/active" --target <version>`, or remove it, then re-run the rename."
|
|
174
|
+
5. Remove what the copy made at `{new_skill_group}/active`. A link is removed as a link, so nothing it points to is touched; only a real folder, which the copy made from the link, is removed with its contents:
|
|
164
175
|
|
|
165
|
-
|
|
166
|
-
|
|
176
|
+
```bash
|
|
177
|
+
if [ -L "{new_skill_group}/active" ]; then rm -f "{new_skill_group}/active"
|
|
178
|
+
elif [ -e "{new_skill_group}/active" ]; then rm -rf "{new_skill_group}/active"
|
|
179
|
+
fi
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
6. Create the link:
|
|
167
183
|
|
|
168
184
|
```bash
|
|
169
|
-
|
|
170
|
-
--link {new_skill_group}/active \
|
|
171
|
-
--target {target_version}
|
|
185
|
+
uv run {atomicWriteHelper} flip-link \
|
|
186
|
+
--link "{new_skill_group}/active" \
|
|
187
|
+
--target "{target_version}"
|
|
172
188
|
```
|
|
173
189
|
|
|
174
|
-
|
|
190
|
+
On exit 0, bind `{active_link_kind}` ← `kind` (`symlink` or `junction`) from the JSON it prints on stdout. On any other exit, bind `{flip_error}` ← `message` from the `{"status": "error", "message": …}` line it prints on stderr, or set it to the helper's whole stderr when there is no such line, and take the rollback below with `{flip_error}` as the reason.
|
|
191
|
+
|
|
192
|
+
**Rollback on a failure in step 2, 4 or 6:**
|
|
175
193
|
|
|
176
|
-
|
|
194
|
+
- `rm -rf {new_skill_group}`, plus `rm -rf {new_forge_group}` when `{forge_move}` is true (this run created it), each without a trailing `/`
|
|
195
|
+
- Halt with: "**Failed to repair the `active` link** in `{new_skill_group}`: {reason}. Rolled back the new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "write-failed"`, `emit-halt` phase `execute:active-link`).
|
|
177
196
|
|
|
178
|
-
|
|
179
|
-
- Release the lock: `rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`
|
|
180
|
-
- Halt with: "**Failed to repair `active` symlink** in `{new_skill_group}`: {captured stderr}. Rolled back both new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "write-failed"`). In headless, emit the error envelope.
|
|
197
|
+
Report: "**`active` link:** `{new_skill_group}/active` → `{target_version}` ({active_link_kind}).{if `{old_active_link}` is not `{target_version}`: ' Repointed from `{old_active_link}`.'}" When step 1 skipped this section: "**`active` link:** none in `{old_skill_group}`, nothing to carry over."
|
|
181
198
|
|
|
182
199
|
### 5. Verify — No Trace of `{old_name}` Inside the New Location
|
|
183
200
|
|
|
184
|
-
This is the commit-point check
|
|
201
|
+
This is the commit-point check: if any structural reference to `{old_name}` remains, the rename is not safe to commit. Invoke `{verifyNoTraceHelper}` once:
|
|
185
202
|
|
|
186
203
|
```bash
|
|
187
|
-
|
|
204
|
+
uv run {verifyNoTraceHelper} "{new_skill_group}" \
|
|
188
205
|
--forge-group "{new_forge_group}" \
|
|
189
206
|
--old-name {old_name} --new-name {new_name} \
|
|
190
|
-
--versions {comma-separated
|
|
207
|
+
--versions {comma-separated renamed_versions}
|
|
191
208
|
```
|
|
192
209
|
|
|
193
|
-
|
|
210
|
+
It scans each renamed version's SKILL.md, metadata.json, context-snippet.md and provenance-map.json and the version's folder listing, and returns `clean`, `hard_matches` (the old name where it must not stay), `body_warnings` (mentions in a SKILL.md body, which stay) and `dir_violations`. A value that names the upstream source never counts, since §2 leaves it unchanged, and a missing file is listed under `skipped`, never as a match. Exit 0 = clean; exit 1 = at least one hard match or dir violation.
|
|
194
211
|
|
|
195
|
-
Read the JSON and decide:
|
|
212
|
+
Read the JSON and decide. An exit code of 2 with no JSON on stdout (the helper refuses an empty `--versions` list) counts as `clean` false: take the rollback below.
|
|
196
213
|
|
|
197
214
|
- **If `clean` is `true` (empty `hard_matches` AND empty `dir_violations`):** the rename is safe to commit. Set `verification_warnings` = the returned `body_warnings` (informational SKILL.md body mentions of `{old_name}` that are retained). Proceed.
|
|
198
215
|
- **If `clean` is `false`:** this is a hard failure —
|
|
199
|
-
- `rm -rf {new_skill_group}
|
|
200
|
-
-
|
|
201
|
-
- Halt with: "**Verification failed.** `{old_name}` still appears in: {the files from `hard_matches` plus any `dir_violations`}. Rolled back both new directories. Old skill is intact." HALT (exit code 5, `halt_reason: "verify-failed"`). In headless, emit the error envelope.
|
|
216
|
+
- `rm -rf {new_skill_group}`, plus `rm -rf {new_forge_group}` when `{forge_move}` is true (this run created it), each without a trailing `/`
|
|
217
|
+
- Halt with: "**Verification failed.** `{old_name}` still appears in: {the files from `hard_matches` plus any `dir_violations`}. Rolled back the new directories. Old skill is intact. Where a match is a note an earlier run wrote, or a `context-snippet.md` line such as `|gotchas:`, edit it in the old skill's file, then re-run the rename. Where it names the library or repository the skill is named after (a `description`, an export, a source path), or `{old_name}` is a word of the snippet template itself, such as `api`, `root` or `data`, the skill cannot be renamed: create it again as `{new_name}` with `[BS] Brief Skill` and `[CS] Create Skill`. The troubleshooting guide's `verify-failed` entry has the details." HALT (exit code 5, `halt_reason: "verify-failed"`, `emit-halt` phase `execute:verify`).
|
|
202
218
|
|
|
203
|
-
Report: "**Verified
|
|
219
|
+
Report: "**Verified:** no structural references to `{old_name}` remain inside the new location across the {number of `renamed_versions`} version(s) it checked. {if verification_warnings is non-empty: 'Informational body-text mentions retained in SKILL.md: {list}.'}"
|
|
204
220
|
|
|
205
221
|
### 6. Update Export Manifest
|
|
206
222
|
|
|
207
|
-
**If `manifest_exists = false` (step 1
|
|
223
|
+
**If `manifest_exists = false` (step 1 read no entry in the manifest):**
|
|
208
224
|
|
|
209
|
-
Skip this section entirely. Set `
|
|
225
|
+
Skip this section entirely. Set `manifest_rekeyed = false`. There is no manifest entry to re-key: the skill was never exported. Section 7 still rebuilds any managed section it finds, which drops a row of `{old_name}` if one is there.
|
|
210
226
|
|
|
211
|
-
Report: "**Manifest update skipped
|
|
227
|
+
Report: "**Manifest update skipped:** the export manifest has no entries. The rename is a pure on-disk operation."
|
|
212
228
|
|
|
213
|
-
**If `manifest_exists = true`:**
|
|
229
|
+
**If `manifest_exists = true`:** when the manifest has no `exports.{old_name}` (the skill was on disk but never exported), skip both items below: the manifest has nothing to change. Otherwise:
|
|
230
|
+
|
|
231
|
+
1. **Back up the manifest file** into the run folder, byte for byte, for the rollback below. A halt keeps the run folder, so the backup stays with the user too:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
cp "{skills_output_folder}/.export-manifest.json" "{run_dir}/export-manifest.backup.json"
|
|
235
|
+
```
|
|
214
236
|
|
|
215
|
-
|
|
216
|
-
2. **Re-key via the helper
|
|
237
|
+
When the copy fails, take the rollback below with the copy's first stderr line as `{manifest_error}`: this run has not changed the manifest yet.
|
|
238
|
+
2. **Re-key via the helper:**
|
|
217
239
|
|
|
218
240
|
```bash
|
|
219
|
-
|
|
241
|
+
uv run {manifestOpsHelper} {skills_output_folder} rename {old_name} {new_name}
|
|
220
242
|
```
|
|
221
243
|
|
|
222
|
-
The helper preserves `active_version`, `versions` map, and all fields, then writes the manifest atomically via temp + rename.
|
|
244
|
+
The helper preserves `active_version`, `versions` map, and all fields, then writes the manifest atomically via temp + rename. It prints its result as JSON on stdout, errors included, and exits 0 only when `status` is `"ok"`. On a non-zero exit, bind `{manifest_error}` ← `error` and `{manifest_status}` ← `status`. A `not_found` result carries no `error`, because `exports.{old_name}` left the manifest after the check above: when `{manifest_status}` is `not_found`, set `{manifest_error}` to "`exports.{old_name}` is no longer in the manifest". When stdout holds no JSON (a Python traceback), set `{manifest_error}` to the helper's stderr.
|
|
245
|
+
|
|
246
|
+
**Rollback on a failed backup or a helper non-zero exit:**
|
|
247
|
+
|
|
248
|
+
- After a failed backup, set `{manifest_restore}` to `unchanged`. After a failed re-key, ask the manifest helper which state it left, never reading the file by eye:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
uv run {manifestOpsHelper} {skills_output_folder} get {new_name}
|
|
252
|
+
uv run {manifestOpsHelper} {skills_output_folder} get {old_name}
|
|
253
|
+
```
|
|
223
254
|
|
|
224
|
-
|
|
255
|
+
The helper writes the manifest in one rename at its very end, so the only change a failed re-key can leave is the finished re-key. Only when the first prints `status` `ok` and the second `status` `not_found` (`exports.{new_name}` is there and `exports.{old_name}` is gone), restore the backup:
|
|
225
256
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
- Halt with: "**Manifest update failed:** {captured stderr}. Restored manifest from backup and rolled back new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "manifest-write-failed"`). In headless, emit the error envelope.
|
|
257
|
+
```bash
|
|
258
|
+
uv run {atomicWriteHelper} write --target "{skills_output_folder}/.export-manifest.json" < "{run_dir}/export-manifest.backup.json"
|
|
259
|
+
```
|
|
230
260
|
|
|
231
|
-
Set
|
|
261
|
+
Set `{manifest_restore}` to `restored` when it exits 0, else to `restore-failed`. In every other state (`exports.{old_name}` still there, `exports.{new_name}` absent, or a manifest that is missing or does not parse), this run did not change the manifest, and another process may have written it since step 1: set `{manifest_restore}` to `unchanged` and write nothing.
|
|
262
|
+
- `rm -rf {new_skill_group}`, plus `rm -rf {new_forge_group}` when `{forge_move}` is true (this run created it), each without a trailing `/`
|
|
263
|
+
- Halt with: "**Manifest update failed:** {manifest_error}. {if `{manifest_restore}` is `unchanged`: 'This run did not change the manifest.'}{if `restored`: 'Restored the manifest from the backup.'}{if `restore-failed`: 'Could not restore the manifest, which may still list `{new_name}` in place of `{old_name}`: re-key it back with `uv run {manifestOpsHelper} "{skills_output_folder}" rename {new_name} {old_name}`, or copy `{run_dir}/export-manifest.backup.json` back over it.'} Rolled back the new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "manifest-write-failed"`, `emit-halt` phase `execute:manifest`).
|
|
232
264
|
|
|
233
|
-
|
|
265
|
+
Set context flag `manifest_rekeyed = true` when the helper ran and exited 0, else `false` (no `exports.{old_name}` to re-key).
|
|
266
|
+
|
|
267
|
+
Report: "**Manifest updated:** re-keyed `exports.{old_name}` → `exports.{new_name}`." When it skipped the call: "**Manifest unchanged:** it has no `exports.{old_name}` entry."
|
|
234
268
|
|
|
235
269
|
### 7. Rebuild Context Files
|
|
236
270
|
|
|
237
|
-
After §6 re-keys the manifest from `{old_name}` to `{new_name}`, every IDE's context file (`CLAUDE.md`, `.cursorrules`, `AGENTS.md`, etc.) still carries the old name in its managed-section
|
|
271
|
+
After §6 re-keys the manifest from `{old_name}` to `{new_name}`, every IDE's context file (`CLAUDE.md`, `.cursorrules`, `AGENTS.md`, etc.) still carries the old name in its managed-section rows. This section rebuilds each one through `{rebuildManagedSectionsHelper}` (resolved in §0), the way export-skill writes it. It runs only on the success path: the §1 to §6 rollbacks never reach here. It is best-effort: nothing here halts or rolls back the rename.
|
|
272
|
+
|
|
273
|
+
**7a. Resolve the context files.** Map the `ides` list of `config.yaml` (an absent key is an empty list) through the IDE mapping export-skill writes the section with:
|
|
238
274
|
|
|
239
|
-
|
|
275
|
+
```bash
|
|
276
|
+
python3 {rebuildManagedSectionsHelper} resolve-targets --ides "{ides}"
|
|
277
|
+
```
|
|
240
278
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
4. If `config.yaml.ides` is absent or the mapping yields an empty list, fall back to `[{context_file: "{unknownIdeDefaultContextFile}", skill_root: "{unknownIdeDefaultSkillRoot}"}]` and emit a note: `No IDEs configured in config.yaml — defaulting to {unknownIdeDefaultContextFile}`.
|
|
279
|
+
`{ides}` is the comma-joined list. Store `targets` as `target_context_files` (one `{context_file, skill_root, ides}` entry per file; an IDE the mapping does not list, and an empty list, resolve to AGENTS.md with `.agents/skills/`), and show each `warnings[]` and `notes[]` line. When the helper exits non-zero, rebuild nothing: leave `context_files_updated` empty, set `context_files_failed` to the one entry `all context files: resolve-targets failed: {error}` (the helper's stderr when stdout holds no JSON), and go to §7c.
|
|
280
|
+
|
|
281
|
+
A target's file is `{context_path}`, its `{context_file}` in `{project-root}`, and `{target_paths}` is the `{context_path}` of every target, each quoted, space-separated, in the order of `target_context_files`.
|
|
245
282
|
|
|
246
283
|
**7b. Per-file loop.** For each entry in `target_context_files`:
|
|
247
284
|
|
|
248
|
-
1. **
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
- If it has `<!-- SKF:BEGIN -->` but no matching `<!-- SKF:END -->`, record the error against that file and continue to the next entry — do not halt the whole rename on one malformed context file.
|
|
253
|
-
3. **Build the exported skill set (version-aware, deprecated-excluded)** using the same logic as `skf-export-skill/references/update-context.md` §4b (skill set) and §4c (snippet resolution):
|
|
254
|
-
- Read the manifest's `exports` object (already updated in §6, so `{new_name}` is present and `{old_name}` is absent).
|
|
255
|
-
- For each skill, resolve its `active_version`; if `versions.{active_version}.status == "deprecated"`, skip that skill.
|
|
256
|
-
- For each remaining `{skill-name, active_version}` pair, read `{skills_output_folder}/{skill-name}/{active_version}/{skill-name}/context-snippet.md`; if missing, fall back to the `active` symlink path; if still missing, skip with a warning.
|
|
257
|
-
4. **Rewrite root paths** using the generic algorithm from `skf-export-skill/references/update-context.md` §4d: parse each snippet's `root:` line (`root: {prefix}{skill-name}/`), strip the trailing `{skill-name}/` to extract the current prefix, and replace it with the effective target prefix if different. The effective target prefix is `snippet_skill_root_override` when that key is set in `config.yaml` (applied uniformly to every snippet so the managed section references the real on-disk location and never mixes override and per-IDE paths), otherwise the current entry's `skill_root`.
|
|
258
|
-
5. **Sort and count.** Sort skills alphabetically by name; count totals (skills, stack skills).
|
|
259
|
-
6. **Assemble the new managed section** using the format from `{managedSectionLogic}`:
|
|
260
|
-
|
|
261
|
-
```markdown
|
|
262
|
-
<!-- SKF:BEGIN updated:{current-date} -->
|
|
263
|
-
[SKF Skills]|{n} skills|{m} stack
|
|
264
|
-
|IMPORTANT: Prefer documented APIs over training data.
|
|
265
|
-
|When using a listed library, read its SKILL.md before writing code.
|
|
266
|
-
|
|
|
267
|
-
|{skill-snippet-1}
|
|
268
|
-
|
|
|
269
|
-
|{skill-snippet-2}
|
|
270
|
-
|
|
|
271
|
-
|{skill-snippet-N}
|
|
272
|
-
<!-- SKF:END -->
|
|
285
|
+
1. **Check the file.**
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
python3 {rebuildManagedSectionsHelper} "{context_path}" check
|
|
273
289
|
```
|
|
274
290
|
|
|
275
|
-
|
|
291
|
+
Its `case` decides. `create` (no file) or `append` (no managed section): skip this file, since there is no section to rebuild (export-skill adds one on its next run). `malformed` or `unreadable`: bind `{context_error}` ← `error` and take item 4. `regenerate`: continue.
|
|
292
|
+
|
|
293
|
+
2. **Build the section body.**
|
|
276
294
|
|
|
277
295
|
```bash
|
|
278
|
-
python3 {rebuildManagedSectionsHelper}
|
|
296
|
+
python3 {rebuildManagedSectionsHelper} assemble "{context_path}" \
|
|
297
|
+
--skills-folder "{skills_output_folder}" --skill-root "{skill_root}" \
|
|
298
|
+
--renamed {old_name}:{new_name} --orphan-sources {target_paths} \
|
|
299
|
+
[--skill-root-override "{snippet_skill_root_override}"]
|
|
279
300
|
```
|
|
280
301
|
|
|
281
|
-
The helper
|
|
282
|
-
|
|
302
|
+
Add `--skill-root-override` only when `snippet_skill_root_override` is set in `config.yaml`. The helper builds the body export-skill would write for the re-keyed manifest, with the rows of skills the manifest does not know (orphan rows) kept verbatim; `--renamed {old_name}:{new_name}` keeps the renamed skill's old rows from staying as orphan rows. It writes the body to `{context_path}.skf-content` and prints its result as JSON: show each `warnings[]` line and each `skipped_*` entry as a warning. On a non-zero exit, bind `{context_error}` ← `error` and take item 4.
|
|
303
|
+
|
|
304
|
+
3. **Replace the section.** Feed the staged body to the helper on stdin. Never pass the body inline as `--content "…"` or through `echo`: the shell would expand the backticks and `$` the snippets carry.
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
python3 {rebuildManagedSectionsHelper} "{context_path}" replace < "{context_path}.skf-content"
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Delete `{context_path}.skf-content` once the helper returns, whatever its exit code. It refuses a body that holds a marker of its own, and then leaves the file unchanged. It exits 0 only when the `status` of its JSON is `"ok"`. On a non-zero exit, bind `{context_error}` ← `error`, or the helper's stderr when stdout holds no JSON.
|
|
311
|
+
|
|
312
|
+
4. **On per-file failure**, record `{context_error}` against that context file and continue to the next entry. Do not halt the rename on a per-context-file error: the manifest and filesystem are already consistent, so the context files can be rebuilt later with `[EX] Export Skill`.
|
|
283
313
|
|
|
284
314
|
**7c. After the loop**, record:
|
|
285
315
|
|
|
@@ -288,46 +318,62 @@ After §6 re-keys the manifest from `{old_name}` to `{new_name}`, every IDE's co
|
|
|
288
318
|
|
|
289
319
|
Report: `**Rebuilt managed sections in:** {list of updated files}. {if any failed: 'Failed: {list} — re-run [EX] Export Skill to retry.'}` Then proceed to §8.
|
|
290
320
|
|
|
291
|
-
**Note:** §7 failures do not trigger a rollback
|
|
321
|
+
**Note:** §7 failures do not trigger a rollback, and never delete `{new_skill_group}`. Platform context files are derived artifacts; the manifest and on-disk skill directories are the canonical state.
|
|
292
322
|
|
|
293
323
|
### 8. Delete Old Directories (Point of No Return)
|
|
294
324
|
|
|
295
|
-
This is the only section after which rollback is impossible. Precondition: §1–7 have fully materialized and verified the new name (
|
|
325
|
+
This is the only section after which rollback is impossible. Precondition: §1–7 have fully materialized and verified the new name (the new directories renamed, no `{old_name}` references remaining, manifest re-keyed, context files rebuilt best-effort) — only now is deleting the old name safe.
|
|
296
326
|
|
|
297
|
-
|
|
327
|
+
Delete the old folders through the guarded delete of `{skillInventoryHelper}` (resolved in §0), never by hand, with the skills folder and the forge folder as the only folders it may delete inside:
|
|
298
328
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
6. Verify deletion succeeded
|
|
329
|
+
```bash
|
|
330
|
+
uv run {skillInventoryHelper} guarded-delete --root "{skills_output_folder}" --root "{forge_data_folder}" "{old_skill_group}"
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Only when `{forge_move}` is true, add `"{old_forge_group}"` after `"{old_skill_group}"`. Otherwise the forge folder stays: `{forge_left_in_place}` keeps its name, and with `{same_folder}` the skill folder is the forge folder. The helper removes any trailing `/`, deletes only a plain folder inside a root that no link or junction leads to (SKF never deletes through a link), and checks that each one is gone. Bind `deletion_errors` ← `delete_failures` (each `{path, error}`). On a non-zero exit, or no JSON on stdout, record the helper's `error` (its stderr when stdout holds no JSON) against each path in `deletion_errors`.
|
|
305
334
|
|
|
306
335
|
**On deletion error:**
|
|
307
336
|
|
|
308
|
-
- Record the error in `deletion_errors` against the specific path
|
|
309
|
-
- Continue attempting the other path — partial cleanup is still better than none
|
|
310
337
|
- Do NOT attempt any rollback — the new name is already committed and the old name's remnants can be removed manually
|
|
311
338
|
|
|
312
|
-
Report: "**Deleted old directories:** `{old_skill_group}` and `{old_forge_group}
|
|
339
|
+
Report: "**Deleted old directories:** `{old_skill_group}`{if forge_move: ' and `{old_forge_group}`'}. {if deletion_errors is non-empty: 'Errors: {list} — remove manually with `rm -rf {path}`.'}"
|
|
340
|
+
|
|
341
|
+
**Installed copies.** A copy `npx skills add` installed in an IDE skill folder keeps the old name, while §7 pointed the rows at `{new_name}`. When `snippet_skill_root_override` is unset in `config.yaml`, list the copies under the `skill_root` of the `target_context_files` entries:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
for root in {the skill_root of each target_context_files entry, each quoted}; do
|
|
345
|
+
[ "{project-root}/${root}" -ef "{skills_output_folder}" ] && continue
|
|
346
|
+
copy="{project-root}/${root}{old_name}"
|
|
347
|
+
if [ -e "$copy" ] || [ -L "$copy" ]; then printf '%s\n' "$copy"; fi
|
|
348
|
+
done | sort -u
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Bind `installed_copies` to the lines it prints, each a folder or a link (a dangling one included): empty when the override is set or §7a resolved no target. It skips a skill root that is the skills folder itself, where the path is `{old_skill_group}`, gone after the delete or reported in `deletion_errors`. Record each path in the run sink, and never stop on the result:
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
uv run {emitEnvelopeHelper} record --run-dir "{run_dir}" --warning "installed-copy-not-renamed: {path}"
|
|
355
|
+
```
|
|
313
356
|
|
|
314
357
|
### 9. Store Results in Context
|
|
315
358
|
|
|
316
359
|
Store the following for step 3:
|
|
317
360
|
|
|
318
|
-
- `old_name
|
|
319
|
-
- `new_name
|
|
320
|
-
- `affected_versions
|
|
321
|
-
- `
|
|
322
|
-
- `
|
|
323
|
-
- `
|
|
324
|
-
- `
|
|
325
|
-
- `
|
|
326
|
-
- `
|
|
327
|
-
- `
|
|
328
|
-
- `
|
|
329
|
-
- `
|
|
330
|
-
- `
|
|
361
|
+
- `old_name`: the previous skill name
|
|
362
|
+
- `new_name`: the new skill name
|
|
363
|
+
- `affected_versions`: every version step 1 §7 listed, the version folders §1 copied, including any whose package §2 found missing
|
|
364
|
+
- `manifest_rekeyed`: true only when section 6 ran the re-key and the helper exited 0
|
|
365
|
+
- `context_files_updated`: list of successfully rebuilt files
|
|
366
|
+
- `context_files_failed`: list of files that failed to rebuild (empty if none)
|
|
367
|
+
- `verification_warnings`: list of informational SKILL.md body mentions of `{old_name}` retained (empty if none)
|
|
368
|
+
- `deletion_errors`: list of post-commit deletion errors (empty if none)
|
|
369
|
+
- `installed_copies`: the copies §8 found installed under `{old_name}` in IDE skill folders (empty if none)
|
|
370
|
+
- `target_version`: the version §4 pointed `active` at (unset when the old skill had no `active` link)
|
|
371
|
+
- `forge_move`: carried from step 1 (true when the forge folder was moved)
|
|
372
|
+
- `forge_left_in_place`: carried from step 1 (the forge folder left under the old name, or null)
|
|
373
|
+
- `same_folder`: carried from step 1 (true when `skills_output_folder` and `forge_data_folder` name one folder)
|
|
374
|
+
- `run_id`, `run_dir` and `lock_owner`: carried from step 1
|
|
375
|
+
|
|
376
|
+
§2's record, `{run_dir}/rename-rewrite.json`, holds `renamed_versions`, `files_rewritten`, `counts`, `package_warnings` and `missing_files`: step 3 reads them there. The run's auto-decisions stay in `{run_dir}`, where step 1's gates recorded them.
|
|
331
377
|
|
|
332
378
|
### 10. Load Next Step
|
|
333
379
|
|