bmad-module-skill-forge 0.7.4 → 0.8.1
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/package.json +1 -1
- package/src/agents/forger.agent.yaml +1 -1
- package/src/knowledge/ccc-bridge.md +3 -3
- package/src/knowledge/tool-resolution.md +4 -3
- package/src/module.yaml +5 -3
- package/src/workflows/analyze-source/data/skill-brief-schema.md +11 -2
- package/src/workflows/analyze-source/data/unit-detection-heuristics.md +9 -0
- package/src/workflows/analyze-source/steps-c/step-05-recommend.md +1 -1
- package/src/workflows/analyze-source/steps-c/step-06-generate-briefs.md +2 -1
- package/src/workflows/brief-skill/data/scope-templates.md +41 -0
- package/src/workflows/brief-skill/data/skill-brief-schema.md +11 -3
- package/src/workflows/brief-skill/steps-c/step-03-scope-definition.md +6 -6
- package/src/workflows/create-skill/data/compile-assembly-rules.md +108 -0
- package/src/workflows/create-skill/data/extraction-patterns.md +94 -3
- package/src/workflows/create-skill/data/skill-sections.md +76 -0
- package/src/workflows/create-skill/data/source-resolution-protocols.md +21 -9
- package/src/workflows/create-skill/steps-c/step-02b-ccc-discover.md +2 -2
- package/src/workflows/create-skill/steps-c/step-03-extract.md +44 -29
- package/src/workflows/create-skill/steps-c/step-03d-component-extraction.md +292 -0
- package/src/workflows/create-skill/steps-c/step-05-compile.md +9 -0
- package/src/workflows/test-skill/data/scoring-rules.md +12 -0
- package/src/workflows/test-skill/steps-c/step-04b-external-validators.md +11 -4
- package/src/workflows/update-skill/steps-c/step-03-re-extract.md +18 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "bmad-module-skill-forge",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.1",
|
|
5
5
|
"description": "BMAD module — Turn code and docs into instructions AI agents can actually follow. Progressive capability tiers (Quick/Forge/Forge+/Deep).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"bmad",
|
|
@@ -33,7 +33,7 @@ When either condition is false, calling steps skip ccc discovery silently and pr
|
|
|
33
33
|
|
|
34
34
|
### `ccc_bridge.search(query, path?, top_k?)`
|
|
35
35
|
|
|
36
|
-
**Resolves to:** `
|
|
36
|
+
**Resolves to:** `cd {path} && ccc search --limit {top_k} "{query}"` (CLI) or the `ccc` MCP search tool (preferred). Note: `ccc search` operates on the index in the current working directory — there is no flag to specify a project directory. The `--path` flag is a file path glob filter within the index, not a project selector.
|
|
37
37
|
|
|
38
38
|
Returns: list of `{file, score, snippet}` entries ranked by semantic relevance to the query. These are **candidates** for ast-grep extraction — not verified exports.
|
|
39
39
|
|
|
@@ -41,7 +41,7 @@ Returns: list of `{file, score, snippet}` entries ranked by semantic relevance t
|
|
|
41
41
|
|
|
42
42
|
### `ccc_bridge.ensure_index(path)`
|
|
43
43
|
|
|
44
|
-
**Resolves to:** Check `ccc_index.status` in forge-tier.yaml. If `"none"` or the indexed_path does not match, run `
|
|
44
|
+
**Resolves to:** Check `ccc_index.status` in forge-tier.yaml. If `"none"` or the indexed_path does not match, run `cd {path} && ccc init` then `ccc index` and update forge-tier.yaml. Note: `ccc init` takes no positional arguments — it initializes the index for the current working directory.
|
|
45
45
|
|
|
46
46
|
**Usage context:** Called by setup-forge step-01b to ensure the project root is indexed. Called lazily by extraction steps when `ccc_index.status` is `"none"` but ccc is available.
|
|
47
47
|
|
|
@@ -102,7 +102,7 @@ For remote repository sources (GitHub URLs), CCC cannot operate during step-02b
|
|
|
102
102
|
|
|
103
103
|
1. **step-02b:** Detects remote source, sets `{ccc_discovery: []}`, displays deferred message
|
|
104
104
|
2. **step-03:** After ephemeral clone succeeds, detects the deferred scenario (`tools.ccc == true AND {ccc_discovery} is empty AND ephemeral_clone_active == true AND tier is Forge+/Deep`)
|
|
105
|
-
3. **step-03:** Runs `
|
|
105
|
+
3. **step-03:** Runs `cd {temp_path} && ccc init` + `ccc index` on the ephemeral clone (extended timeout or background mode, verified via `ccc status`)
|
|
106
106
|
4. **step-03:** Executes CCC search and populates `{ccc_discovery}` before AST extraction begins
|
|
107
107
|
|
|
108
108
|
The ephemeral clone index is not registered in `ccc_index_registry` — the clone is deleted after extraction and the CCC daemon's own GC handles orphaned indexes.
|
|
@@ -7,12 +7,13 @@ Bridge names (`ast_bridge`, `ccc_bridge`, `qmd_bridge`, `gh_bridge`) and subproc
|
|
|
7
7
|
| Bridge | Operation | Claude Code | Cursor | CLI | Fallback |
|
|
8
8
|
|--------------|----------------------------------|------------------------------------------------------------------|----------------|----------------------------------------------------|----------------------------------|
|
|
9
9
|
| `ast_bridge` | `scan_definitions()` | `mcp__ast-grep__find_code` or `mcp__ast-grep__find_code_by_rule` | ast-grep MCP | `sg run` / `ast-grep -p` | Source reading (T1-low) |
|
|
10
|
-
| `ast_bridge` | `detect_co_imports()` | `mcp__ast-grep__find_code_by_rule` with co-import YAML rule | ast-grep MCP | `ast-grep -p 'import $$$' --json=stream`
|
|
11
|
-
| `ccc_bridge` | `search(query, root, top_k)` | `/ccc` skill search | ccc MCP server | `
|
|
12
|
-
| `ccc_bridge` | `ensure_index(root)` | `/ccc` skill indexing | ccc MCP server | `ccc init` + `ccc index
|
|
10
|
+
| `ast_bridge` | `detect_co_imports()` | `mcp__ast-grep__find_code_by_rule` with co-import YAML rule | ast-grep MCP | `ast-grep run -p 'import $$$' --json=stream` | grep-based co-import count |
|
|
11
|
+
| `ccc_bridge` | `search(query, root, top_k)` | `/ccc` skill search | ccc MCP server | `cd {root} && ccc search --limit {top_k} "{query}"` | Skip silently |
|
|
12
|
+
| `ccc_bridge` | `ensure_index(root)` | `/ccc` skill indexing | ccc MCP server | `cd {root} && ccc init` + `ccc index` | Skip silently |
|
|
13
13
|
| `ccc_bridge` | `status()` | `/ccc` skill status | ccc MCP server | `ccc --help` + `ccc doctor` | Unavailable = `tools.ccc: false` |
|
|
14
14
|
| `qmd_bridge` | `search(query)` | `mcp__plugin_qmd-plugin_qmd__search` | qmd MCP server | `qmd search "{query}"` | Skip enrichment |
|
|
15
15
|
| `qmd_bridge` | `vector_search(query)` | `mcp__plugin_qmd-plugin_qmd__vector_search` | qmd MCP server | `qmd vector_search "{query}"` | Use BM25 search only |
|
|
16
|
+
| `qmd_bridge` | `version()` | `qmd --version` → parse `"qmd X.Y.Z"` → `"X.Y.Z"` | qmd MCP server | `qmd --version` | `"unknown"` |
|
|
16
17
|
| `gh_bridge` | `list_tree(owner, repo, branch)` | `gh api repos/{owner}/{repo}/git/trees/{branch}?recursive=1` | gh CLI | `gh api ...` | Direct file listing if local |
|
|
17
18
|
| `gh_bridge` | `read_file(owner, repo, path)` | `gh api repos/{owner}/{repo}/contents/{path}` | gh CLI | `gh api ...` | Direct file read if local |
|
|
18
19
|
|
package/src/module.yaml
CHANGED
|
@@ -15,11 +15,13 @@ forge_data_folder:
|
|
|
15
15
|
default: "forge-data"
|
|
16
16
|
result: "{project-root}/{value}"
|
|
17
17
|
|
|
18
|
+
sidecar_path:
|
|
19
|
+
prompt: false
|
|
20
|
+
default: "_bmad/_memory/forger-sidecar"
|
|
21
|
+
result: "{project-root}/{value}"
|
|
22
|
+
|
|
18
23
|
# Variables from Core Config inserted:
|
|
19
24
|
## user_name
|
|
20
25
|
## communication_language
|
|
21
26
|
## document_output_language
|
|
22
27
|
## output_folder
|
|
23
|
-
|
|
24
|
-
# Variables from Agent Sidecar Config:
|
|
25
|
-
## sidecar_path (from forger.agent.yaml metadata.sidecar-path)
|
|
@@ -55,12 +55,20 @@ The create-skill workflow (step-03-extract) also performs version reconciliation
|
|
|
55
55
|
|
|
56
56
|
```yaml
|
|
57
57
|
scope:
|
|
58
|
-
type: full-library | specific-modules | public-api | docs-only
|
|
58
|
+
type: full-library | specific-modules | public-api | component-library | docs-only
|
|
59
59
|
include:
|
|
60
60
|
- 'src/**/*.ts' # At least one required
|
|
61
61
|
exclude:
|
|
62
62
|
- 'src/**/*.test.ts' # Optional
|
|
63
63
|
notes: 'Optional rationale for scope decision'
|
|
64
|
+
# Additional fields when scope.type is "component-library":
|
|
65
|
+
# registry_path: "path/to/registry.ts" # Optional — auto-detected if omitted
|
|
66
|
+
# ui_variants: # Optional — design system variants
|
|
67
|
+
# - name: "shadcnui"
|
|
68
|
+
# package: "packages/components/react-shadcn"
|
|
69
|
+
# demo_patterns: # Optional — auto-detected if omitted
|
|
70
|
+
# - "**/demo/**"
|
|
71
|
+
# - "**/*.stories.*"
|
|
64
72
|
```
|
|
65
73
|
|
|
66
74
|
### Scope Types
|
|
@@ -70,6 +78,7 @@ scope:
|
|
|
70
78
|
| full-library | Entire codebase of a unit |
|
|
71
79
|
| specific-modules | Selected components or packages |
|
|
72
80
|
| public-api | Only exported interfaces |
|
|
81
|
+
| component-library | UI component libraries with registries, props-based APIs, and design system variants |
|
|
73
82
|
| docs-only | When source_type is docs-only — no source code available, all content from doc_urls |
|
|
74
83
|
|
|
75
84
|
## YAML Template
|
|
@@ -98,7 +107,7 @@ created_by: '{user_name}'
|
|
|
98
107
|
1. **Name uniqueness**: No duplicate names within forge_data_folder
|
|
99
108
|
2. **Source accessibility**: source_repo path must exist or be reachable
|
|
100
109
|
3. **Language recognized**: Must be a known programming language
|
|
101
|
-
4. **Scope type valid**: Must match one of the
|
|
110
|
+
4. **Scope type valid**: Must match one of the five defined types (full-library, specific-modules, public-api, component-library, docs-only)
|
|
102
111
|
5. **Include patterns**: At least one include glob pattern required (exception: `docs-only` scope, where include patterns are optional since no source code is available)
|
|
103
112
|
6. **Forge tier match**: Must match value in forge-tier.yaml
|
|
104
113
|
7. **Docs-only mode**: When `source_type: "docs-only"`, `doc_urls` required (>= 1), `source_repo` optional
|
|
@@ -59,6 +59,15 @@ Rules for identifying discrete skillable units within a project. A "skillable un
|
|
|
59
59
|
- Custom wrappers, configurations, or integration code
|
|
60
60
|
- Scope type: `public-api`
|
|
61
61
|
|
|
62
|
+
### Component Library Boundary
|
|
63
|
+
- Contains a component registry or catalog file (array of component definitions with IDs, names, categories)
|
|
64
|
+
- Has `components/`, `packages/components/`, or similar multi-component directory structure
|
|
65
|
+
- Multiple design system variant directories (e.g., `react-shadcn/`, `react-baseui/`, `react-carbon/`)
|
|
66
|
+
- Significant demo/story/example file ratio (>30% of total files)
|
|
67
|
+
- CLI-based installation pattern (e.g., `npx <tool> add <component-id>`)
|
|
68
|
+
- Props interfaces outnumber function signatures as primary API surface
|
|
69
|
+
- Scope type: `component-library`
|
|
70
|
+
|
|
62
71
|
## Disqualification Rules
|
|
63
72
|
|
|
64
73
|
Do NOT recommend as a skillable unit if:
|
|
@@ -90,7 +90,7 @@ For EACH qualifying unit, prepare a recommendation card:
|
|
|
90
90
|
|
|
91
91
|
**Proposed Brief Fields:**
|
|
92
92
|
- name: {suggested kebab-case name}
|
|
93
|
-
- scope.type: {full-library / specific-modules / public-api}
|
|
93
|
+
- scope.type: {full-library / specific-modules / public-api / component-library}
|
|
94
94
|
- scope.include: {suggested glob patterns}
|
|
95
95
|
- description: {suggested 1-3 sentence description}
|
|
96
96
|
```
|
|
@@ -97,7 +97,7 @@ For each generated brief, check against {schemaFile} validation rules:
|
|
|
97
97
|
1. **Name uniqueness** — no duplicate names within the batch or existing skills
|
|
98
98
|
2. **Source accessible** — project_path exists
|
|
99
99
|
3. **Language recognized** — valid programming language identifier
|
|
100
|
-
4. **Scope type valid** — matches `full-library`, `specific-modules`,
|
|
100
|
+
4. **Scope type valid** — matches `full-library`, `specific-modules`, `public-api`, or `component-library`
|
|
101
101
|
5. **Include patterns** — at least one glob pattern present
|
|
102
102
|
6. **Forge tier match** — matches forge_tier from config
|
|
103
103
|
|
|
@@ -152,6 +152,7 @@ For each generated brief, recommend the appropriate next workflow:
|
|
|
152
152
|
| Condition | Recommendation |
|
|
153
153
|
|-----------|---------------|
|
|
154
154
|
| Brief has `scope.type: full-library` and unit is well-bounded | create-skill — brief is sufficient for direct skill creation |
|
|
155
|
+
| Brief has `scope.type: component-library` and registry defines boundaries | create-skill — component boundaries defined by registry |
|
|
155
156
|
| Brief has `scope.type: specific-modules` or scope needs refinement | brief-skill — refine scope before creating skill |
|
|
156
157
|
| Brief has `scope.type: public-api` or complex interface | brief-skill — detailed scoping needed |
|
|
157
158
|
| Unit flagged as stack skill candidate | create-stack-skill — after individual skills exist |
|
|
@@ -16,6 +16,12 @@ Present these options to the user for selection:
|
|
|
16
16
|
- Entry points and exported interfaces only
|
|
17
17
|
- Internal implementation excluded
|
|
18
18
|
|
|
19
|
+
**[C] Component Library** — Optimized for UI component libraries with registries, props-based APIs, and design system variants.
|
|
20
|
+
- Component registry as primary API surface (not individual exports)
|
|
21
|
+
- Props interfaces as API contracts (not function signatures)
|
|
22
|
+
- Auto-exclude demo/example/story files (with user confirmation)
|
|
23
|
+
- Variant consolidation across design systems
|
|
24
|
+
|
|
19
25
|
## Boundary Definitions by Scope Type
|
|
20
26
|
|
|
21
27
|
### Full Library Boundaries
|
|
@@ -69,6 +75,41 @@ Prompt: "Any additional items you'd like to include or exclude?"
|
|
|
69
75
|
|
|
70
76
|
Prompt: "Any additional documentation URLs to include? Or URLs to exclude from the ones collected?"
|
|
71
77
|
|
|
78
|
+
### Component Library Boundaries
|
|
79
|
+
|
|
80
|
+
**Phase 1 — Registry Detection:**
|
|
81
|
+
|
|
82
|
+
Auto-detect or accept explicit `registry_path` from user. Scan source tree for files matching common registry patterns:
|
|
83
|
+
- Files named `registry.ts`, `components.ts`, `index.ts` in `registry/`, `catalog/`, or `components/` directories
|
|
84
|
+
- Arrays of objects with `{ id, name, component }` structure and 10+ entries
|
|
85
|
+
- Files with `Component[]` type annotations
|
|
86
|
+
|
|
87
|
+
Present detected registry candidate(s) to user for confirmation.
|
|
88
|
+
Prompt: "I found what looks like a component registry at {path} ({count} entries). Is this correct? Or provide the registry path:"
|
|
89
|
+
|
|
90
|
+
**Phase 2 — Demo/Example Exclusion:**
|
|
91
|
+
|
|
92
|
+
Auto-detect demo directories and file patterns:
|
|
93
|
+
- Directories: `demo/`, `demos/`, `stories/`, `examples/`, `__stories__/`, `storybook/`
|
|
94
|
+
- Files: `*.stories.*`, `*.story.*`, `*.example.*`, `*.demo.*`
|
|
95
|
+
|
|
96
|
+
Present detected patterns to user before applying (do NOT exclude silently).
|
|
97
|
+
Prompt: "**Auto-detected {N} demo/example files** in {M} directories. Confirm exclusion? [Y/n] Or adjust patterns:"
|
|
98
|
+
|
|
99
|
+
**Phase 3 — Variant Selection (if applicable):**
|
|
100
|
+
|
|
101
|
+
If multiple design system variant directories detected (e.g., `react-shadcn/`, `react-baseui/`, `react-carbon/`):
|
|
102
|
+
- Present detected variants with component counts per variant
|
|
103
|
+
- User selects primary variant and which variants to include
|
|
104
|
+
- Record as `ui_variants` in brief
|
|
105
|
+
|
|
106
|
+
Prompt: "I detected {count} design system variants: {list with counts}. Which is the primary variant? Include all? [Y/n]"
|
|
107
|
+
|
|
108
|
+
**Phase 4 — Scope Confirmation:**
|
|
109
|
+
|
|
110
|
+
Summary showing: component count, excluded demo count, variant summary, include/exclude patterns.
|
|
111
|
+
Prompt: "Does this component library scope look right? Adjust before continuing."
|
|
112
|
+
|
|
72
113
|
## Scripts & Assets Detection (Optional Refinement)
|
|
73
114
|
|
|
74
115
|
When `scripts_intent` or `assets_intent` is `detect` (default), SKF auto-detects from source directories matching: `scripts/`, `bin/`, `tools/`, `cli/` (for scripts) and `assets/`, `templates/`, `schemas/`, `configs/`, `examples/` (for assets). Detection applies to all scope types except `docs-only`.
|
|
@@ -51,13 +51,21 @@ The create-skill workflow (step-03-extract) also performs version reconciliation
|
|
|
51
51
|
|
|
52
52
|
```yaml
|
|
53
53
|
scope:
|
|
54
|
-
type: full-library | specific-modules | public-api | docs-only
|
|
54
|
+
type: full-library | specific-modules | public-api | component-library | docs-only
|
|
55
55
|
include:
|
|
56
56
|
- "src/**/*.ts" # Glob patterns for included files/directories
|
|
57
57
|
exclude:
|
|
58
58
|
- "**/*.test.*" # Glob patterns for excluded files
|
|
59
59
|
- "**/node_modules/**"
|
|
60
60
|
notes: "Optional notes about scope decisions"
|
|
61
|
+
# Additional fields when scope.type is "component-library":
|
|
62
|
+
# registry_path: "path/to/registry.ts" # Optional — auto-detected if omitted
|
|
63
|
+
# ui_variants: # Optional — design system variants
|
|
64
|
+
# - name: "shadcnui"
|
|
65
|
+
# package: "packages/components/react-shadcn"
|
|
66
|
+
# demo_patterns: # Optional — auto-detected if omitted
|
|
67
|
+
# - "**/demo/**"
|
|
68
|
+
# - "**/*.stories.*"
|
|
61
69
|
```
|
|
62
70
|
|
|
63
71
|
## YAML Template
|
|
@@ -74,7 +82,7 @@ forge_tier: "{Quick|Forge|Forge+|Deep}"
|
|
|
74
82
|
created: "{date}"
|
|
75
83
|
created_by: "{user_name}"
|
|
76
84
|
scope:
|
|
77
|
-
type: "{full-library|specific-modules|public-api|docs-only}"
|
|
85
|
+
type: "{full-library|specific-modules|public-api|component-library|docs-only}"
|
|
78
86
|
include:
|
|
79
87
|
- "{pattern}"
|
|
80
88
|
exclude:
|
|
@@ -133,7 +141,7 @@ Created by: {created_by}
|
|
|
133
141
|
1. `name` must be unique within {forge_data_folder}
|
|
134
142
|
2. `source_repo` must be accessible (gh api for GitHub, path exists for local)
|
|
135
143
|
3. `language` must be a recognized programming language
|
|
136
|
-
4. `scope.type` must be one of the
|
|
144
|
+
4. `scope.type` must be one of the five defined types
|
|
137
145
|
5. `scope.include` must have at least one pattern (exception: `docs-only` scope, where include patterns are optional since no source code is available)
|
|
138
146
|
6. `forge_tier` must be one of: Quick, Forge, Forge+, Deep (Title Case, must match the tier from forge-tier.yaml, or default to Quick)
|
|
139
147
|
7. When `source_type: "docs-only"`: `doc_urls` must have >= 1 entry, `source_repo` becomes optional
|
|
@@ -106,9 +106,9 @@ Wait for confirmation. Record any changes to `doc_urls`.
|
|
|
106
106
|
|
|
107
107
|
### 2c. Offer Scope Templates
|
|
108
108
|
|
|
109
|
-
Load `{scopeTemplatesFile}` for the scope type options ([F], [M], [P]) and their descriptions.
|
|
109
|
+
Load `{scopeTemplatesFile}` for the scope type options ([F], [M], [P], [C]) and their descriptions.
|
|
110
110
|
|
|
111
|
-
Present: "**How broadly should this skill cover the library?**" followed by the
|
|
111
|
+
Present: "**How broadly should this skill cover the library?**" followed by the scope type options from the loaded reference.
|
|
112
112
|
|
|
113
113
|
Ask: "Which scope type fits your needs?"
|
|
114
114
|
|
|
@@ -116,7 +116,7 @@ Wait for user selection.
|
|
|
116
116
|
|
|
117
117
|
### 3. Define Boundaries Based on Selection
|
|
118
118
|
|
|
119
|
-
Using the boundary definitions from `{scopeTemplatesFile}`, present the appropriate flow for the user's selected scope type ([F], [M], or [
|
|
119
|
+
Using the boundary definitions from `{scopeTemplatesFile}`, present the appropriate flow for the user's selected scope type ([F], [M], [P], or [C]). Follow each type's prompts and wait for user input at each phase before proceeding.
|
|
120
120
|
|
|
121
121
|
### 4. Handle Language Override
|
|
122
122
|
|
|
@@ -132,7 +132,7 @@ Wait for confirmation or override.
|
|
|
132
132
|
|
|
133
133
|
"**Scope Summary:**
|
|
134
134
|
|
|
135
|
-
**Type:** {Full Library / Specific Modules / Public API}
|
|
135
|
+
**Type:** {Full Library / Specific Modules / Public API / Component Library}
|
|
136
136
|
|
|
137
137
|
**Include:**
|
|
138
138
|
{bulleted list of include patterns}
|
|
@@ -151,7 +151,7 @@ Wait for confirmation. Make adjustments if requested.
|
|
|
151
151
|
|
|
152
152
|
### 5b. Scripts & Assets Intent (Optional)
|
|
153
153
|
|
|
154
|
-
**Only ask when `scope.type` is `full-library` or `
|
|
154
|
+
**Only ask when `scope.type` is `full-library`, `specific-modules`, or `component-library` (skip for `public-api` and `docs-only`).**
|
|
155
155
|
|
|
156
156
|
"Does this library include executable scripts (CLI tools, validation scripts, setup helpers) or static assets (config templates, JSON schemas, example configs) that should be packaged with the skill?"
|
|
157
157
|
|
|
@@ -189,7 +189,7 @@ ONLY WHEN C is selected and scope boundaries are confirmed will you load and rea
|
|
|
189
189
|
|
|
190
190
|
### ✅ SUCCESS:
|
|
191
191
|
|
|
192
|
-
- Scope type selected by user (Full Library, Specific Modules, or
|
|
192
|
+
- Scope type selected by user (Full Library, Specific Modules, Public API, or Component Library)
|
|
193
193
|
- Include patterns defined and confirmed
|
|
194
194
|
- Exclude patterns defined and confirmed
|
|
195
195
|
- Language confirmed (or overridden if detection was low confidence)
|
|
@@ -108,6 +108,114 @@ Assemble Sections 9-11 (Full API Reference, Full Type Definitions, Full Integrat
|
|
|
108
108
|
|
|
109
109
|
Do NOT repeat Tier 1's name/purpose/key-params table format in Tier 2. Tier 2 is a deep reference, not a reformatted summary. This distinction prevents conciseness scorers from flagging the two-tier design as redundancy.
|
|
110
110
|
|
|
111
|
+
### Component Library Assembly Overrides
|
|
112
|
+
|
|
113
|
+
When `scope.type: "component-library"` in the brief AND `component_catalog[]` is available in context, apply these overrides to the standard assembly. All other sections remain unchanged.
|
|
114
|
+
|
|
115
|
+
**Section 2 (Quick Start) — CLI-first override:**
|
|
116
|
+
|
|
117
|
+
Replace the standard function-based Quick Start with CLI installation:
|
|
118
|
+
|
|
119
|
+
```markdown
|
|
120
|
+
## Quick Start
|
|
121
|
+
|
|
122
|
+
Install a component:
|
|
123
|
+
`npx {cli-name} add {top-component-id}`
|
|
124
|
+
|
|
125
|
+
{If provider wrapping detected in source:}
|
|
126
|
+
Set up providers:
|
|
127
|
+
\`\`\`tsx
|
|
128
|
+
import { ThemeProvider, UILibraryProvider } from "{primary-package}";
|
|
129
|
+
|
|
130
|
+
<ThemeProvider>
|
|
131
|
+
<UILibraryProvider>
|
|
132
|
+
<YourApp />
|
|
133
|
+
</UILibraryProvider>
|
|
134
|
+
</ThemeProvider>
|
|
135
|
+
\`\`\`
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Detect CLI name from: `package.json` `bin` field, README usage examples, or `registry_path` context. If no CLI detected, fall back to standard import-based Quick Start.
|
|
139
|
+
|
|
140
|
+
**Section 4 (Key API Summary) — Component Catalog override:**
|
|
141
|
+
|
|
142
|
+
Replace the function table with a Component Catalog organized by category:
|
|
143
|
+
|
|
144
|
+
```markdown
|
|
145
|
+
## Component Catalog
|
|
146
|
+
|
|
147
|
+
| Category | Count | Key Components |
|
|
148
|
+
|----------|-------|---------------|
|
|
149
|
+
| {category} | {count} | {top 3-5 component names, comma-separated} |
|
|
150
|
+
|
|
151
|
+
**Design system variants:** {variant list with primary marked}
|
|
152
|
+
**Total components:** {unique count} | {Per variant: **With {name}:** {count}}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Source: `component_catalog[]` from step-03d. Group by `category` field. Provenance: cite the registry file.
|
|
156
|
+
|
|
157
|
+
**Section 5 (Key Types) — Props-focused override:**
|
|
158
|
+
|
|
159
|
+
Replace generic types with the top 5 most-used Props interfaces (by component count or prominence):
|
|
160
|
+
|
|
161
|
+
```markdown
|
|
162
|
+
## Key Types
|
|
163
|
+
|
|
164
|
+
### {ComponentName}Props
|
|
165
|
+
| Prop | Type | Default | Required |
|
|
166
|
+
|------|------|---------|----------|
|
|
167
|
+
| {prop} | {type} | {default or —} | {yes/no} |
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Show only the 5 most important Props interfaces inline. Full Props details go in Tier 2.
|
|
171
|
+
|
|
172
|
+
**Tier 2 (Full API Reference) — Props Reference override:**
|
|
173
|
+
|
|
174
|
+
Organize by component (not by function). Per component:
|
|
175
|
+
|
|
176
|
+
```markdown
|
|
177
|
+
### {ComponentName}
|
|
178
|
+
|
|
179
|
+
**Install:** `npx {cli} add {component-id}`
|
|
180
|
+
**Available in:** {variant list}
|
|
181
|
+
**Props:** `{ComponentName}Props`
|
|
182
|
+
|
|
183
|
+
| Prop | Type | Default | Description |
|
|
184
|
+
|------|------|---------|-------------|
|
|
185
|
+
| {prop} | {type} | {default} | {JSDoc description or —} |
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**context-snippet.md — Component Library format:**
|
|
189
|
+
|
|
190
|
+
```markdown
|
|
191
|
+
[{name} v{version}]|root: skills/{name}/
|
|
192
|
+
|IMPORTANT: {name} v{version} — read SKILL.md before writing {name} code. Do NOT rely on training data.
|
|
193
|
+
|install: npx {cli} add <component-id>
|
|
194
|
+
|catalog:{SKILL.md#component-catalog} — {N} components: {category(count), ...}
|
|
195
|
+
|variants: {variant list} — {provider wrapping note if applicable}
|
|
196
|
+
|key-props:{SKILL.md#key-types} — {top props interfaces with key fields}
|
|
197
|
+
|gotchas: {detected gotchas}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**metadata.json — Component Library stats:**
|
|
201
|
+
|
|
202
|
+
When `scope.type: "component-library"`, add these fields to `stats`:
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"stats": {
|
|
207
|
+
"components_registered": 0,
|
|
208
|
+
"components_documented": 0,
|
|
209
|
+
"props_interfaces_extracted": 0,
|
|
210
|
+
"components_unique": 0,
|
|
211
|
+
"demo_files_excluded": 0,
|
|
212
|
+
"design_variants": {}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
These are in addition to the standard stats fields (exports_documented, etc.).
|
|
218
|
+
|
|
111
219
|
### Assembly Rules
|
|
112
220
|
|
|
113
221
|
1. Assemble all Tier 1 sections first — these form the essential standalone body
|
|
@@ -130,7 +130,7 @@ Files in scope 101–500
|
|
|
130
130
|
→ Parse compact text output into extraction inventory
|
|
131
131
|
|
|
132
132
|
Files in scope > 500
|
|
133
|
-
→ CLI streaming fallback: ast-grep --json=stream + line-by-line Python processing
|
|
133
|
+
→ CLI streaming fallback: ast-grep run --json=stream + line-by-line Python processing
|
|
134
134
|
→ Process in directory batches, cap per-batch output
|
|
135
135
|
→ Merge batch results into extraction inventory
|
|
136
136
|
```
|
|
@@ -171,6 +171,7 @@ When MCP tools are unavailable or the repo exceeds 500 files in scope, use `--js
|
|
|
171
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
172
|
- **Default (Quick/Forge, any scope):** `N = 200`
|
|
173
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)
|
|
174
175
|
|
|
175
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.
|
|
176
177
|
|
|
@@ -181,7 +182,8 @@ For full-library skills at higher tiers, the larger cap prevents silently droppi
|
|
|
181
182
|
# Patterns are matched against the full file path as emitted by ast-grep.
|
|
182
183
|
# Ensure paths are relative to the same root as the patterns (strip ./ prefix if needed).
|
|
183
184
|
# {HEAD_CAP} = 200 (default) or 500 (Forge+/Deep full-library) — see head cap selection above.
|
|
184
|
-
|
|
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 "
|
|
185
187
|
import sys, json, fnmatch, signal
|
|
186
188
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
187
189
|
|
|
@@ -244,9 +246,11 @@ constraints:
|
|
|
244
246
|
|
|
245
247
|
**JavaScript/TypeScript — exported functions:**
|
|
246
248
|
|
|
249
|
+
> **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: `export function` patterns may fail with `tsx` on ast-grep 0.41.x (see Known Limitations #5) — use source reading as fallback for those.
|
|
250
|
+
|
|
247
251
|
```yaml
|
|
248
252
|
id: js-exported-functions
|
|
249
|
-
language: typescript
|
|
253
|
+
language: typescript # Use 'tsx' for .tsx files — see language selection note above
|
|
250
254
|
rule:
|
|
251
255
|
pattern: 'export function $NAME($$$PARAMS)'
|
|
252
256
|
```
|
|
@@ -311,6 +315,67 @@ constraints:
|
|
|
311
315
|
regex: '^[A-Z]'
|
|
312
316
|
```
|
|
313
317
|
|
|
318
|
+
### Component Library YAML Rule Recipes
|
|
319
|
+
|
|
320
|
+
These patterns are used by `step-03d-component-extraction.md` when `scope.type: "component-library"`. They prioritize Props interfaces and PascalCase component exports.
|
|
321
|
+
|
|
322
|
+
**React/TypeScript — Props interfaces (primary API contracts):**
|
|
323
|
+
|
|
324
|
+
```yaml
|
|
325
|
+
id: react-props-interfaces
|
|
326
|
+
language: typescript # Use 'tsx' for .tsx files
|
|
327
|
+
rule:
|
|
328
|
+
pattern: 'export interface $NAME { $$$ }'
|
|
329
|
+
constraints:
|
|
330
|
+
NAME:
|
|
331
|
+
regex: '.*Props$'
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**React/TypeScript — Component function exports (PascalCase):**
|
|
335
|
+
|
|
336
|
+
> **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.
|
|
337
|
+
|
|
338
|
+
```yaml
|
|
339
|
+
id: react-component-functions
|
|
340
|
+
language: tsx
|
|
341
|
+
rule:
|
|
342
|
+
pattern: 'export function $NAME($$$PARAMS)'
|
|
343
|
+
constraints:
|
|
344
|
+
NAME:
|
|
345
|
+
regex: '^[A-Z]'
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**React/TypeScript — Component arrow function exports:**
|
|
349
|
+
|
|
350
|
+
```yaml
|
|
351
|
+
id: react-component-arrow-functions
|
|
352
|
+
language: typescript
|
|
353
|
+
rule:
|
|
354
|
+
pattern: 'export const $NAME = ($$$PARAMS) => $BODY'
|
|
355
|
+
constraints:
|
|
356
|
+
NAME:
|
|
357
|
+
regex: '^[A-Z]'
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**Vue — defineProps extraction:**
|
|
361
|
+
|
|
362
|
+
```yaml
|
|
363
|
+
id: vue-define-props
|
|
364
|
+
language: typescript
|
|
365
|
+
rule:
|
|
366
|
+
pattern: 'defineProps<$TYPE>()'
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Props-to-Component linking strategy:**
|
|
370
|
+
|
|
371
|
+
After extracting Props interfaces and component exports, link them using this 3-level fallback chain:
|
|
372
|
+
|
|
373
|
+
1. **Naming convention (primary):** Strip `Props` suffix from interface name → match to component export (e.g., `NativeLiquidButtonProps` → `NativeLiquidButton`)
|
|
374
|
+
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
|
|
375
|
+
3. **Generic parameter (deep fallback):** Search for `ComponentProps<typeof $NAME>` or `React.ComponentProps<typeof $NAME>` patterns that reference the component by name
|
|
376
|
+
|
|
377
|
+
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).
|
|
378
|
+
|
|
314
379
|
### Known ast-grep Limitations
|
|
315
380
|
|
|
316
381
|
When using ast-grep for extraction, be aware of these documented limitations:
|
|
@@ -326,6 +391,32 @@ When using ast-grep for extraction, be aware of these documented limitations:
|
|
|
326
391
|
- Second: if `find_code()` also fails, fall back to source reading for that pattern category (T1-low confidence)
|
|
327
392
|
- Never silently accept zero results for a pattern category that the source language commonly uses
|
|
328
393
|
|
|
394
|
+
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.
|
|
395
|
+
|
|
396
|
+
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.
|
|
397
|
+
|
|
398
|
+
### Component Library Demo/Example Auto-Exclusion
|
|
399
|
+
|
|
400
|
+
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.
|
|
401
|
+
|
|
402
|
+
**Auto-detect directory patterns:**
|
|
403
|
+
- `**/demo/**`, `**/demos/**`
|
|
404
|
+
- `**/stories/**`, `**/__stories__/**`, `**/storybook/**`
|
|
405
|
+
- `**/examples/**`, `**/example/**`
|
|
406
|
+
|
|
407
|
+
**Auto-detect file patterns:**
|
|
408
|
+
- `**/*.stories.*`, `**/*.story.*`
|
|
409
|
+
- `**/*.example.*`, `**/*.demo.*`
|
|
410
|
+
|
|
411
|
+
If `demo_patterns` is specified in the brief, use those instead of auto-detection.
|
|
412
|
+
|
|
413
|
+
**Procedure:**
|
|
414
|
+
1. Scan the scoped file tree for matching directories and files
|
|
415
|
+
2. Count matches per pattern category
|
|
416
|
+
3. Present to user: "**Auto-detected {N} demo/example files** in {M} directories matching these patterns: {list}. Confirm exclusion? [Y/n] Or adjust patterns:"
|
|
417
|
+
4. Apply confirmed patterns to the exclude list before AST extraction
|
|
418
|
+
5. Record in extraction inventory: `demo_files_excluded: {count}`
|
|
419
|
+
|
|
329
420
|
### Re-Export Tracing and Script/Asset Extraction
|
|
330
421
|
|
|
331
422
|
See `extraction-patterns-tracing.md` for:
|
|
@@ -59,6 +59,82 @@ SKILL.md uses a two-tier structure to ensure actionable content survives `split-
|
|
|
59
59
|
- **Section 4b (Migration & Deprecation Warnings)** is conditional: only emitted for Deep tier when T2-future annotations exist. Quick/Forge/Forge+ tiers and Deep tiers without T2-future annotations omit it entirely (no empty section). Parsers and validators must treat this section as optional.
|
|
60
60
|
- **Section 7b (Scripts & Assets)** is conditional: only emitted when `scripts_inventory` or `assets_inventory` is non-empty. Omitted entirely when no scripts or assets are detected. Parsers and validators must treat this section as optional.
|
|
61
61
|
|
|
62
|
+
### Component Library Section Overrides
|
|
63
|
+
|
|
64
|
+
When `scope.type: "component-library"`, these section formats replace their standard counterparts. All other sections (Overview, Common Workflows, Architecture, CLI, Manual Sections, etc.) use the standard format.
|
|
65
|
+
|
|
66
|
+
#### Section 4 — Component Catalog (replaces Key API Summary)
|
|
67
|
+
|
|
68
|
+
```markdown
|
|
69
|
+
## Component Catalog
|
|
70
|
+
|
|
71
|
+
| Category | Count | Key Components |
|
|
72
|
+
|----------|-------|---------------|
|
|
73
|
+
| {category} | {count} | {ComponentA}, {ComponentB}, {ComponentC}, ... |
|
|
74
|
+
|
|
75
|
+
**Design system variants:** {primary} (primary), {variant2}, {variant3}
|
|
76
|
+
**Total components:** {unique_count} | **With {variant1}:** {count1} | **With {variant2}:** {count2}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- Source: `component_catalog[]` from step-03d extraction
|
|
80
|
+
- Group by `category` field from registry
|
|
81
|
+
- Show top 3-5 component names per category
|
|
82
|
+
- Cite registry file: `[SRC:{registry_file}:L1]`
|
|
83
|
+
- Budget: ~20 lines (same as standard Section 4)
|
|
84
|
+
|
|
85
|
+
#### Section 5 — Key Props (replaces Key Types)
|
|
86
|
+
|
|
87
|
+
```markdown
|
|
88
|
+
## Key Types
|
|
89
|
+
|
|
90
|
+
### {ComponentName}Props
|
|
91
|
+
|
|
92
|
+
| Prop | Type | Default | Required |
|
|
93
|
+
|------|------|---------|----------|
|
|
94
|
+
| {propName} | {type} | {default or —} | {yes/no} |
|
|
95
|
+
|
|
96
|
+
{Repeat for top 5 Props interfaces}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- Show only the 5 most-used Props interfaces (by component count or documentation prominence)
|
|
100
|
+
- Full Props details for all components go in Tier 2 reference
|
|
101
|
+
- Budget: ~20 lines (same as standard Section 5)
|
|
102
|
+
|
|
103
|
+
#### Tier 2 — Props Reference (replaces Full API Reference)
|
|
104
|
+
|
|
105
|
+
```markdown
|
|
106
|
+
## Full API Reference
|
|
107
|
+
|
|
108
|
+
### {ComponentName}
|
|
109
|
+
|
|
110
|
+
**Install:** `npx {cli} add {component-id}`
|
|
111
|
+
**Available in:** {variant list}
|
|
112
|
+
**Props:** `{ComponentName}Props`
|
|
113
|
+
|
|
114
|
+
| Prop | Type | Default | Description |
|
|
115
|
+
|------|------|---------|-------------|
|
|
116
|
+
| {prop} | {type} | {default} | {description from JSDoc or —} |
|
|
117
|
+
|
|
118
|
+
**Provenance:** `[AST:{file}:L{line}]`
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- Organize by component, not by function
|
|
122
|
+
- Each component shows: install command, variant availability, full props table
|
|
123
|
+
- Include JSDoc descriptions for props when available
|
|
124
|
+
- Standard provenance citations apply
|
|
125
|
+
|
|
126
|
+
#### context-snippet.md — Component Library Format
|
|
127
|
+
|
|
128
|
+
```markdown
|
|
129
|
+
[{name} v{version}]|root: skills/{name}/
|
|
130
|
+
|IMPORTANT: {name} v{version} — read SKILL.md before writing {name} code. Do NOT rely on training data.
|
|
131
|
+
|install: npx {cli} add <component-id>
|
|
132
|
+
|catalog:{SKILL.md#component-catalog} — {N} components: {category(count), ...}
|
|
133
|
+
|variants: {variant list} — {provider wrapping note if applicable}
|
|
134
|
+
|key-props:{SKILL.md#key-types} — {top props interfaces with key fields}
|
|
135
|
+
|gotchas: {detected gotchas}
|
|
136
|
+
```
|
|
137
|
+
|
|
62
138
|
### Provenance Citation Format
|
|
63
139
|
|
|
64
140
|
| Tier | Format | Example |
|
|
@@ -68,8 +68,8 @@ If `source_repo` is a remote URL (GitHub URL or owner/repo format) AND tier is F
|
|
|
68
68
|
|
|
69
69
|
When `exclude_patterns` exist, use `--no-cone` mode to pass both include and exclude patterns directly as gitignore-style rules:
|
|
70
70
|
|
|
71
|
-
1. Convert `include_patterns` to gitignore-style patterns.
|
|
72
|
-
2. Convert `exclude_patterns` to negation patterns by prepending `!`. Apply the same
|
|
71
|
+
1. Convert `include_patterns` to gitignore-style patterns. For patterns without glob characters (`*`, `?`, `[`) that do not end with `/`, apply the **file-detection heuristic**: if the last path segment contains a `.` (file extension), it is an **individual file** — prepend `/` and keep as-is (e.g., `packages/registry/registry.json` → `/packages/registry/registry.json`). If the last path segment has no extension, it is a **bare directory name** — append `/**` (e.g., `cognee` → `cognee/**`). Patterns that already contain glob characters are kept as-is (e.g., `cognee/**` → kept as-is).
|
|
72
|
+
2. Convert `exclude_patterns` to negation patterns by prepending `!`. Apply the same file-detection heuristic: individual files (last segment has `.` extension) get `!/` prefix only (e.g., `src/internal/config.json` → `!/src/internal/config.json`); bare directory names get `/**` appended (e.g., `cognee/tests` → `!cognee/tests/**`). Patterns with globs are kept as-is with `!` prefix (e.g., `cognee/tests/**` → `!cognee/tests/**`; `**/test_*` → `!**/test_*`).
|
|
73
73
|
3. **CRITICAL:** List all include patterns BEFORE negated exclude patterns — git processes patterns in order and a negation can only suppress a prior inclusion.
|
|
74
74
|
4. Pass to sparse-checkout — include patterns first, then negated exclude patterns:
|
|
75
75
|
|
|
@@ -79,15 +79,17 @@ If `source_repo` is a remote URL (GitHub URL or owner/repo format) AND tier is F
|
|
|
79
79
|
|
|
80
80
|
Example transformation:
|
|
81
81
|
```
|
|
82
|
-
Brief include_patterns:
|
|
83
|
-
cognee/**
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
Brief include_patterns: Brief exclude_patterns:
|
|
83
|
+
cognee/** cognee/tests/**
|
|
84
|
+
packages/registry/registry.json cognee/alembic/**
|
|
85
|
+
**/test_*
|
|
86
86
|
|
|
87
87
|
sparse-checkout args (--no-cone):
|
|
88
|
-
'cognee/**' '!cognee/tests/**' '!cognee/alembic/**' '!**/test_*'
|
|
88
|
+
'cognee/**' '/packages/registry/registry.json' '!cognee/tests/**' '!cognee/alembic/**' '!**/test_*'
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
Note: `registry.json` is an individual file (has `.json` extension), so it gets `/` prefix instead of `/**` suffix.
|
|
92
|
+
|
|
91
93
|
**Note:** `--no-cone` mode is slower than cone mode for very large repositories but eliminates downloading excluded blobs entirely.
|
|
92
94
|
|
|
93
95
|
**Always-included root files:**
|
|
@@ -112,7 +114,13 @@ If `source_repo` is a remote URL (GitHub URL or owner/repo format) AND tier is F
|
|
|
112
114
|
|
|
113
115
|
Proceed with Quick tier extraction strategy below. Note the degradation reason in context for the evidence report.
|
|
114
116
|
|
|
115
|
-
**Ephemeral clone cleanup:** After extraction is complete for all files in scope (whether successful or partially failed), before presenting the Gate 2 summary (Section 6), if `ephemeral_clone_active
|
|
117
|
+
**Ephemeral clone cleanup:** After extraction is complete for all files in scope (whether successful or partially failed), before presenting the Gate 2 summary (Section 6), if `ephemeral_clone_active`:
|
|
118
|
+
|
|
119
|
+
1. **Reset working directory first:** Before deleting the clone, ensure the shell working directory is not inside the temp path. Run `cd {project-root}` using the **absolute path** captured at workflow start (not a relative path). This prevents `getcwd` errors when the temp directory is deleted while it is the shell's cwd — which happens if `cd {temp_path}` was used during CCC init or extraction operations.
|
|
120
|
+
2. **Delete the clone:** `rm -rf {temp_path}`
|
|
121
|
+
3. **Log:** "Ephemeral source clone cleaned up."
|
|
122
|
+
|
|
123
|
+
This ensures cleanup runs even if some extractions failed, as long as the step itself is still executing. **If any error halts the extraction step before Gate 2 is reached**, cleanup must still occur: reset cwd to `{project-root}` and attempt to delete `{temp_path}` before halting. Log the cleanup attempt regardless of success.
|
|
116
124
|
|
|
117
125
|
---
|
|
118
126
|
|
|
@@ -137,7 +145,11 @@ Store the result as `source_commit` in context. If capture fails (not a git repo
|
|
|
137
145
|
After the source path is accessible (local path from step-01, or ephemeral clone from above), check whether the source contains a version identifier and reconcile it with `brief.version`. Look for the first matching version file in the resolved source path:
|
|
138
146
|
|
|
139
147
|
- Python: `pyproject.toml` (`[project] version`), `setup.py` (`version=`), `__version__` in `__init__.py`
|
|
140
|
-
- JavaScript/TypeScript: `package.json` (`"version"`)
|
|
148
|
+
- JavaScript/TypeScript: `package.json` (`"version"`). **Monorepo resolution:** When multiple `package.json` files exist (workspace root + packages), resolve version using this priority:
|
|
149
|
+
1. Package whose `name` field matches `brief.name` (e.g., the skill's target library name)
|
|
150
|
+
2. Package with a `bin` field (CLI entry point — represents the published version)
|
|
151
|
+
3. Root workspace `package.json` version (if present)
|
|
152
|
+
4. Fall back to `brief.version` if no version found. For monorepos using workspace protocols (pnpm, yarn, npm workspaces), the root `package.json` often has no `version` field — this is expected, not an error.
|
|
141
153
|
- Rust: `Cargo.toml` (`[package] version`)
|
|
142
154
|
- Go: `go.mod` (module version if tagged)
|
|
143
155
|
|
|
@@ -79,7 +79,7 @@ Read `ccc_index` from forge-tier.yaml:
|
|
|
79
79
|
- If `ccc_index.status` is `"stale"`: display brief note — "CCC index is stale — discovery results may miss recent changes." Continue to section 3.
|
|
80
80
|
- If `ccc_index.status` is `"none"` or `"failed"`: attempt lazy indexing via `ccc_bridge.ensure_index(source_root)`. If indexing succeeds, continue to section 3. If indexing fails, set `{ccc_discovery: []}` and auto-proceed to section 5.
|
|
81
81
|
|
|
82
|
-
**Tool resolution for ccc_bridge.ensure_index:** Use `/ccc` skill indexing (Claude Code), ccc MCP server (Cursor), or `ccc init` + `ccc index
|
|
82
|
+
**Tool resolution for ccc_bridge.ensure_index:** Use `/ccc` skill indexing (Claude Code), ccc MCP server (Cursor), or `cd {source_root} && ccc init` + `ccc index` (CLI). Note: `ccc init` takes no positional arguments — it initializes the index for the current working directory. See [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md).
|
|
83
83
|
|
|
84
84
|
### 3. Construct Semantic Query
|
|
85
85
|
|
|
@@ -97,7 +97,7 @@ Where:
|
|
|
97
97
|
|
|
98
98
|
Run `ccc_bridge.search(query, source_root, top_k=20)`:
|
|
99
99
|
|
|
100
|
-
**Tool resolution for ccc_bridge.search:** Use `/ccc` skill search (Claude Code), ccc MCP server (Cursor), or `ccc search "{query}"
|
|
100
|
+
**Tool resolution for ccc_bridge.search:** Use `/ccc` skill search (Claude Code), ccc MCP server (Cursor), or `cd {source_root} && ccc search --limit 20 "{query}"` (CLI). Note: `ccc search` operates on the index in the current working directory — there is no flag to specify a project directory. See [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md).
|
|
101
101
|
|
|
102
102
|
**If search succeeds:**
|
|
103
103
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: 'step-03-extract'
|
|
3
3
|
description: 'Tier-dependent source code extraction — AST or source reading for exports, signatures, and types'
|
|
4
4
|
nextStepFile: './step-03b-fetch-temporal.md'
|
|
5
|
+
componentExtractionStepFile: './step-03d-component-extraction.md'
|
|
5
6
|
extractionPatternsData: '../data/extraction-patterns.md'
|
|
6
7
|
extractionPatternsTracingData: '../data/extraction-patterns-tracing.md'
|
|
7
8
|
tierDegradationRulesData: '../data/tier-degradation-rules.md'
|
|
@@ -49,7 +50,7 @@ To extract all public exports, function signatures, type definitions, and co-imp
|
|
|
49
50
|
- Available: brief_data, tier, source_root, file_tree from step-01; ecosystem check outcome from step-02 (proceed/halt decision — no named variable stored)
|
|
50
51
|
- Focus: Source code extraction and inventory building
|
|
51
52
|
- Limits: Do NOT compile, assemble, or write any output
|
|
52
|
-
- Dependencies: Source code must be accessible (resolved in step-01)
|
|
53
|
+
- Dependencies: Source code must be accessible (local repos resolved in step-01; remote repos cloned in section 2a)
|
|
53
54
|
|
|
54
55
|
## MANDATORY SEQUENCE
|
|
55
56
|
|
|
@@ -69,32 +70,9 @@ From the brief, apply scope and pattern filters:
|
|
|
69
70
|
|
|
70
71
|
Build the filtered file list from the source tree resolved in step-01. Record the result: "**Filtered file count: {N} files in scope**" — this count is the input to the AST Extraction Protocol decision tree in the extraction patterns data file.
|
|
71
72
|
|
|
72
|
-
###
|
|
73
|
-
|
|
74
|
-
**If `source_type: "docs-only"` in the brief data:**
|
|
75
|
-
|
|
76
|
-
"**Docs-only mode:** No source code to extract. Documentation content will be fetched from `doc_urls` in step-03c."
|
|
77
|
-
|
|
78
|
-
Build an empty extraction inventory with zero exports. Set `extraction_mode: "docs-only"` in context. Auto-proceed through Gate 2 (section 6) — display the empty inventory and note that T3 content will be produced by the doc-fetcher step.
|
|
79
|
-
|
|
80
|
-
**If `source_type: "source"` (default):** Continue with extraction below.
|
|
81
|
-
|
|
82
|
-
### 4. Execute Tier-Dependent Extraction
|
|
83
|
-
|
|
84
|
-
Load `{sourceResolutionData}` completely. Follow the **Remote Source Resolution** protocol for Forge/Deep tiers (ephemeral clone, sparse-checkout, cleanup) and the **Version Reconciliation** protocol for all tiers. Apply the protocols before proceeding with the tier-specific extraction strategy below.
|
|
85
|
-
|
|
86
|
-
**Quick Tier (No AST tools):**
|
|
73
|
+
### 2a. Resolve Source Access
|
|
87
74
|
|
|
88
|
-
|
|
89
|
-
2. Identify entry points: index files, main exports, public modules
|
|
90
|
-
3. Use `gh_bridge.read_file(owner, repo, path)` to read each entry point
|
|
91
|
-
4. Extract from source text: exported function names, parameter lists, return types
|
|
92
|
-
5. Infer types from JSDoc, docstrings, type annotations
|
|
93
|
-
6. Confidence: All results T1-low — `[SRC:{file}:L{line}]`
|
|
94
|
-
|
|
95
|
-
**Tool resolution for gh_bridge:** Use `gh api repos/{owner}/{repo}/git/trees/{branch}?recursive=1` for list_tree, `gh api repos/{owner}/{repo}/contents/{path}` for read_file. If source is local, use direct file listing/reading instead. See [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md).
|
|
96
|
-
|
|
97
|
-
**Forge/Forge+/Deep Tier (AST available):**
|
|
75
|
+
Load `{sourceResolutionData}` completely. Follow the **Remote Source Resolution** protocol for Forge/Deep tiers (ephemeral clone, sparse-checkout, cleanup), the **Source Commit Capture** protocol for all tiers, and the **Version Reconciliation** protocol for all tiers. This ensures source code is accessible regardless of which extraction path is taken below (standard, component-library, or docs-only).
|
|
98
76
|
|
|
99
77
|
**Deferred CCC Discovery (Forge+ and Deep — remote sources only):**
|
|
100
78
|
|
|
@@ -106,12 +84,12 @@ If ALL of these conditions are true:
|
|
|
106
84
|
|
|
107
85
|
Then run CCC indexing and discovery on the ephemeral clone:
|
|
108
86
|
|
|
109
|
-
1. **Index the clone:** Run `
|
|
87
|
+
1. **Index the clone:** Run `cd {temp_path} && ccc init` then `ccc index` with an extended timeout or in background mode — `ccc init` takes no positional arguments and initializes the index for the current working directory. Indexing can take several minutes on large codebases (1000+ files). Use `ccc status` to verify completion — check that `Chunks` and `Files` counts are non-zero. If init fails or indexing fails, set `{ccc_discovery: []}` and continue — this is not an error.
|
|
110
88
|
|
|
111
89
|
2. **Construct semantic query:** Build from brief data: `"{brief.name} {brief.scope}"`. Truncate to 80 characters — keep the full skill name and trim `brief.scope` from the end. If `brief.scope` is very short (< 10 chars), append terms from `brief.description` to fill the remaining space.
|
|
112
90
|
|
|
113
91
|
3. **Execute search:** Run `ccc_bridge.search(query, temp_path, top_k=20)`:
|
|
114
|
-
- **Tool resolution:** Use `/ccc` skill search (Claude Code), ccc MCP server (Cursor), or `ccc search "{query}"
|
|
92
|
+
- **Tool resolution:** Use `/ccc` skill search (Claude Code), ccc MCP server (Cursor), or `cd {temp_path} && ccc search --limit 20 "{query}"` (CLI). Note: `ccc search` operates on the index in the current working directory. See [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md).
|
|
115
93
|
|
|
116
94
|
4. **Store results:** If search succeeds, store as `{ccc_discovery: [{file, score, snippet}]}`. Display: "**CCC semantic discovery (post-clone): {N} relevant regions identified across {M} unique files.**"
|
|
117
95
|
|
|
@@ -126,7 +104,44 @@ If `{ccc_discovery}` is in context and non-empty (populated by step-02b or defer
|
|
|
126
104
|
|
|
127
105
|
If `{ccc_discovery}` is empty or not in context: proceed with existing file ordering (no change to current behavior).
|
|
128
106
|
|
|
129
|
-
|
|
107
|
+
### 2b. Component Library Delegation
|
|
108
|
+
|
|
109
|
+
**If `scope.type: "component-library"` in the brief:**
|
|
110
|
+
|
|
111
|
+
"**Component library detected.** Delegating to specialized extraction strategy for registry-first, props-focused extraction."
|
|
112
|
+
|
|
113
|
+
Load and execute `{componentExtractionStepFile}` completely. When that step completes, it returns control here. Resume at section 5 (Build Extraction Inventory) with the enriched extraction data and `component_catalog[]` from the component extraction step.
|
|
114
|
+
|
|
115
|
+
**Otherwise:** Continue with standard extraction below.
|
|
116
|
+
|
|
117
|
+
### 3. Check for Docs-Only Mode
|
|
118
|
+
|
|
119
|
+
**If `source_type: "docs-only"` in the brief data:**
|
|
120
|
+
|
|
121
|
+
"**Docs-only mode:** No source code to extract. Documentation content will be fetched from `doc_urls` in step-03c."
|
|
122
|
+
|
|
123
|
+
Build an empty extraction inventory with zero exports. Set `extraction_mode: "docs-only"` in context. Auto-proceed through Gate 2 (section 6) — display the empty inventory and note that T3 content will be produced by the doc-fetcher step.
|
|
124
|
+
|
|
125
|
+
**If `source_type: "source"` (default):** Continue with extraction below.
|
|
126
|
+
|
|
127
|
+
### 4. Execute Tier-Dependent Extraction
|
|
128
|
+
|
|
129
|
+
Source resolution, version reconciliation, and CCC discovery were completed in section 2a. Proceed with the tier-specific extraction strategy below.
|
|
130
|
+
|
|
131
|
+
**Quick Tier (No AST tools):**
|
|
132
|
+
|
|
133
|
+
1. Use `gh_bridge.list_tree(owner, repo, branch)` to map source structure (if remote)
|
|
134
|
+
2. Identify entry points: index files, main exports, public modules
|
|
135
|
+
3. Use `gh_bridge.read_file(owner, repo, path)` to read each entry point
|
|
136
|
+
4. Extract from source text: exported function names, parameter lists, return types
|
|
137
|
+
5. Infer types from JSDoc, docstrings, type annotations
|
|
138
|
+
6. Confidence: All results T1-low — `[SRC:{file}:L{line}]`
|
|
139
|
+
|
|
140
|
+
**Tool resolution for gh_bridge:** Use `gh api repos/{owner}/{repo}/git/trees/{branch}?recursive=1` for list_tree, `gh api repos/{owner}/{repo}/contents/{path}` for read_file. If source is local, use direct file listing/reading instead. See [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md).
|
|
141
|
+
|
|
142
|
+
**Forge/Forge+/Deep Tier (AST available):**
|
|
143
|
+
|
|
144
|
+
⚠️ **CRITICAL:** Before executing AST extraction, load the **AST Extraction Protocol** section from `{extractionPatternsData}`. Follow the decision tree based on the file count from step-01's file tree. This determines whether to use the MCP tool, scoped YAML rules, or CLI streaming. Never use `ast-grep --json` (without `=stream`) — it loads the entire result set into memory and will fail on large codebases. Always use the explicit `run` subcommand with streaming: `ast-grep run -p '{pattern}' --json=stream`.
|
|
130
145
|
|
|
131
146
|
1. Detect language from brief or file extensions
|
|
132
147
|
2. Follow the AST Extraction Protocol decision tree from `{extractionPatternsData}`:
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 'step-03d-component-extraction'
|
|
3
|
+
description: 'Component-library extraction strategy — registry detection, props-first extraction, variant consolidation, demo exclusion'
|
|
4
|
+
returnToStep: './step-03-extract.md'
|
|
5
|
+
extractionPatternsData: '../data/extraction-patterns.md'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Step 3d: Component Library Extraction
|
|
9
|
+
|
|
10
|
+
## STEP GOAL:
|
|
11
|
+
|
|
12
|
+
When `scope.type: "component-library"`, perform specialized extraction that treats the component registry as the primary API surface and props interfaces as API contracts. This step replaces the standard AST extraction flow (step-03 sections 4-4c) and returns control to step-03 section 5 (Build Extraction Inventory).
|
|
13
|
+
|
|
14
|
+
## MANDATORY EXECUTION RULES (READ FIRST):
|
|
15
|
+
|
|
16
|
+
### Universal Rules:
|
|
17
|
+
|
|
18
|
+
- 📖 CRITICAL: Read the complete step file before taking any action
|
|
19
|
+
- 🎯 ALWAYS follow the exact instructions in the step file
|
|
20
|
+
- ⚙️ TOOL/SUBPROCESS FALLBACK: If any instruction references a tool you do not have access to, you MUST still achieve the outcome in your main context thread
|
|
21
|
+
- ✅ YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`
|
|
22
|
+
|
|
23
|
+
### Role Reinforcement:
|
|
24
|
+
|
|
25
|
+
- ✅ You are a skill compilation engine performing component-library-specialized extraction
|
|
26
|
+
- ✅ Zero hallucination tolerance — every extracted item must trace to source code
|
|
27
|
+
- ✅ Component registry is the source of truth for the API surface
|
|
28
|
+
- ✅ Props interfaces are the API contracts, not function signatures
|
|
29
|
+
|
|
30
|
+
### Step-Specific Rules:
|
|
31
|
+
|
|
32
|
+
- 🎯 Focus ONLY on extracting component catalog, props interfaces, and shared types
|
|
33
|
+
- 🚫 FORBIDDEN to compile SKILL.md content — that is step-05
|
|
34
|
+
- 🚫 FORBIDDEN to write any output files — extraction stays in context
|
|
35
|
+
- 🚫 FORBIDDEN to include content that cannot be cited to a source location
|
|
36
|
+
- ⚒️ Every extracted item MUST have a provenance citation: `[AST:{file}:L{line}]` or `[SRC:{file}:L{line}]`
|
|
37
|
+
|
|
38
|
+
## CONTEXT BOUNDARIES:
|
|
39
|
+
|
|
40
|
+
- Available: brief_data (including `scope.registry_path`, `scope.ui_variants`, `scope.demo_patterns` if present), tier, source_root (may be `temp_path` from ephemeral clone for remote repos — use the working source path resolved in step-03 section 2a), filtered file list from step-03 section 2, CCC discovery results (if available from step-03 section 2a)
|
|
41
|
+
- Focus: Component-specific extraction and inventory building
|
|
42
|
+
- Limits: Do NOT compile, assemble, or write output
|
|
43
|
+
- Dependencies: Source code accessible (resolved in step-03 section 2a — ephemeral clone for remote repos), scope filters already applied
|
|
44
|
+
|
|
45
|
+
## MANDATORY SEQUENCE
|
|
46
|
+
|
|
47
|
+
**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise.
|
|
48
|
+
|
|
49
|
+
### Phase 1: Demo/Example Exclusion
|
|
50
|
+
|
|
51
|
+
Before extraction, identify and exclude demo/example files to avoid inflating export counts.
|
|
52
|
+
|
|
53
|
+
**If `scope.demo_patterns` is specified in the brief:** Use those patterns directly.
|
|
54
|
+
|
|
55
|
+
**Otherwise, auto-detect:**
|
|
56
|
+
|
|
57
|
+
1. Scan the filtered file list for directories matching: `demo/`, `demos/`, `stories/`, `examples/`, `__stories__/`, `storybook/`
|
|
58
|
+
2. Scan for file patterns matching: `*.stories.*`, `*.story.*`, `*.example.*`, `*.demo.*`
|
|
59
|
+
3. Count matches per pattern category
|
|
60
|
+
|
|
61
|
+
**User confirmation required:**
|
|
62
|
+
|
|
63
|
+
"**Auto-detected {N} demo/example files** in {M} directories matching these patterns:
|
|
64
|
+
{list detected patterns with counts}
|
|
65
|
+
|
|
66
|
+
Confirm exclusion? [Y/n] Or adjust patterns:"
|
|
67
|
+
|
|
68
|
+
Wait for user response. Apply confirmed patterns to the exclude list. Record `demo_files_excluded: {count}` in context.
|
|
69
|
+
|
|
70
|
+
Update the filtered file list by removing excluded demo files before proceeding.
|
|
71
|
+
|
|
72
|
+
### Phase 2: Registry Detection
|
|
73
|
+
|
|
74
|
+
The component registry is the primary API surface for component libraries.
|
|
75
|
+
|
|
76
|
+
**If `scope.registry_path` is specified in the brief:**
|
|
77
|
+
|
|
78
|
+
Read the specified file directly. Parse it as described below.
|
|
79
|
+
|
|
80
|
+
**Otherwise, auto-detect:**
|
|
81
|
+
|
|
82
|
+
1. Search the filtered file list for files matching these patterns (in priority order):
|
|
83
|
+
- Files named `registry.ts`, `registry.tsx`, `registry.js` in any directory
|
|
84
|
+
- Files named `components.ts`, `components.tsx` in `registry/`, `catalog/`, or `components/` directories
|
|
85
|
+
- Files named `index.ts`, `index.tsx` in `registry/` or `catalog/` directories
|
|
86
|
+
|
|
87
|
+
2. For each candidate, read the file and look for:
|
|
88
|
+
- Arrays of objects with fields like `id`, `name`, `component`, `category`
|
|
89
|
+
- Type annotations containing `Component[]` or similar array types
|
|
90
|
+
- 10+ entries to qualify as a registry (reject small arrays)
|
|
91
|
+
|
|
92
|
+
3. **Confidence scoring** for each candidate:
|
|
93
|
+
- +3 points: Contains `id` field per entry
|
|
94
|
+
- +2 points: Contains `name` or `component` field per entry
|
|
95
|
+
- +2 points: Contains `category` or `tags` field per entry
|
|
96
|
+
- +1 point: Located in a `registry/` or `catalog/` directory
|
|
97
|
+
- +1 point: Has 20+ entries
|
|
98
|
+
- Minimum threshold: 5 points to qualify
|
|
99
|
+
|
|
100
|
+
4. **User confirmation required:**
|
|
101
|
+
|
|
102
|
+
"**Registry candidate detected** at `{path}` (confidence: {score}/9, {count} entries).
|
|
103
|
+
|
|
104
|
+
Sample entries:
|
|
105
|
+
{show 3-5 sample entries with id, name, category}
|
|
106
|
+
|
|
107
|
+
Is this the component registry? [Y/n] Or provide the correct path:"
|
|
108
|
+
|
|
109
|
+
Wait for user response.
|
|
110
|
+
|
|
111
|
+
**If no registry found and no `registry_path` in brief:**
|
|
112
|
+
|
|
113
|
+
"**No component registry detected.** Component-library extraction works best with a registry file. Options:
|
|
114
|
+
- **[P]** Provide the registry file path
|
|
115
|
+
- **[S]** Skip registry — proceed with standard props-first extraction only"
|
|
116
|
+
|
|
117
|
+
Wait for user response.
|
|
118
|
+
|
|
119
|
+
### Phase 3: Parse Registry
|
|
120
|
+
|
|
121
|
+
If a registry was confirmed, parse it into `component_catalog[]`:
|
|
122
|
+
|
|
123
|
+
**Per-component entry:**
|
|
124
|
+
|
|
125
|
+
- `id` — registry key (used for CLI `add` command)
|
|
126
|
+
- `name` — display name (PascalCase)
|
|
127
|
+
- `description` — from registry or empty
|
|
128
|
+
- `category` — from registry field or directory structure
|
|
129
|
+
- `available_in[]` — which design system variants include this component
|
|
130
|
+
- `code_paths[]` — source file path for each variant
|
|
131
|
+
- `tags[]` — from registry or empty
|
|
132
|
+
- Provenance citation: `[SRC:{registry_file}:L{line}]`
|
|
133
|
+
|
|
134
|
+
Display: "**Parsed component catalog: {N} components across {M} categories.**"
|
|
135
|
+
|
|
136
|
+
**If no registry:** Set `component_catalog: []` and proceed to Phase 4.
|
|
137
|
+
|
|
138
|
+
### Phase 4: Props-First Extraction
|
|
139
|
+
|
|
140
|
+
Extract props interfaces as the primary API contracts, then link to components.
|
|
141
|
+
|
|
142
|
+
**Step 1 — Extract Props interfaces:**
|
|
143
|
+
|
|
144
|
+
Load `{extractionPatternsData}` and use the component-library-specific patterns.
|
|
145
|
+
|
|
146
|
+
Using AST tools (Forge/Deep) or source reading (Quick):
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
# React/TypeScript props interfaces
|
|
150
|
+
id: react-props-interfaces
|
|
151
|
+
language: typescript
|
|
152
|
+
rule:
|
|
153
|
+
pattern: 'export interface $NAME { $$$ }'
|
|
154
|
+
constraints:
|
|
155
|
+
NAME:
|
|
156
|
+
regex: '.*Props$'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
For each `*Props` interface found:
|
|
160
|
+
- Extract all fields with types, optionality, and default values
|
|
161
|
+
- Extract JSDoc descriptions per field (if present)
|
|
162
|
+
- Record: interface name, fields[], source file, line number
|
|
163
|
+
- Provenance: `[AST:{file}:L{line}]` or `[SRC:{file}:L{line}]`
|
|
164
|
+
|
|
165
|
+
**Step 2 — Extract component exports:**
|
|
166
|
+
|
|
167
|
+
```yaml
|
|
168
|
+
# React component exports (PascalCase)
|
|
169
|
+
id: react-component-exports
|
|
170
|
+
language: tsx # Use 'tsx' for .tsx files, 'typescript' for .ts files
|
|
171
|
+
rule:
|
|
172
|
+
pattern: 'export function $NAME($$$PARAMS)'
|
|
173
|
+
constraints:
|
|
174
|
+
NAME:
|
|
175
|
+
regex: '^[A-Z]'
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Also run `export const $NAME` patterns for arrow function components.
|
|
179
|
+
|
|
180
|
+
For each component export: record name, source file, line number. Do NOT document the function signature in detail (it's always `(props: XProps) => JSX.Element`).
|
|
181
|
+
|
|
182
|
+
**Step 3 — Link Props to Components:**
|
|
183
|
+
|
|
184
|
+
Use a 3-level fallback chain:
|
|
185
|
+
|
|
186
|
+
1. **Naming convention (primary):** Match `FooProps` → `Foo` component by stripping the `Props` suffix
|
|
187
|
+
2. **File co-location (fallback):** If naming doesn't match, check if a Props interface and a component are defined in the same file
|
|
188
|
+
3. **Generic parameter (deep fallback):** Look for `ComponentProps<typeof Foo>` or similar generic patterns that reference the component
|
|
189
|
+
|
|
190
|
+
For each linked pair, record the association. For unlinked Props interfaces, include them as standalone type exports.
|
|
191
|
+
|
|
192
|
+
**Step 4 — Extract shared types:**
|
|
193
|
+
|
|
194
|
+
Extract non-Props type exports using standard AST patterns (same as Forge tier):
|
|
195
|
+
- `export type $NAME = $VALUE`
|
|
196
|
+
- `export enum $NAME { $$$ }`
|
|
197
|
+
- `export interface $NAME { $$$ }` (excluding `*Props` already captured)
|
|
198
|
+
|
|
199
|
+
### Phase 5: Variant Consolidation
|
|
200
|
+
|
|
201
|
+
**Skip this phase if `scope.ui_variants` is not specified and no variant directories detected.**
|
|
202
|
+
|
|
203
|
+
When multiple design system variants exist:
|
|
204
|
+
|
|
205
|
+
1. **Group components by registry `id`** (NOT by filename — registry is source of truth):
|
|
206
|
+
- For each `id` in `component_catalog[]`, collect all variant paths from `available_in[]` and `code_paths[]`
|
|
207
|
+
|
|
208
|
+
2. **Select canonical props definition:**
|
|
209
|
+
- Use the primary variant (first in `scope.ui_variants` list) as canonical
|
|
210
|
+
- If primary variant's props are unavailable, use the first available variant
|
|
211
|
+
|
|
212
|
+
3. **Detect props differences between variants:**
|
|
213
|
+
- For components available in 2+ variants, compare Props interfaces
|
|
214
|
+
- Record any variant-specific props as notes (e.g., "Base UI variant adds `slots` prop")
|
|
215
|
+
|
|
216
|
+
4. **Deduplicate export counts:**
|
|
217
|
+
- Count unique components (by registry `id`), not total files across variants
|
|
218
|
+
- Record: `components_unique: {N}`, `components_total_with_variants: {M}`
|
|
219
|
+
|
|
220
|
+
Display: "**Variant consolidation: {unique} unique components across {variant_count} variants** ({total} total including variants). Primary variant: {primary_name}."
|
|
221
|
+
|
|
222
|
+
### Phase 6: Build Component Extraction Results
|
|
223
|
+
|
|
224
|
+
Compile all extracted data into the format expected by step-03 section 5:
|
|
225
|
+
|
|
226
|
+
**Per-export entry (for Props interfaces — primary API):**
|
|
227
|
+
|
|
228
|
+
- Interface name (e.g., `NativeLiquidButtonProps`)
|
|
229
|
+
- Full interface with all fields and types
|
|
230
|
+
- Parameters: each field as name, type, required/optional, default
|
|
231
|
+
- Linked component name (e.g., `NativeLiquidButton`)
|
|
232
|
+
- Source file and line number
|
|
233
|
+
- Provenance citation
|
|
234
|
+
- Confidence tier (T1 or T1-low)
|
|
235
|
+
|
|
236
|
+
**Per-export entry (for component functions):**
|
|
237
|
+
|
|
238
|
+
- Component name
|
|
239
|
+
- Linked Props interface (if found)
|
|
240
|
+
- Source file and line number
|
|
241
|
+
- Provenance citation
|
|
242
|
+
- Confidence tier
|
|
243
|
+
|
|
244
|
+
**Per-export entry (for shared types):**
|
|
245
|
+
|
|
246
|
+
- Same as standard extraction format
|
|
247
|
+
|
|
248
|
+
**Component library aggregate counts:**
|
|
249
|
+
|
|
250
|
+
- `components_registered`: count from registry (or 0)
|
|
251
|
+
- `components_documented`: count of components with linked Props
|
|
252
|
+
- `props_interfaces_extracted`: count of `*Props` interfaces
|
|
253
|
+
- `components_unique`: deduplicated count (after variant consolidation)
|
|
254
|
+
- `demo_files_excluded`: count from Phase 1
|
|
255
|
+
- `design_variants`: map of variant name → component count (if variants exist)
|
|
256
|
+
|
|
257
|
+
**Store `component_catalog[]` in context** — this is consumed by step-05 for the Component Catalog section.
|
|
258
|
+
|
|
259
|
+
Display: "**Component extraction complete.** Returning to main extraction flow."
|
|
260
|
+
|
|
261
|
+
## RETURN PROTOCOL
|
|
262
|
+
|
|
263
|
+
After Phase 6 completes, return control to step-03 section 5 (Build Extraction Inventory). The extraction results from this step are merged into the standard extraction inventory format. Step-03 continues with its normal Gate 2 summary and menu.
|
|
264
|
+
|
|
265
|
+
Do NOT load `{returnToStep}` — the calling step (step-03) will continue from where it delegated.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## SYSTEM SUCCESS/FAILURE METRICS
|
|
270
|
+
|
|
271
|
+
### SUCCESS:
|
|
272
|
+
|
|
273
|
+
- Demo/example files detected and excluded with user confirmation
|
|
274
|
+
- Registry detected (or user provided path) and parsed into component_catalog
|
|
275
|
+
- Props interfaces extracted as primary API contracts
|
|
276
|
+
- Components linked to Props via 3-level fallback chain
|
|
277
|
+
- Variant consolidation produced deduplicated counts (if applicable)
|
|
278
|
+
- All extracted items have provenance citations
|
|
279
|
+
- Results compatible with step-03 section 5 inventory format
|
|
280
|
+
- component_catalog stored in context for step-05
|
|
281
|
+
|
|
282
|
+
### FAILURE:
|
|
283
|
+
|
|
284
|
+
- Excluding demo files without user confirmation
|
|
285
|
+
- Accepting a registry candidate without user confirmation
|
|
286
|
+
- Not extracting Props interfaces as primary API surface
|
|
287
|
+
- Documenting component function signatures instead of Props
|
|
288
|
+
- Including hallucinated component data not in source
|
|
289
|
+
- Variant deduplication based on filenames instead of registry IDs
|
|
290
|
+
- Not returning control to step-03 after completion
|
|
291
|
+
|
|
292
|
+
**Master Rule:** Zero hallucination — every extraction must trace to source code. The component registry is the source of truth for the API surface.
|
|
@@ -117,6 +117,15 @@ Following the structure from the skill-sections data file:
|
|
|
117
117
|
3. `{project-root}/_bmad/skf/VERSION` → read plain text file (single line containing version string, written by the SKF installer)
|
|
118
118
|
4. `"unknown"` (final fallback — add a warning to the evidence report)
|
|
119
119
|
Never hardcode the version.
|
|
120
|
+
- Resolve `{ast_grep_version}` using this resolution chain (try each in order, use the first that succeeds):
|
|
121
|
+
1. `ast-grep --version` → parse version string from output (e.g., `ast-grep 0.41.1` → `"0.41.1"`)
|
|
122
|
+
2. `mcp__ast-grep__find_code` tool metadata (if version is exposed by the MCP server)
|
|
123
|
+
3. `"unknown"` (final fallback — add a warning to the evidence report)
|
|
124
|
+
- Resolve `{qmd_version}` using this resolution chain (try each in order, use the first that succeeds):
|
|
125
|
+
1. `qmd --version` → parse version string from output (e.g., `qmd 2.0.1` → `"2.0.1"`)
|
|
126
|
+
2. `mcp__plugin_qmd-plugin_qmd__status` → parse version if exposed in status output
|
|
127
|
+
3. `"unknown"` (final fallback — add a warning to the evidence report)
|
|
128
|
+
Note: QMD is a Bun/Node package (`@tobilu/qmd`). Install via `bun install -g @tobilu/qmd`.
|
|
120
129
|
- Store `commit_short` = first 8 characters of `source_commit` (or `"unknown"` if unavailable) for use in step-08 report.
|
|
121
130
|
- If `scripts_inventory` is non-empty, populate `scripts[]` array and set `stats.scripts_count`. If `assets_inventory` is non-empty, populate `assets[]` array and set `stats.assets_count`. Omit these fields entirely when inventories are empty.
|
|
122
131
|
|
|
@@ -54,6 +54,18 @@ When `docs_only_mode: true` is set by step-03 (indicating a Quick tier skill whe
|
|
|
54
54
|
|
|
55
55
|
This is functionally identical to Quick tier weight redistribution but with a different coverage denominator (self-consistency instead of source comparison).
|
|
56
56
|
|
|
57
|
+
### State 2 Source Access (Any Tier, Provenance-Map Only)
|
|
58
|
+
|
|
59
|
+
When source is not locally available and analysis resolves to State 2 (provenance-map baseline per source-access-protocol.md):
|
|
60
|
+
|
|
61
|
+
- **Signature Accuracy:** N/A — provenance-map stores parameters as flat string arrays; verification is string comparison only, not semantic AST verification. Type aliases (`str` vs `String`, `list` vs `List[Any]`) cannot be resolved without live source.
|
|
62
|
+
- **Type Coverage:** N/A — cannot verify type completeness without local source access for AST re-parsing.
|
|
63
|
+
- **Weight redistribution:** Same as Quick tier — Signature Accuracy (22%) and Type Coverage (14%) weights redistributed proportionally to remaining active categories (Export Coverage, Coherence, External Validation).
|
|
64
|
+
- **Applies regardless of detected tier** (including Forge, Forge+, Deep) whenever `analysis_confidence` is `provenance-map` and local source is unavailable.
|
|
65
|
+
- **Export Coverage denominator:** Uses the union of provenance-map entry names and metadata.json `exports[]` names (per source-access-protocol.md State 2 rules).
|
|
66
|
+
|
|
67
|
+
Note: When provenance-map entries are predominantly T1 (AST-verified at compilation time), the coverage and name-matching data is already at highest confidence. The N/A categories reflect the inability to re-verify at test time, not low-quality extraction data.
|
|
68
|
+
|
|
57
69
|
### Forge Tier (ast-grep)
|
|
58
70
|
- Export Coverage: AST-backed export comparison
|
|
59
71
|
- Signature Accuracy: AST-verified signature matching
|
|
@@ -60,13 +60,20 @@ Read {outputFile} frontmatter to get the skill directory path (`skillDir`).
|
|
|
60
60
|
|
|
61
61
|
Before running external validators, check if `{forge_data_folder}/{skill_name}/evidence-report.md` contains validation results (a `## Validation Results` section with quality scores).
|
|
62
62
|
|
|
63
|
-
**Staleness check:** Determine whether SKILL.md has changed since the evidence report was generated.
|
|
63
|
+
**Staleness check:** Determine whether SKILL.md has changed since the evidence report was generated. Walk through these checks in order:
|
|
64
64
|
|
|
65
|
-
**
|
|
65
|
+
**Pre-check (untracked or staged-only file):** Run `git ls-files --error-unmatch {skillDir}/SKILL.md 2>/dev/null`.
|
|
66
|
+
- If the command fails (exit code non-zero) or git is not available, the file is either **untracked** (new, never committed) or we're in a **non-git environment**:
|
|
67
|
+
- Check if `{skillDir}/metadata.json` exists and has a `generation_date` field
|
|
68
|
+
- Compare `metadata.json` `generation_date` against the evidence report's generation date (from its frontmatter or `## Validation Results` timestamp)
|
|
69
|
+
- If timestamps match within the same minute (same workflow session): auto-reuse is safe — the evidence report was generated from the same SKILL.md content
|
|
70
|
+
- If timestamps differ or metadata.json is missing: treat as stale, proceed to section 2 for a fresh run
|
|
71
|
+
- Note: "Staleness check: SKILL.md is untracked/non-git — using metadata.json timestamp comparison."
|
|
72
|
+
- If the command succeeds (file is tracked by git), continue to Primary check below.
|
|
66
73
|
|
|
67
|
-
**
|
|
74
|
+
**Primary (git-tracked):** Run `git log -1 --format=%cI -- {skillDir}/SKILL.md` to get the last commit date of SKILL.md. Compare against the evidence report's generation date (from its frontmatter or the `## Validation Results` timestamp). If SKILL.md's last commit is newer, results are stale.
|
|
68
75
|
|
|
69
|
-
**
|
|
76
|
+
**Secondary (uncommitted changes):** Run `git diff --name-only -- {skillDir}/SKILL.md`. If output is non-empty, SKILL.md has uncommitted changes — treat results as stale regardless of commit dates. Also check `git diff --cached --name-only -- {skillDir}/SKILL.md` for staged-but-uncommitted changes — if non-empty, SKILL.md has been staged since last commit, treat results as stale.
|
|
70
77
|
|
|
71
78
|
If SKILL.md was modified after the evidence report was generated (e.g., after update-skill), the cached results are stale — skip auto-reuse and proceed to section 2 for a fresh run.
|
|
72
79
|
|
|
@@ -76,9 +76,25 @@ Perform tier-aware extraction on only the changed files identified in step 02, p
|
|
|
76
76
|
|
|
77
77
|
**Remote Source Resolution (Forge/Deep only):**
|
|
78
78
|
|
|
79
|
-
**MCP source access
|
|
79
|
+
**MCP source access (ordered fallback):** When `source_repo` is set in metadata.json, try each MCP tool in order to fetch only the changed files from the change manifest. This avoids ephemeral clone overhead entirely. Tools are ordered by data freshness — gh API returns live GitHub content and is preferred for update-skill where current file versions are required. zread and deepwiki depend on manual indexing and may return stale data if indexes haven't been refreshed since the changes being extracted.
|
|
80
80
|
|
|
81
|
-
**
|
|
81
|
+
1. **gh API** — `gh api repos/{owner}/{repo}/contents/{path}` for raw file content
|
|
82
|
+
- If accessible: fetch file content (base64-decoded), always current
|
|
83
|
+
- If rate-limited, 404, or inaccessible: log tool and reason, continue to next tool
|
|
84
|
+
2. **zread** — `get_repo_structure` + `read_file` for targeted file access
|
|
85
|
+
- If repo found: fetch changed files, proceed with extraction
|
|
86
|
+
- If "repo not found" or error: log tool and reason, continue to next tool
|
|
87
|
+
- Caveat: indexed data — may be stale if index wasn't refreshed after the target changes
|
|
88
|
+
3. **deepwiki** — `ask_question` for targeted export/signature queries
|
|
89
|
+
- If repo indexed and returns usable source data: extract from response
|
|
90
|
+
- If no results or repo not indexed: log tool and reason, continue to next tool
|
|
91
|
+
- Caveat: returns synthesized content, not raw source — extraction quality varies; index may be stale
|
|
92
|
+
|
|
93
|
+
**Confidence labeling:** MCP-fetched content written to a temp file and analyzed with ast-grep → T1. MCP-fetched content analyzed with pattern matching (AST unavailable) → T1-low.
|
|
94
|
+
|
|
95
|
+
**If all MCP tools fail for this repo:** Fall back to ephemeral clone — load and follow `{remoteSourceResolutionData}` for clone setup, version reconciliation, and AST tool unavailability handling.
|
|
96
|
+
|
|
97
|
+
**If all approaches fail (MCP + ephemeral clone):** Degrade to provenance-map-only analysis (State 2, T1 confidence from compilation-time data). Warn user: "Source access failed for {source_repo}. Analysis limited to provenance-map baseline."
|
|
82
98
|
|
|
83
99
|
**Quick tier (text pattern matching):**
|
|
84
100
|
- Extract function/class/type names via regex patterns
|