bmad-module-skill-forge 2.2.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 +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 +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 +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 +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 +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 +1 -1
- 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 +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 +15 -5
- 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 +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 +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 -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 +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 -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
|
@@ -12,7 +12,7 @@ Source reading via gh_bridge — infer exports from file structure and content.
|
|
|
12
12
|
5. Infer types from JSDoc, docstrings, type annotations in source
|
|
13
13
|
|
|
14
14
|
### Confidence
|
|
15
|
-
-
|
|
15
|
+
- 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
16
|
- No co-import detection available
|
|
17
17
|
- No AST-backed line numbers
|
|
18
18
|
|
|
@@ -28,65 +28,56 @@ Source reading via gh_bridge — infer exports from file structure and content.
|
|
|
28
28
|
|
|
29
29
|
Structural extraction via ast-grep — verified exports with line-level citations.
|
|
30
30
|
|
|
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.
|
|
31
|
+
> **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
32
|
|
|
39
33
|
### Strategy
|
|
40
34
|
|
|
41
|
-
1.
|
|
42
|
-
2.
|
|
43
|
-
3.
|
|
44
|
-
4.
|
|
45
|
-
5. Build extraction rules YAML for reproducibility
|
|
35
|
+
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
|
|
36
|
+
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
|
|
37
|
+
3. Use ast-grep to detect co-imported symbols in `path` for the given `libraries[]`
|
|
38
|
+
4. Record the recipe set, the recipes and the ast-grep version the runner reports, for reproducibility
|
|
46
39
|
|
|
47
40
|
### Confidence
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
41
|
+
- Each entry is labeled by the tool that produced it, not by the tier:
|
|
42
|
+
- 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)
|
|
43
|
+
- 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`
|
|
44
|
+
- Co-import patterns ast-grep detected: T1
|
|
51
45
|
- Internal/private functions: excluded (not part of public API)
|
|
52
46
|
|
|
53
47
|
### ast-grep Patterns
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
- Python: function definitions within `__all__` list
|
|
57
|
-
- Go: capitalized function definitions
|
|
48
|
+
|
|
49
|
+
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
50
|
|
|
59
51
|
---
|
|
60
52
|
|
|
61
53
|
## Forge+ Tier (AST + CCC)
|
|
62
54
|
|
|
63
|
-
Identical extraction to Forge tier. CCC adds an upstream semantic discovery step that
|
|
55
|
+
Identical extraction to Forge tier. CCC adds an upstream semantic discovery step that ranks the files extraction reads one at a time.
|
|
64
56
|
|
|
65
57
|
### When CCC Pre-Discovery Applies
|
|
66
58
|
|
|
67
59
|
CCC pre-discovery runs in ccc-discover (before this extraction step) when ALL of the following are true:
|
|
68
60
|
- Tier is Forge+ or Deep
|
|
69
61
|
- `tools.ccc: true` in forge-tier.yaml
|
|
70
|
-
- `ccc_index.status` is `"fresh"`, `"
|
|
62
|
+
- 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
63
|
|
|
72
|
-
The discovery step stores `{ccc_discovery: [{file, score, snippet}]}` in context. This extraction step
|
|
64
|
+
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
65
|
|
|
74
66
|
### CCC Pre-Ranking Strategy
|
|
75
67
|
|
|
76
|
-
When `{ccc_discovery}` is present and non-empty:
|
|
68
|
+
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
69
|
|
|
78
|
-
1. Files appearing in `{ccc_discovery}` results
|
|
79
|
-
2. Files not in CCC results
|
|
70
|
+
1. Files appearing in `{ccc_discovery}` results come first, sorted by relevance score descending
|
|
71
|
+
2. Files not in CCC results follow them: they are not excluded, only deprioritized
|
|
80
72
|
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
73
|
|
|
83
74
|
### ast-grep Patterns
|
|
84
75
|
|
|
85
|
-
Same
|
|
76
|
+
Same recipes as Forge tier. CCC pre-ranking changes no recipe.
|
|
86
77
|
|
|
87
78
|
### Confidence
|
|
88
79
|
|
|
89
|
-
|
|
80
|
+
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
81
|
|
|
91
82
|
### Important
|
|
92
83
|
|
|
@@ -104,90 +95,118 @@ Same extraction as Forge tier. Deep tier adds enrichment in step 4, not extracti
|
|
|
104
95
|
- Extraction results carry forward unchanged
|
|
105
96
|
|
|
106
97
|
### Confidence
|
|
107
|
-
- Extraction: same as Forge (T1)
|
|
98
|
+
- Extraction: labeled by tool, same as Forge (T1 for an ast-grep match, T1-low for an export read by eye)
|
|
108
99
|
- Enrichment annotations added in step 4: T2
|
|
109
100
|
|
|
110
101
|
---
|
|
111
102
|
|
|
112
103
|
## AST Extraction Protocol
|
|
113
104
|
|
|
114
|
-
When AST tools are available (Forge
|
|
105
|
+
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
106
|
|
|
116
|
-
|
|
107
|
+
### Recipe Runner
|
|
117
108
|
|
|
118
|
-
|
|
109
|
+
- **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.
|
|
110
|
+
- **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.
|
|
111
|
+
- **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.
|
|
112
|
+
- **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.
|
|
113
|
+
- **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.
|
|
114
|
+
- **Entry points:** `entry_point_diff` diffs the names the package's entry points export with the recipe matches (`public`, `internal`, `extraction_gaps`, `outside_scope`), `counts` gives `exports_public_api`, `exports_internal` and `effective_denominator`, and `arms` the monorepo, specific-modules and multi-subpath `exports` flags.
|
|
115
|
+
- **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, and the `extraction_gaps` names.
|
|
119
116
|
|
|
120
|
-
|
|
117
|
+
Act on its `status`, not its exit code: `ok`, every file in scope was read; `incomplete`, an ast-grep run failed or timed out: keep its exports and warn that the files of each `errors[]` item (how many, and the first) may be unread; `no-ast-grep`, no ast-grep it can run, so no recipe ran.
|
|
121
118
|
|
|
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
|
|
119
|
+
### When the Runner Cannot Run
|
|
126
120
|
|
|
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
|
|
121
|
+
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 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
122
|
|
|
132
|
-
Files in scope
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
→ Merge batch results into extraction inventory
|
|
136
|
-
```
|
|
123
|
+
**"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.
|
|
124
|
+
|
|
125
|
+
### Known ast-grep Limitations
|
|
137
126
|
|
|
138
|
-
|
|
127
|
+
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
128
|
|
|
140
|
-
If
|
|
129
|
+
4. **Fallback protocol:** If an ast-grep pattern returns errors or zero results when results are expected:
|
|
130
|
+
- First: retry with `find_code()` using a simpler pattern (drop type annotations, use broader match)
|
|
131
|
+
- Second: if `find_code()` also fails, fall back to source reading for that pattern category (T1-low confidence)
|
|
132
|
+
- Never silently accept zero results for a pattern category that the source language commonly uses
|
|
141
133
|
|
|
142
|
-
|
|
134
|
+
Read the forms #11 lists by eye whether or not the runner ran:
|
|
143
135
|
|
|
144
|
-
**
|
|
136
|
+
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.
|
|
137
|
+
- **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.
|
|
138
|
+
- **`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).
|
|
139
|
+
- **`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`.
|
|
140
|
+
- **`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).
|
|
141
|
+
- **`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`.
|
|
142
|
+
- **`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.
|
|
143
|
+
- **`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`).
|
|
144
|
+
- **`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`.
|
|
145
|
+
- **`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.
|
|
146
|
+
- **`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
147
|
|
|
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
|
-
```
|
|
148
|
+
### Re-Export Tracing and Script/Asset Extraction
|
|
155
149
|
|
|
156
|
-
|
|
150
|
+
See `extraction-patterns-tracing.md` for:
|
|
151
|
+
- **Re-export tracing protocol:** resolving module imports through `__init__.py`, barrel files, `pub use`
|
|
152
|
+
- **Script/asset extraction patterns:** detection heuristics, inclusion rules, provenance, inventory structure
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Relabel Rule
|
|
157
|
+
|
|
158
|
+
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.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Running the Recipes Without the Runner
|
|
163
|
+
|
|
164
|
+
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.
|
|
165
|
+
|
|
166
|
+
### Decision Tree
|
|
167
|
+
|
|
168
|
+
Apply the first matching condition:
|
|
157
169
|
|
|
158
170
|
```
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
output_format="
|
|
164
|
-
)
|
|
171
|
+
.vue files (the Vue recipes), at any scope size
|
|
172
|
+
→ CLI streaming with -c {scratch}/sgconfig.yml (find_code_by_rule cannot read them; see the Vue note in extraction-patterns-by-hand.md)
|
|
173
|
+
|
|
174
|
+
Files in scope ≤ 500
|
|
175
|
+
→ Use ast-grep MCP tool: find_code_by_rule(yaml=<recipe>, max_results=150, output_format="json")
|
|
176
|
+
→ Run every recipe for the language (see recipes below), one call per recipe
|
|
177
|
+
→ Read $NAME (and $SOURCE) from each match's metaVariables, and its line from $NAME
|
|
178
|
+
→ Merge the matches into extraction inventory
|
|
179
|
+
|
|
180
|
+
Files in scope > 500
|
|
181
|
+
→ CLI streaming: ast-grep scan -r {recipe_file} --json=stream + line-by-line Python processing
|
|
182
|
+
→ Process in directory batches, cap per-batch output
|
|
183
|
+
→ Merge batch results into extraction inventory
|
|
165
184
|
```
|
|
166
185
|
|
|
167
|
-
|
|
186
|
+
`extraction-patterns-by-hand.md`'s MCP Tool Usage shows the call with a recipe as its `yaml`.
|
|
168
187
|
|
|
169
|
-
|
|
188
|
+
### CLI Streaming Fallback
|
|
170
189
|
|
|
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)
|
|
190
|
+
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
191
|
|
|
176
|
-
|
|
192
|
+
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
193
|
|
|
178
194
|
```bash
|
|
179
|
-
#
|
|
180
|
-
# {
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
ast-grep
|
|
195
|
+
# {recipe_file}: one recipe's YAML in a scratch file (never inline: its regexes are quoted).
|
|
196
|
+
# {recipe_id}, {node_kind}: its id and declared kind, each export's ast_recipe and ast_node_type.
|
|
197
|
+
# .vue files: add -c {scratch}/sgconfig.yml (the by-hand file's Vue note). {HEAD_CAP}: the Recipe Runner's head cap.
|
|
198
|
+
# {exclude_patterns}: the brief's scope.exclude as a Python list, [] when it has none.
|
|
199
|
+
# fnmatch is not the Files in scope rule above: its `*` also crosses `/`, and `**/x`
|
|
200
|
+
# needs a folder before x, so add x too for a top-level file ('test_*' beside '**/test_*').
|
|
201
|
+
# The patterns match ast-grep's file paths, relative to the root they name (no ./).
|
|
202
|
+
ast-grep scan -r {recipe_file} --json=stream {path} | python3 -c "
|
|
187
203
|
import sys, json, fnmatch, signal
|
|
188
|
-
|
|
204
|
+
if hasattr(signal, 'SIGPIPE'): # POSIX only; Windows has no SIGPIPE
|
|
205
|
+
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
189
206
|
|
|
190
207
|
EXCLUDES = {exclude_patterns}
|
|
208
|
+
RECIPE = '{recipe_id}'
|
|
209
|
+
KIND = '{node_kind}'
|
|
191
210
|
|
|
192
211
|
for line in sys.stdin:
|
|
193
212
|
try:
|
|
@@ -195,35 +214,50 @@ for line in sys.stdin:
|
|
|
195
214
|
f = m.get('file','')
|
|
196
215
|
if EXCLUDES and any(fnmatch.fnmatch(f, pat) for pat in EXCLUDES):
|
|
197
216
|
continue
|
|
198
|
-
v = m.get('metaVariables',{})
|
|
199
|
-
name = v.get('
|
|
217
|
+
v = m.get('metaVariables',{}).get('single',{})
|
|
218
|
+
name = v.get('NAME',{}).get('text','')
|
|
200
219
|
if name and not name.startswith('_'):
|
|
201
|
-
ln =
|
|
202
|
-
|
|
203
|
-
|
|
220
|
+
ln = v['NAME'].get('range',{}).get('start',{}).get('line',0)+1
|
|
221
|
+
first = m.get('range',{}).get('start',{}).get('line',0)+1
|
|
222
|
+
text = m.get('text','').split(chr(10))
|
|
223
|
+
sig = text[min(ln-first, len(text)-1)].strip()
|
|
224
|
+
src = v.get('SOURCE',{}).get('text','')
|
|
225
|
+
print(f'[AST:{f}:L{ln}] {RECIPE} kind={KIND} name={name}' + (f' from={src}' if src else '') + f' {sig}')
|
|
204
226
|
except: pass
|
|
205
227
|
" | head -{HEAD_CAP}
|
|
206
228
|
```
|
|
207
229
|
|
|
208
|
-
|
|
230
|
+
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
231
|
|
|
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)
|
|
232
|
+
**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
233
|
|
|
215
234
|
### YAML Rule Recipes by Language
|
|
216
235
|
|
|
236
|
+
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.
|
|
237
|
+
|
|
217
238
|
**Python — public functions:**
|
|
218
239
|
|
|
219
240
|
```yaml
|
|
220
241
|
id: python-public-functions
|
|
221
242
|
language: python
|
|
222
243
|
rule:
|
|
223
|
-
pattern: 'def $NAME
|
|
244
|
+
pattern: 'def $NAME'
|
|
245
|
+
kind: function_definition
|
|
224
246
|
inside:
|
|
225
247
|
kind: module
|
|
226
|
-
stopBy:
|
|
248
|
+
stopBy:
|
|
249
|
+
any:
|
|
250
|
+
- kind: function_definition
|
|
251
|
+
- kind: class_definition
|
|
252
|
+
not:
|
|
253
|
+
inside:
|
|
254
|
+
kind: block
|
|
255
|
+
stopBy: end
|
|
256
|
+
inside:
|
|
257
|
+
kind: if_statement
|
|
258
|
+
has:
|
|
259
|
+
field: condition
|
|
260
|
+
regex: '^\(?\s*(__name__\s*==\s*[''"]__main__[''"]|[''"]__main__[''"]\s*==\s*__name__)\s*\)?$'
|
|
227
261
|
constraints:
|
|
228
262
|
NAME:
|
|
229
263
|
regex: '^[^_]'
|
|
@@ -239,23 +273,84 @@ rule:
|
|
|
239
273
|
kind: class_definition
|
|
240
274
|
inside:
|
|
241
275
|
kind: module
|
|
242
|
-
stopBy:
|
|
276
|
+
stopBy:
|
|
277
|
+
any:
|
|
278
|
+
- kind: function_definition
|
|
279
|
+
- kind: class_definition
|
|
280
|
+
not:
|
|
281
|
+
inside:
|
|
282
|
+
kind: block
|
|
283
|
+
stopBy: end
|
|
284
|
+
inside:
|
|
285
|
+
kind: if_statement
|
|
286
|
+
has:
|
|
287
|
+
field: condition
|
|
288
|
+
regex: '^\(?\s*(__name__\s*==\s*[''"]__main__[''"]|[''"]__main__[''"]\s*==\s*__name__)\s*\)?$'
|
|
243
289
|
constraints:
|
|
244
290
|
NAME:
|
|
245
291
|
regex: '^[^_]'
|
|
246
292
|
```
|
|
247
293
|
|
|
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
294
|
**JavaScript/TypeScript — exported functions:**
|
|
251
295
|
|
|
252
|
-
|
|
296
|
+
```yaml
|
|
297
|
+
id: js-exported-functions
|
|
298
|
+
language: typescript # Use 'tsx' for .tsx files; the javascript form below for .js
|
|
299
|
+
rule:
|
|
300
|
+
kind: export_statement
|
|
301
|
+
inside:
|
|
302
|
+
kind: program
|
|
303
|
+
any:
|
|
304
|
+
- has:
|
|
305
|
+
field: declaration
|
|
306
|
+
any:
|
|
307
|
+
- kind: function_declaration
|
|
308
|
+
- kind: generator_function_declaration
|
|
309
|
+
- kind: function_signature
|
|
310
|
+
has:
|
|
311
|
+
field: name
|
|
312
|
+
pattern: $NAME
|
|
313
|
+
- has:
|
|
314
|
+
field: declaration
|
|
315
|
+
kind: ambient_declaration
|
|
316
|
+
has:
|
|
317
|
+
kind: function_signature
|
|
318
|
+
has:
|
|
319
|
+
field: name
|
|
320
|
+
pattern: $NAME
|
|
321
|
+
not:
|
|
322
|
+
has:
|
|
323
|
+
field: declaration
|
|
324
|
+
any:
|
|
325
|
+
- kind: function_declaration
|
|
326
|
+
- kind: generator_function_declaration
|
|
327
|
+
follows:
|
|
328
|
+
stopBy:
|
|
329
|
+
not:
|
|
330
|
+
kind: comment
|
|
331
|
+
kind: export_statement
|
|
332
|
+
has:
|
|
333
|
+
field: declaration
|
|
334
|
+
kind: function_signature
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**JavaScript: exported functions (`.js`, `.jsx`, `.mjs`, `.cjs`):**
|
|
253
338
|
|
|
254
339
|
```yaml
|
|
255
340
|
id: js-exported-functions
|
|
256
|
-
language:
|
|
341
|
+
language: javascript
|
|
257
342
|
rule:
|
|
258
|
-
|
|
343
|
+
kind: export_statement
|
|
344
|
+
inside:
|
|
345
|
+
kind: program
|
|
346
|
+
has:
|
|
347
|
+
field: declaration
|
|
348
|
+
any:
|
|
349
|
+
- kind: function_declaration
|
|
350
|
+
- kind: generator_function_declaration
|
|
351
|
+
has:
|
|
352
|
+
field: name
|
|
353
|
+
pattern: $NAME
|
|
259
354
|
```
|
|
260
355
|
|
|
261
356
|
**JavaScript/TypeScript — exported constants:**
|
|
@@ -264,7 +359,26 @@ rule:
|
|
|
264
359
|
id: js-exported-constants
|
|
265
360
|
language: typescript
|
|
266
361
|
rule:
|
|
267
|
-
|
|
362
|
+
kind: export_statement
|
|
363
|
+
inside:
|
|
364
|
+
kind: program
|
|
365
|
+
has:
|
|
366
|
+
field: declaration
|
|
367
|
+
kind: lexical_declaration
|
|
368
|
+
all:
|
|
369
|
+
- has:
|
|
370
|
+
field: kind
|
|
371
|
+
regex: '^const$'
|
|
372
|
+
- has:
|
|
373
|
+
kind: variable_declarator
|
|
374
|
+
all:
|
|
375
|
+
- has:
|
|
376
|
+
field: name
|
|
377
|
+
kind: identifier
|
|
378
|
+
pattern: $NAME
|
|
379
|
+
- has:
|
|
380
|
+
field: value
|
|
381
|
+
pattern: $VALUE
|
|
268
382
|
```
|
|
269
383
|
|
|
270
384
|
**JavaScript/TypeScript — exported arrow functions:**
|
|
@@ -273,25 +387,193 @@ rule:
|
|
|
273
387
|
id: js-exported-arrow-functions
|
|
274
388
|
language: typescript
|
|
275
389
|
rule:
|
|
276
|
-
|
|
390
|
+
kind: export_statement
|
|
391
|
+
inside:
|
|
392
|
+
kind: program
|
|
393
|
+
has:
|
|
394
|
+
field: declaration
|
|
395
|
+
kind: lexical_declaration
|
|
396
|
+
all:
|
|
397
|
+
- has:
|
|
398
|
+
field: kind
|
|
399
|
+
regex: '^const$'
|
|
400
|
+
- has:
|
|
401
|
+
kind: variable_declarator
|
|
402
|
+
all:
|
|
403
|
+
- has:
|
|
404
|
+
field: name
|
|
405
|
+
kind: identifier
|
|
406
|
+
pattern: $NAME
|
|
407
|
+
- has:
|
|
408
|
+
field: value
|
|
409
|
+
kind: arrow_function
|
|
410
|
+
pattern: $VALUE
|
|
277
411
|
```
|
|
278
412
|
|
|
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
413
|
**JavaScript/TypeScript — exported classes:**
|
|
282
414
|
|
|
283
415
|
```yaml
|
|
284
416
|
id: js-exported-classes
|
|
285
417
|
language: typescript
|
|
286
418
|
rule:
|
|
287
|
-
|
|
419
|
+
kind: export_statement
|
|
420
|
+
inside:
|
|
421
|
+
kind: program
|
|
422
|
+
not:
|
|
423
|
+
has:
|
|
424
|
+
regex: '^default$'
|
|
425
|
+
has:
|
|
426
|
+
field: declaration
|
|
427
|
+
all:
|
|
428
|
+
- has:
|
|
429
|
+
field: name
|
|
430
|
+
pattern: $NAME
|
|
431
|
+
- has:
|
|
432
|
+
field: body
|
|
433
|
+
kind: class_body
|
|
288
434
|
```
|
|
289
435
|
|
|
290
|
-
|
|
436
|
+
**TypeScript: exported interfaces, type aliases and enums:**
|
|
291
437
|
|
|
292
|
-
|
|
438
|
+
```yaml
|
|
439
|
+
id: ts-exported-types
|
|
440
|
+
language: typescript # Use 'tsx' for .tsx files
|
|
441
|
+
rule:
|
|
442
|
+
kind: export_statement
|
|
443
|
+
inside:
|
|
444
|
+
kind: program
|
|
445
|
+
not:
|
|
446
|
+
has:
|
|
447
|
+
regex: '^default$'
|
|
448
|
+
has:
|
|
449
|
+
field: declaration
|
|
450
|
+
any:
|
|
451
|
+
- any:
|
|
452
|
+
- kind: interface_declaration
|
|
453
|
+
- kind: type_alias_declaration
|
|
454
|
+
- kind: enum_declaration
|
|
455
|
+
has:
|
|
456
|
+
field: name
|
|
457
|
+
pattern: $NAME
|
|
458
|
+
- kind: ambient_declaration
|
|
459
|
+
has:
|
|
460
|
+
any:
|
|
461
|
+
- kind: interface_declaration
|
|
462
|
+
- kind: type_alias_declaration
|
|
463
|
+
- kind: enum_declaration
|
|
464
|
+
has:
|
|
465
|
+
field: name
|
|
466
|
+
pattern: $NAME
|
|
467
|
+
```
|
|
293
468
|
|
|
294
|
-
|
|
469
|
+
**JavaScript/TypeScript: re-exported names:**
|
|
470
|
+
|
|
471
|
+
```yaml
|
|
472
|
+
id: js-reexports
|
|
473
|
+
language: typescript
|
|
474
|
+
rule:
|
|
475
|
+
kind: export_specifier
|
|
476
|
+
inside:
|
|
477
|
+
kind: export_clause
|
|
478
|
+
inside:
|
|
479
|
+
kind: export_statement
|
|
480
|
+
inside:
|
|
481
|
+
kind: program
|
|
482
|
+
has:
|
|
483
|
+
field: source
|
|
484
|
+
has:
|
|
485
|
+
kind: string_fragment
|
|
486
|
+
pattern: $SOURCE
|
|
487
|
+
any:
|
|
488
|
+
- has:
|
|
489
|
+
field: alias
|
|
490
|
+
any:
|
|
491
|
+
- has:
|
|
492
|
+
kind: string_fragment
|
|
493
|
+
pattern: $NAME
|
|
494
|
+
- not:
|
|
495
|
+
kind: string
|
|
496
|
+
pattern: $NAME
|
|
497
|
+
- all:
|
|
498
|
+
- not:
|
|
499
|
+
has:
|
|
500
|
+
field: alias
|
|
501
|
+
regex: '.'
|
|
502
|
+
- has:
|
|
503
|
+
field: name
|
|
504
|
+
any:
|
|
505
|
+
- has:
|
|
506
|
+
kind: string_fragment
|
|
507
|
+
pattern: $NAME
|
|
508
|
+
- not:
|
|
509
|
+
kind: string
|
|
510
|
+
pattern: $NAME
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
**JavaScript/TypeScript: namespace re-exports:**
|
|
514
|
+
|
|
515
|
+
```yaml
|
|
516
|
+
id: js-namespace-reexports
|
|
517
|
+
language: typescript
|
|
518
|
+
rule:
|
|
519
|
+
kind: export_statement
|
|
520
|
+
inside:
|
|
521
|
+
kind: program
|
|
522
|
+
all:
|
|
523
|
+
- has:
|
|
524
|
+
field: source
|
|
525
|
+
has:
|
|
526
|
+
kind: string_fragment
|
|
527
|
+
pattern: $SOURCE
|
|
528
|
+
- has:
|
|
529
|
+
kind: namespace_export
|
|
530
|
+
any:
|
|
531
|
+
- has:
|
|
532
|
+
kind: identifier
|
|
533
|
+
pattern: $NAME
|
|
534
|
+
- has:
|
|
535
|
+
kind: string
|
|
536
|
+
has:
|
|
537
|
+
kind: string_fragment
|
|
538
|
+
pattern: $NAME
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**JavaScript/TypeScript: local export lists:**
|
|
542
|
+
|
|
543
|
+
```yaml
|
|
544
|
+
id: js-local-exports
|
|
545
|
+
language: typescript # Use 'tsx' for .tsx files, 'javascript' for .js files
|
|
546
|
+
rule:
|
|
547
|
+
kind: export_specifier
|
|
548
|
+
inside:
|
|
549
|
+
kind: export_clause
|
|
550
|
+
inside:
|
|
551
|
+
kind: export_statement
|
|
552
|
+
inside:
|
|
553
|
+
kind: program
|
|
554
|
+
not:
|
|
555
|
+
has:
|
|
556
|
+
field: source
|
|
557
|
+
kind: string
|
|
558
|
+
any:
|
|
559
|
+
- has:
|
|
560
|
+
field: alias
|
|
561
|
+
any:
|
|
562
|
+
- has:
|
|
563
|
+
kind: string_fragment
|
|
564
|
+
pattern: $NAME
|
|
565
|
+
- not:
|
|
566
|
+
kind: string
|
|
567
|
+
pattern: $NAME
|
|
568
|
+
- all:
|
|
569
|
+
- not:
|
|
570
|
+
has:
|
|
571
|
+
field: alias
|
|
572
|
+
regex: '.'
|
|
573
|
+
- has:
|
|
574
|
+
field: name
|
|
575
|
+
pattern: $NAME
|
|
576
|
+
```
|
|
295
577
|
|
|
296
578
|
**Rust — public functions:**
|
|
297
579
|
|
|
@@ -299,9 +581,32 @@ Use `find_code()` with pattern `export { $$$NAMES } from $SOURCE` for re-export
|
|
|
299
581
|
id: rust-public-functions
|
|
300
582
|
language: rust
|
|
301
583
|
rule:
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
584
|
+
kind: function_item
|
|
585
|
+
has:
|
|
586
|
+
field: name
|
|
587
|
+
pattern: $NAME
|
|
588
|
+
all:
|
|
589
|
+
- has:
|
|
590
|
+
kind: visibility_modifier
|
|
591
|
+
regex: '^pub$'
|
|
592
|
+
- inside:
|
|
593
|
+
any:
|
|
594
|
+
- kind: source_file
|
|
595
|
+
- kind: declaration_list
|
|
596
|
+
inside:
|
|
597
|
+
kind: mod_item
|
|
598
|
+
- not:
|
|
599
|
+
inside:
|
|
600
|
+
kind: mod_item
|
|
601
|
+
stopBy: end
|
|
602
|
+
not:
|
|
603
|
+
has:
|
|
604
|
+
kind: visibility_modifier
|
|
605
|
+
regex: '^pub$'
|
|
606
|
+
- not:
|
|
607
|
+
inside:
|
|
608
|
+
kind: block
|
|
609
|
+
stopBy: end
|
|
305
610
|
```
|
|
306
611
|
|
|
307
612
|
**Go — exported functions (capitalized):**
|
|
@@ -310,12 +615,17 @@ rule:
|
|
|
310
615
|
id: go-exported-functions
|
|
311
616
|
language: go
|
|
312
617
|
rule:
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
618
|
+
kind: function_declaration
|
|
619
|
+
has:
|
|
620
|
+
field: name
|
|
621
|
+
pattern: $NAME
|
|
622
|
+
not:
|
|
623
|
+
has:
|
|
624
|
+
field: receiver
|
|
625
|
+
kind: parameter_list
|
|
316
626
|
constraints:
|
|
317
627
|
NAME:
|
|
318
|
-
regex: '
|
|
628
|
+
regex: '^\p{Lu}'
|
|
319
629
|
```
|
|
320
630
|
|
|
321
631
|
### Component Library YAML Rule Recipes
|
|
@@ -328,7 +638,18 @@ These patterns are used by `component-extraction.md` when `scope.type: "componen
|
|
|
328
638
|
id: react-props-interfaces
|
|
329
639
|
language: typescript # Use 'tsx' for .tsx files
|
|
330
640
|
rule:
|
|
331
|
-
|
|
641
|
+
kind: export_statement
|
|
642
|
+
inside:
|
|
643
|
+
kind: program
|
|
644
|
+
not:
|
|
645
|
+
has:
|
|
646
|
+
regex: '^default$'
|
|
647
|
+
has:
|
|
648
|
+
field: declaration
|
|
649
|
+
kind: interface_declaration
|
|
650
|
+
has:
|
|
651
|
+
field: name
|
|
652
|
+
pattern: $NAME
|
|
332
653
|
constraints:
|
|
333
654
|
NAME:
|
|
334
655
|
regex: '.*Props$'
|
|
@@ -336,28 +657,133 @@ constraints:
|
|
|
336
657
|
|
|
337
658
|
**React/TypeScript — Component function exports (PascalCase):**
|
|
338
659
|
|
|
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
660
|
```yaml
|
|
342
661
|
id: react-component-functions
|
|
343
662
|
language: tsx
|
|
344
663
|
rule:
|
|
345
|
-
|
|
664
|
+
kind: export_statement
|
|
665
|
+
inside:
|
|
666
|
+
kind: program
|
|
667
|
+
any:
|
|
668
|
+
- has:
|
|
669
|
+
field: declaration
|
|
670
|
+
any:
|
|
671
|
+
- kind: function_declaration
|
|
672
|
+
- kind: function_signature
|
|
673
|
+
has:
|
|
674
|
+
field: name
|
|
675
|
+
pattern: $NAME
|
|
676
|
+
- has:
|
|
677
|
+
field: declaration
|
|
678
|
+
kind: ambient_declaration
|
|
679
|
+
has:
|
|
680
|
+
kind: function_signature
|
|
681
|
+
has:
|
|
682
|
+
field: name
|
|
683
|
+
pattern: $NAME
|
|
684
|
+
not:
|
|
685
|
+
has:
|
|
686
|
+
field: declaration
|
|
687
|
+
kind: function_declaration
|
|
688
|
+
follows:
|
|
689
|
+
stopBy:
|
|
690
|
+
not:
|
|
691
|
+
kind: comment
|
|
692
|
+
kind: export_statement
|
|
693
|
+
has:
|
|
694
|
+
field: declaration
|
|
695
|
+
kind: function_signature
|
|
346
696
|
constraints:
|
|
347
697
|
NAME:
|
|
348
|
-
regex: '
|
|
698
|
+
regex: '^\p{Lu}'
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
**React/JavaScript: component function exports (`.js`, `.jsx`, `.mjs`, `.cjs`):**
|
|
702
|
+
|
|
703
|
+
```yaml
|
|
704
|
+
id: react-component-functions
|
|
705
|
+
language: javascript
|
|
706
|
+
rule:
|
|
707
|
+
kind: export_statement
|
|
708
|
+
inside:
|
|
709
|
+
kind: program
|
|
710
|
+
has:
|
|
711
|
+
field: declaration
|
|
712
|
+
kind: function_declaration
|
|
713
|
+
has:
|
|
714
|
+
field: name
|
|
715
|
+
pattern: $NAME
|
|
716
|
+
constraints:
|
|
717
|
+
NAME:
|
|
718
|
+
regex: '^\p{Lu}'
|
|
349
719
|
```
|
|
350
720
|
|
|
351
721
|
**React/TypeScript — Component arrow function exports:**
|
|
352
722
|
|
|
353
723
|
```yaml
|
|
354
724
|
id: react-component-arrow-functions
|
|
355
|
-
language: typescript
|
|
725
|
+
language: typescript # Use 'tsx' for .tsx files
|
|
356
726
|
rule:
|
|
357
|
-
|
|
727
|
+
kind: export_statement
|
|
728
|
+
inside:
|
|
729
|
+
kind: program
|
|
730
|
+
has:
|
|
731
|
+
field: declaration
|
|
732
|
+
kind: lexical_declaration
|
|
733
|
+
all:
|
|
734
|
+
- has:
|
|
735
|
+
field: kind
|
|
736
|
+
regex: '^const$'
|
|
737
|
+
- has:
|
|
738
|
+
kind: variable_declarator
|
|
739
|
+
all:
|
|
740
|
+
- has:
|
|
741
|
+
field: name
|
|
742
|
+
kind: identifier
|
|
743
|
+
regex: '^\p{Lu}'
|
|
744
|
+
pattern: $NAME
|
|
745
|
+
- has:
|
|
746
|
+
field: value
|
|
747
|
+
kind: arrow_function
|
|
748
|
+
pattern: $VALUE
|
|
358
749
|
constraints:
|
|
359
750
|
NAME:
|
|
360
|
-
regex: '
|
|
751
|
+
regex: '^\p{Lu}'
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
**React: wrapped component exports (`memo`, `forwardRef`, `lazy`):**
|
|
755
|
+
|
|
756
|
+
```yaml
|
|
757
|
+
id: react-wrapped-components
|
|
758
|
+
language: tsx
|
|
759
|
+
rule:
|
|
760
|
+
kind: export_statement
|
|
761
|
+
inside:
|
|
762
|
+
kind: program
|
|
763
|
+
has:
|
|
764
|
+
field: declaration
|
|
765
|
+
kind: lexical_declaration
|
|
766
|
+
all:
|
|
767
|
+
- has:
|
|
768
|
+
field: kind
|
|
769
|
+
regex: '^const$'
|
|
770
|
+
- has:
|
|
771
|
+
kind: variable_declarator
|
|
772
|
+
all:
|
|
773
|
+
- has:
|
|
774
|
+
field: name
|
|
775
|
+
kind: identifier
|
|
776
|
+
regex: '^\p{Lu}'
|
|
777
|
+
pattern: $NAME
|
|
778
|
+
- has:
|
|
779
|
+
field: value
|
|
780
|
+
kind: call_expression
|
|
781
|
+
has:
|
|
782
|
+
field: function
|
|
783
|
+
regex: '^(React\.)?(memo|forwardRef|lazy)$'
|
|
784
|
+
constraints:
|
|
785
|
+
NAME:
|
|
786
|
+
regex: '^\p{Lu}'
|
|
361
787
|
```
|
|
362
788
|
|
|
363
789
|
**Vue — defineProps extraction:**
|
|
@@ -366,78 +792,40 @@ constraints:
|
|
|
366
792
|
id: vue-define-props
|
|
367
793
|
language: typescript
|
|
368
794
|
rule:
|
|
369
|
-
pattern: 'defineProps<$
|
|
795
|
+
pattern: 'defineProps<$NAME>()'
|
|
796
|
+
kind: call_expression
|
|
797
|
+
not:
|
|
798
|
+
inside:
|
|
799
|
+
stopBy: end
|
|
800
|
+
any:
|
|
801
|
+
- kind: statement_block
|
|
802
|
+
- kind: arrow_function
|
|
803
|
+
- kind: class_body
|
|
804
|
+
- kind: if_statement
|
|
805
|
+
- kind: for_statement
|
|
806
|
+
- kind: for_in_statement
|
|
807
|
+
- kind: while_statement
|
|
808
|
+
- kind: switch_case
|
|
370
809
|
```
|
|
371
810
|
|
|
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
|
|
811
|
+
**Vue: defineProps extraction for `<script setup lang="tsx">`:**
|
|
443
812
|
|
|
813
|
+
```yaml
|
|
814
|
+
id: vue-define-props-tsx
|
|
815
|
+
language: tsx
|
|
816
|
+
rule:
|
|
817
|
+
pattern: 'defineProps<$NAME>()'
|
|
818
|
+
kind: call_expression
|
|
819
|
+
not:
|
|
820
|
+
inside:
|
|
821
|
+
stopBy: end
|
|
822
|
+
any:
|
|
823
|
+
- kind: statement_block
|
|
824
|
+
- kind: arrow_function
|
|
825
|
+
- kind: class_body
|
|
826
|
+
- kind: if_statement
|
|
827
|
+
- kind: for_statement
|
|
828
|
+
- kind: for_in_statement
|
|
829
|
+
- kind: while_statement
|
|
830
|
+
- kind: switch_case
|
|
831
|
+
```
|