bmad-module-skill-forge 2.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +49 -49
- package/docs/404.md +10 -8
- package/docs/_data/pinned.yaml +22 -13
- package/docs/_internal/STABILITY.md +58 -35
- package/docs/agents.md +39 -53
- package/docs/architecture.md +65 -51
- package/docs/bmad-synergy.md +53 -51
- package/docs/campaign.md +127 -75
- package/docs/concepts.md +34 -28
- package/docs/examples.md +70 -68
- package/docs/forge-auto.md +34 -31
- package/docs/getting-started.md +118 -57
- package/docs/how-it-works.md +25 -21
- package/docs/index.md +15 -15
- package/docs/skill-model.md +70 -59
- package/docs/troubleshooting.md +143 -18
- package/docs/verifying-a-skill.md +87 -57
- package/docs/why-skf.md +24 -22
- package/docs/workflows.md +274 -110
- package/package.json +18 -10
- package/src/forger/preferences.yaml +8 -1
- package/src/knowledge/agentskills-spec.md +2 -0
- package/src/knowledge/ccc-bridge.md +40 -24
- package/src/knowledge/confidence-tiers.md +9 -5
- package/src/knowledge/overview.md +3 -3
- package/src/knowledge/progressive-capability.md +8 -8
- package/src/knowledge/provenance-tracking.md +9 -5
- package/src/knowledge/qmd-registry.md +3 -3
- package/src/knowledge/skf-knowledge-index.csv +2 -2
- package/src/knowledge/skill-lifecycle.md +18 -11
- package/src/knowledge/split-body-strategy.md +0 -3
- package/src/knowledge/tool-resolution.md +4 -2
- package/src/knowledge/version-paths.md +101 -15
- package/src/module-help.csv +3 -3
- package/src/module.yaml +10 -0
- package/src/shared/data/ast-grep-recipes.yaml +608 -0
- package/src/shared/data/ide-context-files.json +30 -0
- package/src/shared/health-check.md +31 -59
- package/src/shared/references/description-guard-protocol.md +12 -9
- package/src/shared/references/feasibility-report-schema.md +19 -13
- package/src/shared/references/headless-gate-convention.md +55 -3
- package/src/shared/references/output-contract-schema.md +19 -8
- package/src/shared/references/pipeline-contracts.md +94 -29
- package/src/shared/references/tessl-review.md +77 -0
- package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
- package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
- package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
- package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
- package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
- package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
- package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
- package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
- package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
- package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
- package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
- package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
- package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
- package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
- package/src/shared/scripts/skf-atomic-write.py +233 -64
- package/src/shared/scripts/skf-build-change-manifest.py +2753 -28
- package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
- package/src/shared/scripts/skf-check-unit-records.py +184 -0
- package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
- package/src/shared/scripts/skf-classify-changed-files.py +772 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +267 -105
- package/src/shared/scripts/skf-count-imports.py +1867 -0
- package/src/shared/scripts/skf-count-tokens.py +1 -1
- package/src/shared/scripts/skf-derive-assembly-shape.py +21 -3
- package/src/shared/scripts/skf-description-guard.py +99 -11
- package/src/shared/scripts/skf-detect-docs.py +694 -2
- package/src/shared/scripts/skf-detect-language.py +486 -107
- package/src/shared/scripts/skf-detect-registry.py +887 -0
- package/src/shared/scripts/skf-detect-scripts-assets.py +197 -55
- package/src/shared/scripts/skf-detect-tools.py +209 -27
- package/src/shared/scripts/skf-detect-workspaces.py +506 -30
- package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
- package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
- package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
- package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
- package/src/shared/scripts/skf-extract-public-api.py +5247 -96
- package/src/shared/scripts/skf-extraction-inventory.py +1280 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +664 -0
- package/src/shared/scripts/skf-fetch-temporal.py +674 -0
- package/src/shared/scripts/skf-find-cycles.py +97 -29
- package/src/shared/scripts/skf-find-test-report.py +476 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +469 -205
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +700 -0
- package/src/shared/scripts/skf-hash-content.py +180 -20
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +161 -27
- package/src/shared/scripts/skf-manifest-ops.py +1 -1
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
- package/src/shared/scripts/skf-merge-doc-urls.py +143 -20
- package/src/shared/scripts/skf-names-present.py +221 -0
- package/src/shared/scripts/skf-pair-intersect.py +119 -28
- package/src/shared/scripts/skf-parse-gaps.py +1384 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-preflight.py +176 -28
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +64 -8
- package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
- package/src/shared/scripts/skf-quick-batch.py +774 -0
- package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
- package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
- package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
- package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
- package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
- package/src/shared/scripts/skf-resolve-authoritative-files.py +155 -14
- package/src/shared/scripts/skf-resolve-package.py +523 -106
- package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
- package/src/shared/scripts/skf-run-lock.py +577 -0
- package/src/shared/scripts/skf-scan-manifests.py +998 -57
- package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
- package/src/shared/scripts/skf-severity-classify.py +712 -108
- package/src/shared/scripts/skf-shape-detect.py +298 -204
- package/src/shared/scripts/skf-shard-body.py +9 -8
- package/src/shared/scripts/skf-skill-inventory.py +2412 -89
- package/src/shared/scripts/skf-skills-module.py +472 -0
- package/src/shared/scripts/skf-source-tree.py +1796 -0
- package/src/shared/scripts/skf-structural-diff.py +787 -121
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +120 -67
- package/src/shared/scripts/skf-update-run-state.py +624 -0
- package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
- package/src/shared/scripts/skf-validate-brief-schema.py +23 -2
- package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
- package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
- package/src/shared/scripts/skf-validate-output.py +712 -64
- package/src/shared/scripts/skf-validate-pins.py +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +116 -10
- package/src/shared/scripts/skf-verify-provenance-completeness.py +3945 -152
- package/src/shared/scripts/skf-write-skill-brief.py +406 -25
- package/src/shared/tool-requirements.yaml +201 -0
- package/src/skf-analyze-source/SKILL.md +41 -36
- package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
- package/src/skf-analyze-source/customize.toml +36 -24
- package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
- package/src/skf-analyze-source/references/continue.md +2 -13
- package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
- package/src/skf-analyze-source/references/generate-briefs.md +121 -55
- package/src/skf-analyze-source/references/headless-contract.md +42 -15
- package/src/skf-analyze-source/references/identify-units.md +96 -110
- package/src/skf-analyze-source/references/init.md +73 -71
- package/src/skf-analyze-source/references/map-and-detect.md +123 -105
- package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
- package/src/skf-analyze-source/references/recommend.md +51 -70
- package/src/skf-analyze-source/references/scan-project.md +60 -84
- package/src/skf-analyze-source/references/scan-root.md +39 -0
- package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
- package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
- package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
- package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
- package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
- package/src/skf-audit-skill/SKILL.md +43 -51
- package/src/skf-audit-skill/assets/drift-report-template.md +28 -3
- package/src/skf-audit-skill/customize.toml +41 -20
- package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
- package/src/skf-audit-skill/references/doc-drift.md +141 -0
- package/src/skf-audit-skill/references/headless-contract.md +29 -0
- package/src/skf-audit-skill/references/health-check.md +2 -0
- package/src/skf-audit-skill/references/init.md +149 -210
- package/src/skf-audit-skill/references/re-index.md +103 -110
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +34 -25
- package/src/skf-audit-skill/references/severity-classify.md +79 -65
- package/src/skf-audit-skill/references/severity-rules.md +15 -6
- package/src/skf-audit-skill/references/structural-diff.md +80 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +712 -0
- package/src/skf-brief-skill/SKILL.md +37 -26
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +18 -25
- package/src/skf-brief-skill/assets/skill-brief-schema.md +30 -23
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +144 -127
- package/src/skf-brief-skill/references/confirm-brief.md +11 -9
- package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
- package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
- package/src/skf-brief-skill/references/gather-intent.md +87 -182
- package/src/skf-brief-skill/references/headless-args.md +84 -16
- package/src/skf-brief-skill/references/health-check.md +1 -1
- package/src/skf-brief-skill/references/invocation-contract.md +18 -13
- package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
- package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
- package/src/skf-brief-skill/references/scope-definition.md +123 -47
- package/src/skf-brief-skill/references/step-auto-brief.md +26 -100
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +7 -10
- package/src/skf-brief-skill/references/write-brief.md +66 -57
- package/src/skf-campaign/SKILL.md +31 -34
- package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
- package/src/skf-campaign/customize.toml +47 -16
- package/src/skf-campaign/references/campaign-contracts.md +39 -29
- package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
- package/src/skf-campaign/references/health-check.md +7 -16
- package/src/skf-campaign/references/step-01-setup.md +46 -84
- package/src/skf-campaign/references/step-02-strategy.md +31 -30
- package/src/skf-campaign/references/step-03-pins.md +26 -18
- package/src/skf-campaign/references/step-04-provenance.md +24 -23
- package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
- package/src/skf-campaign/references/step-06-batch.md +41 -34
- package/src/skf-campaign/references/step-07-capstone.md +40 -25
- package/src/skf-campaign/references/step-08-verify.md +28 -29
- package/src/skf-campaign/references/step-09-refine.md +29 -30
- package/src/skf-campaign/references/step-10-export.md +48 -36
- package/src/skf-campaign/references/step-11-maintenance.md +31 -34
- package/src/skf-campaign/references/step-resume.md +37 -68
- package/src/skf-campaign/scripts/campaign-deps.py +57 -18
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
- package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
- package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
- package/src/skf-campaign/scripts/campaign-report.py +204 -37
- package/src/skf-campaign/scripts/campaign-state.py +1128 -0
- package/src/skf-campaign/scripts/campaign-status.py +10 -74
- package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
- package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
- package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
- package/src/skf-campaign/templates/campaign-report-template.md +5 -1
- package/src/skf-campaign/templates/kickoff-template.md +0 -14
- package/src/skf-create-skill/SKILL.md +27 -20
- package/src/skf-create-skill/assets/compile-assembly-rules.md +11 -8
- package/src/skf-create-skill/assets/skill-sections.md +21 -11
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +36 -58
- package/src/skf-create-skill/references/batch-mode.md +81 -0
- package/src/skf-create-skill/references/ccc-index-check.md +27 -0
- package/src/skf-create-skill/references/compile.md +119 -70
- package/src/skf-create-skill/references/component-extraction.md +113 -91
- package/src/skf-create-skill/references/enrich.md +41 -23
- package/src/skf-create-skill/references/entry-points-by-hand.md +37 -0
- package/src/skf-create-skill/references/extract.md +204 -162
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +11 -11
- package/src/skf-create-skill/references/extraction-patterns.md +588 -201
- package/src/skf-create-skill/references/generate-artifacts.md +145 -93
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +53 -36
- package/src/skf-create-skill/references/relabel-rule.md +12 -0
- package/src/skf-create-skill/references/report.md +37 -57
- package/src/skf-create-skill/references/source-resolution-protocols.md +58 -169
- package/src/skf-create-skill/references/step-auto-shard.md +20 -93
- package/src/skf-create-skill/references/step-doc-rot.md +44 -60
- package/src/skf-create-skill/references/step-doc-sources.md +28 -19
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
- package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
- package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
- package/src/skf-create-skill/references/validate.md +173 -99
- package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
- package/src/skf-create-stack-skill/SKILL.md +29 -56
- package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
- package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
- package/src/skf-create-stack-skill/customize.toml +23 -12
- package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
- package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
- package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
- package/src/skf-create-stack-skill/references/generate-output.md +138 -128
- package/src/skf-create-stack-skill/references/init.md +90 -32
- package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
- package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
- package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
- package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
- package/src/skf-create-stack-skill/references/report.md +39 -33
- package/src/skf-create-stack-skill/references/validate.md +20 -39
- package/src/skf-drop-skill/SKILL.md +28 -51
- package/src/skf-drop-skill/customize.toml +44 -30
- package/src/skf-drop-skill/references/execute.md +83 -146
- package/src/skf-drop-skill/references/health-check.md +2 -0
- package/src/skf-drop-skill/references/invocation-contract.md +64 -0
- package/src/skf-drop-skill/references/report.md +46 -30
- package/src/skf-drop-skill/references/select.md +122 -124
- package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
- package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
- package/src/skf-export-skill/SKILL.md +40 -62
- package/src/skf-export-skill/assets/managed-section-format.md +14 -50
- package/src/skf-export-skill/assets/snippet-format.md +3 -1
- package/src/skf-export-skill/customize.toml +42 -13
- package/src/skf-export-skill/references/generate-snippet.md +54 -46
- package/src/skf-export-skill/references/health-check.md +2 -0
- package/src/skf-export-skill/references/invocation-contract.md +15 -0
- package/src/skf-export-skill/references/load-skill.md +88 -62
- package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
- package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
- package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
- package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
- package/src/skf-export-skill/references/package.md +15 -73
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
- package/src/skf-export-skill/references/result-envelope.md +31 -16
- package/src/skf-export-skill/references/summary.md +41 -17
- package/src/skf-export-skill/references/token-report.md +4 -12
- package/src/skf-export-skill/references/update-context.md +118 -237
- package/src/skf-forger/SKILL.md +61 -37
- package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
- package/src/skf-forger/customize.toml +43 -0
- package/src/skf-forger/references/pipeline-mode.md +73 -18
- package/src/skf-forger/scripts/forge-status.py +299 -0
- package/src/skf-forger/scripts/parse-pipeline.py +322 -54
- package/src/skf-forger/scripts/pipeline-gate.py +428 -0
- package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
- package/src/skf-quick-skill/SKILL.md +54 -53
- package/src/skf-quick-skill/assets/skill-template.md +4 -2
- package/src/skf-quick-skill/customize.toml +51 -20
- package/src/skf-quick-skill/references/batch-mode.md +74 -21
- package/src/skf-quick-skill/references/compile.md +30 -31
- package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
- package/src/skf-quick-skill/references/finalize.md +69 -18
- package/src/skf-quick-skill/references/halt-contract.md +41 -29
- package/src/skf-quick-skill/references/health-check.md +5 -3
- package/src/skf-quick-skill/references/quick-extract.md +114 -45
- package/src/skf-quick-skill/references/registry-resolution.md +9 -64
- package/src/skf-quick-skill/references/resolve-target.md +116 -66
- package/src/skf-quick-skill/references/write-and-validate.md +79 -40
- package/src/skf-refine-architecture/SKILL.md +43 -53
- package/src/skf-refine-architecture/customize.toml +49 -20
- package/src/skf-refine-architecture/references/compile.md +97 -54
- package/src/skf-refine-architecture/references/exit-codes.md +30 -0
- package/src/skf-refine-architecture/references/finding-storage.md +21 -0
- package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
- package/src/skf-refine-architecture/references/improvements.md +14 -20
- package/src/skf-refine-architecture/references/init.md +98 -57
- package/src/skf-refine-architecture/references/issue-detection.md +32 -39
- package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
- package/src/skf-refine-architecture/references/report.md +65 -54
- package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
- package/src/skf-rename-skill/SKILL.md +19 -54
- package/src/skf-rename-skill/customize.toml +32 -26
- package/src/skf-rename-skill/references/execute.md +230 -184
- package/src/skf-rename-skill/references/exit-codes.md +7 -7
- package/src/skf-rename-skill/references/health-check.md +1 -7
- package/src/skf-rename-skill/references/invocation-contract.md +25 -0
- package/src/skf-rename-skill/references/report.md +63 -52
- package/src/skf-rename-skill/references/select.md +197 -115
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
- package/src/skf-setup/SKILL.md +26 -26
- package/src/skf-setup/customize.toml +14 -10
- package/src/skf-setup/references/auto-index.md +50 -63
- package/src/skf-setup/references/ccc-index.md +29 -90
- package/src/skf-setup/references/detect-and-tier.md +58 -67
- package/src/skf-setup/references/health-check.md +2 -0
- package/src/skf-setup/references/invocation-contract.md +14 -0
- package/src/skf-setup/references/report.md +43 -166
- package/src/skf-setup/references/tier-rules.md +5 -5
- package/src/skf-setup/references/write-config.md +34 -57
- package/src/skf-test-skill/SKILL.md +17 -57
- package/src/skf-test-skill/assets/output-section-formats.md +33 -34
- package/src/skf-test-skill/customize.toml +27 -13
- package/src/skf-test-skill/references/coherence-check.md +134 -62
- package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
- package/src/skf-test-skill/references/coverage-check.md +209 -264
- package/src/skf-test-skill/references/detect-mode.md +5 -5
- package/src/skf-test-skill/references/external-validators.md +94 -82
- package/src/skf-test-skill/references/health-check.md +6 -7
- package/src/skf-test-skill/references/init.md +164 -91
- package/src/skf-test-skill/references/invocation-contract.md +66 -0
- package/src/skf-test-skill/references/migration-section-rules.md +5 -2
- package/src/skf-test-skill/references/report.md +164 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +42 -155
- package/src/skf-test-skill/references/source-access-protocol.md +18 -94
- package/src/skf-test-skill/references/step-hard-gate.md +51 -33
- package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
- package/src/skf-test-skill/scripts/build-result-context.py +380 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
- package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
- package/src/skf-test-skill/scripts/compute-score.py +223 -45
- package/src/skf-test-skill/scripts/gap-ledger.py +1666 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +1198 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +547 -79
- package/src/skf-test-skill/scripts/score-signatures.py +479 -0
- package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +133 -56
- package/src/skf-test-skill/templates/test-report-template.md +21 -15
- package/src/skf-update-skill/SKILL.md +38 -25
- package/src/skf-update-skill/customize.toml +27 -12
- package/src/skf-update-skill/references/detect-changes.md +253 -223
- package/src/skf-update-skill/references/gap-driven.md +336 -0
- package/src/skf-update-skill/references/health-check.md +31 -5
- package/src/skf-update-skill/references/init.md +254 -84
- package/src/skf-update-skill/references/invocation-contract.md +12 -0
- package/src/skf-update-skill/references/manual-section-rules.md +6 -23
- package/src/skf-update-skill/references/merge.md +182 -49
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +102 -35
- package/src/skf-update-skill/references/write.md +357 -155
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +183 -46
- package/src/skf-verify-stack/SKILL.md +23 -42
- package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
- package/src/skf-verify-stack/customize.toml +55 -22
- package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
- package/src/skf-verify-stack/references/coverage.md +67 -64
- package/src/skf-verify-stack/references/exit-codes.md +21 -8
- package/src/skf-verify-stack/references/init.md +107 -62
- package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
- package/src/skf-verify-stack/references/integrations.md +106 -65
- package/src/skf-verify-stack/references/report.md +59 -42
- package/src/skf-verify-stack/references/requirements.md +32 -9
- package/src/skf-verify-stack/references/synthesize.md +53 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
- package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
- package/tools/cli/commands/install.js +11 -4
- package/tools/cli/commands/status.js +15 -3
- package/tools/cli/commands/update.js +11 -4
- package/tools/cli/lib/tool-check.js +320 -0
- package/tools/cli/lib/version-check.js +22 -9
- package/tools/cli/skf-cli.js +4 -1
- package/.gitattributes +0 -16
- package/.nvmrc +0 -1
- package/docs/_internal/RELEASING.md +0 -679
- package/release-audits/v1.0.0-launch-audit.md +0 -728
- package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
- package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
- package/src/skf-campaign/manifest.yaml +0 -15
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
- package/src/skf-create-skill/references/ecosystem-check.md +0 -74
- package/src/skf-drop-skill/references/headless-contract.md +0 -18
- package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
- package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
- package/src/skf-update-skill/references/validate.md +0 -124
- package/tools/validate-docs-drift.js +0 -233
- package/tools/validate-docs-links.js +0 -665
|
@@ -5,14 +5,13 @@
|
|
|
5
5
|
Source reading via gh_bridge — infer exports from file structure and content.
|
|
6
6
|
|
|
7
7
|
### Strategy
|
|
8
|
-
1.
|
|
9
|
-
2.
|
|
10
|
-
3.
|
|
11
|
-
4.
|
|
12
|
-
5. Infer types from JSDoc, docstrings, type annotations in source
|
|
8
|
+
1. Files, entry points: step 3 §2's `files_in_scope_list`, `files_without_recipes_list`, `entry_points.files`
|
|
9
|
+
2. Read each file that defines public API, locally or with `gh_bridge.read_file(owner, repo, path)`
|
|
10
|
+
3. Extract: exported function names, parameter lists, return types (from signatures)
|
|
11
|
+
4. Infer types from JSDoc, docstrings, type annotations in source
|
|
13
12
|
|
|
14
13
|
### Confidence
|
|
15
|
-
-
|
|
14
|
+
- Every export is read by eye, so every entry is T1-low (source reading without structural verification): a `[SRC:...]` citation, `extraction_method: source-read` and `ast_node_type: null`
|
|
16
15
|
- No co-import detection available
|
|
17
16
|
- No AST-backed line numbers
|
|
18
17
|
|
|
@@ -28,65 +27,56 @@ Source reading via gh_bridge — infer exports from file structure and content.
|
|
|
28
27
|
|
|
29
28
|
Structural extraction via ast-grep — verified exports with line-level citations.
|
|
30
29
|
|
|
31
|
-
> **Note:** `ast_bridge.*`, `qmd_bridge.*`, and `
|
|
32
|
-
> - `ast_bridge.*` → ast-grep MCP tools (`mcp__ast-grep__find_code`, `mcp__ast-grep__find_code_by_rule`) or `ast-grep` CLI
|
|
33
|
-
> - `qmd_bridge.*` → QMD MCP `query` tool (`mcp__plugin_qmd-plugin_qmd__query`) taking `searches=[{type:'lex'|'vec'|'hyde', query, intent}]`, or `qmd` CLI (`qmd search` / `qmd vector-search`). The legacy `vector_search` MCP tool has been removed; if a client surfaces a tool-not-found error, degrade gracefully per the QMD step 4 tool-probe note — do not retry the stale name.
|
|
34
|
-
> - `ccc_bridge.*` → `/ccc` skill (Claude Code), ccc MCP server (Cursor), or `ccc` CLI
|
|
35
|
-
> - `gh_bridge.*` → `gh api` commands or direct file I/O for local sources
|
|
36
|
-
>
|
|
37
|
-
> See `knowledge/tool-resolution.md` for the complete resolution table. Also see the AST Extraction Protocol section below and the TOOL/SUBPROCESS FALLBACK rule for dispatch details.
|
|
30
|
+
> **Note:** `ast_bridge.*`, `qmd_bridge.*`, `ccc_bridge.*` and `gh_bridge.*` below are **conceptual interfaces**, not callable functions: `ast_bridge.*` is the ast-grep MCP tools (`find_code`, `find_code_by_rule`) or the `ast-grep` CLI; `qmd_bridge.*` the QMD MCP `query` tool or the `qmd` CLI (`qmd search` / `qmd vsearch`), whose tool-not-found error is non-fatal, as step 4's tool probe says; `ccc_bridge.*` the `/ccc` skill, the ccc MCP server or the `ccc` CLI; `gh_bridge.*` `gh api` or direct file reads of a local source. `knowledge/tool-resolution.md` has the full table.
|
|
38
31
|
|
|
39
32
|
### Strategy
|
|
40
33
|
|
|
41
|
-
1.
|
|
42
|
-
2.
|
|
43
|
-
3.
|
|
44
|
-
4.
|
|
45
|
-
5. Build extraction rules YAML for reproducibility
|
|
34
|
+
1. Run the AST Extraction Protocol below: the recipe runner finds every export in the files in scope, each with its file, `$NAME`'s line, recipe and node kind, and a function's signature, parameters and return type
|
|
35
|
+
2. For each export: take its `signature`, `params` and `return_type` from the runner's record; read them from the source at its line only for a function whose `params` is null
|
|
36
|
+
3. Use ast-grep to detect co-imported symbols in `path` for the given `libraries[]`
|
|
37
|
+
4. Record the recipe set, the recipes and the ast-grep version the runner reports, for reproducibility
|
|
46
38
|
|
|
47
39
|
### Confidence
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
40
|
+
- Each entry is labeled by the tool that produced it, not by the tier:
|
|
41
|
+
- An export an ast-grep rule matched (a function with its full signature, a type definition, an interface): T1 (AST-verified), an `[AST:...]` citation, `extraction_method: ast-grep` and `ast_node_type` set to the `kind` the matching recipe declares (see the recipes below)
|
|
42
|
+
- An export read by eye (ast-grep could not parse its file, the rules missed it, or the file was read instead of matched): T1-low, a `[SRC:...]` citation, `extraction_method: source-read` and `ast_node_type: null`
|
|
43
|
+
- Co-import patterns ast-grep detected: T1
|
|
51
44
|
- Internal/private functions: excluded (not part of public API)
|
|
52
45
|
|
|
53
46
|
### ast-grep Patterns
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
- Python: function definitions within `__all__` list
|
|
57
|
-
- Go: capitalized function definitions
|
|
47
|
+
|
|
48
|
+
One recipe matches each export shape: the recipes are under **YAML Rule Recipes by Language** below, and the table that gives each shape its recipe and kind, a `find_code` pattern's included, is in `extraction-patterns-by-hand.md`.
|
|
58
49
|
|
|
59
50
|
---
|
|
60
51
|
|
|
61
52
|
## Forge+ Tier (AST + CCC)
|
|
62
53
|
|
|
63
|
-
Identical extraction to Forge tier. CCC adds an upstream semantic discovery step that
|
|
54
|
+
Identical extraction to Forge tier. CCC adds an upstream semantic discovery step that ranks the files extraction reads one at a time.
|
|
64
55
|
|
|
65
56
|
### When CCC Pre-Discovery Applies
|
|
66
57
|
|
|
67
58
|
CCC pre-discovery runs in ccc-discover (before this extraction step) when ALL of the following are true:
|
|
68
59
|
- Tier is Forge+ or Deep
|
|
69
60
|
- `tools.ccc: true` in forge-tier.yaml
|
|
70
|
-
- `ccc_index.status` is `"fresh"`, `"
|
|
61
|
+
- The source index is available: step 2b searches with `--refresh` when `ccc_index.status` is `"fresh"`, `"created"`, `"skipped"` or a status it does not know (such as a `"stale"` an older SKF recorded), and first attempts lazy indexing when it is `"none"` or `"failed"`
|
|
71
62
|
|
|
72
|
-
The discovery step stores `{ccc_discovery: [{file, score, snippet}]}` in context. This extraction step
|
|
63
|
+
The discovery step stores `{ccc_discovery: [{file, score, snippet}]}` in context. This extraction step ranks by those results the files it reads one at a time.
|
|
73
64
|
|
|
74
65
|
### CCC Pre-Ranking Strategy
|
|
75
66
|
|
|
76
|
-
When `{ccc_discovery}` is present and non-empty:
|
|
67
|
+
When `{ccc_discovery}` is present and non-empty, rank the files extraction reads one at a time: those the recipe runner leaves to source reading (its `file_issues`, its extraction gaps and the files of a language no recipe reads), or the filtered file list when extraction runs without the runner.
|
|
77
68
|
|
|
78
|
-
1. Files appearing in `{ccc_discovery}` results
|
|
79
|
-
2. Files not in CCC results
|
|
69
|
+
1. Files appearing in `{ccc_discovery}` results come first, sorted by relevance score descending
|
|
70
|
+
2. Files not in CCC results follow them: they are not excluded, only deprioritized
|
|
80
71
|
3. If the CCC intersection with scoped files produces <10 files: include all scoped files (CCC results too narrow)
|
|
81
|
-
4. Proceed with the AST Extraction Protocol on the pre-ranked list
|
|
82
72
|
|
|
83
73
|
### ast-grep Patterns
|
|
84
74
|
|
|
85
|
-
Same
|
|
75
|
+
Same recipes as Forge tier. CCC pre-ranking changes no recipe.
|
|
86
76
|
|
|
87
77
|
### Confidence
|
|
88
78
|
|
|
89
|
-
|
|
79
|
+
Labeled by tool, exactly as at Forge tier: an export an ast-grep rule matched is T1 (AST-verified), an export read by eye is T1-low. CCC is upstream discovery only and is invisible in the output artifact.
|
|
90
80
|
|
|
91
81
|
### Important
|
|
92
82
|
|
|
@@ -104,90 +94,118 @@ Same extraction as Forge tier. Deep tier adds enrichment in step 4, not extracti
|
|
|
104
94
|
- Extraction results carry forward unchanged
|
|
105
95
|
|
|
106
96
|
### Confidence
|
|
107
|
-
- Extraction: same as Forge (T1)
|
|
97
|
+
- Extraction: labeled by tool, same as Forge (T1 for an ast-grep match, T1-low for an export read by eye)
|
|
108
98
|
- Enrichment annotations added in step 4: T2
|
|
109
99
|
|
|
110
100
|
---
|
|
111
101
|
|
|
112
102
|
## AST Extraction Protocol
|
|
113
103
|
|
|
114
|
-
When AST tools are available (Forge
|
|
104
|
+
When AST tools are available (Forge, Forge+ and Deep tiers) and the step that runs this protocol gives the recipe runner's command, the runner extracts: `skf-extract-public-api.py --mode full` runs the recipes below over the files in scope in one call and writes every export, with its exact file, line, name and node kind, as JSON. The command names `--source-root` and either the brief (`--brief`, for its scope globs, scope type and language) or the files to read (`--files-from`, one path per line relative to the source root), and `-o` for the JSON, a file the step removes before the call, so that a JSON there after the call is this call's. While the runner can run, never run the recipes one at a time, batch them, or merge and dedupe their matches by hand.
|
|
115
105
|
|
|
116
|
-
|
|
106
|
+
### Recipe Runner
|
|
117
107
|
|
|
118
|
-
|
|
108
|
+
- **Files in scope:** a file is in scope when an include glob matches it (every file, when there is none) and no exclude glob does. `**` spans any number of path segments, none included, and `*` and `?` stay inside one, so `src/**/*.ts` matches `src/index.ts` and `**/test_*` matches a top-level `test_x.py`. The runner reads those a recipe reads (`.vue` files included) and counts them in `files_in_scope`, the filtered file count; `files_without_recipes` counts by extension those it leaves, in a language no recipe reads. `skf-extract-public-api.py --help` gives the rest of its rules.
|
|
109
|
+
- **Recipes:** the recipes below, which SKF's shared recipe file, `ast-grep-recipes.yaml`, holds too: the `standard` set, or the `component-library` set for that scope type.
|
|
110
|
+
- **Head cap:** each recipe keeps at most 200 matches, or at Forge+ and Deep 500 for `scope.type: "full-library"` and 300 for `scope.type: "component-library"`, in file and line order. `truncated` is true, and so is that recipe's `truncated` in `recipes[]`, when a recipe matched more: the matches past the cap are missing, so warn about them.
|
|
111
|
+
- **Each export** is one name in one file, and gives `export_name`, `source_file`, `source_line` (`$NAME`'s line), `signature_line` (the source line holding it), `citation` (`[AST:{file}:L{line}]`), `ast_recipe`, `ast_node_type` (the `kind` its recipe declares), `export_type`, `from` (a re-export's module), `signature` (the declaration on one line), `params`, `return_type`, `confidence: T1` and `extraction_method: ast-grep`. Record them as they are.
|
|
112
|
+
- **Signatures:** a function's `params` lists each parameter (its name, type, default and whether it is optional), and is null for any other export and for a declaration the runner does not parse; `return_type` is null when the declaration states none.
|
|
113
|
+
- **Entry points:** `entry_point_diff` diffs the names the package's entry points export with the recipe matches (`public`, `internal`, `extraction_gaps`, `outside_scope`; a `namespace` item's `members` stand in for it), `counts` gives `exports_public_api`, `exports_internal` and `effective_denominator`, and `arms` the monorepo, specific-modules and multi-subpath `exports` flags.
|
|
114
|
+
- **Read by eye (T1-low)** only what it leaves: each file in `file_issues` (a syntax error where a recipe can miss an export, or a file that is not UTF-8, unreadable or missing), the files `files_without_recipes` counts that hold public API (by the Quick tier Strategy), the forms Known Limitation #11 below lists, the `unread` files of a rerun, and the `extraction_gaps` names.
|
|
119
115
|
|
|
120
|
-
|
|
116
|
+
Act on its `status`, not its exit code: `ok`, every file in scope was read; `incomplete`, an ast-grep run failed or timed out: run the step's command once more, and when it is still incomplete keep its exports and read by eye each file an `errors[]` item lists in `unread`; `no-ast-grep`, no ast-grep it can run, so no recipe ran.
|
|
121
117
|
|
|
122
|
-
|
|
123
|
-
Files in scope ≤ 100
|
|
124
|
-
→ Use ast-grep MCP tool: find_code(pattern, max_results=100, output_format="text")
|
|
125
|
-
→ Parse compact text output directly into extraction inventory
|
|
118
|
+
### When the Runner Cannot Run
|
|
126
119
|
|
|
127
|
-
|
|
128
|
-
→ Use ast-grep MCP tool: find_code_by_rule(yaml, max_results=150, output_format="text")
|
|
129
|
-
→ Use scoped YAML rules (see recipes below) to filter at the AST level
|
|
130
|
-
→ Parse compact text output into extraction inventory
|
|
120
|
+
There is no runner result when the step gives no runner command, no runner path resolves, or no JSON is at the `-o` path after the call (`uv` missing or failing, an input error, which prints one line on stderr, a crash, or a shell timeout that stopped it). Then, and when its `status` is `no-ast-grep`, run the recipes as **Running the Recipes Without the Runner** below says, on the filtered file list: read this file on from that heading (a run the runner serves stops there), and first load `extraction-patterns-by-hand.md`, beside this file, completely: it holds each recipe's notes and the limitations of patterns run by hand. When no JSON is there and a stderr line holds `error:` (the runner's input error or crash, or `uv` failing; a shell timeout prints none), warn "**Recipe runner failed:** {that line}. Extraction ran without it." and keep the warning with the step's other warnings. When no ast-grep can run them either (no `ast-grep` CLI and no ast-grep MCP tool), extraction degrades to source reading: see `tier-degradation-rules.md` "AST Tool Unavailable". When the runner's `scope.languages` is empty, whatever its `status`, no recipe reads the brief's language (the runner warns `no recipe reads {language} files` and reads no file): extract by the Quick tier Strategy (source reading, T1-low).
|
|
131
121
|
|
|
132
|
-
Files in scope
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
→ Merge batch results into extraction inventory
|
|
136
|
-
```
|
|
122
|
+
**"Files in scope"** are the files the brief's include and exclude globs keep, filtered by the language's extensions, never the repository's whole file count: use the filtered count from step 3 section 2 as the decision tree input.
|
|
123
|
+
|
|
124
|
+
### Known ast-grep Limitations
|
|
137
125
|
|
|
138
|
-
|
|
126
|
+
Limitation #11 applies to every run: the runner reads with the same recipes. #4 is the fallback of a recipe run by hand, which `find_code` serves; #1 to #3 and #5 to #10 concern patterns run by hand too, and are in `extraction-patterns-by-hand.md`.
|
|
139
127
|
|
|
140
|
-
If
|
|
128
|
+
4. **Fallback protocol:** If an ast-grep pattern returns errors or zero results when results are expected:
|
|
129
|
+
- First: retry with `find_code()` using a simpler pattern (drop type annotations, use broader match)
|
|
130
|
+
- Second: if `find_code()` also fails, fall back to source reading for that pattern category (T1-low confidence)
|
|
131
|
+
- Never silently accept zero results for a pattern category that the source language commonly uses
|
|
141
132
|
|
|
142
|
-
|
|
133
|
+
Read the forms #11 lists by eye whether or not the runner ran:
|
|
143
134
|
|
|
144
|
-
**
|
|
135
|
+
11. **Forms the recipes deliberately do not cover (ast-grep 0.45.3):** read these by eye at T1-low when the source uses them, or follow them with the Re-Export Tracing protocol in `extraction-patterns-tracing.md` where noted.
|
|
136
|
+
- **Every JS/TS `export_statement` recipe:** `export` followed by a line break before the declaration (tree-sitter reads the bare `export` as a statement of its own, so there is no `export_statement` to match; formatters never write it); an export nested in a `namespace`, `declare module` or `declare global` block, a `.d.ts` file's `declare module "pkg" { ... }` included, since it is a member, not a module export.
|
|
137
|
+
- **`js-exported-functions`, `react-component-functions`:** an anonymous `export default function () {}` (#3); a function exported through a list (`export { f }` and `export { f as g }`, which `js-local-exports` finds at the list's line), `export default f;` or `export = f`; a function bound to a `const` (the constants and arrow-function recipes find it); a wrapped default such as `export default memo(function Name() {})` or `forwardRef(...)`, whose value is a call, not a declaration; class, object-literal and interface methods; the implementation of an overloaded function (its signatures match instead). The React recipes also skip generator functions (an overload signature of one still matches, since a signature does not show it) and class components and keep a PascalCase function that is not a component (such as a Next.js `GET` handler).
|
|
138
|
+
- **`js-exported-constants`, `js-exported-arrow-functions`, `react-component-arrow-functions`, `react-wrapped-components`:** every declarator after the first one a recipe accepts in `export const a = 1, b = () => 2` (one match per statement); destructuring (`export const { x } = obj`, which has no identifier name); `let`, `var` and `export declare const`. The arrow-function recipes also skip an arrow wrapped in parentheses, `as`, `satisfies` or a call, and a `function` expression; the constants recipe reports them, and `react-wrapped-components` reports a PascalCase `memo`, `forwardRef` or `lazy` call. `react-wrapped-components` skips any other wrapper (`observer(...)`, `styled.div`, `connect(...)(Component)`), a wrapped call cast with `as` or `satisfies`, and `export default memo(...)`, whose exposed name is `default`.
|
|
139
|
+
- **`js-exported-classes`, `react-props-interfaces`:** `export default class` and `export default interface` (their exposed name is `default`); `export declare class`, and `export declare interface` (`ts-exported-types` finds it); a class expression bound to a `const` (the constants recipe reports it); a props type written as a type alias (`export type XProps = {...}`, which `ts-exported-types` finds); a type exported through a list (`export type { T }`, which `js-local-exports` or `js-reexports` finds).
|
|
140
|
+
- **`ts-exported-types`:** `export default interface` (its exposed name is `default`); an interface, type alias or enum inside a `namespace`, `declare module` or `declare global` block, a member rather than a module export; a type exported through a list (`export type { T }`, `export { type T }`), which `js-local-exports` finds, or `js-reexports` when the list has a `from`.
|
|
141
|
+
- **`js-reexports`, `js-namespace-reexports`, `js-local-exports`:** a bare `export * from '...'`, which exposes no name of its own; an `export { a } from '...' with { type: 'json' }` statement, or the legacy `export { a } from '...' assert { type: 'json' }`, which parse as ERROR nodes; `export default x;` and `export = x`; a list inside a `namespace`, `declare module` or `declare global` block, a member rather than a module export; in a `.js` file, `default` as a list item's name or alias (`export { default } from '...'`, `export { x as default }`), a keyword token there that no `$NAME` captures (TypeScript parses it as a name). Follow these with the Re-Export Tracing protocol.
|
|
142
|
+
- **`rust-public-functions`:** a `pub fn` in an `impl` block (#8); trait methods, which carry no `pub`; `pub fn` imports in an `extern "C" { }` block; functions a macro generates (`macro_rules!` and `cfg_if!` bodies are token trees, which ast-grep does not parse). One file cannot show reachability across files: a `pub fn` at the top of `foo.rs` matches whether or not `mod foo;` is `pub`, so check `pub use` re-exports with the Re-Export Tracing protocol. `#[cfg]`-gated and `#[doc(hidden)]` functions still match, and a raw identifier keeps its prefix (`r#match`).
|
|
143
|
+
- **`go-exported-functions`:** methods; an exported function-typed variable (`var F = func() {}`). `Test*`, `Benchmark*` and `Example*` functions in `_test.go` files, and the exported functions of `package main` or an `internal/` package, match but are not importable API: exclude them through `scope.exclude`.
|
|
144
|
+
- **`python-public-functions`, `python-public-classes`:** a definition under `elif __name__ == "__main__":` or a compound condition (`__name__ == "__main__" or DEBUG`), which still matches; a function made by `lambda`, `partial(...)` or `exec`, or declared `global` inside another function; a class made by `type(...)`, `NamedTuple(...)`, `TypedDict(...)` or `Enum(...)`, and an alias (`X = Other`); names created at runtime (`globals()`, `setattr`); names imported into the module (`from .x import name`: Re-Export Tracing). The recipes do not read `__all__`: a public-looking name it leaves out still matches, and a name it lists but imports from elsewhere is found by Re-Export Tracing.
|
|
145
|
+
- **`vue-define-props`, `vue-define-props-tsx`:** a call with two type arguments (`defineProps<A, B>()`); runtime `defineProps({ ... })` and `defineProps([...])`, which carry no type; the Options API `props:` option; `defineProps?.<X>()` and `(defineProps)<X>()`; `defineProps` inside a function, an arrow function, a class, a block, or an `if`, `for`, `while` or `switch` statement; a `<script setup>` with no `lang` (plain JavaScript, no type argument). `find_code_by_rule` never reaches a `.vue` file, and the CLI does only with a scratch `sgconfig.yml` (see the Vue note in `extraction-patterns-by-hand.md`).
|
|
145
146
|
|
|
146
|
-
|
|
147
|
-
find_code(
|
|
148
|
-
project_folder="{source_path}",
|
|
149
|
-
pattern="async def $NAME($$$PARAMS)",
|
|
150
|
-
language="python",
|
|
151
|
-
max_results=100,
|
|
152
|
-
output_format="text"
|
|
153
|
-
)
|
|
154
|
-
```
|
|
147
|
+
### Re-Export Tracing and Script/Asset Extraction
|
|
155
148
|
|
|
156
|
-
|
|
149
|
+
See `extraction-patterns-tracing.md` for:
|
|
150
|
+
- **Re-export tracing protocol:** resolving module imports through `__init__.py`, barrel files, `pub use`
|
|
151
|
+
- **Script/asset extraction patterns:** detection heuristics, inclusion rules, provenance, inventory structure
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Relabel Rule
|
|
156
|
+
|
|
157
|
+
The rule that sets a provenance entry's labels from its `extraction_method` is in `relabel-rule.md`, beside this file, which compile.md §4 and validate.md §7 and §7a load themselves: load it when another reader, such as update-skill's write.md, meets a `provenance.entries[<i>].*` violation.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Running the Recipes Without the Runner
|
|
162
|
+
|
|
163
|
+
Read this part only when **When the Runner Cannot Run** sends you here: a run the recipe runner serves stops reading this file at this heading. It holds how to run the recipes one at a time, the CLI streaming template, and the recipes themselves, which the runner's recipe file, `ast-grep-recipes.yaml`, mirrors and `kind-at` reads here.
|
|
164
|
+
|
|
165
|
+
### Decision Tree
|
|
166
|
+
|
|
167
|
+
Apply the first matching condition:
|
|
157
168
|
|
|
158
169
|
```
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
output_format="
|
|
164
|
-
)
|
|
170
|
+
.vue files (the Vue recipes), at any scope size
|
|
171
|
+
→ CLI streaming with -c {scratch}/sgconfig.yml (find_code_by_rule cannot read them; see the Vue note in extraction-patterns-by-hand.md)
|
|
172
|
+
|
|
173
|
+
Files in scope ≤ 500
|
|
174
|
+
→ Use ast-grep MCP tool: find_code_by_rule(yaml=<recipe>, max_results=150, output_format="json")
|
|
175
|
+
→ Run every recipe for the language (see recipes below), one call per recipe
|
|
176
|
+
→ Read $NAME (and $SOURCE) from each match's metaVariables, and its line from $NAME
|
|
177
|
+
→ Merge the matches into extraction inventory
|
|
178
|
+
|
|
179
|
+
Files in scope > 500
|
|
180
|
+
→ CLI streaming: ast-grep scan -r {recipe_file} --json=stream + line-by-line Python processing
|
|
181
|
+
→ Process in directory batches, cap per-batch output
|
|
182
|
+
→ Merge batch results into extraction inventory
|
|
165
183
|
```
|
|
166
184
|
|
|
167
|
-
|
|
185
|
+
`extraction-patterns-by-hand.md`'s MCP Tool Usage shows the call with a recipe as its `yaml`.
|
|
168
186
|
|
|
169
|
-
|
|
187
|
+
### CLI Streaming Fallback
|
|
170
188
|
|
|
171
|
-
|
|
172
|
-
- **Default (Quick/Forge, any scope):** `N = 200`
|
|
173
|
-
- **Forge+/Deep with `scope.type: "full-library"`:** `N = 500`
|
|
174
|
-
- **Forge+/Deep with `scope.type: "component-library"`:** `N = 300` (components have fewer but richer exports; props interfaces are the primary API surface)
|
|
189
|
+
When MCP tools are unavailable or more than 500 files are in scope, stream the matches (`--json=stream`, never `--json`, which loads them all into memory) through line-by-line Python:
|
|
175
190
|
|
|
176
|
-
|
|
191
|
+
The `| head -N` at the end of the pipeline caps the exports kept, after the exclude filter, at the Recipe Runner's head cap for the tier and scope type (`{HEAD_CAP}` below).
|
|
177
192
|
|
|
178
193
|
```bash
|
|
179
|
-
#
|
|
180
|
-
# {
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
ast-grep
|
|
194
|
+
# {recipe_file}: one recipe's YAML in a scratch file (never inline: its regexes are quoted).
|
|
195
|
+
# {recipe_id}, {node_kind}: its id and declared kind, each export's ast_recipe and ast_node_type.
|
|
196
|
+
# .vue files: add -c {scratch}/sgconfig.yml (the by-hand file's Vue note). {HEAD_CAP}: the Recipe Runner's head cap.
|
|
197
|
+
# {exclude_patterns}: the brief's scope.exclude as a Python list, [] when it has none.
|
|
198
|
+
# fnmatch is not the Files in scope rule above: its `*` also crosses `/`, and `**/x`
|
|
199
|
+
# needs a folder before x, so add x too for a top-level file ('test_*' beside '**/test_*').
|
|
200
|
+
# The patterns match ast-grep's file paths, relative to the root they name (no ./).
|
|
201
|
+
ast-grep scan -r {recipe_file} --json=stream {path} | python3 -c "
|
|
187
202
|
import sys, json, fnmatch, signal
|
|
188
|
-
|
|
203
|
+
if hasattr(signal, 'SIGPIPE'): # POSIX only; Windows has no SIGPIPE
|
|
204
|
+
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
189
205
|
|
|
190
206
|
EXCLUDES = {exclude_patterns}
|
|
207
|
+
RECIPE = '{recipe_id}'
|
|
208
|
+
KIND = '{node_kind}'
|
|
191
209
|
|
|
192
210
|
for line in sys.stdin:
|
|
193
211
|
try:
|
|
@@ -195,35 +213,50 @@ for line in sys.stdin:
|
|
|
195
213
|
f = m.get('file','')
|
|
196
214
|
if EXCLUDES and any(fnmatch.fnmatch(f, pat) for pat in EXCLUDES):
|
|
197
215
|
continue
|
|
198
|
-
v = m.get('metaVariables',{})
|
|
199
|
-
name = v.get('
|
|
216
|
+
v = m.get('metaVariables',{}).get('single',{})
|
|
217
|
+
name = v.get('NAME',{}).get('text','')
|
|
200
218
|
if name and not name.startswith('_'):
|
|
201
|
-
ln =
|
|
202
|
-
|
|
203
|
-
|
|
219
|
+
ln = v['NAME'].get('range',{}).get('start',{}).get('line',0)+1
|
|
220
|
+
first = m.get('range',{}).get('start',{}).get('line',0)+1
|
|
221
|
+
text = m.get('text','').split(chr(10))
|
|
222
|
+
sig = text[min(ln-first, len(text)-1)].strip()
|
|
223
|
+
src = v.get('SOURCE',{}).get('text','')
|
|
224
|
+
print(f'[AST:{f}:L{ln}] {RECIPE} kind={KIND} name={name}' + (f' from={src}' if src else '') + f' {sig}')
|
|
204
225
|
except: pass
|
|
205
226
|
" | head -{HEAD_CAP}
|
|
206
227
|
```
|
|
207
228
|
|
|
208
|
-
|
|
229
|
+
Past 500 files, run the template per top-level source folder, 20 to 50 files a batch, with the same head cap, then merge the results by export name and file, keeping the first line (overloads and a definition in both branches of an `if` repeat a name in one file).
|
|
209
230
|
|
|
210
|
-
-
|
|
211
|
-
- Process line-by-line (`for line in sys.stdin`), not `json.load(sys.stdin)`
|
|
212
|
-
- Cap output with `| head -N` as a safety valve
|
|
213
|
-
- For repos > 500 files, process in directory batches of 20-50 files each: split by top-level source directory, run the CLI streaming template per batch with the same head cap, then merge results and deduplicate by export name (keep the first occurrence if duplicates exist across batches)
|
|
231
|
+
**Line numbers are 0-based in ast-grep JSON** (the CLI's and the MCP tools'), and the line to cite is `$NAME`'s: every `[AST:{file}:L{line}]` citation and provenance `source_line` is `metaVariables.single.NAME.range.start.line + 1`, never the match's own first line, which for a decorated class is the decorator's.
|
|
214
232
|
|
|
215
233
|
### YAML Rule Recipes by Language
|
|
216
234
|
|
|
235
|
+
Each recipe declares the `kind` of the node it matches (an export it matched records it as its `ast_node_type`) and captures the export's name as `$NAME`; each was verified on ast-grep 0.45.3. The runner's recipe file, `ast-grep-recipes.yaml`, holds the same rules, and `kind-at` reads them here. To run one without the runner, `extraction-patterns-by-hand.md` gives each recipe's notes, and Known Limitation #11 above lists the forms each recipe deliberately does not cover.
|
|
236
|
+
|
|
217
237
|
**Python — public functions:**
|
|
218
238
|
|
|
219
239
|
```yaml
|
|
220
240
|
id: python-public-functions
|
|
221
241
|
language: python
|
|
222
242
|
rule:
|
|
223
|
-
pattern: 'def $NAME
|
|
243
|
+
pattern: 'def $NAME'
|
|
244
|
+
kind: function_definition
|
|
224
245
|
inside:
|
|
225
246
|
kind: module
|
|
226
|
-
stopBy:
|
|
247
|
+
stopBy:
|
|
248
|
+
any:
|
|
249
|
+
- kind: function_definition
|
|
250
|
+
- kind: class_definition
|
|
251
|
+
not:
|
|
252
|
+
inside:
|
|
253
|
+
kind: block
|
|
254
|
+
stopBy: end
|
|
255
|
+
inside:
|
|
256
|
+
kind: if_statement
|
|
257
|
+
has:
|
|
258
|
+
field: condition
|
|
259
|
+
regex: '^\(?\s*(__name__\s*==\s*[''"]__main__[''"]|[''"]__main__[''"]\s*==\s*__name__)\s*\)?$'
|
|
227
260
|
constraints:
|
|
228
261
|
NAME:
|
|
229
262
|
regex: '^[^_]'
|
|
@@ -239,23 +272,84 @@ rule:
|
|
|
239
272
|
kind: class_definition
|
|
240
273
|
inside:
|
|
241
274
|
kind: module
|
|
242
|
-
stopBy:
|
|
275
|
+
stopBy:
|
|
276
|
+
any:
|
|
277
|
+
- kind: function_definition
|
|
278
|
+
- kind: class_definition
|
|
279
|
+
not:
|
|
280
|
+
inside:
|
|
281
|
+
kind: block
|
|
282
|
+
stopBy: end
|
|
283
|
+
inside:
|
|
284
|
+
kind: if_statement
|
|
285
|
+
has:
|
|
286
|
+
field: condition
|
|
287
|
+
regex: '^\(?\s*(__name__\s*==\s*[''"]__main__[''"]|[''"]__main__[''"]\s*==\s*__name__)\s*\)?$'
|
|
243
288
|
constraints:
|
|
244
289
|
NAME:
|
|
245
290
|
regex: '^[^_]'
|
|
246
291
|
```
|
|
247
292
|
|
|
248
|
-
> **Pattern note:** The minimal `class $NAME` pattern (with `kind: class_definition` to disambiguate the AST node) works on ast-grep 0.42.x via both MCP `find_code_by_rule` and CLI `--json=stream`. The previously documented `class $NAME($$$BASES)` and `class $NAME($$$BASES):` variants are known-broken on 0.42.x — see Known Limitations #7 below. For simple CLI extraction without a YAML rule, use `ast-grep run -p 'class $NAME' -l python --json=stream {path}` and post-filter names via the `^[^_]` regex in the Python processing step of the CLI streaming template.
|
|
249
|
-
|
|
250
293
|
**JavaScript/TypeScript — exported functions:**
|
|
251
294
|
|
|
252
|
-
|
|
295
|
+
```yaml
|
|
296
|
+
id: js-exported-functions
|
|
297
|
+
language: typescript # Use 'tsx' for .tsx files; the javascript form below for .js
|
|
298
|
+
rule:
|
|
299
|
+
kind: export_statement
|
|
300
|
+
inside:
|
|
301
|
+
kind: program
|
|
302
|
+
any:
|
|
303
|
+
- has:
|
|
304
|
+
field: declaration
|
|
305
|
+
any:
|
|
306
|
+
- kind: function_declaration
|
|
307
|
+
- kind: generator_function_declaration
|
|
308
|
+
- kind: function_signature
|
|
309
|
+
has:
|
|
310
|
+
field: name
|
|
311
|
+
pattern: $NAME
|
|
312
|
+
- has:
|
|
313
|
+
field: declaration
|
|
314
|
+
kind: ambient_declaration
|
|
315
|
+
has:
|
|
316
|
+
kind: function_signature
|
|
317
|
+
has:
|
|
318
|
+
field: name
|
|
319
|
+
pattern: $NAME
|
|
320
|
+
not:
|
|
321
|
+
has:
|
|
322
|
+
field: declaration
|
|
323
|
+
any:
|
|
324
|
+
- kind: function_declaration
|
|
325
|
+
- kind: generator_function_declaration
|
|
326
|
+
follows:
|
|
327
|
+
stopBy:
|
|
328
|
+
not:
|
|
329
|
+
kind: comment
|
|
330
|
+
kind: export_statement
|
|
331
|
+
has:
|
|
332
|
+
field: declaration
|
|
333
|
+
kind: function_signature
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**JavaScript: exported functions (`.js`, `.jsx`, `.mjs`, `.cjs`):**
|
|
253
337
|
|
|
254
338
|
```yaml
|
|
255
339
|
id: js-exported-functions
|
|
256
|
-
language:
|
|
340
|
+
language: javascript
|
|
257
341
|
rule:
|
|
258
|
-
|
|
342
|
+
kind: export_statement
|
|
343
|
+
inside:
|
|
344
|
+
kind: program
|
|
345
|
+
has:
|
|
346
|
+
field: declaration
|
|
347
|
+
any:
|
|
348
|
+
- kind: function_declaration
|
|
349
|
+
- kind: generator_function_declaration
|
|
350
|
+
has:
|
|
351
|
+
field: name
|
|
352
|
+
pattern: $NAME
|
|
259
353
|
```
|
|
260
354
|
|
|
261
355
|
**JavaScript/TypeScript — exported constants:**
|
|
@@ -264,7 +358,26 @@ rule:
|
|
|
264
358
|
id: js-exported-constants
|
|
265
359
|
language: typescript
|
|
266
360
|
rule:
|
|
267
|
-
|
|
361
|
+
kind: export_statement
|
|
362
|
+
inside:
|
|
363
|
+
kind: program
|
|
364
|
+
has:
|
|
365
|
+
field: declaration
|
|
366
|
+
kind: lexical_declaration
|
|
367
|
+
all:
|
|
368
|
+
- has:
|
|
369
|
+
field: kind
|
|
370
|
+
regex: '^const$'
|
|
371
|
+
- has:
|
|
372
|
+
kind: variable_declarator
|
|
373
|
+
all:
|
|
374
|
+
- has:
|
|
375
|
+
field: name
|
|
376
|
+
kind: identifier
|
|
377
|
+
pattern: $NAME
|
|
378
|
+
- has:
|
|
379
|
+
field: value
|
|
380
|
+
pattern: $VALUE
|
|
268
381
|
```
|
|
269
382
|
|
|
270
383
|
**JavaScript/TypeScript — exported arrow functions:**
|
|
@@ -273,25 +386,193 @@ rule:
|
|
|
273
386
|
id: js-exported-arrow-functions
|
|
274
387
|
language: typescript
|
|
275
388
|
rule:
|
|
276
|
-
|
|
389
|
+
kind: export_statement
|
|
390
|
+
inside:
|
|
391
|
+
kind: program
|
|
392
|
+
has:
|
|
393
|
+
field: declaration
|
|
394
|
+
kind: lexical_declaration
|
|
395
|
+
all:
|
|
396
|
+
- has:
|
|
397
|
+
field: kind
|
|
398
|
+
regex: '^const$'
|
|
399
|
+
- has:
|
|
400
|
+
kind: variable_declarator
|
|
401
|
+
all:
|
|
402
|
+
- has:
|
|
403
|
+
field: name
|
|
404
|
+
kind: identifier
|
|
405
|
+
pattern: $NAME
|
|
406
|
+
- has:
|
|
407
|
+
field: value
|
|
408
|
+
kind: arrow_function
|
|
409
|
+
pattern: $VALUE
|
|
277
410
|
```
|
|
278
411
|
|
|
279
|
-
> **JS/TS Pattern Merging:** Modern TypeScript codebases often use `export const` exclusively for all exports (arrow functions, objects, constants). Run ALL four JS/TS patterns (functions, arrow functions, constants, classes) and merge results by `$NAME`. Priority when deduplicating: arrow function match > function declaration match > constant match. Arrow function matches capture parameters directly; constant matches require inspecting `$VALUE` to extract signatures.
|
|
280
|
-
|
|
281
412
|
**JavaScript/TypeScript — exported classes:**
|
|
282
413
|
|
|
283
414
|
```yaml
|
|
284
415
|
id: js-exported-classes
|
|
285
416
|
language: typescript
|
|
286
417
|
rule:
|
|
287
|
-
|
|
418
|
+
kind: export_statement
|
|
419
|
+
inside:
|
|
420
|
+
kind: program
|
|
421
|
+
not:
|
|
422
|
+
has:
|
|
423
|
+
regex: '^default$'
|
|
424
|
+
has:
|
|
425
|
+
field: declaration
|
|
426
|
+
all:
|
|
427
|
+
- has:
|
|
428
|
+
field: name
|
|
429
|
+
pattern: $NAME
|
|
430
|
+
- has:
|
|
431
|
+
field: body
|
|
432
|
+
kind: class_body
|
|
288
433
|
```
|
|
289
434
|
|
|
290
|
-
|
|
435
|
+
**TypeScript: exported interfaces, type aliases and enums:**
|
|
291
436
|
|
|
292
|
-
|
|
437
|
+
```yaml
|
|
438
|
+
id: ts-exported-types
|
|
439
|
+
language: typescript # Use 'tsx' for .tsx files
|
|
440
|
+
rule:
|
|
441
|
+
kind: export_statement
|
|
442
|
+
inside:
|
|
443
|
+
kind: program
|
|
444
|
+
not:
|
|
445
|
+
has:
|
|
446
|
+
regex: '^default$'
|
|
447
|
+
has:
|
|
448
|
+
field: declaration
|
|
449
|
+
any:
|
|
450
|
+
- any:
|
|
451
|
+
- kind: interface_declaration
|
|
452
|
+
- kind: type_alias_declaration
|
|
453
|
+
- kind: enum_declaration
|
|
454
|
+
has:
|
|
455
|
+
field: name
|
|
456
|
+
pattern: $NAME
|
|
457
|
+
- kind: ambient_declaration
|
|
458
|
+
has:
|
|
459
|
+
any:
|
|
460
|
+
- kind: interface_declaration
|
|
461
|
+
- kind: type_alias_declaration
|
|
462
|
+
- kind: enum_declaration
|
|
463
|
+
has:
|
|
464
|
+
field: name
|
|
465
|
+
pattern: $NAME
|
|
466
|
+
```
|
|
293
467
|
|
|
294
|
-
|
|
468
|
+
**JavaScript/TypeScript: re-exported names:**
|
|
469
|
+
|
|
470
|
+
```yaml
|
|
471
|
+
id: js-reexports
|
|
472
|
+
language: typescript
|
|
473
|
+
rule:
|
|
474
|
+
kind: export_specifier
|
|
475
|
+
inside:
|
|
476
|
+
kind: export_clause
|
|
477
|
+
inside:
|
|
478
|
+
kind: export_statement
|
|
479
|
+
inside:
|
|
480
|
+
kind: program
|
|
481
|
+
has:
|
|
482
|
+
field: source
|
|
483
|
+
has:
|
|
484
|
+
kind: string_fragment
|
|
485
|
+
pattern: $SOURCE
|
|
486
|
+
any:
|
|
487
|
+
- has:
|
|
488
|
+
field: alias
|
|
489
|
+
any:
|
|
490
|
+
- has:
|
|
491
|
+
kind: string_fragment
|
|
492
|
+
pattern: $NAME
|
|
493
|
+
- not:
|
|
494
|
+
kind: string
|
|
495
|
+
pattern: $NAME
|
|
496
|
+
- all:
|
|
497
|
+
- not:
|
|
498
|
+
has:
|
|
499
|
+
field: alias
|
|
500
|
+
regex: '.'
|
|
501
|
+
- has:
|
|
502
|
+
field: name
|
|
503
|
+
any:
|
|
504
|
+
- has:
|
|
505
|
+
kind: string_fragment
|
|
506
|
+
pattern: $NAME
|
|
507
|
+
- not:
|
|
508
|
+
kind: string
|
|
509
|
+
pattern: $NAME
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**JavaScript/TypeScript: namespace re-exports:**
|
|
513
|
+
|
|
514
|
+
```yaml
|
|
515
|
+
id: js-namespace-reexports
|
|
516
|
+
language: typescript
|
|
517
|
+
rule:
|
|
518
|
+
kind: export_statement
|
|
519
|
+
inside:
|
|
520
|
+
kind: program
|
|
521
|
+
all:
|
|
522
|
+
- has:
|
|
523
|
+
field: source
|
|
524
|
+
has:
|
|
525
|
+
kind: string_fragment
|
|
526
|
+
pattern: $SOURCE
|
|
527
|
+
- has:
|
|
528
|
+
kind: namespace_export
|
|
529
|
+
any:
|
|
530
|
+
- has:
|
|
531
|
+
kind: identifier
|
|
532
|
+
pattern: $NAME
|
|
533
|
+
- has:
|
|
534
|
+
kind: string
|
|
535
|
+
has:
|
|
536
|
+
kind: string_fragment
|
|
537
|
+
pattern: $NAME
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**JavaScript/TypeScript: local export lists:**
|
|
541
|
+
|
|
542
|
+
```yaml
|
|
543
|
+
id: js-local-exports
|
|
544
|
+
language: typescript # Use 'tsx' for .tsx files, 'javascript' for .js files
|
|
545
|
+
rule:
|
|
546
|
+
kind: export_specifier
|
|
547
|
+
inside:
|
|
548
|
+
kind: export_clause
|
|
549
|
+
inside:
|
|
550
|
+
kind: export_statement
|
|
551
|
+
inside:
|
|
552
|
+
kind: program
|
|
553
|
+
not:
|
|
554
|
+
has:
|
|
555
|
+
field: source
|
|
556
|
+
kind: string
|
|
557
|
+
any:
|
|
558
|
+
- has:
|
|
559
|
+
field: alias
|
|
560
|
+
any:
|
|
561
|
+
- has:
|
|
562
|
+
kind: string_fragment
|
|
563
|
+
pattern: $NAME
|
|
564
|
+
- not:
|
|
565
|
+
kind: string
|
|
566
|
+
pattern: $NAME
|
|
567
|
+
- all:
|
|
568
|
+
- not:
|
|
569
|
+
has:
|
|
570
|
+
field: alias
|
|
571
|
+
regex: '.'
|
|
572
|
+
- has:
|
|
573
|
+
field: name
|
|
574
|
+
pattern: $NAME
|
|
575
|
+
```
|
|
295
576
|
|
|
296
577
|
**Rust — public functions:**
|
|
297
578
|
|
|
@@ -299,9 +580,32 @@ Use `find_code()` with pattern `export { $$$NAMES } from $SOURCE` for re-export
|
|
|
299
580
|
id: rust-public-functions
|
|
300
581
|
language: rust
|
|
301
582
|
rule:
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
583
|
+
kind: function_item
|
|
584
|
+
has:
|
|
585
|
+
field: name
|
|
586
|
+
pattern: $NAME
|
|
587
|
+
all:
|
|
588
|
+
- has:
|
|
589
|
+
kind: visibility_modifier
|
|
590
|
+
regex: '^pub$'
|
|
591
|
+
- inside:
|
|
592
|
+
any:
|
|
593
|
+
- kind: source_file
|
|
594
|
+
- kind: declaration_list
|
|
595
|
+
inside:
|
|
596
|
+
kind: mod_item
|
|
597
|
+
- not:
|
|
598
|
+
inside:
|
|
599
|
+
kind: mod_item
|
|
600
|
+
stopBy: end
|
|
601
|
+
not:
|
|
602
|
+
has:
|
|
603
|
+
kind: visibility_modifier
|
|
604
|
+
regex: '^pub$'
|
|
605
|
+
- not:
|
|
606
|
+
inside:
|
|
607
|
+
kind: block
|
|
608
|
+
stopBy: end
|
|
305
609
|
```
|
|
306
610
|
|
|
307
611
|
**Go — exported functions (capitalized):**
|
|
@@ -310,12 +614,17 @@ rule:
|
|
|
310
614
|
id: go-exported-functions
|
|
311
615
|
language: go
|
|
312
616
|
rule:
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
617
|
+
kind: function_declaration
|
|
618
|
+
has:
|
|
619
|
+
field: name
|
|
620
|
+
pattern: $NAME
|
|
621
|
+
not:
|
|
622
|
+
has:
|
|
623
|
+
field: receiver
|
|
624
|
+
kind: parameter_list
|
|
316
625
|
constraints:
|
|
317
626
|
NAME:
|
|
318
|
-
regex: '
|
|
627
|
+
regex: '^\p{Lu}'
|
|
319
628
|
```
|
|
320
629
|
|
|
321
630
|
### Component Library YAML Rule Recipes
|
|
@@ -328,7 +637,18 @@ These patterns are used by `component-extraction.md` when `scope.type: "componen
|
|
|
328
637
|
id: react-props-interfaces
|
|
329
638
|
language: typescript # Use 'tsx' for .tsx files
|
|
330
639
|
rule:
|
|
331
|
-
|
|
640
|
+
kind: export_statement
|
|
641
|
+
inside:
|
|
642
|
+
kind: program
|
|
643
|
+
not:
|
|
644
|
+
has:
|
|
645
|
+
regex: '^default$'
|
|
646
|
+
has:
|
|
647
|
+
field: declaration
|
|
648
|
+
kind: interface_declaration
|
|
649
|
+
has:
|
|
650
|
+
field: name
|
|
651
|
+
pattern: $NAME
|
|
332
652
|
constraints:
|
|
333
653
|
NAME:
|
|
334
654
|
regex: '.*Props$'
|
|
@@ -336,28 +656,133 @@ constraints:
|
|
|
336
656
|
|
|
337
657
|
**React/TypeScript — Component function exports (PascalCase):**
|
|
338
658
|
|
|
339
|
-
> **Language note:** Use `language: tsx` for `.tsx` files. The `export function` pattern may fail with tsx on ast-grep 0.41.x (see Known Limitations #5). Use `export const` patterns as primary and fall back to source reading for `export function` in tsx files.
|
|
340
|
-
|
|
341
659
|
```yaml
|
|
342
660
|
id: react-component-functions
|
|
343
661
|
language: tsx
|
|
344
662
|
rule:
|
|
345
|
-
|
|
663
|
+
kind: export_statement
|
|
664
|
+
inside:
|
|
665
|
+
kind: program
|
|
666
|
+
any:
|
|
667
|
+
- has:
|
|
668
|
+
field: declaration
|
|
669
|
+
any:
|
|
670
|
+
- kind: function_declaration
|
|
671
|
+
- kind: function_signature
|
|
672
|
+
has:
|
|
673
|
+
field: name
|
|
674
|
+
pattern: $NAME
|
|
675
|
+
- has:
|
|
676
|
+
field: declaration
|
|
677
|
+
kind: ambient_declaration
|
|
678
|
+
has:
|
|
679
|
+
kind: function_signature
|
|
680
|
+
has:
|
|
681
|
+
field: name
|
|
682
|
+
pattern: $NAME
|
|
683
|
+
not:
|
|
684
|
+
has:
|
|
685
|
+
field: declaration
|
|
686
|
+
kind: function_declaration
|
|
687
|
+
follows:
|
|
688
|
+
stopBy:
|
|
689
|
+
not:
|
|
690
|
+
kind: comment
|
|
691
|
+
kind: export_statement
|
|
692
|
+
has:
|
|
693
|
+
field: declaration
|
|
694
|
+
kind: function_signature
|
|
346
695
|
constraints:
|
|
347
696
|
NAME:
|
|
348
|
-
regex: '
|
|
697
|
+
regex: '^\p{Lu}'
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
**React/JavaScript: component function exports (`.js`, `.jsx`, `.mjs`, `.cjs`):**
|
|
701
|
+
|
|
702
|
+
```yaml
|
|
703
|
+
id: react-component-functions
|
|
704
|
+
language: javascript
|
|
705
|
+
rule:
|
|
706
|
+
kind: export_statement
|
|
707
|
+
inside:
|
|
708
|
+
kind: program
|
|
709
|
+
has:
|
|
710
|
+
field: declaration
|
|
711
|
+
kind: function_declaration
|
|
712
|
+
has:
|
|
713
|
+
field: name
|
|
714
|
+
pattern: $NAME
|
|
715
|
+
constraints:
|
|
716
|
+
NAME:
|
|
717
|
+
regex: '^\p{Lu}'
|
|
349
718
|
```
|
|
350
719
|
|
|
351
720
|
**React/TypeScript — Component arrow function exports:**
|
|
352
721
|
|
|
353
722
|
```yaml
|
|
354
723
|
id: react-component-arrow-functions
|
|
355
|
-
language: typescript
|
|
724
|
+
language: typescript # Use 'tsx' for .tsx files
|
|
356
725
|
rule:
|
|
357
|
-
|
|
726
|
+
kind: export_statement
|
|
727
|
+
inside:
|
|
728
|
+
kind: program
|
|
729
|
+
has:
|
|
730
|
+
field: declaration
|
|
731
|
+
kind: lexical_declaration
|
|
732
|
+
all:
|
|
733
|
+
- has:
|
|
734
|
+
field: kind
|
|
735
|
+
regex: '^const$'
|
|
736
|
+
- has:
|
|
737
|
+
kind: variable_declarator
|
|
738
|
+
all:
|
|
739
|
+
- has:
|
|
740
|
+
field: name
|
|
741
|
+
kind: identifier
|
|
742
|
+
regex: '^\p{Lu}'
|
|
743
|
+
pattern: $NAME
|
|
744
|
+
- has:
|
|
745
|
+
field: value
|
|
746
|
+
kind: arrow_function
|
|
747
|
+
pattern: $VALUE
|
|
358
748
|
constraints:
|
|
359
749
|
NAME:
|
|
360
|
-
regex: '
|
|
750
|
+
regex: '^\p{Lu}'
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
**React: wrapped component exports (`memo`, `forwardRef`, `lazy`):**
|
|
754
|
+
|
|
755
|
+
```yaml
|
|
756
|
+
id: react-wrapped-components
|
|
757
|
+
language: tsx
|
|
758
|
+
rule:
|
|
759
|
+
kind: export_statement
|
|
760
|
+
inside:
|
|
761
|
+
kind: program
|
|
762
|
+
has:
|
|
763
|
+
field: declaration
|
|
764
|
+
kind: lexical_declaration
|
|
765
|
+
all:
|
|
766
|
+
- has:
|
|
767
|
+
field: kind
|
|
768
|
+
regex: '^const$'
|
|
769
|
+
- has:
|
|
770
|
+
kind: variable_declarator
|
|
771
|
+
all:
|
|
772
|
+
- has:
|
|
773
|
+
field: name
|
|
774
|
+
kind: identifier
|
|
775
|
+
regex: '^\p{Lu}'
|
|
776
|
+
pattern: $NAME
|
|
777
|
+
- has:
|
|
778
|
+
field: value
|
|
779
|
+
kind: call_expression
|
|
780
|
+
has:
|
|
781
|
+
field: function
|
|
782
|
+
regex: '^(React\.)?(memo|forwardRef|lazy)$'
|
|
783
|
+
constraints:
|
|
784
|
+
NAME:
|
|
785
|
+
regex: '^\p{Lu}'
|
|
361
786
|
```
|
|
362
787
|
|
|
363
788
|
**Vue — defineProps extraction:**
|
|
@@ -366,78 +791,40 @@ constraints:
|
|
|
366
791
|
id: vue-define-props
|
|
367
792
|
language: typescript
|
|
368
793
|
rule:
|
|
369
|
-
pattern: 'defineProps<$
|
|
794
|
+
pattern: 'defineProps<$NAME>()'
|
|
795
|
+
kind: call_expression
|
|
796
|
+
not:
|
|
797
|
+
inside:
|
|
798
|
+
stopBy: end
|
|
799
|
+
any:
|
|
800
|
+
- kind: statement_block
|
|
801
|
+
- kind: arrow_function
|
|
802
|
+
- kind: class_body
|
|
803
|
+
- kind: if_statement
|
|
804
|
+
- kind: for_statement
|
|
805
|
+
- kind: for_in_statement
|
|
806
|
+
- kind: while_statement
|
|
807
|
+
- kind: switch_case
|
|
370
808
|
```
|
|
371
809
|
|
|
372
|
-
**
|
|
373
|
-
|
|
374
|
-
After extracting Props interfaces and component exports, link them using this 3-level fallback chain:
|
|
375
|
-
|
|
376
|
-
1. **Naming convention (primary):** Strip `Props` suffix from interface name → match to component export (e.g., `NativeLiquidButtonProps` → `NativeLiquidButton`)
|
|
377
|
-
2. **File co-location (fallback):** If naming doesn't match, check if a Props interface and a PascalCase export function are defined in the same file — link them
|
|
378
|
-
3. **Generic parameter (deep fallback):** Search for `ComponentProps<typeof $NAME>` or `React.ComponentProps<typeof $NAME>` patterns that reference the component by name
|
|
379
|
-
|
|
380
|
-
Unlinked Props interfaces are included as standalone type exports. Unlinked component exports are included with a note that no Props interface was found (signature-only, T1-low confidence for API contract).
|
|
381
|
-
|
|
382
|
-
### Known ast-grep Limitations
|
|
383
|
-
|
|
384
|
-
When using ast-grep for extraction, be aware of these documented limitations:
|
|
385
|
-
|
|
386
|
-
1. **`export class $NAME` needs a body on 0.42.x; `find_code_by_rule` needs explicit `kind`:** The bare `export class $NAME` pattern returns zero through **both** `find_code()` and the CLI on ast-grep 0.42.x — add the body, `export class $NAME { $$$ }` (see #9). With `find_code_by_rule`, a class export additionally needs a `kind` rule for the tree-sitter node type; the simpler `find_code()` with the body-form pattern is the lighter path.
|
|
387
|
-
|
|
388
|
-
2. **Re-export patterns produce multiple AST nodes:** `export { A, B, C } from './module'` decomposes into multiple metavariable bindings for `$$$NAMES`. Results require post-processing to split comma-separated names.
|
|
389
|
-
|
|
390
|
-
3. **Default anonymous exports capture no name:** `export default function $NAME` works, but `export default $EXPR` (anonymous default export) captures no name in `$NAME`. Fall back to source reading (T1-low) for anonymous defaults.
|
|
391
|
-
|
|
392
|
-
4. **Fallback protocol:** If an ast-grep pattern returns errors or zero results when results are expected:
|
|
393
|
-
- First: retry with `find_code()` using a simpler pattern (drop type annotations, use broader match)
|
|
394
|
-
- Second: if `find_code()` also fails, fall back to source reading for that pattern category (T1-low confidence)
|
|
395
|
-
- Never silently accept zero results for a pattern category that the source language commonly uses
|
|
396
|
-
|
|
397
|
-
5. **TSX `export function` pattern failure:** The `export function $NAME($$$PARAMS)` pattern may return zero results in TSX files with ast-grep 0.41.x. This affects both MCP tools and CLI. `export const` and `export type` patterns are unaffected. **Workaround:** For TSX files, use `export const` patterns first (which work), then fall back to source reading (grep/file read) for `export function` declarations. When a TSX codebase shows zero `export function` matches but source files clearly contain them, this is a known ast-grep tree-sitter tsx parser limitation — not an extraction error. Log it in the evidence report and proceed with T1-low confidence for those exports.
|
|
398
|
-
|
|
399
|
-
6. **CLI `--json=stream` may produce no output:** On ast-grep 0.41.x, `--json=stream` may produce empty output for certain patterns. The `--json=stream` flag requires the explicit `run` subcommand: use `ast-grep run -p '{pattern}' --json=stream` (not `ast-grep -p '{pattern}' --json=stream`). If streaming still produces no output, fall back to the MCP tool or source reading.
|
|
400
|
-
|
|
401
|
-
7. **Python class patterns with bases/colon return zero (ast-grep 0.42.x):** The patterns `class $NAME($$$BASES)` and `class $NAME($$$BASES):` return zero matches on real Python sources with ast-grep 0.42.0, even on files containing dozens of subclassed public classes. `find_code_by_rule` also rejects the bare inline rule without `kind` as `Rule must specify a set of AST kinds to match. Try adding \`kind\` rule.` **Workaround:** Use the minimal `class $NAME` pattern with `kind: class_definition` (YAML) or `ast-grep run -p 'class $NAME' -l python --json=stream` (CLI), then post-filter names via the `^[^_]` regex. The `^[^_]` constraint enforces the "public" filter since ast-grep's base-match rule is what's broken, not the name-match rule. See the Python — public classes recipe above.
|
|
402
|
-
|
|
403
|
-
8. **Rust `pub fn` any-pattern returns zero; bare `pub fn $NAME` over-captures (ast-grep 0.42.x):** The `rust-public-functions` recipe's `any:` of `pub fn $NAME($$$PARAMS) -> $RET` / `pub fn $NAME($$$PARAMS)` returns "No matches found" on real Rust sources with ast-grep 0.42.2, even on crates containing 200+ public functions. Dropping to the bare `pub fn $NAME` pattern matches, but over-captures restricted-visibility functions such as `pub(crate) fn` / `pub(super) fn`, which are **not** public API. **Workaround:** Prefer a visibility-constrained source grep — `rg '^\s*pub fn ' <src>` filtered to exclude lines beginning `pub(` — cross-checked against the AN-verified public surface, at T1-low confidence. Never silently accept zero results for Rust public functions, and never treat a bare `pub fn $NAME` match set as the public API without stripping `pub(...)`-restricted items. See the Rust — public functions recipe above.
|
|
404
|
-
|
|
405
|
-
9. **Plain `language: typescript` declaration patterns without a body return zero (ast-grep 0.42.x):** For `language: typescript` on ast-grep 0.42.2, the incomplete-statement patterns `export class $NAME`, `export function $NAME($$$PARAMS)`, `export type $NAME`, and `export enum $NAME` all return **zero** matches against real `.ts` sources — `export class` / `export type` / `export enum` additionally print `Pattern contains an ERROR node`. This affects the CLI (`ast-grep run -p ... -l typescript`) and the MCP `find_code()` API **identically** — `find_code()` is not a workaround. Only `export const $NAME = $VALUE` matches as documented. The cause is that a declaration pattern missing its body/initializer does not parse as a complete statement. **Workarounds (verified on 0.42.2 via both CLI and `find_code`):**
|
|
406
|
-
- **class:** add the body — `export class $NAME { $$$ }` matches.
|
|
407
|
-
- **enum:** add the body — `export enum $NAME { $$$ }` matches.
|
|
408
|
-
- **type alias:** drop `export` and include the initializer — `type $NAME = $T` matches (and captures both `export type` and bare `type` declarations).
|
|
409
|
-
- **interface:** `export interface $NAME { $$$ }` already carries a body and **works** for plain interfaces — but it misses generic (`interface $NAME<T>`) and `extends` forms; source-read those at T1-low.
|
|
410
|
-
- **function:** the body form `export function $NAME($$$PARAMS) { $$$ }` matches only functions with no return-type annotation and no `async` modifier, so it is unreliable. Prefer a source-read fallback (or a barrel cross-check) at T1-low for `export function`, mirroring the tsx guidance in #5.
|
|
411
|
-
|
|
412
|
-
Never silently accept zero results for a declaration form the source language commonly uses.
|
|
413
|
-
|
|
414
|
-
10. **Generic class declarations do not match non-generic class patterns (ast-grep 0.42.x):** The non-generic patterns `export class $NAME { $$$ }` and `export class $NAME extends $BASE { $$$ }` silently skip every generic form on ast-grep 0.42.2 — verified via both the CLI (`ast-grep run -p ... -l typescript`) and `find_code()`, the first matched only a plain `Plain` and the second only a plain `PlainExtends` on a fixture of `Plain` / `Generic<T>` / `GenericExtends<T> extends Base<T>` / `abstract AbstractGeneric<T>` / `PlainExtends`. The per-shape generic patterns `export class $NAME<$$$P> { $$$ }`, `export class $NAME<$$$P> extends $BASE { $$$ }`, and `export abstract class $NAME<$$$P> { $$$ }` each match exactly **one** shape — no single pattern covers all of them. **Workaround:** Always run a source-read fallback `^export (abstract )?class` over the in-scope `.ts` sources (T1-low) and merge by name+file with the AST results, mirroring the `export function` guidance in #9. The bare `class $NAME` pattern catches every form but over-captures non-exported classes, so it still needs the source-read pass to re-impose the exported-only filter — this is the opposite trade from the Python #7 `^[^_]` re-filter, since TS has no name-prefix convention for exports. Never accept a class inventory that omits generic classes when the source uses them.
|
|
415
|
-
|
|
416
|
-
### Component Library Demo/Example Auto-Exclusion
|
|
417
|
-
|
|
418
|
-
When `scope.type: "component-library"`, auto-detect and propose demo/example exclusions before extraction begins. **User confirmation is required before applying** — some `examples/` directories contain API-level code.
|
|
419
|
-
|
|
420
|
-
**Auto-detect directory patterns:**
|
|
421
|
-
- `**/demo/**`, `**/demos/**`
|
|
422
|
-
- `**/stories/**`, `**/__stories__/**`, `**/storybook/**`
|
|
423
|
-
- `**/examples/**`, `**/example/**`
|
|
424
|
-
|
|
425
|
-
**Auto-detect file patterns:**
|
|
426
|
-
- `**/*.stories.*`, `**/*.story.*`
|
|
427
|
-
- `**/*.example.*`, `**/*.demo.*`
|
|
428
|
-
|
|
429
|
-
If `demo_patterns` is specified in the brief, use those instead of auto-detection.
|
|
430
|
-
|
|
431
|
-
**Procedure:**
|
|
432
|
-
1. Scan the scoped file tree for matching directories and files
|
|
433
|
-
2. Count matches per pattern category
|
|
434
|
-
3. Present to user: "**Auto-detected {N} demo/example files** in {M} directories matching these patterns: {list}. Confirm exclusion? [Y/n] Or adjust patterns:"
|
|
435
|
-
4. Apply confirmed patterns to the exclude list before AST extraction
|
|
436
|
-
5. Record in extraction inventory: `demo_files_excluded: {count}`
|
|
437
|
-
|
|
438
|
-
### Re-Export Tracing and Script/Asset Extraction
|
|
439
|
-
|
|
440
|
-
See `extraction-patterns-tracing.md` for:
|
|
441
|
-
- **Re-export tracing protocol** — resolving module imports through `__init__.py`, barrel files, `pub use`
|
|
442
|
-
- **Script/asset extraction patterns** — detection heuristics, inclusion rules, provenance, inventory structure
|
|
810
|
+
**Vue: defineProps extraction for `<script setup lang="tsx">`:**
|
|
443
811
|
|
|
812
|
+
```yaml
|
|
813
|
+
id: vue-define-props-tsx
|
|
814
|
+
language: tsx
|
|
815
|
+
rule:
|
|
816
|
+
pattern: 'defineProps<$NAME>()'
|
|
817
|
+
kind: call_expression
|
|
818
|
+
not:
|
|
819
|
+
inside:
|
|
820
|
+
stopBy: end
|
|
821
|
+
any:
|
|
822
|
+
- kind: statement_block
|
|
823
|
+
- kind: arrow_function
|
|
824
|
+
- kind: class_body
|
|
825
|
+
- kind: if_statement
|
|
826
|
+
- kind: for_statement
|
|
827
|
+
- kind: for_in_statement
|
|
828
|
+
- kind: while_statement
|
|
829
|
+
- kind: switch_case
|
|
830
|
+
```
|