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.
Files changed (437) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +49 -49
  3. package/docs/404.md +10 -8
  4. package/docs/_data/pinned.yaml +22 -13
  5. package/docs/_internal/STABILITY.md +58 -35
  6. package/docs/agents.md +39 -53
  7. package/docs/architecture.md +65 -51
  8. package/docs/bmad-synergy.md +53 -51
  9. package/docs/campaign.md +127 -75
  10. package/docs/concepts.md +34 -28
  11. package/docs/examples.md +70 -68
  12. package/docs/forge-auto.md +34 -31
  13. package/docs/getting-started.md +118 -57
  14. package/docs/how-it-works.md +25 -21
  15. package/docs/index.md +15 -15
  16. package/docs/skill-model.md +70 -59
  17. package/docs/troubleshooting.md +143 -18
  18. package/docs/verifying-a-skill.md +87 -57
  19. package/docs/why-skf.md +24 -22
  20. package/docs/workflows.md +274 -110
  21. package/package.json +18 -10
  22. package/src/forger/preferences.yaml +8 -1
  23. package/src/knowledge/agentskills-spec.md +2 -0
  24. package/src/knowledge/ccc-bridge.md +40 -24
  25. package/src/knowledge/confidence-tiers.md +9 -5
  26. package/src/knowledge/overview.md +3 -3
  27. package/src/knowledge/progressive-capability.md +8 -8
  28. package/src/knowledge/provenance-tracking.md +9 -5
  29. package/src/knowledge/qmd-registry.md +3 -3
  30. package/src/knowledge/skf-knowledge-index.csv +2 -2
  31. package/src/knowledge/skill-lifecycle.md +18 -11
  32. package/src/knowledge/split-body-strategy.md +0 -3
  33. package/src/knowledge/tool-resolution.md +4 -2
  34. package/src/knowledge/version-paths.md +101 -15
  35. package/src/module-help.csv +3 -3
  36. package/src/module.yaml +10 -0
  37. package/src/shared/data/ast-grep-recipes.yaml +608 -0
  38. package/src/shared/data/ide-context-files.json +30 -0
  39. package/src/shared/health-check.md +31 -59
  40. package/src/shared/references/description-guard-protocol.md +12 -9
  41. package/src/shared/references/feasibility-report-schema.md +19 -13
  42. package/src/shared/references/headless-gate-convention.md +55 -3
  43. package/src/shared/references/output-contract-schema.md +19 -8
  44. package/src/shared/references/pipeline-contracts.md +94 -29
  45. package/src/shared/references/tessl-review.md +77 -0
  46. package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
  47. package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
  48. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
  49. package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
  50. package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
  51. package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
  52. package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
  53. package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
  54. package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
  55. package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
  56. package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
  57. package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
  58. package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
  59. package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
  60. package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
  61. package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
  62. package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
  63. package/src/shared/scripts/skf-atomic-write.py +233 -64
  64. package/src/shared/scripts/skf-build-change-manifest.py +2753 -28
  65. package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
  66. package/src/shared/scripts/skf-check-unit-records.py +184 -0
  67. package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
  68. package/src/shared/scripts/skf-classify-changed-files.py +772 -0
  69. package/src/shared/scripts/skf-comention-pairs.py +1333 -123
  70. package/src/shared/scripts/skf-compare-file-hashes.py +267 -105
  71. package/src/shared/scripts/skf-count-imports.py +1867 -0
  72. package/src/shared/scripts/skf-count-tokens.py +1 -1
  73. package/src/shared/scripts/skf-derive-assembly-shape.py +21 -3
  74. package/src/shared/scripts/skf-description-guard.py +99 -11
  75. package/src/shared/scripts/skf-detect-docs.py +694 -2
  76. package/src/shared/scripts/skf-detect-language.py +486 -107
  77. package/src/shared/scripts/skf-detect-registry.py +887 -0
  78. package/src/shared/scripts/skf-detect-scripts-assets.py +197 -55
  79. package/src/shared/scripts/skf-detect-tools.py +209 -27
  80. package/src/shared/scripts/skf-detect-workspaces.py +506 -30
  81. package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
  82. package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
  83. package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
  84. package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
  85. package/src/shared/scripts/skf-extract-public-api.py +5247 -96
  86. package/src/shared/scripts/skf-extraction-inventory.py +1280 -0
  87. package/src/shared/scripts/skf-extraction-snapshot.py +664 -0
  88. package/src/shared/scripts/skf-fetch-temporal.py +674 -0
  89. package/src/shared/scripts/skf-find-cycles.py +97 -29
  90. package/src/shared/scripts/skf-find-test-report.py +476 -0
  91. package/src/shared/scripts/skf-forge-tier-rw.py +469 -205
  92. package/src/shared/scripts/skf-github-fetch.py +365 -0
  93. package/src/shared/scripts/skf-github-probe.py +700 -0
  94. package/src/shared/scripts/skf-hash-content.py +180 -20
  95. package/src/shared/scripts/skf-language-corpora.py +1 -1
  96. package/src/shared/scripts/skf-load-provenance.py +161 -27
  97. package/src/shared/scripts/skf-manifest-ops.py +1 -1
  98. package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
  99. package/src/shared/scripts/skf-merge-doc-urls.py +143 -20
  100. package/src/shared/scripts/skf-names-present.py +221 -0
  101. package/src/shared/scripts/skf-pair-intersect.py +119 -28
  102. package/src/shared/scripts/skf-parse-gaps.py +1384 -0
  103. package/src/shared/scripts/skf-preapply.py +1 -1
  104. package/src/shared/scripts/skf-preflight.py +176 -28
  105. package/src/shared/scripts/skf-promote-staged.py +430 -0
  106. package/src/shared/scripts/skf-provenance-gap-dispatch.py +64 -8
  107. package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
  108. package/src/shared/scripts/skf-quick-batch.py +774 -0
  109. package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
  110. package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
  111. package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
  112. package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
  113. package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
  114. package/src/shared/scripts/skf-resolve-authoritative-files.py +155 -14
  115. package/src/shared/scripts/skf-resolve-package.py +523 -106
  116. package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
  117. package/src/shared/scripts/skf-run-lock.py +577 -0
  118. package/src/shared/scripts/skf-scan-manifests.py +998 -57
  119. package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
  120. package/src/shared/scripts/skf-severity-classify.py +712 -108
  121. package/src/shared/scripts/skf-shape-detect.py +298 -204
  122. package/src/shared/scripts/skf-shard-body.py +9 -8
  123. package/src/shared/scripts/skf-skill-inventory.py +2412 -89
  124. package/src/shared/scripts/skf-skills-module.py +472 -0
  125. package/src/shared/scripts/skf-source-tree.py +1796 -0
  126. package/src/shared/scripts/skf-structural-diff.py +787 -121
  127. package/src/shared/scripts/skf-tessl-review.py +706 -0
  128. package/src/shared/scripts/skf-update-active-symlink.py +120 -67
  129. package/src/shared/scripts/skf-update-run-state.py +624 -0
  130. package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
  131. package/src/shared/scripts/skf-validate-brief-schema.py +23 -2
  132. package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
  133. package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
  134. package/src/shared/scripts/skf-validate-output.py +712 -64
  135. package/src/shared/scripts/skf-validate-pins.py +1 -1
  136. package/src/shared/scripts/skf-verify-no-trace.py +116 -10
  137. package/src/shared/scripts/skf-verify-provenance-completeness.py +3945 -152
  138. package/src/shared/scripts/skf-write-skill-brief.py +406 -25
  139. package/src/shared/tool-requirements.yaml +201 -0
  140. package/src/skf-analyze-source/SKILL.md +41 -36
  141. package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
  142. package/src/skf-analyze-source/customize.toml +36 -24
  143. package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
  144. package/src/skf-analyze-source/references/continue.md +2 -13
  145. package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
  146. package/src/skf-analyze-source/references/generate-briefs.md +121 -55
  147. package/src/skf-analyze-source/references/headless-contract.md +42 -15
  148. package/src/skf-analyze-source/references/identify-units.md +96 -110
  149. package/src/skf-analyze-source/references/init.md +73 -71
  150. package/src/skf-analyze-source/references/map-and-detect.md +123 -105
  151. package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
  152. package/src/skf-analyze-source/references/recommend.md +51 -70
  153. package/src/skf-analyze-source/references/scan-project.md +60 -84
  154. package/src/skf-analyze-source/references/scan-root.md +39 -0
  155. package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
  156. package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
  157. package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
  158. package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
  159. package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
  160. package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
  161. package/src/skf-audit-skill/SKILL.md +43 -51
  162. package/src/skf-audit-skill/assets/drift-report-template.md +28 -3
  163. package/src/skf-audit-skill/customize.toml +41 -20
  164. package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
  165. package/src/skf-audit-skill/references/doc-drift.md +141 -0
  166. package/src/skf-audit-skill/references/headless-contract.md +29 -0
  167. package/src/skf-audit-skill/references/health-check.md +2 -0
  168. package/src/skf-audit-skill/references/init.md +149 -210
  169. package/src/skf-audit-skill/references/re-index.md +103 -110
  170. package/src/skf-audit-skill/references/report.md +96 -33
  171. package/src/skf-audit-skill/references/semantic-diff.md +34 -25
  172. package/src/skf-audit-skill/references/severity-classify.md +79 -65
  173. package/src/skf-audit-skill/references/severity-rules.md +15 -6
  174. package/src/skf-audit-skill/references/structural-diff.md +80 -90
  175. package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
  176. package/src/skf-audit-skill/scripts/render-drift-tables.py +712 -0
  177. package/src/skf-brief-skill/SKILL.md +37 -26
  178. package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
  179. package/src/skf-brief-skill/assets/scope-templates.md +18 -25
  180. package/src/skf-brief-skill/assets/skill-brief-schema.md +30 -23
  181. package/src/skf-brief-skill/customize.toml +48 -20
  182. package/src/skf-brief-skill/references/analyze-target.md +144 -127
  183. package/src/skf-brief-skill/references/confirm-brief.md +11 -9
  184. package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
  185. package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
  186. package/src/skf-brief-skill/references/gather-intent.md +87 -182
  187. package/src/skf-brief-skill/references/headless-args.md +84 -16
  188. package/src/skf-brief-skill/references/health-check.md +1 -1
  189. package/src/skf-brief-skill/references/invocation-contract.md +18 -13
  190. package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
  191. package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
  192. package/src/skf-brief-skill/references/scope-definition.md +123 -47
  193. package/src/skf-brief-skill/references/step-auto-brief.md +26 -100
  194. package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
  195. package/src/skf-brief-skill/references/version-resolution.md +7 -10
  196. package/src/skf-brief-skill/references/write-brief.md +66 -57
  197. package/src/skf-campaign/SKILL.md +31 -34
  198. package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
  199. package/src/skf-campaign/customize.toml +47 -16
  200. package/src/skf-campaign/references/campaign-contracts.md +39 -29
  201. package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
  202. package/src/skf-campaign/references/health-check.md +7 -16
  203. package/src/skf-campaign/references/step-01-setup.md +46 -84
  204. package/src/skf-campaign/references/step-02-strategy.md +31 -30
  205. package/src/skf-campaign/references/step-03-pins.md +26 -18
  206. package/src/skf-campaign/references/step-04-provenance.md +24 -23
  207. package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
  208. package/src/skf-campaign/references/step-06-batch.md +41 -34
  209. package/src/skf-campaign/references/step-07-capstone.md +40 -25
  210. package/src/skf-campaign/references/step-08-verify.md +28 -29
  211. package/src/skf-campaign/references/step-09-refine.md +29 -30
  212. package/src/skf-campaign/references/step-10-export.md +48 -36
  213. package/src/skf-campaign/references/step-11-maintenance.md +31 -34
  214. package/src/skf-campaign/references/step-resume.md +37 -68
  215. package/src/skf-campaign/scripts/campaign-deps.py +57 -18
  216. package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
  217. package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
  218. package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
  219. package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
  220. package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
  221. package/src/skf-campaign/scripts/campaign-report.py +204 -37
  222. package/src/skf-campaign/scripts/campaign-state.py +1128 -0
  223. package/src/skf-campaign/scripts/campaign-status.py +10 -74
  224. package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
  225. package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
  226. package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
  227. package/src/skf-campaign/templates/campaign-report-template.md +5 -1
  228. package/src/skf-campaign/templates/kickoff-template.md +0 -14
  229. package/src/skf-create-skill/SKILL.md +27 -20
  230. package/src/skf-create-skill/assets/compile-assembly-rules.md +11 -8
  231. package/src/skf-create-skill/assets/skill-sections.md +21 -11
  232. package/src/skf-create-skill/customize.toml +20 -8
  233. package/src/skf-create-skill/references/authoritative-files-protocol.md +36 -58
  234. package/src/skf-create-skill/references/batch-mode.md +81 -0
  235. package/src/skf-create-skill/references/ccc-index-check.md +27 -0
  236. package/src/skf-create-skill/references/compile.md +119 -70
  237. package/src/skf-create-skill/references/component-extraction.md +113 -91
  238. package/src/skf-create-skill/references/enrich.md +41 -23
  239. package/src/skf-create-skill/references/entry-points-by-hand.md +37 -0
  240. package/src/skf-create-skill/references/extract.md +204 -162
  241. package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
  242. package/src/skf-create-skill/references/extraction-patterns-tracing.md +11 -11
  243. package/src/skf-create-skill/references/extraction-patterns.md +588 -201
  244. package/src/skf-create-skill/references/generate-artifacts.md +145 -93
  245. package/src/skf-create-skill/references/health-check.md +1 -1
  246. package/src/skf-create-skill/references/load-brief.md +53 -36
  247. package/src/skf-create-skill/references/relabel-rule.md +12 -0
  248. package/src/skf-create-skill/references/report.md +37 -57
  249. package/src/skf-create-skill/references/source-resolution-protocols.md +58 -169
  250. package/src/skf-create-skill/references/step-auto-shard.md +20 -93
  251. package/src/skf-create-skill/references/step-doc-rot.md +44 -60
  252. package/src/skf-create-skill/references/step-doc-sources.md +28 -19
  253. package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
  254. package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
  255. package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
  256. package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
  257. package/src/skf-create-skill/references/validate.md +173 -99
  258. package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
  259. package/src/skf-create-stack-skill/SKILL.md +29 -56
  260. package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
  261. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
  262. package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
  263. package/src/skf-create-stack-skill/customize.toml +23 -12
  264. package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
  265. package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
  266. package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
  267. package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
  268. package/src/skf-create-stack-skill/references/generate-output.md +138 -128
  269. package/src/skf-create-stack-skill/references/init.md +90 -32
  270. package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
  271. package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
  272. package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
  273. package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
  274. package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
  275. package/src/skf-create-stack-skill/references/report.md +39 -33
  276. package/src/skf-create-stack-skill/references/validate.md +20 -39
  277. package/src/skf-drop-skill/SKILL.md +28 -51
  278. package/src/skf-drop-skill/customize.toml +44 -30
  279. package/src/skf-drop-skill/references/execute.md +83 -146
  280. package/src/skf-drop-skill/references/health-check.md +2 -0
  281. package/src/skf-drop-skill/references/invocation-contract.md +64 -0
  282. package/src/skf-drop-skill/references/report.md +46 -30
  283. package/src/skf-drop-skill/references/select.md +122 -124
  284. package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
  285. package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
  286. package/src/skf-export-skill/SKILL.md +40 -62
  287. package/src/skf-export-skill/assets/managed-section-format.md +14 -50
  288. package/src/skf-export-skill/assets/snippet-format.md +3 -1
  289. package/src/skf-export-skill/customize.toml +42 -13
  290. package/src/skf-export-skill/references/generate-snippet.md +54 -46
  291. package/src/skf-export-skill/references/health-check.md +2 -0
  292. package/src/skf-export-skill/references/invocation-contract.md +15 -0
  293. package/src/skf-export-skill/references/load-skill.md +88 -62
  294. package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
  295. package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
  296. package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
  297. package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
  298. package/src/skf-export-skill/references/package.md +15 -73
  299. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
  300. package/src/skf-export-skill/references/result-envelope.md +31 -16
  301. package/src/skf-export-skill/references/summary.md +41 -17
  302. package/src/skf-export-skill/references/token-report.md +4 -12
  303. package/src/skf-export-skill/references/update-context.md +118 -237
  304. package/src/skf-forger/SKILL.md +61 -37
  305. package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
  306. package/src/skf-forger/customize.toml +43 -0
  307. package/src/skf-forger/references/pipeline-mode.md +73 -18
  308. package/src/skf-forger/scripts/forge-status.py +299 -0
  309. package/src/skf-forger/scripts/parse-pipeline.py +322 -54
  310. package/src/skf-forger/scripts/pipeline-gate.py +428 -0
  311. package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
  312. package/src/skf-quick-skill/SKILL.md +54 -53
  313. package/src/skf-quick-skill/assets/skill-template.md +4 -2
  314. package/src/skf-quick-skill/customize.toml +51 -20
  315. package/src/skf-quick-skill/references/batch-mode.md +74 -21
  316. package/src/skf-quick-skill/references/compile.md +30 -31
  317. package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
  318. package/src/skf-quick-skill/references/finalize.md +69 -18
  319. package/src/skf-quick-skill/references/halt-contract.md +41 -29
  320. package/src/skf-quick-skill/references/health-check.md +5 -3
  321. package/src/skf-quick-skill/references/quick-extract.md +114 -45
  322. package/src/skf-quick-skill/references/registry-resolution.md +9 -64
  323. package/src/skf-quick-skill/references/resolve-target.md +116 -66
  324. package/src/skf-quick-skill/references/write-and-validate.md +79 -40
  325. package/src/skf-refine-architecture/SKILL.md +43 -53
  326. package/src/skf-refine-architecture/customize.toml +49 -20
  327. package/src/skf-refine-architecture/references/compile.md +97 -54
  328. package/src/skf-refine-architecture/references/exit-codes.md +30 -0
  329. package/src/skf-refine-architecture/references/finding-storage.md +21 -0
  330. package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
  331. package/src/skf-refine-architecture/references/improvements.md +14 -20
  332. package/src/skf-refine-architecture/references/init.md +98 -57
  333. package/src/skf-refine-architecture/references/issue-detection.md +32 -39
  334. package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
  335. package/src/skf-refine-architecture/references/report.md +65 -54
  336. package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
  337. package/src/skf-rename-skill/SKILL.md +19 -54
  338. package/src/skf-rename-skill/customize.toml +32 -26
  339. package/src/skf-rename-skill/references/execute.md +230 -184
  340. package/src/skf-rename-skill/references/exit-codes.md +7 -7
  341. package/src/skf-rename-skill/references/health-check.md +1 -7
  342. package/src/skf-rename-skill/references/invocation-contract.md +25 -0
  343. package/src/skf-rename-skill/references/report.md +63 -52
  344. package/src/skf-rename-skill/references/select.md +197 -115
  345. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
  346. package/src/skf-setup/SKILL.md +26 -26
  347. package/src/skf-setup/customize.toml +14 -10
  348. package/src/skf-setup/references/auto-index.md +50 -63
  349. package/src/skf-setup/references/ccc-index.md +29 -90
  350. package/src/skf-setup/references/detect-and-tier.md +58 -67
  351. package/src/skf-setup/references/health-check.md +2 -0
  352. package/src/skf-setup/references/invocation-contract.md +14 -0
  353. package/src/skf-setup/references/report.md +43 -166
  354. package/src/skf-setup/references/tier-rules.md +5 -5
  355. package/src/skf-setup/references/write-config.md +34 -57
  356. package/src/skf-test-skill/SKILL.md +17 -57
  357. package/src/skf-test-skill/assets/output-section-formats.md +33 -34
  358. package/src/skf-test-skill/customize.toml +27 -13
  359. package/src/skf-test-skill/references/coherence-check.md +134 -62
  360. package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
  361. package/src/skf-test-skill/references/coverage-check.md +209 -264
  362. package/src/skf-test-skill/references/detect-mode.md +5 -5
  363. package/src/skf-test-skill/references/external-validators.md +94 -82
  364. package/src/skf-test-skill/references/health-check.md +6 -7
  365. package/src/skf-test-skill/references/init.md +164 -91
  366. package/src/skf-test-skill/references/invocation-contract.md +66 -0
  367. package/src/skf-test-skill/references/migration-section-rules.md +5 -2
  368. package/src/skf-test-skill/references/report.md +164 -142
  369. package/src/skf-test-skill/references/score.md +80 -107
  370. package/src/skf-test-skill/references/scoring-rules.md +42 -155
  371. package/src/skf-test-skill/references/source-access-protocol.md +18 -94
  372. package/src/skf-test-skill/references/step-hard-gate.md +51 -33
  373. package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
  374. package/src/skf-test-skill/scripts/build-result-context.py +380 -0
  375. package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
  376. package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
  377. package/src/skf-test-skill/scripts/compute-score.py +223 -45
  378. package/src/skf-test-skill/scripts/gap-ledger.py +1666 -0
  379. package/src/skf-test-skill/scripts/hard-gate.py +203 -0
  380. package/src/skf-test-skill/scripts/load-coverage-inputs.py +1198 -0
  381. package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
  382. package/src/skf-test-skill/scripts/reconcile-coverage.py +547 -79
  383. package/src/skf-test-skill/scripts/score-signatures.py +479 -0
  384. package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
  385. package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
  386. package/src/skf-test-skill/scripts/verify-declared-numerator.py +133 -56
  387. package/src/skf-test-skill/templates/test-report-template.md +21 -15
  388. package/src/skf-update-skill/SKILL.md +38 -25
  389. package/src/skf-update-skill/customize.toml +27 -12
  390. package/src/skf-update-skill/references/detect-changes.md +253 -223
  391. package/src/skf-update-skill/references/gap-driven.md +336 -0
  392. package/src/skf-update-skill/references/health-check.md +31 -5
  393. package/src/skf-update-skill/references/init.md +254 -84
  394. package/src/skf-update-skill/references/invocation-contract.md +12 -0
  395. package/src/skf-update-skill/references/manual-section-rules.md +6 -23
  396. package/src/skf-update-skill/references/merge.md +182 -49
  397. package/src/skf-update-skill/references/re-extract.md +53 -262
  398. package/src/skf-update-skill/references/report.md +102 -35
  399. package/src/skf-update-skill/references/write.md +357 -155
  400. package/src/skf-update-skill/scripts/skf-new-file-diff.py +183 -46
  401. package/src/skf-verify-stack/SKILL.md +23 -42
  402. package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
  403. package/src/skf-verify-stack/customize.toml +55 -22
  404. package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
  405. package/src/skf-verify-stack/references/coverage.md +67 -64
  406. package/src/skf-verify-stack/references/exit-codes.md +21 -8
  407. package/src/skf-verify-stack/references/init.md +107 -62
  408. package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
  409. package/src/skf-verify-stack/references/integrations.md +106 -65
  410. package/src/skf-verify-stack/references/report.md +59 -42
  411. package/src/skf-verify-stack/references/requirements.md +32 -9
  412. package/src/skf-verify-stack/references/synthesize.md +53 -39
  413. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
  414. package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
  415. package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
  416. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
  417. package/tools/cli/commands/install.js +11 -4
  418. package/tools/cli/commands/status.js +15 -3
  419. package/tools/cli/commands/update.js +11 -4
  420. package/tools/cli/lib/tool-check.js +320 -0
  421. package/tools/cli/lib/version-check.js +22 -9
  422. package/tools/cli/skf-cli.js +4 -1
  423. package/.gitattributes +0 -16
  424. package/.nvmrc +0 -1
  425. package/docs/_internal/RELEASING.md +0 -679
  426. package/release-audits/v1.0.0-launch-audit.md +0 -728
  427. package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
  428. package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
  429. package/src/skf-campaign/manifest.yaml +0 -15
  430. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
  431. package/src/skf-create-skill/references/ecosystem-check.md +0 -74
  432. package/src/skf-drop-skill/references/headless-contract.md +0 -18
  433. package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
  434. package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
  435. package/src/skf-update-skill/references/validate.md +0 -124
  436. package/tools/validate-docs-drift.js +0 -233
  437. 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. `gh_bridge.list_tree(owner, repo, branch)` — map source structure
9
- 2. Identify entry points: index files, main exports, public modules
10
- 3. `gh_bridge.read_file(owner, repo, path)` — read each entry point
11
- 4. Extract: exported function names, parameter lists, return types (from signatures)
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
- - All results: T1-low (source reading without structural verification)
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 `ccc_bridge.*` references below are **conceptual interfaces**, not callable functions. Resolve them as follows:
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. Detect language from brief or file extensions
42
- 2. Use ast-grep to extract all exports from `path` for the given `language` (scan definitions)
43
- 3. For each export: function name, full signature, parameter types, return type, line number
44
- 4. Use ast-grep to detect co-imported symbols in `path` for the given `libraries[]`
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
- - Exported functions with full signatures: T1 (AST-verified)
49
- - Type definitions and interfaces: T1
50
- - Co-import patterns: T1
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
- - JS/TS: `export function $NAME($$$PARAMS): $RET` / `export const $NAME = ($$$PARAMS) => $BODY` / `export const $NAME` / `export class $NAME`
55
- - Rust: `pub fn $NAME($$$PARAMS) -> $RET`
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 pre-ranks the file extraction queue.
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"`, `"stale"`, `"created"`, or `"none"`/`"failed"` (step 2b attempts lazy indexing for the latter two)
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 consumes those results to pre-rank the file list.
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 move to the front of the extraction queue, sorted by relevance score descending
79
- 2. Files not in CCC results remain in the queue — they are not excluded, only deprioritized
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 patterns as Forge tier — see Forge tier section above. CCC pre-ranking does not change which AST patterns are used, only which files are processed first.
75
+ Same recipes as Forge tier. CCC pre-ranking changes no recipe.
86
76
 
87
77
  ### Confidence
88
78
 
89
- All results: T1 (AST-verified) — identical to Forge tier. CCC is upstream discovery only and is invisible in the output artifact.
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/Deep tier), follow this deterministic protocol to prevent output overflow on large codebases.
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
- **"Files in scope"** = files remaining after applying `include_patterns` and `exclude_patterns` from the brief, filtered by the target language extension. This is not the total repository file count from step 1's tree listing. Use the filtered count from step 3 section 2 as the decision tree input.
106
+ ### Recipe Runner
117
107
 
118
- ### Decision Tree
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
- Apply the first matching condition:
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
- Files in scope 101–500
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 > 500
133
- → CLI streaming fallback: ast-grep run --json=stream + line-by-line Python processing
134
- → Process in directory batches, cap per-batch output
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
- ### Safety Valve
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 any ast-grep operation (MCP or CLI) visibly causes a timeout, returns an error related to output size, or produces unexpectedly large output: immediately switch to the CLI streaming fallback with `--json=stream`. Do not retry the same approach. When falling back to the CLI streaming template, inject the brief's `scope.exclude` patterns into the `EXCLUDES` list (use `[]` if absent) — this applies regardless of which path triggered the fallback. Note: `max_results` in the MCP tool and `| head -N` in the CLI path provide hard caps, but this safety valve covers cases where the upstream tool itself fails before returning results (e.g., OOM during JSON serialization).
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
- ### MCP Tool Usage (Preferred)
133
+ Read the forms #11 lists by eye whether or not the runner ran:
143
134
 
144
- **Simple pattern search:**
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
- **Scoped YAML rule search (for larger repos):**
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
- find_code_by_rule(
160
- project_folder="{source_path}",
161
- yaml="id: public-api\nlanguage: python\nrule:\n pattern: 'def $NAME($$$PARAMS)'\n inside:\n kind: module\n stopBy: end\nconstraints:\n NAME:\n regex: '^[^_]'",
162
- max_results=150,
163
- output_format="text"
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
- ### CLI Streaming Fallback
185
+ `extraction-patterns-by-hand.md`'s MCP Tool Usage shows the call with a recipe as its `yaml`.
168
186
 
169
- When MCP tools are unavailable or the repo exceeds 500 files in scope, use `--json=stream` (not `--json` or `--json=pretty`, which load the whole result set into memory) with line-by-line Python processing:
187
+ ### CLI Streaming Fallback
170
188
 
171
- **Head cap selection:** The `| head -N` cap at the end of the pipeline controls how many exports are captured. Select `N` based on scope and tier:
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
- For full-library skills at higher tiers, the larger cap prevents silently dropping internal module exports that maintainers need. The cap is applied AFTER exclude-pattern filtering, so useful results are not wasted on excluded files.
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
- # Note: use $$$ for variadic params in ast-grep patterns (e.g., 'def $NAME($$$PARAMS)')
180
- # {exclude_patterns} = Python list from brief's scope.exclude, e.g. ['tests/**', '**/test_*']
181
- # If scope.exclude is absent or empty in the brief, inject [] as the default.
182
- # Patterns are matched against the full file path as emitted by ast-grep.
183
- # Ensure paths are relative to the same root as the patterns (strip ./ prefix if needed).
184
- # {HEAD_CAP} = 200 (default) or 500 (Forge+/Deep full-library) — see head cap selection above.
185
- # IMPORTANT: The explicit 'run' subcommand is required for --json=stream to work.
186
- ast-grep run -p '{pattern}' -l {language} --json=stream {path} | python3 -c "
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
- signal.signal(signal.SIGPIPE, signal.SIG_DFL)
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('single',{}).get('NAME',{}).get('text','')
216
+ v = m.get('metaVariables',{}).get('single',{})
217
+ name = v.get('NAME',{}).get('text','')
200
218
  if name and not name.startswith('_'):
201
- ln = m.get('range',{}).get('start',{}).get('line',0)+1
202
- sig = m.get('text','').split(chr(10))[0].strip()
203
- print(f'[AST:{f}:L{ln}] {sig}')
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
- **Streaming constraints (these prevent OOM on large result sets):**
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
- - Use `--json=stream`, not `--json` — the latter loads the entire array into memory
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($$$PARAMS)'
243
+ pattern: 'def $NAME'
244
+ kind: function_definition
224
245
  inside:
225
246
  kind: module
226
- stopBy: end
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: end
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
- > **Language selection:** Use `language: typescript` for `.ts` files and `language: tsx` for `.tsx` files. Patterns that work with `typescript` may return zero results with `tsx` and vice versa — they use different tree-sitter parsers. For mixed codebases, run each pattern twice (once per language) and merge results. Note: the `export function $NAME($$$PARAMS)` pattern returns **zero** with `tsx` on ast-grep 0.41.x (see Known Limitation #5) **and** with plain `typescript` on 0.42.x (see Known Limitation #9) — use source reading as the fallback for `export function` on both.
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: typescript # Use 'tsx' for .tsx files — see language selection note above
340
+ language: javascript
257
341
  rule:
258
- pattern: 'export function $NAME($$$PARAMS)'
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
- pattern: 'export const $NAME = $VALUE'
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
- pattern: 'export const $NAME = ($$$PARAMS) => $BODY'
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
- pattern: 'export class $NAME { $$$ }'
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
- > **Important:** The body (`{ $$$ }`) is required on ast-grep 0.42.x. The bare `export class $NAME` pattern returns zero matches — and emits a `Pattern contains an ERROR node` warning — through **both** `find_code()` and the CLI, because an incomplete class declaration does not parse as a complete statement (see Known Limitation #9). With the body present, the simple `find_code()` pattern detects class exports reliably — it matches non-generic classes only; generic (`export class $NAME<T>`) and generic-extends (`export class $NAME<T> extends $BASE`) forms are skipped, so source-read them via `^export (abstract )?class` and merge by name+file (see Known Limitation #10). `find_code_by_rule` would additionally require an explicit AST `kind` rule.
435
+ **TypeScript: exported interfaces, type aliases and enums:**
291
436
 
292
- **JavaScript/TypeScript — re-export detection (use `find_code`):**
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
- Use `find_code()` with pattern `export { $$$NAMES } from $SOURCE` for re-export detection. Note: this pattern may produce multiple AST node matches. Post-process results to split comma-separated names from `$$$NAMES`. For complex re-export chains (aliased exports, default re-exports, namespace re-exports), fall back to the Re-Export Tracing protocol in `extraction-patterns-tracing.md`.
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
- any:
303
- - pattern: 'pub fn $NAME($$$PARAMS) -> $RET'
304
- - pattern: 'pub fn $NAME($$$PARAMS)'
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
- any:
314
- - pattern: 'func $NAME($$$PARAMS) $RET'
315
- - pattern: 'func $NAME($$$PARAMS)'
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: '^[A-Z]'
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
- pattern: 'export interface $NAME { $$$ }'
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
- pattern: 'export function $NAME($$$PARAMS)'
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: '^[A-Z]'
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
- pattern: 'export const $NAME = ($$$PARAMS) => $BODY'
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: '^[A-Z]'
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<$TYPE>()'
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
- **Props-to-Component linking strategy:**
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
+ ```