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,34 +1,63 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'sub/fetch-temporal.md'
|
|
3
3
|
componentExtractionStepFile: 'component-extraction.md'
|
|
4
|
-
extractionPatternsData: 'references/extraction-patterns.md'
|
|
5
4
|
extractionPatternsTracingData: 'references/extraction-patterns-tracing.md'
|
|
6
5
|
tierDegradationRulesData: 'references/tier-degradation-rules.md'
|
|
7
6
|
sourceResolutionData: 'references/source-resolution-protocols.md'
|
|
8
7
|
authoritativeFilesProtocol: 'references/authoritative-files-protocol.md'
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- '{project-root}/src/shared/scripts/skf-atomic-write.py'
|
|
15
|
-
# Resolve `{detectScriptsAssetsHelper}` to the first existing path; HALT if
|
|
16
|
-
# neither candidate exists. §4c relies on the helper for deterministic
|
|
17
|
-
# script/asset detection (file walk, SHA-256 hashing, header-comment purpose
|
|
18
|
-
# extraction); falling back to prose-driven detection would lose hash stability.
|
|
8
|
+
cccIndexCheckData: 'references/ccc-index-check.md'
|
|
9
|
+
entryPointsByHandData: 'references/entry-points-by-hand.md'
|
|
10
|
+
# Each probe order lists the installed path first, then the src/ dev-checkout
|
|
11
|
+
# path; the first existing path wins. §4c: deterministic script and asset
|
|
12
|
+
# detection, with stable hashes.
|
|
19
13
|
detectScriptsAssetsProbeOrder:
|
|
20
14
|
- '{project-root}/_bmad/skf/shared/scripts/skf-detect-scripts-assets.py'
|
|
21
15
|
- '{project-root}/src/shared/scripts/skf-detect-scripts-assets.py'
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# authoritative AI documentation files, classify each against scope
|
|
25
|
-
# filters + amendments, and load previews + content hashes — all five
|
|
26
|
-
# deterministic phases in one call. Falling back to prose-driven file
|
|
27
|
-
# walking + glob matching + hashing would let the LLM drift on the
|
|
28
|
-
# heuristic list and miss auth-doc files at deeper directory depths.
|
|
16
|
+
# §2a: the authoritative-files scan, classification, previews and hashes in
|
|
17
|
+
# one call.
|
|
29
18
|
resolveAuthoritativeFilesProbeOrder:
|
|
30
19
|
- '{project-root}/_bmad/skf/shared/scripts/skf-resolve-authoritative-files.py'
|
|
31
20
|
- '{project-root}/src/shared/scripts/skf-resolve-authoritative-files.py'
|
|
21
|
+
# Resolve `{cccGitHygieneHelper}` to the first existing path. It keeps ccc's
|
|
22
|
+
# index folders and SKF's workspace lock out of git, and undoes the
|
|
23
|
+
# `.gitignore` edit `ccc init` makes in a workspace clone. If neither path
|
|
24
|
+
# exists, skip the call and continue: it never gates the workflow.
|
|
25
|
+
cccGitHygieneProbeOrder:
|
|
26
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-ccc-git-hygiene.py'
|
|
27
|
+
- '{project-root}/src/shared/scripts/skf-ccc-git-hygiene.py'
|
|
28
|
+
# §2b reads a remote source into a private tree through it, and step 7 and
|
|
29
|
+
# every HALT after §2b remove the tree; without it §2b reads the source by
|
|
30
|
+
# eye.
|
|
31
|
+
sourceTreeProbeOrder:
|
|
32
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-source-tree.py'
|
|
33
|
+
- '{project-root}/src/shared/scripts/skf-source-tree.py'
|
|
34
|
+
# §2b's deferred ccc discovery prepares the clone's settings.yml; skipped
|
|
35
|
+
# without it.
|
|
36
|
+
mergeCccExclusionsProbeOrder:
|
|
37
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-merge-ccc-exclusions.py'
|
|
38
|
+
- '{project-root}/src/shared/scripts/skf-merge-ccc-exclusions.py'
|
|
39
|
+
# §4's recipe runner (--mode full); without it §4 follows the protocol's
|
|
40
|
+
# fallback.
|
|
41
|
+
extractPublicApiProbeOrder:
|
|
42
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-extract-public-api.py'
|
|
43
|
+
- '{project-root}/src/shared/scripts/skf-extract-public-api.py'
|
|
44
|
+
# Steps 5 and 6 bind it the same way.
|
|
45
|
+
extractionPatternsDataProbeOrder:
|
|
46
|
+
- '{project-root}/_bmad/skf/skf-create-skill/references/extraction-patterns.md'
|
|
47
|
+
- '{project-root}/src/skf-create-skill/references/extraction-patterns.md'
|
|
48
|
+
# §3 and §5 write the inventory through it (`init`, `patch`, `add`, `set`);
|
|
49
|
+
# steps 3c and 4 append with its `add`, and step 7 writes the rules with it.
|
|
50
|
+
extractionInventoryProbeOrder:
|
|
51
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-extraction-inventory.py'
|
|
52
|
+
- '{project-root}/src/shared/scripts/skf-extraction-inventory.py'
|
|
53
|
+
# §2a's protocol records each decision in the brief through its `amend`.
|
|
54
|
+
writeSkillBriefProbeOrder:
|
|
55
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-write-skill-brief.py'
|
|
56
|
+
- '{project-root}/src/shared/scripts/skf-write-skill-brief.py'
|
|
57
|
+
# HARD HALT helper (Rules).
|
|
58
|
+
emitEnvelopeProbeOrder:
|
|
59
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
|
|
60
|
+
- '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
|
|
32
61
|
---
|
|
33
62
|
|
|
34
63
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -42,104 +71,115 @@ To extract all public exports, function signatures, type definitions, and co-imp
|
|
|
42
71
|
## Rules
|
|
43
72
|
|
|
44
73
|
- Focus only on extracting exports, signatures, types from source code — do not compile SKILL.md
|
|
45
|
-
-
|
|
74
|
+
- Write only beside the staging folder (the recipe runner's JSON, §4, the detector's JSON, §4c, and the extraction inventory, §5), and the brief only through §2a's protocol
|
|
46
75
|
- Every extracted item must have a provenance citation: `[AST:{file}:L{line}]` or `[SRC:{file}:L{line}]`
|
|
76
|
+
- A HARD HALT, once step 3 §2b has bound `{source_tree}`, first runs `uv run {sourceTreeHelper} close --tree "{source_tree}"` from `{project-root}` (resolved from `{sourceTreeProbeOrder}`) and goes on whatever it prints, and emits through `{emitEnvelopeHelper}`, resolved from `{emitEnvelopeProbeOrder}` when it is not bound. After its envelope, under `--batch` it ends only this brief: return to `references/batch-mode.md` §3, even when the halt reads as the end of the run.
|
|
47
77
|
|
|
48
78
|
## MANDATORY SEQUENCE
|
|
49
79
|
|
|
50
80
|
### 1. Load Extraction Patterns
|
|
51
81
|
|
|
52
|
-
|
|
82
|
+
Resolve `{extractionPatternsData}` ← first existing path in `{extractionPatternsDataProbeOrder}` and load it up to its `## Running the Recipes Without the Runner` heading, for the current tier's strategy and the AST Extraction Protocol: the rest (the decision tree, the CLI streaming template and the recipes) serves only a run without the recipe runner, and the protocol's **When the Runner Cannot Run** section sends such a run there. If neither path exists, **HARD HALT** (exit code 3, `helper-missing`, phase `extract`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot extract: extraction-patterns.md is missing. Re-install SKF, then re-run create-skill."
|
|
53
83
|
|
|
54
84
|
### 2. Apply Scope Filters
|
|
55
85
|
|
|
56
86
|
From the brief, apply scope and pattern filters:
|
|
57
87
|
|
|
58
|
-
- `scope.type
|
|
88
|
+
- `scope.type`: what to extract (`full-library`, `specific-modules`, `public-api`, `component-library`, `reference-app` or `docs-only`). A `reference-app` brief documents a whole app's wiring patterns rather than public exports: it triggers the compile-assembly overrides in `assets/compile-assembly-rules.md`, which replace "Key API Summary" with a "Pattern Surface" section and make `stats.exports_documented` count patterns.
|
|
59
89
|
- `scope.include` — file globs to include
|
|
60
90
|
- `scope.exclude` — file globs to exclude
|
|
61
91
|
|
|
62
|
-
Build the filtered file list from the source tree resolved in step 1
|
|
92
|
+
At Forge tier and above the recipe runner (§4) applies these globs to the source tree itself, and its `files_in_scope` is the filtered file count. Build the filtered file list by hand only where a step reads it: at Quick tier, for a `component-library` brief (§2c), and in a §4 branch that extracts without the runner. Build it from the source tree resolved in step 1 (for a remote source at Forge tier or above, §2b builds it again from the tree it reads), matching the globs by the **Files in scope** rule of the Recipe Runner section in `{extractionPatternsData}`, and record the result: "**Filtered file count: {N} files in scope**".
|
|
63
93
|
|
|
64
|
-
|
|
94
|
+
Sections 2b and 2a follow in that order: §2b resolves the source to a local tree, and §2a scans that tree for authoritative files.
|
|
65
95
|
|
|
66
|
-
|
|
96
|
+
### 2b. Resolve Source Access
|
|
67
97
|
|
|
68
|
-
|
|
98
|
+
**Start clean:** first, for every brief, docs-only included, set `{source_tree}`, `{workspace_clone}` and `{remote_clone_path}` to null and `{resolved-source-path}` to `{source_root}` (null for a docs-only brief), so that in a `--batch` run one brief's source never carries into the next. Bind `{extraction_inventory}` ← `{project-root}/_bmad-output/.skf-stage/{skill-name}.inventory.json`, `{detected_json}` ← `{project-root}/_bmad-output/.skf-stage/{skill-name}.detected.json` and `{extraction_json}` ← `{project-root}/_bmad-output/.skf-stage/{skill-name}.extraction.json`, and run `rm -f "{extraction_inventory}" "{detected_json}" "{extraction_json}" "{project-root}/_bmad-output/.skf-stage/{skill-name}.language-guide.json"`: §4 (or step 3d), §4c, §5 and step 3c write this run's, so §5 never seeds from an earlier run's runner JSON and step 5 never reads an earlier run's Language Guide.
|
|
69
99
|
|
|
70
|
-
|
|
100
|
+
**If `source_type: "docs-only"`:** skip the rest of §2b: there is no source to resolve. Proceed directly to §2c (component library delegation, which is itself skipped for docs-only) and then §3 (Check for Docs-Only Mode). Tag resolution, reading the source into a tree, source-commit capture, version reconciliation, and deferred CCC discovery all require a source tree and have nothing to do in docs-only mode.
|
|
71
101
|
|
|
72
|
-
|
|
102
|
+
Load `{sourceResolutionData}` completely. It says which brief field picks the ref and how to choose between several matching tags, and it holds the tag warnings, the Local Source Warning, Source Commit Capture and Version Reconciliation.
|
|
73
103
|
|
|
74
|
-
**
|
|
104
|
+
**Local source, or a Quick-tier remote source:** nothing to resolve. Apply the Local Source Warning to a local path. A Quick-tier remote source is read through `gh_bridge` in §4, and its `source_ref` is `HEAD`.
|
|
75
105
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
106
|
+
**Remote source at Forge, Forge+ or Deep tier:** `{sourceTreeHelper}` reads the source into a private tree at one commit, which no other run can move, and in the same call moves SKF's workspace clone of the repository to that commit (`{sourceResolutionData}` "Remote Source Resolution"). Resolve `{sourceTreeHelper}` ← first existing path in `{sourceTreeProbeOrder}`; it stays bound for the rest of the run (step 7 and every HALT use it). Resolve `{cccGitHygieneHelper}` ← first existing path in `{cccGitHygieneProbeOrder}`. Bind `{tree_timeout}` to the seconds the helper may take, a little under the longest timeout your shell tool can be given, since a first fetch of a large repository is slow: `540` when it takes a 10-minute timeout, `100` when its longest is two minutes or you do not know it. Give the command that longest shell timeout: the helper stops itself within `--timeout` seconds and still prints its result. From `{project-root}`, run:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv run {sourceTreeHelper} resolve \
|
|
110
|
+
--source-repo "{source_repo}" \
|
|
111
|
+
[--target-ref "{brief.target_ref}"] \
|
|
112
|
+
[--version "{brief.target_version}" --name "{brief.name}"] \
|
|
113
|
+
[--version "{brief.version}" --implicit] \
|
|
114
|
+
--update-clone \
|
|
115
|
+
[--hygiene-helper "{cccGitHygieneHelper}"] \
|
|
116
|
+
--timeout "{tree_timeout}"
|
|
117
|
+
```
|
|
81
118
|
|
|
82
|
-
|
|
119
|
+
Pass `--target-ref` when the brief sets `target_ref`. Pass the first `--version` line when the brief sets `target_version`, else the second when it sets `version`, never both. Pass `--hygiene-helper` when `{cccGitHygieneHelper}` resolved.
|
|
83
120
|
|
|
84
|
-
|
|
121
|
+
Bind from its JSON `source_ref` ← `source_ref`, `source_commit` ← `source_commit`, `tag_resolution` ← `tag_resolution`, `{workspace_path}` ← `workspace_path`, `{workspace_clone}` ← `clone`, `{source_tree}` ← `tree`, `{source_resolve_status}` ← `status`, `{source_resolve_reason}` ← `reason`, `{source_resolve_message}` ← `message`, `{clone_status}` ← `clone_status` and `{clone_skip_reason}` ← `clone_skip_reason`, and display each entry of `warnings`.
|
|
85
122
|
|
|
86
|
-
|
|
87
|
-
- `tools.ccc` is true in forge-tier.yaml
|
|
88
|
-
- `{ccc_discovery}` is empty (step 2b deferred because source was remote)
|
|
89
|
-
- `remote_clone_path` is set (source resolution succeeded for a remote URL)
|
|
90
|
-
- Tier is Forge+ or Deep
|
|
123
|
+
Dispatch on `{source_resolve_status}`:
|
|
91
124
|
|
|
92
|
-
|
|
125
|
+
- **`ready`** (exit 0): bind `{source_root}` ← `{source_tree}`. Every later read of the source reads this tree: the §2 file list, the §2a scan, extraction, step 6's citation check and step 7's script and asset copies. Build the §2 filtered file list again from `{source_root}` when §2 builds one (a `component-library` brief), since step 1 listed the remote's default branch, which need not hold `source_commit`. Bind `{resolved-source-path}` ← `{workspace_clone}`, or ← `{source_repo}` when `{workspace_clone}` is null (the folder at `{workspace_path}` is not SKF's clone of the repository): it is the `source_root` metadata.json records (`{sourceResolutionData}` "Source Commit Capture"). When `{clone_status}` is `advanced` or `ok`, SKF's clone now holds `source_commit`: bind `{remote_clone_path}` ← `{workspace_clone}`, the folder the deferred ccc discovery below and step 7 §6b index. Otherwise leave it null and display "SKF's clone of `{source_repo}` at `{workspace_path}` was not moved ({clone_skip_reason}), so this run skips ccc discovery and the ccc index registration. Extraction reads this run's own tree." Then report the outcome of `tag_resolution` as `{sourceResolutionData}` "Tag Resolution" says.
|
|
126
|
+
- **`ambiguous`** (exit 0): several tags match, and nothing was read. Make the choice in `{sourceResolutionData}` "Several Matching Tags", run the command again with `--target-ref "{chosen tag}"` (`HEAD` for the default branch) in place of `--version`, `--name`, `--implicit` and any `--target-ref` from the brief, and dispatch on that result.
|
|
127
|
+
- **`skipped`** (exit 0): the helper does not read `{source_repo}` as a remote repository (`skip_reason` is `not-remote`), so treat it as a local source, above.
|
|
128
|
+
- **`unavailable`** (exit 3): no commit could be read, and no tree was left behind (`{source_resolve_reason}` is `invalid-ref`, `git-unavailable`, `upstream-unreachable`, `ref-not-found`, `fetch-failed`, `checkout-failed`, `tree-folder-failed` or `timed-out`). ⚠️ Warn the user explicitly: "Could not read `{source_repo}`: {source_resolve_message}. Degrading to source reading (T1-low) for this run. For T1 (AST-verified) confidence, clone the repository locally and update `source_repo` in your brief to the local path." Keep `{source_root}` the remote URL, bind `source_ref` ← `source_ref` when it is not null and `HEAD` otherwise, and extract with the Quick tier strategy in §4. Note the degradation reason in context for the evidence report.
|
|
129
|
+
- **No candidate resolves, or the command exits 1 or 2, or prints no JSON:** continue as for `unavailable`, with `{source_resolve_message}` = "skf-source-tree.py did not finish: {the first stderr line; 'the shell stopped it before it printed a result' when your shell tool's timeout ended it; or 'it is missing; re-install SKF'}". A later run removes a tree a stopped run left behind once it is seven days old.
|
|
93
130
|
|
|
94
|
-
|
|
131
|
+
Then run Source Commit Capture and Version Reconciliation from `{sourceResolutionData}` on `{source_root}`. This ensures source code is accessible regardless of which extraction path is taken below (standard, component-library, or docs-only).
|
|
95
132
|
|
|
96
|
-
|
|
133
|
+
**Deferred CCC Discovery (Forge+ and Deep, remote sources only):**
|
|
97
134
|
|
|
98
|
-
|
|
135
|
+
If ALL of these conditions are true:
|
|
136
|
+
- `tools.ccc` is true in forge-tier.yaml
|
|
137
|
+
- `{ccc_discovery}` is empty (step 2b deferred because source was remote)
|
|
138
|
+
- `{remote_clone_path}` is set (SKF's clone holds `source_commit`)
|
|
139
|
+
- Tier is Forge+ or Deep
|
|
99
140
|
|
|
100
|
-
|
|
101
|
-
node_modules/, dist/, build/, .git/, vendor/, __pycache__/, .cache/, .next/, .nuxt/, target/, out/, .venv/, .tox/
|
|
102
|
-
```
|
|
141
|
+
Then index SKF's clone and search it. The clone persists across forges, so an index an earlier forge built there is brought up to date rather than rebuilt. ccc's results only rank files; extraction still reads `{source_root}`.
|
|
103
142
|
|
|
104
|
-
|
|
143
|
+
1. **Prepare the settings:** resolve `{mergeCccExclusionsHelper}` ← first existing path in `{mergeCccExclusionsProbeOrder}` and, from `{project-root}`, run `uv run {mergeCccExclusionsHelper} --clone-root "{remote_clone_path}"`. It runs `ccc init -f` in the clone when `.cocoindex_code/settings.yml` is missing, and appends the standard build and dependency exclusions the file lacks (`**/node_modules`, `**/dist`, `**/build`, `**/target` and the like), on a first run and on a reused index alike, keeping every entry already there. These are standard artifact patterns, not SKF paths: the clone is a source repository, not an SKF project. When `settings_yml_existed` is true and `patterns_added_list` is not empty, display: "Added {patterns_added} standard exclusions to the reused workspace index settings." When `settings_ready` is false, the command fails or no candidate resolves, set `{ccc_discovery: []}` and continue: this is not an error.
|
|
105
144
|
|
|
106
|
-
**Note:** Brief-specific `include_patterns` and `exclude_patterns` are not written to `settings.yml`. The CCC index is general-purpose
|
|
145
|
+
**Note:** Brief-specific `include_patterns` and `exclude_patterns` are not written to `settings.yml`. The CCC index is general-purpose: it indexes everything (minus standard artifacts). Brief-specific filtering happens at search result time, not index time. This allows a single workspace CCC index to serve multiple briefs with different scope filters.
|
|
107
146
|
|
|
108
|
-
|
|
147
|
+
2. **Index the clone:** run `cd "{remote_clone_path}" && ccc index` in the foreground with an extended timeout. Indexing can take several minutes on large codebases (1000+ files); a reused index processes only what changed. Then load `{cccIndexCheckData}` and run it with `{ccc_root}` = `{remote_clone_path}` and `{ccc_settings_owner}` = `skf`. On **index unverified**, display "CCC index still building (index unverified), skipping the language check." and continue to step 3. When `ccc index` fails, or the check returns **degraded**, set `{ccc_discovery: []}` and continue: this is not an error.
|
|
109
148
|
|
|
110
|
-
|
|
149
|
+
3. **Construct semantic query:** Build from brief data: `"{brief.name} {brief.scope}"`. Truncate to 80 characters: keep the full skill name and trim `brief.scope` from the end. If `brief.scope` is very short (< 10 chars), append terms from `brief.description` to fill the remaining space.
|
|
111
150
|
|
|
112
|
-
|
|
113
|
-
- **If existing index was found (step 1):** Use `cd {remote_clone_path} && ccc search --refresh --limit 20 "{query}"` — this re-indexes if files changed, then searches. If `--refresh` is not supported by the installed ccc version, omit the flag — ccc will use the existing index.
|
|
114
|
-
- **Otherwise:** Use `cd {remote_clone_path} && ccc search --limit 20 "{query}"` after indexing in step 3.
|
|
151
|
+
4. **Execute search:** Run `ccc_bridge.search(query, remote_clone_path, top_k=20)` as `cd "{remote_clone_path}" && ccc search --limit 20 "{query}"`. Step 2 has just brought the index up to date, whether it was reused or new, so the search needs no refresh flag.
|
|
115
152
|
- **Tool resolution:** Use `/ccc` skill search (Claude Code), ccc MCP server (Cursor), or CLI. Note: `ccc search` operates on the index in the current working directory. See `knowledge/tool-resolution.md`.
|
|
116
153
|
|
|
117
|
-
|
|
154
|
+
5. **Store results:** If search succeeds, store as `{ccc_discovery: [{file, score, snippet}]}`. Display: "**CCC semantic discovery: {N} relevant regions identified across {M} unique files.**"
|
|
155
|
+
|
|
156
|
+
If step 1 reported `settings_yml_existed` true (an earlier forge's index was reused), append: "(reused workspace index)"
|
|
118
157
|
|
|
119
|
-
|
|
158
|
+
6. **On failure:** Set `{ccc_discovery: []}`. Display: "CCC discovery unavailable, proceeding with standard extraction." Do not halt.
|
|
120
159
|
|
|
121
|
-
|
|
160
|
+
**Leave the workspace clone clean:** run `uv run {cccGitHygieneHelper} workspace --repo "{remote_clone_path}"` from `{project-root}` once this block is done with the clone: after step 5 or step 6, and also when step 1 or step 2 set `{ccc_discovery: []}`. Every `ccc init` or `ccc index` that creates `settings.yml` in a clone (the helper's `ccc init -f`, or a `ccc index` that initializes the clone itself) appends `# CocoIndex Code (ccc)` and `/.cocoindex_code/` to the clone's tracked `.gitignore`, and that change would make a later forge's move of the clone to another ref fail. The helper restores the `.gitignore` when those two lines are its only change (or deletes a `.gitignore` holding only them) and keeps the index folder out of git through the clone's `.git/info/exclude` instead. Resolve `{cccGitHygieneHelper}` from `{cccGitHygieneProbeOrder}` and read nothing from its output; if neither path exists or the command fails, continue: the next resolve repairs the clone before it moves it.
|
|
122
161
|
|
|
123
162
|
**CCC Discovery Integration (Forge+ and Deep with ccc only):**
|
|
124
163
|
|
|
125
|
-
If `{ccc_discovery}` is in context and non-empty (populated by step 2b or deferred discovery above):
|
|
126
|
-
- Sort the filtered file list by CCC relevance score: files appearing in `{ccc_discovery}` results move to the front of the extraction queue, sorted by their relevance score descending
|
|
127
|
-
- Files not in CCC results remain in the queue after ranked files — they are not excluded, only deprioritized
|
|
128
|
-
- Display: "**CCC discovery: {N} files pre-ranked by semantic relevance** — extraction will prioritize these first."
|
|
164
|
+
If `{ccc_discovery}` is in context and non-empty (populated by step 2b or deferred discovery above), §4 and §4b read the files they read one at a time in its order, as the CCC Pre-Ranking Strategy in `{extractionPatternsData}` says. Display: "**CCC discovery: {N} files ranked by semantic relevance.** Files read one at a time follow this order."
|
|
129
165
|
|
|
130
166
|
If `{ccc_discovery}` is empty or not in context: proceed with existing file ordering (no change to current behavior).
|
|
131
167
|
|
|
132
|
-
###
|
|
168
|
+
### 2a. Discovered Authoritative Files Protocol
|
|
169
|
+
|
|
170
|
+
**Runs after §2b, not before it.** The scan walks a local tree, so it waits for §2b to resolve one: `{source_root}` now names the local source itself, or the private tree §2b read a remote source into, which no other run can move.
|
|
133
171
|
|
|
134
|
-
**
|
|
172
|
+
**Start clean:** set `authoritative_files_scan` to null and `promoted_docs[]` to empty before either skip below, so that in a `--batch` run one brief's scan never carries into the next.
|
|
135
173
|
|
|
136
|
-
**
|
|
174
|
+
**Skip this section entirely if `source_type: "docs-only"`:** there is no source tree to scan.
|
|
137
175
|
|
|
138
|
-
|
|
176
|
+
**Remote source guard:** if `source_root` is still a remote URL after §2b, there is no local tree to walk, and the helper refuses a source root that is not a directory. That happens for a Quick-tier remote source, which §2b never clones, and for a remote source §2b could not read into a tree, which it falls back to reading like Quick tier. Skip the scan and continue to §2c: record `authoritative_files_scan: {not_scanned: "remote source not cloned"}` for the evidence report and display "**Authoritative files scan skipped:** `{source_repo}` was not cloned in this run, so authoritative AI documentation files (`llms.txt`, `AGENTS.md` and the like) outside the brief's scope were not looked for. A run with a local tree (a local checkout, or a remote source cloned at Forge tier or higher) scans them."
|
|
139
177
|
|
|
140
|
-
Load
|
|
178
|
+
Load `{authoritativeFilesProtocol}` and execute it: it scans the source tree for authoritative AI documentation files (`llms.txt`, `AGENTS.md`, `.cursorrules` and the like) the brief's scope filters left out, and records each decision in the brief at once, so re-runs replay it.
|
|
179
|
+
|
|
180
|
+
### 2c. Component Library Delegation
|
|
141
181
|
|
|
142
|
-
**Otherwise
|
|
182
|
+
Skip this section for a `docs-only` brief. When `scope.type` is `"component-library"`, display "**Component library detected.** Delegating to specialized extraction strategy for registry-first, props-focused extraction.", load and execute `{componentExtractionStepFile}` completely, and when it returns control here resume at section 5 (Build Extraction Inventory) with its extraction data and `component_catalog[]`. Otherwise continue with standard extraction below.
|
|
143
183
|
|
|
144
184
|
### 3. Check for Docs-Only Mode
|
|
145
185
|
|
|
@@ -147,163 +187,162 @@ Load and execute `{componentExtractionStepFile}` completely. When that step comp
|
|
|
147
187
|
|
|
148
188
|
"**Docs-only mode:** No source code to extract. Documentation content will be fetched from `doc_urls` in step 3c."
|
|
149
189
|
|
|
150
|
-
|
|
190
|
+
Start the empty inventory with §5's `init` (resolve `{extractionInventoryHelper}` and halt as §5 says), from `{project-root}`:
|
|
151
191
|
|
|
152
|
-
|
|
192
|
+
```bash
|
|
193
|
+
uv run {extractionInventoryHelper} init --inventory "{extraction_inventory}" --skill "{name}" --mode docs-only --tier "{tier}"
|
|
194
|
+
```
|
|
153
195
|
|
|
154
|
-
|
|
196
|
+
It writes `extraction_mode: "docs-only"` with no export and no `top_exports`: steps 3b and 4 skip their per-export work on it, and step 3c merges its T3 items into it. When it fails twice, halt as §5 says. Auto-proceed through Gate 2 (section 6): display the empty inventory and note that the doc-fetcher step produces the T3 content.
|
|
155
197
|
|
|
156
|
-
|
|
198
|
+
**If `source_type: "source"` (default):** Continue with extraction below.
|
|
157
199
|
|
|
158
|
-
|
|
200
|
+
### 4. Execute Tier-Dependent Extraction
|
|
159
201
|
|
|
160
|
-
|
|
161
|
-
2. Identify entry points: index files, main exports, public modules
|
|
162
|
-
3. Use `gh_bridge.read_file(owner, repo, path)` to read each entry point
|
|
163
|
-
4. Extract from source text: exported function names, parameter lists, return types
|
|
164
|
-
5. Infer types from JSDoc, docstrings, type annotations
|
|
165
|
-
6. Confidence: All results T1-low — `[SRC:{file}:L{line}]`
|
|
202
|
+
Source resolution, version reconciliation, and CCC discovery were completed in section 2b. Run the Strategy for the current tier from `{extractionPatternsData}` (loaded in §1): source reading at Quick tier (and for a remote source §2b could not read into a tree), and at Forge, Forge+ and Deep the **AST Extraction Protocol** there, whose recipe runner reads `{source_root}` itself. A branch that extracts without the runner (source reading, or the protocol's fallback) reads the §2 filtered file list: build it first, from `{source_root}`, when §2 did not. Label each export by the tool that produced it, as that file's Confidence sections say.
|
|
166
203
|
|
|
167
|
-
**
|
|
204
|
+
**The recipe runner (Forge, Forge+ and Deep):** resolve `{extractPublicApiHelper}` ← first existing path in `{extractPublicApiProbeOrder}`; it writes `{extraction_json}` (bound in §2b, beside the staging folder step 5 creates, never inside the skill). From `{project-root}`, create that folder (the runner creates no folder) and remove the JSON an earlier run left there, then call the runner with the longest timeout your shell tool takes, since a large tree takes minutes:
|
|
168
205
|
|
|
169
|
-
|
|
206
|
+
```bash
|
|
207
|
+
mkdir -p "{project-root}/_bmad-output/.skf-stage"
|
|
208
|
+
rm -f "{extraction_json}"
|
|
209
|
+
uv run {extractPublicApiHelper} --mode full \
|
|
210
|
+
--source-root "{source_root}" \
|
|
211
|
+
--brief "{brief_path}" \
|
|
212
|
+
--tier "{tier}" \
|
|
213
|
+
-o "{extraction_json}"
|
|
214
|
+
```
|
|
170
215
|
|
|
171
|
-
|
|
216
|
+
`{brief_path}` is the `skill-brief.yaml` step 1 loaded: the runner takes its `scope.include`, `scope.exclude`, `scope.tier_a_include`, `scope.type` and `language` from it, and the head cap from `--tier`. A JSON at `{extraction_json}` after the call is this call's: read it, in parts when it is large, and act on its `status` and fields as the protocol's **Recipe Runner** section says, never on the exit code. Each export it returns is T1 as it stands, its `source_line`, `citation`, `ast_recipe`, `ast_node_type`, `signature`, `params` and `return_type` included: read a signature from the source, at its `source_line`, only for a function whose `params` is null, and read by eye (T1-low) only what the runner leaves. When no path resolves, or a case the protocol's **When the Runner Cannot Run** lists applies, such as no JSON at `{extraction_json}` after the call or an empty `scope.languages` (no recipe reads the brief's language), follow that section.
|
|
172
217
|
|
|
173
|
-
|
|
174
|
-
2. Follow the AST Extraction Protocol decision tree from `{extractionPatternsData}`:
|
|
175
|
-
- ≤100 files: use `find_code()` MCP tool with `max_results` and `output_format="text"`
|
|
176
|
-
- ≤500 files: use `find_code_by_rule()` MCP tool with scoped YAML rules
|
|
177
|
-
- >500 files: use CLI `--json=stream` with line-by-line streaming Python — inject the brief's `scope.exclude` patterns into the Python filter's `EXCLUDES` list (use `[]` if absent) so excluded files are discarded before consuming `head -N` slots (see template in extraction patterns data)
|
|
178
|
-
3. For each export: extract function name, full signature, parameter types, return type, line number
|
|
179
|
-
4. Use `ast_bridge.detect_co_imports(path, libraries[])` to find integration points
|
|
180
|
-
5. Build extraction rules YAML data for reproducibility
|
|
181
|
-
6. Confidence: All results T1 — `[AST:{file}:L{line}]`
|
|
218
|
+
**When `truncated` is true,** a recipe matched more exports than its head cap keeps, and the matches past the cap are missing: a public name among them comes back as an extraction gap (§4b), read by eye, and the others are left out. Warn, and keep the warning for §6 and the evidence report: "**Extraction hit the head cap:** {each `recipes[]` id whose `truncated` is true} matched more than {head_cap} exports, so some exports were read by eye or left out. Narrow `scope.include` in the brief until no recipe reaches the cap."
|
|
182
219
|
|
|
183
|
-
**
|
|
220
|
+
**Co-import detection (Forge tier and above):** use `ast_bridge.detect_co_imports(path, libraries[])` to find integration points: `find_code_by_rule` with a co-import YAML rule scoped to the libraries list, or `ast-grep scan -r {rule_file} --json=stream` (see `knowledge/tool-resolution.md`).
|
|
184
221
|
|
|
185
|
-
**If AST
|
|
222
|
+
**If AST tools are unavailable at Forge, Forge+ or Deep tier** (no ast-grep can run the recipes: see `{tierDegradationRulesData}` for full rules):
|
|
186
223
|
|
|
187
|
-
⚠️ **Warn the user explicitly:** "AST tools are unavailable
|
|
224
|
+
⚠️ **Warn the user explicitly:** "AST tools are unavailable, so extraction will use source reading (T1-low). Run [SF] Setup Forge to detect and configure AST tools for T1 confidence."
|
|
188
225
|
|
|
189
226
|
Degrade to Quick tier extraction. Note the degradation reason in context for the evidence report.
|
|
190
227
|
|
|
191
|
-
**For each file
|
|
228
|
+
**For each file, handle failures gracefully:**
|
|
192
229
|
|
|
193
230
|
- If a file cannot be read: log warning, skip file, continue with remaining files
|
|
194
|
-
- If AST parsing fails on a file: fall back to source reading for that file, continue
|
|
231
|
+
- If AST parsing fails on a file (the runner lists each one in `file_issues`): fall back to source reading for that file, continue
|
|
195
232
|
|
|
196
|
-
**Re-export tracing (Forge
|
|
233
|
+
**Re-export tracing (Forge tier and above):** the runner follows each entry point's re-exports to the file that defines each name. Follow the **Re-Export Tracing** protocol in `{extractionPatternsTracingData}` for what it could not follow: each `entry_points.unresolved` chain, and each `entry_point_diff.extraction_gaps` name with no `file`. Without the runner, check for unresolved public exports from entry points (`__init__.py`, `index.ts`, `lib.rs`) and follow the same protocol to resolve them to their definition files.
|
|
197
234
|
|
|
198
235
|
### 4b. Validate Exports Against Package Entry Point
|
|
199
236
|
|
|
200
|
-
After extraction, validate the collected exports against the package's actual public API surface
|
|
237
|
+
After extraction, validate the collected exports against the package's actual public API surface.
|
|
201
238
|
|
|
202
|
-
|
|
203
|
-
- In AST but not entry point → mark as internal (exclude from `metadata.json` exports)
|
|
204
|
-
- In entry point but not AST → flag as extraction gap (trace via re-export protocol)
|
|
205
|
-
- **TypeScript/JS:** Read `index.ts`/`index.js` — same comparison logic.
|
|
206
|
-
- **Rust:** Read `lib.rs` — extract `pub use` items. Same logic. **Go:** Scan for exported (capitalized) identifiers.
|
|
239
|
+
**When the recipe runner extracted (§4: its JSON's `status` is `ok` or `incomplete`, and `scope.languages` is not empty),** its `entry_point_diff` is this check: do not read the entry points or diff the sets yourself. It read each package's entry points, traced each re-exported name to the file that defines it, and diffed those names with the recipe matches (`skf-extract-public-api.py --help` lists the entry points it reads):
|
|
207
240
|
|
|
208
|
-
|
|
241
|
+
- `public`: the package's public names, which `metadata.json`'s `exports[]` lists. In a language with no entry point, or only empty ones (`entry_points.by_language`), every export the recipes found is public.
|
|
242
|
+
- `internal`: exports the recipes found that no entry point exports or makes reachable. §5's `init` marks each `internal: true` in the inventory, and step 5 keeps them out of `metadata.json`'s `exports[]`.
|
|
243
|
+
- `extraction_gaps`: names an entry point exports that no recipe found: read each by eye at its `file` and `line` (T1-low), or trace it (§4) when it has no `file`.
|
|
244
|
+
- `outside_scope`: names an entry point exports that are defined in files outside the brief's scope. Display each of the runner's `warnings` (one names each `package.json` `exports` subpath whose entry point is outside the files in scope) and list these names with them: widen `scope.include` before extraction, or this surface stays undocumented while `exports_public_api` still counts it, so `public_api_coverage` drops (only `effective_denominator`, for the curated-subset shapes, leaves it out).
|
|
209
245
|
|
|
210
|
-
|
|
211
|
-
- If a resolved `exports` subpath target falls **outside** the brief's `scope.include` globs, surface a note: `"warn: public entry point {path} (exports subpath '{subpath}') resolves outside scope.include — widen scope.include before extraction, or this surface stays undocumented and excluded from the coverage denominator."` Widening `scope.include` here keeps the documented surface aligned with the `effective_denominator` that compile.md §4 derives from those same globs, without mid-run scope surgery.
|
|
246
|
+
§5's `init` records its `counts` (`exports_public_api`, `exports_internal`, `effective_denominator` and `effective_denominator_basis`) and `arms` for step 5 §4. Files you read by eye because no recipe reads their language (`files_without_recipes`) are outside this diff and these counts: read their entry points as **Otherwise** says, add their names to the counts, and send the counts you changed with §5's `set`.
|
|
212
247
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
**If entry point is missing or unreadable:** Skip validation with a warning.
|
|
248
|
+
**Otherwise** (Quick tier, extraction by source reading, a brief whose language no recipe reads included, or the protocol's fallback), read the entry points yourself (when the runner's JSON has `status: no-ast-grep`, its `entry_points.files` lists them, and §5's `init` records its `arms` for step 5 §4): load `{entryPointsByHandData}`, which only this branch reads, compare and count as it says, and send the `counts` (and, without the runner's JSON, the `arms`) with §5's `set`.
|
|
216
249
|
|
|
217
250
|
### 4c. Detect and Inventory Scripts/Assets
|
|
218
251
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
Invoke the deterministic detector — it implements the heuristics from `{extractionPatternsTracingData}` (directory conventions, shebang signals, `package.json` `bin` entry-points, asset filename patterns, binary-extension exclusion, generated-path pruning) so this stage doesn't re-derive them per-run:
|
|
252
|
+
The brief's `scripts_intent` and `assets_intent` are each `"detect"` (also when absent), `"none"` or free text describing the files wanted. The detector takes only `detect` or `none`: pass `none` for `"none"`, else `detect`. Resolve `{detectScriptsAssetsHelper}` ← first existing path in `{detectScriptsAssetsProbeOrder}`; if neither exists, **HARD HALT** (exit code 3, `helper-missing`, phase `extract`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot detect scripts and assets: skf-detect-scripts-assets.py is missing. Re-install SKF, then re-run create-skill." The detector implements the heuristics of `{extractionPatternsTracingData}`. From `{project-root}`, write its JSON to `{detected_json}` (bound in §2b), which §5's `init` reads:
|
|
222
253
|
|
|
223
254
|
```bash
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
--
|
|
255
|
+
mkdir -p "{project-root}/_bmad-output/.skf-stage"
|
|
256
|
+
uv run {detectScriptsAssetsHelper} detect "{source_root}" \
|
|
257
|
+
--scripts-intent {detect|none} \
|
|
258
|
+
--assets-intent {detect|none} \
|
|
227
259
|
[--scope-include "<glob1>,<glob2>,..."] \
|
|
228
|
-
[--max-lines 500]
|
|
260
|
+
[--max-lines 500] > "{detected_json}"
|
|
229
261
|
```
|
|
230
262
|
|
|
231
|
-
|
|
263
|
+
It writes `scripts_inventory[]` and `assets_inventory[]` (each entry with `name`, `source_file`, `purpose`, `content_hash`, `confidence`, `lines` and `size_flag`), `scripts_skipped`, `assets_skipped` and `stats`.
|
|
232
264
|
|
|
233
|
-
|
|
234
|
-
{
|
|
235
|
-
"scripts_inventory": [ {name, source_file, purpose, language, content_hash, confidence, lines, size_flag}, ... ],
|
|
236
|
-
"assets_inventory": [ {name, source_file, purpose, type, content_hash, confidence, lines, size_flag}, ... ],
|
|
237
|
-
"scripts_skipped": <bool>,
|
|
238
|
-
"assets_skipped": <bool>,
|
|
239
|
-
"stats": { "scripts_found": N, "assets_found": M, "files_scanned": K }
|
|
240
|
-
}
|
|
241
|
-
```
|
|
265
|
+
**If it exits non-zero** (a `{source_root}` that is no local folder, as for a remote source read by eye): warn "Scripts and assets were not detected: {the first stderr line}", send the warning with §5's `add --field warnings` for §6 and the evidence report, and run §5's `init` without `--detected`: the inventories stay empty.
|
|
242
266
|
|
|
243
|
-
|
|
267
|
+
**Otherwise** §5's `init` takes every entry, unchanged and already `T1-low` with its `content_hash`, which is the inventory for a `"detect"` intent. For a free-text intent, choose the entries that match it and, after `init`, send them with §5's `set` as `{"intent_mapping": {"scripts": {"intent": "<the text>", "kept": [source_file, ...]}}}`, `"assets"` the same way: the helper keeps only those entries and records the others as the mapping's `left_out`, which §6 lists and step 5 writes into the evidence report. §6 surfaces each `size_flag: "oversized"` entry before bundling.
|
|
244
268
|
|
|
245
269
|
### 5. Build Extraction Inventory
|
|
246
270
|
|
|
247
|
-
|
|
271
|
+
`{extraction_inventory}` (bound in §2b, beside the staging folder, never inside the skill) is the run's extraction record: steps 3b to 7 read it, and steps 3c and 4 add to it, instead of a copy held in context. `{extractionInventoryHelper}` writes it, each call atomically: the runner's and the detector's records go in as those tools wrote them, and you send only what you produced. Resolve `{extractionInventoryHelper}` ← first existing path in `{extractionInventoryProbeOrder}`; if neither exists, **HARD HALT** (exit code 3, `helper-missing`, phase `extract`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot write the extraction inventory: skf-extraction-inventory.py is missing. Re-install SKF, then re-run create-skill." Run each call below from `{project-root}`.
|
|
272
|
+
|
|
273
|
+
**Start the inventory** with `init`, which replaces any file at `{extraction_inventory}`:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
uv run {extractionInventoryHelper} init --inventory "{extraction_inventory}" --skill "{name}" --mode {source|component-library} --tier "{tier}" [--extraction "{extraction_json}"] [--detected "{detected_json}"]
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Pass `--mode component-library` for a component library (§2c), else `source`. Pass `--extraction` when §4's runner, or step 3d's Phase 4 for a component library, left a JSON at `{extraction_json}`, and `--detected` when §4c's detector exited 0. From the runner's JSON, `init` writes each export as the runner recorded it (T1, `ast-grep`, with its `source_file`, `source_line`, `citation`, `ast_recipe`, `ast_node_type` and `export_type`), marked `internal: true` when §4b's `internal` lists it; `files_scanned` (the runner's `files_in_scope`); its `aggregates`, `counts` and `arms`; `extraction_rules` (its `recipe_set`, the `recipes` ids, its `scope` and `ast_grep.version`), from which step 7 writes `extraction-rules.yaml`; and the runner warnings in `warnings`, one line each: the head-cap warning (§4), each `errors[]` item, each `file_issues[]` file, each extension `files_without_recipes` counts, and each of its `warnings`. From the detector's JSON it writes `scripts_inventory` and `assets_inventory`.
|
|
248
280
|
|
|
249
|
-
**
|
|
250
|
-
- Function/type name
|
|
251
|
-
- Full signature with types
|
|
252
|
-
- Parameters (name, type, required/optional)
|
|
253
|
-
- Return type
|
|
254
|
-
- Source file and line number
|
|
255
|
-
- Provenance citation (`[AST:...]` or `[SRC:...]`)
|
|
256
|
-
- Confidence tier (T1 or T1-low)
|
|
281
|
+
**Then send what you produced**, each call with its JSON payload on stdin, leaving out a call with nothing to send:
|
|
257
282
|
|
|
258
|
-
**
|
|
259
|
-
-
|
|
260
|
-
-
|
|
261
|
-
-
|
|
262
|
-
- Confidence breakdown (T1 count, T1-low count)
|
|
263
|
-
- `top_exports[]` — sorted list of the top 10-20 public API function names by prominence (import frequency or documentation position). This named field is consumed by step 3b for targeted temporal fetching and cache fingerprinting.
|
|
283
|
+
- **Signatures** (`patch`): for each function export whose `params` the runner left null (and each Props interface of a component library), the full signature, the parameters (each as `{"name", "type", "default", "optional"}`, as the runner records them) and the return type you read from the source at its `source_line`. It sets only those three fields, matches each entry on `export_name` and `source_file`, and lists in `unmatched` and `ambiguous` the entries it could not place: correct those and send them again.
|
|
284
|
+
- **Exports read by eye** (`add --field exports`): each export §4 or §4b read by eye (an extraction gap, a `file_issues` file, a language no recipe reads, or every export when the runner did not run), with its `export_name`, `export_type`, `signature`, `params`, `return_type`, `source_file`, `source_line` and `[SRC:...]` citation. The helper labels it T1-low (`source-read`, with `ast_node_type` and `ast_recipe` null) unless the entry carries its own labels, as a `find_code` match of the protocol's fallback does (T1, `ast-grep`, the `kind` its recipe or pattern declares, and the pattern as its `ast_recipe`). A component library (§2c) sends here only the exports step 3d read by eye (Quick tier, a `file_issues` file, or the runner's fallback); it sends each Props interface's fields with `patch` as `params`, and `component_catalog` with `set`.
|
|
285
|
+
- **Warnings you raise** (`add --field warnings`): a list of strings, such as a degradation reason (§2b, §4), the detector's failure (§4c) or a file you could not read.
|
|
286
|
+
- **The rest** (`set`), in one JSON object: `top_exports`, the 10 to 20 public API function names by prominence (import frequency or documentation position), which step 3b's targeted temporal fetch reads; `co_imports` (Forge tier and above), the libraries commonly imported alongside the exports, with integration point suggestions; `promoted_docs` and `authoritative_files_scan`, §2a's records; `intent_mapping` for a free-text intent (§4c); a component library's `component_catalog`; and, when the runner did not run, `files_scanned` (§2's filtered file count) and the `counts` and `arms` §4b recorded. `counts` and `arms` merge into what is there, so after the runner send only a count you changed.
|
|
264
287
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
288
|
+
```bash
|
|
289
|
+
uv run {extractionInventoryHelper} patch --inventory "{extraction_inventory}" <<'SKF_INVENTORY'
|
|
290
|
+
[{"export_name": "...", "source_file": "...", "signature": "...", "params": [], "return_type": "..."}]
|
|
291
|
+
SKF_INVENTORY
|
|
292
|
+
uv run {extractionInventoryHelper} add --inventory "{extraction_inventory}" --field exports <<'SKF_INVENTORY'
|
|
293
|
+
[{"export_name": "...", "export_type": "...", "signature": "...", "params": [], "return_type": "...", "source_file": "...", "source_line": 0, "citation": "[SRC:...]"}]
|
|
294
|
+
SKF_INVENTORY
|
|
295
|
+
uv run {extractionInventoryHelper} add --inventory "{extraction_inventory}" --field warnings <<'SKF_INVENTORY'
|
|
296
|
+
["..."]
|
|
297
|
+
SKF_INVENTORY
|
|
298
|
+
uv run {extractionInventoryHelper} set --inventory "{extraction_inventory}" <<'SKF_INVENTORY'
|
|
299
|
+
{"top_exports": [], "co_imports": [], "promoted_docs": [], "authoritative_files_scan": null}
|
|
300
|
+
SKF_INVENTORY
|
|
301
|
+
uv run {extractionInventoryHelper} summary --inventory "{extraction_inventory}"
|
|
302
|
+
```
|
|
268
303
|
|
|
269
|
-
**
|
|
270
|
-
|
|
271
|
-
|
|
304
|
+
A call that exits non-zero changes nothing: fix what its `message` names and run it again. An entry the inventory already holds is not added twice (`duplicates`), so a call run again is safe. When a call fails twice, **HARD HALT** (exit code 4, `write-failed`, phase `extract`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`), with `"path": "{extraction_inventory}"`: "Cannot write the extraction inventory `{extraction_inventory}`: {the helper's message}. Check permissions and disk space."
|
|
305
|
+
|
|
306
|
+
The summary's `counts` give §6 its numbers: `files_scanned`, `exports`, `by_type`, `t1`, `t1_low`, `co_imports`, `scripts` and `assets`.
|
|
272
307
|
|
|
273
308
|
### 6. Present Extraction Summary (Gate 2)
|
|
274
309
|
|
|
275
|
-
**Docs-only note:**
|
|
310
|
+
**Docs-only note:** for `extraction_mode: "docs-only"`, display "Docs-only mode: extraction inventory is empty. Documentation content will be fetched from `doc_urls` in step 3c. Auto-proceeding." and auto-proceed past this gate.
|
|
276
311
|
|
|
277
|
-
**Zero-export sanity check (source mode):** If `extraction_mode != "docs-only"` AND `
|
|
312
|
+
**Zero-export sanity check (source mode):** If `extraction_mode != "docs-only"` AND the §5 summary counts no export (its `exports` is 0) AND the brief declares no `doc_urls` (step 3c applies this check to a brief whose every `doc_urls` fetch failed), the empty extraction is almost always an error, not a valid empty surface. Surface a distinct warning at the gate:
|
|
278
313
|
|
|
279
314
|
"**⚠️ Zero public exports extracted.** A source-type brief produced no documented surface and declares no `doc_urls`. This usually means a scope/branch/tag mismatch (wrong `target_version`, over-narrow `scope.include`) or a failed AST run — the compiled skill would document nothing. Verify the brief's source ref and scope before continuing.
|
|
280
315
|
|
|
281
|
-
**[C] Continue anyway
|
|
316
|
+
**[C] Continue anyway**: compile an empty surface (default)
|
|
317
|
+
**[R] Refine the brief**: stop here"
|
|
282
318
|
|
|
283
|
-
Under `{headless_mode}`, do not auto-pass silently:
|
|
319
|
+
Under `{headless_mode}`, do not auto-pass silently: log `"headless: zero public exports extracted, likely a scope, branch or tag mismatch; continuing"`, stage `{"step": "extract", "gate": "zero-exports", "decision": "C", "rationale": "headless mode: zero exports, no human to confirm scope or ref", "timestamp": "{ISO}"}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-create-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"` (the Workflow Rules' record), and proceed. Step 8 reports a run whose sink holds this decision as `status: "partial"` with `summary.warning: "zero-exports"`, so a run that looks green but is not reaches a person or a pipeline.
|
|
284
320
|
|
|
285
|
-
Display the extraction findings for user confirmation
|
|
321
|
+
Display the extraction findings for user confirmation, the numbers from the §5 summary's `counts` and the lists from `{extraction_inventory}`:
|
|
286
322
|
|
|
287
323
|
"**Extraction complete.**
|
|
288
324
|
|
|
289
|
-
**Files scanned:** {
|
|
290
|
-
**Exports found:** {
|
|
291
|
-
**Confidence:** {
|
|
325
|
+
**Files scanned:** {files_scanned}
|
|
326
|
+
**Exports found:** {exports} ({by_type, each as its count and `export_type`})
|
|
327
|
+
**Confidence:** {t1} T1 (AST-verified), {t1_low} T1-low (source reading)
|
|
292
328
|
**Tier used:** {tier}
|
|
293
|
-
**Co-import patterns:** {
|
|
294
|
-
{if
|
|
295
|
-
{if
|
|
329
|
+
**Co-import patterns:** {co_imports} detected
|
|
330
|
+
{if scripts > 0: **Scripts detected ({scripts}):** each kept entry as `{name}` (`{source_file}`): {purpose}, marked when `size_flag` is oversized}
|
|
331
|
+
{if assets > 0: **Assets detected ({assets}):** the same way}
|
|
332
|
+
{for a free-text intent: the files its `intent_mapping` left out}
|
|
296
333
|
|
|
297
334
|
**Top exports:**
|
|
298
335
|
{list top 10 exports with signatures}
|
|
299
336
|
|
|
300
|
-
{warnings
|
|
337
|
+
{warnings: the inventory's `warnings`}
|
|
301
338
|
|
|
302
339
|
Review the extraction summary above, then confirm to continue."
|
|
303
340
|
|
|
304
341
|
### 7. Gate 2 — Confirm Extraction
|
|
305
342
|
|
|
306
|
-
Docs-only mode (`extraction_mode: "docs-only"`) needs no confirmation
|
|
343
|
+
Docs-only mode (`extraction_mode: "docs-only"`) needs no confirmation: auto-proceed to `{nextStepFile}`.
|
|
344
|
+
|
|
345
|
+
Otherwise halt after the §6 summary and wait for the user to continue (they may ask about the results first). When §6 showed the zero-export or the head-cap warning, also offer **[R] Refine the brief**: stop here. **GATE [default: continue]**: under `{headless_mode}`, auto-proceed, log "headless: auto-approve extraction summary", stage `{"step": "extract", "gate": "review-gate", "decision": "continue", "rationale": "headless mode: no person to review the extraction summary", "timestamp": "{ISO}"}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-create-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"` (the Workflow Rules' record). On continue, load `{nextStepFile}`, read it fully, then execute it.
|
|
307
346
|
|
|
308
|
-
|
|
347
|
+
**On [R]:** **HARD HALT** (exit code 6, `halted-for-brief-refinement`, phase `extract`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "**Halting create-skill:** {the warning that prompted the stop, one line}. Fix `scope.include` or `target_version` in the brief (or re-run `skf-brief-skill`), then re-run `skf-create-skill`."
|
|
309
348
|
|