bmad-module-skill-forge 0.7.1 → 0.7.2
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/knowledge/qmd-registry.md +5 -0
- package/src/workflows/brief-skill/data/skill-brief-schema.md +15 -0
- package/src/workflows/brief-skill/steps-c/step-01-gather-intent.md +16 -0
- package/src/workflows/brief-skill/steps-c/step-02-analyze-target.md +34 -6
- package/src/workflows/brief-skill/steps-c/step-03-scope-definition.md +14 -0
- package/src/workflows/brief-skill/steps-c/step-04-confirm-brief.md +20 -0
- package/src/workflows/brief-skill/steps-c/step-05-write-brief.md +34 -9
- package/src/workflows/brief-skill/workflow.md +1 -1
- package/src/workflows/create-skill/data/extraction-patterns.md +9 -2
- package/src/workflows/create-skill/data/source-resolution-protocols.md +15 -1
- package/src/workflows/create-skill/steps-c/step-01-load-brief.md +4 -4
- package/src/workflows/create-skill/steps-c/step-02b-ccc-discover.md +1 -1
- package/src/workflows/create-skill/steps-c/step-03-extract.md +1 -1
- package/src/workflows/create-skill/steps-c/step-03b-fetch-temporal.md +16 -1
- package/src/workflows/create-skill/steps-c/step-03c-fetch-docs.md +9 -3
- package/src/workflows/create-skill/steps-c/step-05-compile.md +6 -1
- package/src/workflows/create-skill/steps-c/step-07-generate-artifacts.md +1 -1
- package/src/workflows/quick-skill/steps-c/step-04-compile.md +1 -1
- package/src/workflows/test-skill/data/output-section-formats.md +15 -0
- package/src/workflows/test-skill/data/scoring-rules.md +12 -0
- package/src/workflows/test-skill/steps-c/step-03-coverage-check.md +39 -5
- package/src/workflows/test-skill/steps-c/step-04-coherence-check.md +48 -4
- package/src/workflows/test-skill/steps-c/step-04b-external-validators.md +9 -1
- package/src/workflows/test-skill/steps-c/step-05-score.md +2 -0
- package/tools/cli/lib/installer.js +4 -0
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.7.
|
|
4
|
+
"version": "0.7.2",
|
|
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",
|
|
@@ -40,8 +40,13 @@ qmd_collections:
|
|
|
40
40
|
source_workflow: "brief-skill"
|
|
41
41
|
skill_name: "my-lib"
|
|
42
42
|
created_at: "2026-03-14"
|
|
43
|
+
# status: "pending" # Optional — see below
|
|
43
44
|
```
|
|
44
45
|
|
|
46
|
+
**Optional field: `status`**
|
|
47
|
+
|
|
48
|
+
The `status` field is only present when QMD embed verification fails during collection creation. When `status: "pending"` is set, the collection exists in QMD but vector embeddings may be incomplete — only BM25 keyword `search` is reliable. `vector_search` and `deep_search` may return no results until re-embedded. Collections without a `status` field are fully operational. The setup-forge janitor should flag `"pending"` collections for re-embedding.
|
|
49
|
+
|
|
45
50
|
### Collection Types
|
|
46
51
|
|
|
47
52
|
| Type | Producer | Content | Primary Consumers |
|
|
@@ -106,6 +106,21 @@ Scope: {scope.type}
|
|
|
106
106
|
Exclude: {scope.exclude patterns, one per line}
|
|
107
107
|
Notes: {scope.notes}
|
|
108
108
|
|
|
109
|
+
{If source_type is "docs-only":}
|
|
110
|
+
Source Type: docs-only
|
|
111
|
+
Doc URLs:
|
|
112
|
+
{doc_urls, one per line with labels}
|
|
113
|
+
|
|
114
|
+
{If source_type is "source" AND supplemental doc_urls collected:}
|
|
115
|
+
Supplemental Docs:
|
|
116
|
+
{doc_urls, one per line with labels}
|
|
117
|
+
|
|
118
|
+
{If scripts_intent or assets_intent was explicitly set (not default "detect"):}
|
|
119
|
+
Scripts: {scripts_intent}
|
|
120
|
+
Assets: {assets_intent}
|
|
121
|
+
|
|
122
|
+
Source Authority: {source_authority}
|
|
123
|
+
|
|
109
124
|
Version: {version}
|
|
110
125
|
Created: {created}
|
|
111
126
|
Created by: {created_by}
|
|
@@ -82,6 +82,9 @@ We'll work through this together:
|
|
|
82
82
|
3. **Then:** Define scope boundaries
|
|
83
83
|
4. **Finally:** Confirm and write the brief
|
|
84
84
|
|
|
85
|
+
{If tier override was applied:}
|
|
86
|
+
**Your forge tier:** {override tier} (overridden from {original tier}) — this determines what compilation capabilities are available.
|
|
87
|
+
{Else:}
|
|
85
88
|
**Your forge tier:** {detected tier} — this determines what compilation capabilities are available.
|
|
86
89
|
|
|
87
90
|
Let's get started."
|
|
@@ -110,6 +113,14 @@ Wait for user response.
|
|
|
110
113
|
- Optionally ask: "Are there any documentation URLs you'd like to include for supplemental context? (These will be fetched as T3 external references.)"
|
|
111
114
|
- If yes: collect doc URLs into `doc_urls`
|
|
112
115
|
|
|
116
|
+
**Source authority (for all source-type skills):**
|
|
117
|
+
"**Are you the maintainer of this library, or creating a community skill?**"
|
|
118
|
+
- If maintainer: set `source_authority: "official"`
|
|
119
|
+
- If community user: set `source_authority: "community"` (default)
|
|
120
|
+
- If internal/proprietary: set `source_authority: "internal"`
|
|
121
|
+
|
|
122
|
+
Default to `"community"` if user does not specify or skips. For `docs-only` skills, `source_authority` is always forced to `"community"`.
|
|
123
|
+
|
|
113
124
|
Confirm the target.
|
|
114
125
|
|
|
115
126
|
### 4. Gather User Intent
|
|
@@ -154,6 +165,10 @@ Wait for confirmation or alternative.
|
|
|
154
165
|
- **Intent:** {user's intent summary}
|
|
155
166
|
- **Scope hints:** {any hints, or "None — we'll define scope after analysis"}
|
|
156
167
|
- **Skill name:** {confirmed name}
|
|
168
|
+
- **Source type:** {source or docs-only}
|
|
169
|
+
- **Source authority:** {official/community/internal}
|
|
170
|
+
{If doc_urls collected:}
|
|
171
|
+
- **Doc URLs:** {count} supplemental documentation URLs
|
|
157
172
|
- **Forge tier:** {tier}
|
|
158
173
|
|
|
159
174
|
Ready to analyze the target repository?"
|
|
@@ -187,6 +202,7 @@ ONLY WHEN C is selected and target repository is confirmed will you load and rea
|
|
|
187
202
|
- User intent captured with enough context for scoping
|
|
188
203
|
- Skill name derived and confirmed
|
|
189
204
|
- Scope hints noted (if provided)
|
|
205
|
+
- Source type and source authority captured
|
|
190
206
|
- User ready to proceed to analysis
|
|
191
207
|
|
|
192
208
|
### ❌ SYSTEM FAILURE:
|
|
@@ -135,7 +135,12 @@ Based on detected language, identify public API surface:
|
|
|
135
135
|
|
|
136
136
|
If `tools.ccc` is true in forge-tier.yaml, supplement the module listing with a semantic discovery pass:
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
**CCC Semantic Discovery:**
|
|
139
|
+
- **Claude Code:** Use `/ccc search "{repo_name} public API exports modules" {source_path}`
|
|
140
|
+
- **Cursor:** Use `ccc` MCP server `search` tool with query `"{repo_name} public API exports modules"` and path `{source_path}`
|
|
141
|
+
- **CLI fallback:** `ccc search "{repo_name} public API exports modules" --path {source_path} --limit 10`
|
|
142
|
+
|
|
143
|
+
See [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md) for full bridge-to-tool mapping.
|
|
139
144
|
|
|
140
145
|
If results are returned, display:
|
|
141
146
|
|
|
@@ -146,6 +151,22 @@ This supplements — never replaces — the explicit module list above. CCC may
|
|
|
146
151
|
|
|
147
152
|
If CCC is unavailable or returns no results: skip this subsection silently.
|
|
148
153
|
|
|
154
|
+
### 4b. Detect Source Version
|
|
155
|
+
|
|
156
|
+
Attempt to auto-detect the source version using the rules from the skill-brief-schema.md Version Detection section:
|
|
157
|
+
|
|
158
|
+
**For Python:** Check `pyproject.toml` `[project] version` (static) → if `dynamic = ["version"]`, check `__init__.py` for `__version__` → `_version.py` if exists → `setup.py` `version=` → `git describe --tags --abbrev=0`
|
|
159
|
+
**For JavaScript/TypeScript:** Check `package.json` `"version"` field
|
|
160
|
+
**For Rust:** Check `Cargo.toml` `[package] version` (static) → if `version = { workspace = true }`, resolve from workspace root `Cargo.toml` → `git describe --tags --abbrev=0`
|
|
161
|
+
**For Go:** Check `go.mod` or `git describe --tags --abbrev=0`
|
|
162
|
+
|
|
163
|
+
**For GitHub repos:** Use `gh api repos/{owner}/{repo}/contents/{file}` to read version files (decode base64 content).
|
|
164
|
+
**For local repos:** Read the file directly.
|
|
165
|
+
|
|
166
|
+
Display: "**Detected version:** {version or 'Not detected — will default to 1.0.0'}"
|
|
167
|
+
|
|
168
|
+
If detection fails or returns a non-semver value: note that version will default to `"1.0.0"` and the user can override in step 04.
|
|
169
|
+
|
|
149
170
|
### 5. Report Analysis Summary
|
|
150
171
|
|
|
151
172
|
Present the complete analysis:
|
|
@@ -169,6 +190,7 @@ Present the complete analysis:
|
|
|
169
190
|
- Tests: {found/not found — location}
|
|
170
191
|
- Docs: {found/not found — location}
|
|
171
192
|
- Config: {list of config files found}
|
|
193
|
+
- Version: {detected version or "Not detected — defaulting to 1.0.0"}
|
|
172
194
|
|
|
173
195
|
---
|
|
174
196
|
|
|
@@ -179,16 +201,21 @@ Moving to scope definition where you'll choose what to include and exclude."
|
|
|
179
201
|
|
|
180
202
|
### 6. Auto-Proceed to Scope Definition
|
|
181
203
|
|
|
182
|
-
Display: "**Proceeding to scope definition...**
|
|
204
|
+
Display: "**Proceeding to scope definition...**
|
|
205
|
+
|
|
206
|
+
Review the analysis above. If anything looks wrong, let me know now — otherwise I'll proceed to scope definition."
|
|
207
|
+
|
|
208
|
+
Pause briefly for user input. If the user provides corrections or asks questions, address them and re-present any updated analysis findings. Then proceed.
|
|
183
209
|
|
|
184
210
|
#### Menu Handling Logic:
|
|
185
211
|
|
|
186
|
-
- After analysis report is presented to user,
|
|
212
|
+
- After analysis report is presented to user and any corrections addressed, load, read entire file, then execute {nextStepFile}
|
|
187
213
|
|
|
188
214
|
#### EXECUTION RULES:
|
|
189
215
|
|
|
190
|
-
- This is
|
|
191
|
-
-
|
|
216
|
+
- This is a soft auto-proceed step — present the pause prompt, wait briefly for user input
|
|
217
|
+
- If user provides corrections: address them, then proceed
|
|
218
|
+
- If no user input after a brief pause: proceed directly to step 03
|
|
192
219
|
|
|
193
220
|
## CRITICAL STEP COMPLETION NOTE
|
|
194
221
|
|
|
@@ -204,8 +231,9 @@ ONLY WHEN the analysis is complete and the summary has been presented to the use
|
|
|
204
231
|
- Repository structure listed clearly
|
|
205
232
|
- Primary language detected with confidence level
|
|
206
233
|
- Top-level modules and exports identified
|
|
234
|
+
- Source version detected (or default noted)
|
|
207
235
|
- Analysis summary presented factually
|
|
208
|
-
- Auto-proceeded to scope definition
|
|
236
|
+
- Auto-proceeded to scope definition (with pause for corrections)
|
|
209
237
|
|
|
210
238
|
### ❌ SYSTEM FAILURE:
|
|
211
239
|
|
|
@@ -90,6 +90,20 @@ Wait for confirmation. Then skip to section 5 (Summarize Scope Decisions) with:
|
|
|
90
90
|
|
|
91
91
|
**If `source_type: "source"` (default):** Continue to scope templates below.
|
|
92
92
|
|
|
93
|
+
### 2c. Confirm Supplemental Documentation (if doc_urls collected)
|
|
94
|
+
|
|
95
|
+
**If `source_type: "source"` AND supplemental `doc_urls` were collected in step 01:**
|
|
96
|
+
|
|
97
|
+
"**Supplemental documentation URLs:**
|
|
98
|
+
{numbered list of collected doc_urls with labels}
|
|
99
|
+
|
|
100
|
+
These will be included as T3 external references in the skill brief.
|
|
101
|
+
Add, remove, or confirm these URLs."
|
|
102
|
+
|
|
103
|
+
Wait for confirmation. Record any changes to `doc_urls`.
|
|
104
|
+
|
|
105
|
+
**If no supplemental doc_urls were collected:** Skip this subsection.
|
|
106
|
+
|
|
93
107
|
### 2b. Offer Scope Templates
|
|
94
108
|
|
|
95
109
|
Load `{scopeTemplatesFile}` for the scope type options ([F], [M], [P]) and their descriptions.
|
|
@@ -78,6 +78,11 @@ Compile all gathered data from steps 01-03 into the complete brief:
|
|
|
78
78
|
- **scope.include:** {include patterns from step 03}
|
|
79
79
|
- **scope.exclude:** {exclude patterns from step 03}
|
|
80
80
|
- **scope.notes:** {any scope notes from step 03}
|
|
81
|
+
- **source_type:** {source or docs-only, from step 01}
|
|
82
|
+
- **doc_urls:** {collected documentation URLs with labels, from steps 01/03 — include if source_type is "docs-only" or supplemental URLs were collected}
|
|
83
|
+
- **scripts_intent:** {detect/none/description from step 03, or "detect" if not explicitly set}
|
|
84
|
+
- **assets_intent:** {detect/none/description from step 03, or "detect" if not explicitly set}
|
|
85
|
+
- **source_authority:** {official/community/internal from step 01 — default "community"}
|
|
81
86
|
|
|
82
87
|
### 3. Present Brief for Review
|
|
83
88
|
|
|
@@ -101,6 +106,21 @@ Scope: {scope.type}
|
|
|
101
106
|
Exclude: {scope.exclude patterns, one per line}
|
|
102
107
|
Notes: {scope.notes}
|
|
103
108
|
|
|
109
|
+
{If source_type is "docs-only":}
|
|
110
|
+
Source Type: docs-only
|
|
111
|
+
Doc URLs:
|
|
112
|
+
{doc_urls, one per line with labels}
|
|
113
|
+
|
|
114
|
+
{If source_type is "source" AND supplemental doc_urls collected:}
|
|
115
|
+
Supplemental Docs:
|
|
116
|
+
{doc_urls, one per line with labels}
|
|
117
|
+
|
|
118
|
+
{If scripts_intent or assets_intent was explicitly set (not default "detect"):}
|
|
119
|
+
Scripts: {scripts_intent}
|
|
120
|
+
Assets: {assets_intent}
|
|
121
|
+
|
|
122
|
+
Source Authority: {source_authority}
|
|
123
|
+
|
|
104
124
|
Version: {version}
|
|
105
125
|
Created: {created}
|
|
106
126
|
Created by: {created_by}
|
|
@@ -87,19 +87,36 @@ scope:
|
|
|
87
87
|
exclude:
|
|
88
88
|
- "{approved exclude patterns}"
|
|
89
89
|
notes: "{approved scope notes or empty string}"
|
|
90
|
-
# Include doc_urls when source_type is "docs-only" or when supplemental doc URLs were provided
|
|
91
|
-
# doc_urls:
|
|
92
|
-
# - url: "{documentation URL}"
|
|
93
|
-
# label: "{page label}"
|
|
94
|
-
# scripts_intent: detect # Optional: detect | none | description of expected scripts
|
|
95
|
-
# assets_intent: detect # Optional: detect | none | description of expected assets
|
|
96
|
-
# source_authority: community # Optional: official | community | internal
|
|
97
90
|
---
|
|
98
91
|
```
|
|
99
92
|
|
|
100
|
-
**
|
|
93
|
+
**Conditional optional field inclusion:**
|
|
101
94
|
|
|
102
|
-
**If `
|
|
95
|
+
**If `source_type: "docs-only"` OR supplemental `doc_urls` were collected:**
|
|
96
|
+
Include the `doc_urls` array (uncommented) in the generated YAML:
|
|
97
|
+
```yaml
|
|
98
|
+
doc_urls:
|
|
99
|
+
- url: "{documentation URL}"
|
|
100
|
+
label: "{page label}"
|
|
101
|
+
```
|
|
102
|
+
When `source_type: "docs-only"`: `doc_urls` is required (at least one entry), `source_repo` may be set to the doc site URL for reference or omitted.
|
|
103
|
+
|
|
104
|
+
**If `scripts_intent` was collected and is not the default `"detect"`:**
|
|
105
|
+
Include the `scripts_intent` field (uncommented):
|
|
106
|
+
```yaml
|
|
107
|
+
scripts_intent: "{none or description}"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**If `assets_intent` was collected and is not the default `"detect"`:**
|
|
111
|
+
Include the `assets_intent` field (uncommented):
|
|
112
|
+
```yaml
|
|
113
|
+
assets_intent: "{none or description}"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Always include** `source_authority` (default: `"community"`, forced to `"community"` when `source_type: "docs-only"`):
|
|
117
|
+
```yaml
|
|
118
|
+
source_authority: "{official|community|internal}"
|
|
119
|
+
```
|
|
103
120
|
|
|
104
121
|
### 4. Write the File
|
|
105
122
|
|
|
@@ -128,6 +145,13 @@ qmd collection add {forge_data_folder}/{skill-name} --name {skill-name}-brief --
|
|
|
128
145
|
qmd embed
|
|
129
146
|
```
|
|
130
147
|
|
|
148
|
+
**Embed verification:**
|
|
149
|
+
|
|
150
|
+
After `qmd embed` completes, verify the collection was embedded:
|
|
151
|
+
- Run `qmd status` or `qmd collection list` and confirm `{skill-name}-brief` shows document count > 0
|
|
152
|
+
- If verification succeeds: proceed to registry update normally
|
|
153
|
+
- If verification fails: log warning "QMD embed verification failed for {skill-name}-brief — collection may not be searchable yet", still proceed to registry update but add `status: "pending"` field to the registry entry
|
|
154
|
+
|
|
131
155
|
**Registry update:**
|
|
132
156
|
|
|
133
157
|
Read `{sidecar_path}/forge-tier.yaml` and update the `qmd_collections` array.
|
|
@@ -140,6 +164,7 @@ If an entry with `name: "{skill-name}-brief"` already exists, replace it. Otherw
|
|
|
140
164
|
source_workflow: "brief-skill"
|
|
141
165
|
skill_name: "{skill-name}"
|
|
142
166
|
created_at: "{current ISO date}"
|
|
167
|
+
# status: "pending" # Added only when embed verification fails
|
|
143
168
|
```
|
|
144
169
|
|
|
145
170
|
Write the updated forge-tier.yaml.
|
|
@@ -51,7 +51,7 @@ installed_path: '{project-root}/_bmad/skf/workflows/skillforge/brief-skill'
|
|
|
51
51
|
|
|
52
52
|
Load and read full config from {project-root}/_bmad/skf/config.yaml and resolve:
|
|
53
53
|
|
|
54
|
-
- `project_name`, `output_folder`, `user_name`, `communication_language`, `
|
|
54
|
+
- `project_name`, `output_folder`, `user_name`, `communication_language`, `forge_data_folder`, `sidecar_path`
|
|
55
55
|
|
|
56
56
|
### 2. First Step Execution
|
|
57
57
|
|
|
@@ -168,12 +168,19 @@ find_code_by_rule(
|
|
|
168
168
|
|
|
169
169
|
When MCP tools are unavailable or the repo exceeds 500 files in scope, use `--json=stream` (NEVER `--json` or `--json=pretty`) with line-by-line Python processing:
|
|
170
170
|
|
|
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
|
+
|
|
175
|
+
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
|
+
|
|
171
177
|
```bash
|
|
172
178
|
# Note: use $$$ for variadic params in ast-grep patterns (e.g., 'def $NAME($$$PARAMS)')
|
|
173
179
|
# {exclude_patterns} = Python list from brief's scope.exclude, e.g. ['tests/**', '**/test_*']
|
|
174
180
|
# If scope.exclude is absent or empty in the brief, inject [] as the default.
|
|
175
181
|
# Patterns are matched against the full file path as emitted by ast-grep.
|
|
176
182
|
# Ensure paths are relative to the same root as the patterns (strip ./ prefix if needed).
|
|
183
|
+
# {HEAD_CAP} = 200 (default) or 500 (Forge+/Deep full-library) — see head cap selection above.
|
|
177
184
|
ast-grep -p '{pattern}' -l {language} --json=stream {path} | python3 -c "
|
|
178
185
|
import sys, json, fnmatch, signal
|
|
179
186
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
@@ -193,7 +200,7 @@ for line in sys.stdin:
|
|
|
193
200
|
sig = m.get('text','').split(chr(10))[0].strip()
|
|
194
201
|
print(f'[AST:{f}:L{ln}] {sig}')
|
|
195
202
|
except: pass
|
|
196
|
-
" | head -
|
|
203
|
+
" | head -{HEAD_CAP}
|
|
197
204
|
```
|
|
198
205
|
|
|
199
206
|
**Critical constraints:**
|
|
@@ -201,7 +208,7 @@ for line in sys.stdin:
|
|
|
201
208
|
- ALWAYS use `--json=stream` — never `--json` (loads entire array into memory)
|
|
202
209
|
- ALWAYS process line-by-line (`for line in sys.stdin`) — never `json.load(sys.stdin)`
|
|
203
210
|
- ALWAYS cap output with `| head -N` as a safety valve
|
|
204
|
-
- For repos > 500 files, process in directory batches of 20-50 files each
|
|
211
|
+
- 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)
|
|
205
212
|
|
|
206
213
|
### YAML Rule Recipes by Language
|
|
207
214
|
|
|
@@ -102,7 +102,7 @@ If `source_repo` is a remote URL (GitHub URL or owner/repo format) AND tier is F
|
|
|
102
102
|
|
|
103
103
|
After checkout, apply the original glob `include_patterns` as file-level filters when building the extraction file list — sparse-checkout gets the right directories, glob filtering narrows to the exact files. When `--no-cone` mode was used, most exclude filtering is already done at the git level, but apply `exclude_patterns` as a final pass to catch any edge cases where gitignore pattern matching diverges from the brief's glob semantics. Always-included root files (see above) are exempt from post-checkout filtering.
|
|
104
104
|
|
|
105
|
-
3. **If clone succeeds:** Update the working source path to `{temp_path}` for all subsequent AST operations in this step. Proceed with the **Forge/Deep Tier** extraction strategy below. Mark `ephemeral_clone_active = true` for cleanup.
|
|
105
|
+
3. **If clone succeeds:** Update the working source path to `{temp_path}` for all subsequent AST operations in this step. Capture the source commit: `git -C {temp_path} rev-parse HEAD` — store as `source_commit` in context. Proceed with the **Forge/Deep Tier** extraction strategy below. Mark `ephemeral_clone_active = true` for cleanup.
|
|
106
106
|
|
|
107
107
|
4. **If clone fails (network error, auth failure, timeout):**
|
|
108
108
|
|
|
@@ -116,6 +116,20 @@ If `source_repo` is a remote URL (GitHub URL or owner/repo format) AND tier is F
|
|
|
116
116
|
|
|
117
117
|
---
|
|
118
118
|
|
|
119
|
+
## Source Commit Capture (all tiers, source mode only)
|
|
120
|
+
|
|
121
|
+
**If `source_type: "docs-only"`:** skip — set `source_commit: null`.
|
|
122
|
+
|
|
123
|
+
After the source path is accessible, capture the current commit hash for provenance tracking:
|
|
124
|
+
|
|
125
|
+
- **Local path:** `git -C {source_root} rev-parse HEAD` — if the path is a git repo
|
|
126
|
+
- **Ephemeral clone (Forge/Deep):** already captured during clone (step 3 above)
|
|
127
|
+
- **Quick tier (remote, no clone):** `gh api repos/{owner}/{repo}/commits/{branch} --jq '.sha'`
|
|
128
|
+
|
|
129
|
+
Store the result as `source_commit` in context. If capture fails (not a git repo, API unavailable), set `source_commit: null` — this is not an error.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
119
133
|
## Version Reconciliation (all tiers, source mode only)
|
|
120
134
|
|
|
121
135
|
**If `source_type: "docs-only"`:** skip this section — no source files exist to reconcile.
|
|
@@ -111,16 +111,16 @@ Halt with specific error: "Brief validation failed: missing required field `{fie
|
|
|
111
111
|
|
|
112
112
|
### 4. Resolve Source Code Location
|
|
113
113
|
|
|
114
|
-
**If `source_type: "docs-only"`:** Skip source resolution. Set `
|
|
114
|
+
**If `source_type: "docs-only"`:** Skip source resolution. Set `source_root: null` in context. Proceed directly to section 5 (Report Initialization) — docs-only skills have no source to resolve.
|
|
115
115
|
|
|
116
116
|
**If source_repo is a GitHub URL or owner/repo format:**
|
|
117
117
|
- Verify repository exists via `gh_bridge.list_tree(owner, repo, branch)` — **Tool resolution:** `gh api repos/{owner}/{repo}/git/trees/{branch}?recursive=1` or direct file listing if local; see [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md)
|
|
118
118
|
- If branch not specified, detect default branch
|
|
119
|
-
- Store resolved: owner, repo, branch, file tree
|
|
119
|
+
- Store resolved: owner, repo, branch, file tree — note: `source_root` for remote repos is set to the ephemeral clone path during extraction (step-03)
|
|
120
120
|
|
|
121
121
|
**If source_repo is a local path:**
|
|
122
122
|
- Verify path exists and contains source files
|
|
123
|
-
- Store resolved: local path
|
|
123
|
+
- Store resolved: local path as `source_root`, file listing
|
|
124
124
|
|
|
125
125
|
**If source cannot be resolved:**
|
|
126
126
|
Halt with: "Source not found: `{source_repo}`. Verify the repository exists and is accessible."
|
|
@@ -170,7 +170,7 @@ ONLY WHEN forge-tier.yaml is loaded, skill-brief.yaml is validated, and source c
|
|
|
170
170
|
|
|
171
171
|
- Forge tier loaded from sidecar with tool availability
|
|
172
172
|
- Skill brief loaded and all required fields validated
|
|
173
|
-
- Source code location resolved and accessible (or `
|
|
173
|
+
- Source code location resolved and accessible (or `source_root: null` confirmed for docs-only skills)
|
|
174
174
|
- Initialization summary displayed with tier and capabilities
|
|
175
175
|
- Auto-proceeded to step-02
|
|
176
176
|
|
|
@@ -71,7 +71,7 @@ If `tools.ccc` is true, continue to section 2.
|
|
|
71
71
|
|
|
72
72
|
Read `ccc_index` from forge-tier.yaml:
|
|
73
73
|
|
|
74
|
-
- If `ccc_index.status` is `"fresh"`: continue to section 3.
|
|
74
|
+
- If `ccc_index.status` is `"fresh"` or `"created"`: continue to section 3.
|
|
75
75
|
- If `ccc_index.status` is `"stale"`: display brief note — "CCC index is stale — discovery results may miss recent changes." Continue to section 3.
|
|
76
76
|
- 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.
|
|
77
77
|
|
|
@@ -46,7 +46,7 @@ To extract all public exports, function signatures, type definitions, and co-imp
|
|
|
46
46
|
|
|
47
47
|
## CONTEXT BOUNDARIES:
|
|
48
48
|
|
|
49
|
-
- Available: brief_data, tier,
|
|
49
|
+
- 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
50
|
- Focus: Source code extraction and inventory building
|
|
51
51
|
- Limits: Do NOT compile, assemble, or write any output
|
|
52
52
|
- Dependencies: Source code must be accessible (resolved in step-01)
|
|
@@ -57,11 +57,26 @@ To fetch temporal context (issues, PRs, changelogs, release notes) from the sour
|
|
|
57
57
|
Evaluate the following conditions sequentially. **If ANY condition fails, skip silently to section 5 (auto-proceed) with no output:**
|
|
58
58
|
|
|
59
59
|
1. **Tier is Deep:** If tier is Quick, Forge, or Forge+, skip silently.
|
|
60
|
-
2. **Source is GitHub:** Verify `source_repo` is a GitHub URL (`https://github.com/...`) or `owner/repo` format. If the source is a local path, a non-GitHub URL, or any other format,
|
|
60
|
+
2. **Source is GitHub:** Verify `source_repo` is a GitHub URL (`https://github.com/...`) or `owner/repo` format. If the source is a local path, a non-GitHub URL, or any other format, attempt GitHub remote detection (section 1b) before skipping.
|
|
61
61
|
3. **`gh` CLI is available:** Run `gh auth status` to verify the CLI is installed and authenticated. If it fails, skip silently.
|
|
62
62
|
|
|
63
63
|
All three conditions must pass to proceed to section 2.
|
|
64
64
|
|
|
65
|
+
### 1b. GitHub Remote Detection for Local Sources
|
|
66
|
+
|
|
67
|
+
**Only runs when condition 2 above fails because `source_repo` is a local path.**
|
|
68
|
+
|
|
69
|
+
Local repositories that are clones of GitHub repos contain temporal context (issues, PRs, releases) accessible via `gh`. Detect this automatically:
|
|
70
|
+
|
|
71
|
+
1. Check if the local path is a git repository: `git -C {source_repo} rev-parse --is-inside-work-tree`
|
|
72
|
+
2. If not a git repo: skip silently to section 5 (current behavior).
|
|
73
|
+
3. Extract the origin remote: `git -C {source_repo} remote get-url origin`
|
|
74
|
+
4. If the remote URL contains `github.com`:
|
|
75
|
+
- Extract `owner/repo` from the remote URL (strip `.git` suffix, handle both HTTPS and SSH formats)
|
|
76
|
+
- Log: "**Local source with GitHub remote detected:** {owner}/{repo} — fetching temporal context."
|
|
77
|
+
- Use the extracted `owner/repo` for all `gh` API calls in sections 3-4. Continue to condition 3 (gh CLI check).
|
|
78
|
+
5. If no remote, or remote is not GitHub: skip silently to section 5 (current behavior).
|
|
79
|
+
|
|
65
80
|
### 2. Check Cache (Skip If Fresh)
|
|
66
81
|
|
|
67
82
|
Read `forge-tier.yaml` from the sidecar path.
|
|
@@ -85,14 +85,20 @@ Content fetched from external URLs is classified as **T3** (external, untrusted)
|
|
|
85
85
|
|
|
86
86
|
After fetching a URL, apply the following heuristic to detect documentation root pages that contain no useful API content. This is common with modern documentation sites (Mintlify, Docusaurus, ReadTheDocs, GitBook) that render API content on subpages.
|
|
87
87
|
|
|
88
|
-
**Root page detection
|
|
88
|
+
**Root page detection — apply only when the URL path ends in `/`, `/index`, `/index.html`, has no path component (bare domain), or has 1 path segment (e.g., `/docs`). For deeper URL paths (2+ segments like `/api/reference`), skip this heuristic and keep the content as-is.**
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
Subpage discovery is triggered if **either** of the following independent triggers fires:
|
|
91
|
+
|
|
92
|
+
**Trigger 1 — Content-based (both conditions must be true):**
|
|
91
93
|
|
|
92
94
|
1. **Zero API content indicators:** The fetched markdown contains none of: fenced code blocks (`` ``` ``), parameter tables (`|---|`), or function signature patterns (`def `, `function `, `fn `, `func `, `export `).
|
|
93
95
|
2. **High link density:** More than 70% of non-empty lines are markdown links (matching `[text](url)` with no other substantive content on the line).
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
**Trigger 2 — URL-based (independent of content analysis):**
|
|
98
|
+
|
|
99
|
+
The URL matches the path criteria above (ends in `/`, bare domain, or 1 segment) AND the fetched content is under **2000 words**. Short content on root-like URLs almost certainly indicates a navigation hub or landing page, even if it contains introductory code examples that would prevent Trigger 1 from firing. This handles modern doc sites (Mintlify, Docusaurus, GitBook) that include hero sections with code snippets on their root pages.
|
|
100
|
+
|
|
101
|
+
If neither trigger fires, keep the page content as-is and do NOT trigger subpage discovery.
|
|
96
102
|
|
|
97
103
|
**If a root URL with minimal content is detected:**
|
|
98
104
|
|
|
@@ -100,7 +100,12 @@ Following the structure from the skill-sections data file:
|
|
|
100
100
|
- Set `description` from the SKILL.md frontmatter `description` field (already assembled in section 2)
|
|
101
101
|
- Set `language` from source analysis (e.g., `"typescript"`, `"python"`) — use the primary language of the entry point file
|
|
102
102
|
- Set `ast_node_count` from extraction stats if ast-grep was used (Forge/Deep tier), otherwise omit
|
|
103
|
-
- Set `tool_versions` based on tier and available tools. Resolve `{skf_version}`
|
|
103
|
+
- Set `tool_versions` based on tier and available tools. Resolve `{skf_version}` using this resolution chain (try each in order, use the first that succeeds):
|
|
104
|
+
1. `{project-root}/_bmad/skf/package.json` → read `.version` field
|
|
105
|
+
2. `node -p "require('./node_modules/bmad-module-skill-forge/package.json').version"`
|
|
106
|
+
3. `{project-root}/_bmad/skf/VERSION` → read plain text file (single line containing version string, written by the SKF installer)
|
|
107
|
+
4. `"unknown"` (final fallback — add a warning to the evidence report)
|
|
108
|
+
Never hardcode the version.
|
|
104
109
|
- Store `commit_short` = first 8 characters of `source_commit` (or `"unknown"` if unavailable) for use in step-08 report.
|
|
105
110
|
- 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.
|
|
106
111
|
|
|
@@ -43,7 +43,7 @@ To write all compiled content to disk — 4 deliverable files to `{skills_output
|
|
|
43
43
|
|
|
44
44
|
## CONTEXT BOUNDARIES:
|
|
45
45
|
|
|
46
|
-
- Available: All compiled content from step-05, validation results from step-06
|
|
46
|
+
- Available: All compiled content from step-05, validation results from step-06, source_root from step-01 (needed for section 5b CCC registration)
|
|
47
47
|
- Focus: File system operations — create directories, write files
|
|
48
48
|
- Limits: Do NOT modify content during writing
|
|
49
49
|
- Dependencies: All content must be compiled and validated in context
|
|
@@ -145,7 +145,7 @@ Generate metadata.json following the exact structure defined in {skillTemplateDa
|
|
|
145
145
|
"tool_versions": {
|
|
146
146
|
"ast_grep": null,
|
|
147
147
|
"qmd": null,
|
|
148
|
-
"skf": "{skf_version}"
|
|
148
|
+
"skf": "{skf_version}" // Resolution chain: _bmad/skf/package.json → npm require → _bmad/skf/VERSION → "unknown"
|
|
149
149
|
},
|
|
150
150
|
"stats": {
|
|
151
151
|
"exports_documented": "{number of exports found}",
|
|
@@ -17,6 +17,21 @@
|
|
|
17
17
|
**Structural Issues:** {count}
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
## Coherence Analysis — Naive Mode: Reference Consistency (split-body)
|
|
21
|
+
|
|
22
|
+
Only rendered when `references/` directory exists alongside SKILL.md.
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
### Reference Consistency (split-body)
|
|
26
|
+
|
|
27
|
+
| # | Reference File | Export | Issue | SKILL.md Line | Reference Line |
|
|
28
|
+
|---|---------------|--------|-------|---------------|---------------|
|
|
29
|
+
| {per-mismatch rows} |
|
|
30
|
+
|
|
31
|
+
**Exports Cross-Checked:** {count}
|
|
32
|
+
**Mismatches Found:** {count}
|
|
33
|
+
```
|
|
34
|
+
|
|
20
35
|
## Coherence Analysis — Contextual Mode
|
|
21
36
|
|
|
22
37
|
```markdown
|
|
@@ -42,6 +42,18 @@ tessl evaluates SKILL.md body content only — it does not read `references/*.md
|
|
|
42
42
|
- Score based on: structural completeness only
|
|
43
43
|
- Weight redistribution: skipped categories' weights (Signature Accuracy 22% + Type Coverage 14%) redistributed proportionally to remaining active categories
|
|
44
44
|
|
|
45
|
+
### Docs-Only Mode (Quick tier, all [EXT:...] citations)
|
|
46
|
+
|
|
47
|
+
When `docs_only_mode: true` is set by step-03 (indicating a Quick tier skill where all SKILL.md citations are `[EXT:...]` format with no local source code):
|
|
48
|
+
|
|
49
|
+
- **Signature Accuracy:** Not scored (no source to compare against)
|
|
50
|
+
- **Type Coverage:** Not scored (no source to compare against)
|
|
51
|
+
- **Weight redistribution:** Same as Quick tier — Signature Accuracy (22%) and Type Coverage (14%) weights redistributed proportionally to remaining active categories
|
|
52
|
+
- **Export Coverage basis:** Documentation completeness rather than source coverage. Score = (documented_items_with_complete_descriptions / total_documented_items) * 100. A "complete" item has: description, parameters (if function/method), and return type (if function/method).
|
|
53
|
+
- **Coherence:** Standard rules for the detected mode (naive or contextual) apply unchanged
|
|
54
|
+
|
|
55
|
+
This is functionally identical to Quick tier weight redistribution but with a different coverage denominator (self-consistency instead of source comparison).
|
|
56
|
+
|
|
45
57
|
### Forge Tier (ast-grep)
|
|
46
58
|
- Export Coverage: AST-backed export comparison
|
|
47
59
|
- Signature Accuracy: AST-verified signature matching
|
|
@@ -87,6 +87,38 @@ Build the **documented inventory** — a list of everything the SKILL.md claims
|
|
|
87
87
|
|
|
88
88
|
**Split-body traversal:** If a `references/` directory exists alongside SKILL.md and SKILL.md's `## Full` headings are absent or stubs (not a stack skill's structural references), extend the documented inventory scan to include all `references/*.md` files. After split-body, Tier 2 content (Full API Reference, Full Type Definitions) lives in reference files — the inventory must reflect the full skill content regardless of where it resides.
|
|
89
89
|
|
|
90
|
+
### 1b. Cross-Check Split-Body Consistency
|
|
91
|
+
|
|
92
|
+
**Only execute if a `references/` directory exists alongside SKILL.md** (detected during split-body traversal in Section 1). Skip silently otherwise.
|
|
93
|
+
|
|
94
|
+
For each function, class, type, or interface that appears in BOTH the SKILL.md body AND any `references/*.md` file, compare the documented signatures:
|
|
95
|
+
|
|
96
|
+
- **Parameters:** name, type, order, optionality
|
|
97
|
+
- **Return types:** exact type match
|
|
98
|
+
- **Description:** no contradictions (brief vs detailed is acceptable; conflicting semantics is not)
|
|
99
|
+
|
|
100
|
+
**SKILL.md body is authoritative.** When a mismatch is found, the reference file is the one that needs updating.
|
|
101
|
+
|
|
102
|
+
Build a split-body consistency findings list:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"cross_check_mismatches": [
|
|
107
|
+
{
|
|
108
|
+
"export": "formatDate",
|
|
109
|
+
"skill_md_line": 42,
|
|
110
|
+
"reference_file": "references/api-reference.md",
|
|
111
|
+
"reference_line": 18,
|
|
112
|
+
"issue": "SKILL.md shows (date: Date) => string, reference shows (date: Date, format?: string) => string"
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
"exports_cross_checked": 12,
|
|
116
|
+
"mismatches_found": 1
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Flag each mismatch as **High severity** — signature inconsistency between SKILL.md body and reference files undermines agent trust. These findings feed into the gap report (step-06).
|
|
121
|
+
|
|
90
122
|
### 2. Analyze Source Code (Tier-Dependent)
|
|
91
123
|
|
|
92
124
|
Start from the package entry point (see 0b) and identify the public API surface. Then analyze those exports at the appropriate tier depth.
|
|
@@ -181,11 +213,13 @@ Append the **Coverage Analysis** section to `{outputFile}`:
|
|
|
181
213
|
|
|
182
214
|
### Category Scores
|
|
183
215
|
|
|
184
|
-
| Category | Score |
|
|
185
|
-
|
|
186
|
-
| Export Coverage | {N}% |
|
|
187
|
-
| Signature Accuracy | {N}%
|
|
188
|
-
| Type Coverage | {N}%
|
|
216
|
+
| Category | Score |
|
|
217
|
+
|----------|-------|
|
|
218
|
+
| Export Coverage | {N}% |
|
|
219
|
+
| Signature Accuracy | {N}% or N/A |
|
|
220
|
+
| Type Coverage | {N}% or N/A |
|
|
221
|
+
|
|
222
|
+
Note: Weight application is deferred to step-05 where all category weights are calculated after external validation availability is known.
|
|
189
223
|
```
|
|
190
224
|
|
|
191
225
|
### 6. Report Coverage Results
|
|
@@ -91,7 +91,27 @@ Build a simple structural findings list:
|
|
|
91
91
|
}
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
**After naive coherence →
|
|
94
|
+
**After naive coherence → Execute Section 2b if gate conditions met, then skip to Section 6 (Append Results)**
|
|
95
|
+
|
|
96
|
+
### 2b. Migration/Deprecation Verification (Mode-Independent)
|
|
97
|
+
|
|
98
|
+
**Gate check:** Execute this section ONLY IF both conditions are met:
|
|
99
|
+
1. Forge tier is **Deep** (tool-gated)
|
|
100
|
+
2. `{forge_data_folder}/{skill_name}/evidence-report.md` exists (data-gated)
|
|
101
|
+
|
|
102
|
+
If either condition fails, skip silently and proceed to Section 6.
|
|
103
|
+
|
|
104
|
+
**This check runs regardless of naive/contextual mode.** T2-future annotations are a property of the source code and enrichment data, not the skill type.
|
|
105
|
+
|
|
106
|
+
Check whether SKILL.md contains a "Migration & Deprecation Warnings" section (Section 4b). Then check the skill's `evidence-report.md` (at `{forge_data_folder}/{skill_name}/evidence-report.md`) for T2-future annotation counts.
|
|
107
|
+
|
|
108
|
+
- **If T2-future annotations > 0 AND Section 4b is absent:** Flag as Medium severity gap: "Migration section missing — T2-future annotations exist but Section 4b is not present in SKILL.md Tier 1."
|
|
109
|
+
- **If T2-future annotations = 0 AND Section 4b is present:** Flag as Medium severity gap: "Migration section unexpected — Section 4b is present but no T2-future annotations were produced."
|
|
110
|
+
- **If evidence-report.md is unavailable:** Skip this check silently. Note: "Section 4b verification skipped — evidence-report.md not found."
|
|
111
|
+
|
|
112
|
+
Add findings to the coherence analysis results.
|
|
113
|
+
|
|
114
|
+
**After Section 2b (naive path) → Skip to Section 6 (Append Results)**
|
|
95
115
|
|
|
96
116
|
### 3. Contextual Mode: Extract References
|
|
97
117
|
|
|
@@ -121,6 +141,8 @@ DO NOT BE LAZY — For EACH reference found, launch a subprocess that:
|
|
|
121
141
|
|
|
122
142
|
If subprocess unavailable, validate each reference in main thread.
|
|
123
143
|
|
|
144
|
+
4. **Scripts/assets directory check:** If a `scripts/` or `assets/` directory exists alongside SKILL.md, verify that a "Scripts & Assets" section (Section 7b) is present in SKILL.md. This directory-level check applies in both modes (naive mode performs it in Section 2; contextual mode performs it here alongside per-reference validation). Flag absence as Medium severity gap per `{scoringRulesFile}`.
|
|
145
|
+
|
|
124
146
|
### 5. Contextual Mode: Check Integration Pattern Completeness
|
|
125
147
|
|
|
126
148
|
For stack skills, verify integration patterns are complete:
|
|
@@ -146,11 +168,19 @@ Build integration completeness findings:
|
|
|
146
168
|
}
|
|
147
169
|
```
|
|
148
170
|
|
|
149
|
-
|
|
171
|
+
**Zero integration patterns:** If no integration patterns are documented in SKILL.md (e.g., a contextual-mode skill that uses shared types but has no middleware chains, plugin hooks, or event flows): record `patterns_documented: 0`, `patterns_complete: 0`. The coherence score will use reference validity alone — see `{scoringRulesFile}` Coherence Score Aggregation: "If no integration patterns exist, combined coherence equals reference validity."
|
|
150
172
|
|
|
151
|
-
|
|
173
|
+
### 5b. Migration/Deprecation Verification (Contextual Path)
|
|
152
174
|
|
|
153
|
-
|
|
175
|
+
**This section shares logic with Section 2b.** If you are on the contextual mode path (Sections 3-5), execute the migration check here using the same rules as Section 2b:
|
|
176
|
+
|
|
177
|
+
**Gate check:** Execute ONLY IF both conditions are met:
|
|
178
|
+
1. Forge tier is **Deep** (tool-gated)
|
|
179
|
+
2. `{forge_data_folder}/{skill_name}/evidence-report.md` exists (data-gated)
|
|
180
|
+
|
|
181
|
+
If either condition fails, skip silently.
|
|
182
|
+
|
|
183
|
+
Check whether SKILL.md contains a "Migration & Deprecation Warnings" section (Section 4b). Then check the skill's `evidence-report.md` for T2-future annotation counts.
|
|
154
184
|
|
|
155
185
|
- **If T2-future annotations > 0 AND Section 4b is absent:** Flag as Medium severity gap: "Migration section missing — T2-future annotations exist but Section 4b is not present in SKILL.md Tier 1."
|
|
156
186
|
- **If T2-future annotations = 0 AND Section 4b is present:** Flag as Medium severity gap: "Migration section unexpected — Section 4b is present but no T2-future annotations were produced."
|
|
@@ -158,6 +188,20 @@ Check whether SKILL.md contains a "Migration & Deprecation Warnings" section (Se
|
|
|
158
188
|
|
|
159
189
|
Add findings to the coherence analysis results.
|
|
160
190
|
|
|
191
|
+
### 5c. Calculate Coherence Scores
|
|
192
|
+
|
|
193
|
+
**Contextual mode only.** Calculate coherence percentages using the formulas defined in `{scoringRulesFile}` — Coherence Score Aggregation section:
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
reference_validity = (valid_references / total_references) * 100
|
|
197
|
+
integration_completeness = (complete_patterns / total_patterns) * 100
|
|
198
|
+
combined_coherence = (reference_validity * 0.6) + (integration_completeness * 0.4)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Edge case:** If no integration patterns are documented (patterns_documented = 0), combined coherence equals reference validity alone. Do not divide by zero.
|
|
202
|
+
|
|
203
|
+
These values fill the `{percentage}%` placeholders in the output template loaded in Section 6.
|
|
204
|
+
|
|
161
205
|
### 6. Append Coherence Analysis to Output
|
|
162
206
|
|
|
163
207
|
Load `{outputFormatsFile}` and use the appropriate Coherence Analysis section format (naive or contextual) to append findings to `{outputFile}`.
|
|
@@ -60,7 +60,15 @@ 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:**
|
|
63
|
+
**Staleness check:** Determine whether SKILL.md has changed since the evidence report was generated.
|
|
64
|
+
|
|
65
|
+
**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.
|
|
66
|
+
|
|
67
|
+
**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.
|
|
68
|
+
|
|
69
|
+
**Fallback (non-git environments):** If git commands fail (not a git repository), fall back to `metadata.json` `generation_date` comparison with a warning: "Staleness check using metadata.json — may be identical to evidence report timestamp. Consider a git-tracked directory for reliable staleness detection."
|
|
70
|
+
|
|
71
|
+
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.
|
|
64
72
|
|
|
65
73
|
If recent, non-stale results exist (from a create-skill run that just completed), auto-reuse them — skip re-running validators and use the existing scores. Record: "External validation: reused from create-skill evidence report." Skip to section 5 (append results).
|
|
66
74
|
|
|
@@ -64,6 +64,8 @@ Load `{scoringRulesFile}` to get:
|
|
|
64
64
|
- Tier-dependent scoring adjustments
|
|
65
65
|
- Any custom threshold override from workflow input
|
|
66
66
|
|
|
67
|
+
**Docs-only mode check:** If the Coverage Analysis section in `{outputFile}` notes docs-only mode (set by step-03 for skills with all `[EXT:...]` citations and no local source), apply Quick-tier weight redistribution: Signature Accuracy and Type Coverage are not scored, their weights (22% + 14%) are redistributed proportionally to remaining active categories. Coverage score is based on documentation completeness rather than source coverage (as calculated by step-03).
|
|
68
|
+
|
|
67
69
|
### 2. Read Category Scores from Output
|
|
68
70
|
|
|
69
71
|
Read `{outputFile}` and extract the category scores calculated in previous steps:
|
|
@@ -185,6 +185,10 @@ class Installer {
|
|
|
185
185
|
await fs.copy(src, path.join(skfDir, file));
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
+
|
|
189
|
+
// Write VERSION file for SKF version resolution in installed projects
|
|
190
|
+
const packageJson = require('../../../package.json');
|
|
191
|
+
await fs.writeFile(path.join(skfDir, 'VERSION'), packageJson.version, 'utf8');
|
|
188
192
|
}
|
|
189
193
|
|
|
190
194
|
/**
|