bmad-module-skill-forge 2.0.0 → 2.0.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/.claude-plugin/marketplace.json +1 -1
- package/.nvmrc +1 -1
- package/docs/_data/pinned.yaml +1 -1
- package/package.json +2 -2
- package/src/knowledge/skill-lifecycle.md +1 -1
- package/src/module-help.csv +2 -2
- package/src/shared/scripts/skf-comention-pairs.py +350 -0
- package/src/shared/scripts/skf-count-tokens.py +222 -0
- package/src/shared/scripts/skf-detect-docs.py +232 -1
- package/src/shared/scripts/skf-detect-language.py +77 -0
- package/src/shared/scripts/skf-detect-tools.py +105 -2
- package/src/shared/scripts/skf-enumerate-stack-skills.py +111 -2
- package/src/shared/scripts/skf-find-cycles.py +246 -0
- package/src/shared/scripts/skf-hash-content.py +487 -2
- package/src/shared/scripts/skf-manifest-ops.py +67 -1
- package/src/shared/scripts/skf-rebuild-managed-sections.py +180 -0
- package/src/shared/scripts/skf-recommend-scope-type.py +1 -2
- package/src/shared/scripts/skf-render-metadata-stats.py +499 -0
- package/src/shared/scripts/skf-rewrite-skill-name.py +308 -0
- package/src/shared/scripts/skf-shard-body.py +461 -0
- package/src/shared/scripts/skf-skill-inventory.py +139 -3
- package/src/shared/scripts/skf-structural-diff.py +307 -67
- package/src/shared/scripts/skf-validate-brief-schema.py +39 -1
- package/src/shared/scripts/skf-validate-feasibility-report.py +234 -0
- package/src/shared/scripts/skf-validate-frontmatter.py +17 -12
- package/src/shared/scripts/skf-validate-output.py +443 -10
- package/src/shared/scripts/skf-validate-pins.py +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +214 -0
- package/src/shared/scripts/skf-verify-provenance-completeness.py +439 -0
- package/src/skf-analyze-source/SKILL.md +17 -32
- package/src/skf-analyze-source/customize.toml +2 -0
- package/src/skf-analyze-source/references/auto-docs-only.md +116 -0
- package/src/skf-analyze-source/references/continue.md +8 -13
- package/src/skf-analyze-source/references/generate-briefs.md +28 -12
- package/src/skf-analyze-source/references/headless-contract.md +33 -0
- package/src/skf-analyze-source/references/health-check.md +1 -2
- package/src/skf-analyze-source/references/identify-units.md +25 -36
- package/src/skf-analyze-source/references/init.md +12 -25
- package/src/skf-analyze-source/references/map-and-detect.md +8 -20
- package/src/skf-analyze-source/references/recommend.md +4 -14
- package/src/skf-analyze-source/references/scan-project.md +3 -11
- package/src/skf-analyze-source/references/step-auto-scope.md +42 -180
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -2
- package/src/skf-audit-skill/SKILL.md +9 -6
- package/src/skf-audit-skill/customize.toml +2 -0
- package/src/skf-audit-skill/references/init.md +58 -32
- package/src/skf-audit-skill/references/re-index.md +15 -34
- package/src/skf-audit-skill/references/report.md +11 -58
- package/src/skf-audit-skill/references/semantic-diff.md +4 -22
- package/src/skf-audit-skill/references/severity-classify.md +53 -87
- package/src/skf-audit-skill/references/step-doc-drift.md +49 -19
- package/src/skf-audit-skill/references/structural-diff.md +43 -68
- package/src/skf-brief-skill/SKILL.md +7 -36
- package/src/skf-brief-skill/assets/scope-templates.md +1 -1
- package/src/skf-brief-skill/customize.toml +14 -0
- package/src/skf-brief-skill/references/analyze-target.md +6 -14
- package/src/skf-brief-skill/references/confirm-brief.md +2 -14
- package/src/skf-brief-skill/references/draft-checkpoint.md +8 -8
- package/src/skf-brief-skill/references/gather-intent.md +19 -22
- package/src/skf-brief-skill/references/headless-args.md +1 -1
- package/src/skf-brief-skill/references/health-check.md +1 -22
- package/src/skf-brief-skill/references/invocation-contract.md +37 -0
- package/src/skf-brief-skill/references/scope-definition.md +4 -14
- package/src/skf-brief-skill/references/step-auto-brief.md +1 -5
- package/src/skf-brief-skill/references/step-auto-validate.md +1 -5
- package/src/skf-brief-skill/references/version-resolution.md +1 -1
- package/src/skf-brief-skill/references/write-brief.md +17 -10
- package/src/skf-campaign/SKILL.md +15 -84
- package/src/skf-campaign/customize.toml +2 -0
- package/src/skf-campaign/manifest.yaml +4 -0
- package/src/skf-campaign/references/campaign-contracts.md +67 -0
- package/src/skf-campaign/references/campaign-directive-spec.md +14 -103
- package/src/skf-campaign/references/step-01-setup.md +4 -5
- package/src/skf-campaign/references/step-02-strategy.md +8 -3
- package/src/skf-campaign/references/step-03-pins.md +1 -1
- package/src/skf-campaign/references/step-04-provenance.md +1 -1
- package/src/skf-campaign/references/step-05-skill-loop.md +1 -1
- package/src/skf-campaign/references/step-06-batch.md +7 -6
- package/src/skf-campaign/references/step-11-maintenance.md +2 -2
- package/src/skf-campaign/references/step-resume.md +9 -8
- package/src/skf-campaign/scripts/campaign-deps.py +10 -1
- package/src/skf-campaign/scripts/campaign-render-batch.py +199 -0
- package/src/skf-campaign/scripts/campaign-status.py +162 -0
- package/src/skf-campaign/templates/campaign-brief-template.yaml +1 -1
- package/src/skf-create-skill/SKILL.md +14 -3
- package/src/skf-create-skill/assets/compile-assembly-rules.md +17 -38
- package/src/skf-create-skill/assets/skill-sections.md +9 -100
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +4 -13
- package/src/skf-create-skill/customize.toml +13 -0
- package/src/skf-create-skill/references/authoritative-files-protocol.md +7 -7
- package/src/skf-create-skill/references/compile.md +34 -47
- package/src/skf-create-skill/references/component-extraction.md +8 -35
- package/src/skf-create-skill/references/ecosystem-check.md +9 -25
- package/src/skf-create-skill/references/enrich.md +4 -17
- package/src/skf-create-skill/references/extract.md +14 -29
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +1 -1
- package/src/skf-create-skill/references/extraction-patterns.md +7 -7
- package/src/skf-create-skill/references/generate-artifacts.md +9 -23
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +16 -18
- package/src/skf-create-skill/references/report.md +12 -15
- package/src/skf-create-skill/references/source-resolution-protocols.md +3 -3
- package/src/skf-create-skill/references/step-auto-shard.md +52 -25
- package/src/skf-create-skill/references/step-doc-rot.md +30 -12
- package/src/skf-create-skill/references/step-doc-sources.md +2 -2
- package/src/skf-create-skill/references/sub/ccc-discover.md +2 -13
- package/src/skf-create-skill/references/sub/fetch-docs.md +8 -50
- package/src/skf-create-skill/references/sub/fetch-temporal.md +5 -20
- package/src/skf-create-skill/references/tier-degradation-rules.md +6 -8
- package/src/skf-create-skill/references/validate.md +59 -28
- package/src/skf-create-skill/scripts/scan-doc-rot.py +245 -0
- package/src/skf-create-stack-skill/SKILL.md +15 -9
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +1 -1
- package/src/skf-create-stack-skill/customize.toml +10 -0
- package/src/skf-create-stack-skill/references/compile-stack.md +7 -8
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +2 -13
- package/src/skf-create-stack-skill/references/detect-integrations.md +49 -54
- package/src/skf-create-stack-skill/references/detect-manifests.md +37 -30
- package/src/skf-create-stack-skill/references/generate-output.md +24 -75
- package/src/skf-create-stack-skill/references/init.md +9 -81
- package/src/skf-create-stack-skill/references/manifest-patterns.md +5 -35
- package/src/skf-create-stack-skill/references/parallel-extract.md +12 -27
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +6 -6
- package/src/skf-create-stack-skill/references/report.md +27 -62
- package/src/skf-create-stack-skill/references/validate.md +35 -31
- package/src/skf-drop-skill/SKILL.md +20 -23
- package/src/skf-drop-skill/customize.toml +10 -0
- package/src/skf-drop-skill/references/execute.md +51 -31
- package/src/skf-drop-skill/references/headless-contract.md +18 -0
- package/src/skf-drop-skill/references/health-check.md +1 -13
- package/src/skf-drop-skill/references/report.md +42 -10
- package/src/skf-drop-skill/references/select.md +88 -48
- package/src/skf-drop-skill/scripts/dir-sizes.py +116 -0
- package/src/skf-export-skill/SKILL.md +17 -14
- package/src/skf-export-skill/assets/managed-section-format.md +2 -5
- package/src/skf-export-skill/customize.toml +10 -6
- package/src/skf-export-skill/references/generate-snippet.md +21 -35
- package/src/skf-export-skill/references/load-skill.md +44 -42
- package/src/skf-export-skill/references/multi-skill-mode.md +1 -1
- package/src/skf-export-skill/references/orphan-context-detection.md +11 -3
- package/src/skf-export-skill/references/package.md +27 -33
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +24 -5
- package/src/skf-export-skill/references/result-envelope.md +28 -0
- package/src/skf-export-skill/references/summary.md +11 -5
- package/src/skf-export-skill/references/token-report.md +42 -24
- package/src/skf-export-skill/references/update-context.md +32 -33
- package/src/skf-forger/SKILL.md +27 -39
- package/src/skf-forger/references/pipeline-mode.md +34 -0
- package/src/skf-forger/scripts/parse-pipeline.py +270 -0
- package/src/skf-quick-skill/SKILL.md +10 -60
- package/src/skf-quick-skill/customize.toml +9 -0
- package/src/skf-quick-skill/references/batch-mode.md +6 -4
- package/src/skf-quick-skill/references/compile.md +15 -52
- package/src/skf-quick-skill/references/ecosystem-check.md +5 -20
- package/src/skf-quick-skill/references/finalize.md +12 -6
- package/src/skf-quick-skill/references/halt-contract.md +54 -0
- package/src/skf-quick-skill/references/health-check.md +3 -4
- package/src/skf-quick-skill/references/quick-extract.md +7 -18
- package/src/skf-quick-skill/references/registry-resolution.md +1 -23
- package/src/skf-quick-skill/references/resolve-target.md +27 -34
- package/src/skf-quick-skill/references/write-and-validate.md +10 -25
- package/src/skf-refine-architecture/SKILL.md +14 -7
- package/src/skf-refine-architecture/customize.toml +9 -0
- package/src/skf-refine-architecture/references/compile.md +9 -7
- package/src/skf-refine-architecture/references/gap-analysis.md +21 -50
- package/src/skf-refine-architecture/references/health-check.md +1 -1
- package/src/skf-refine-architecture/references/improvements.md +9 -25
- package/src/skf-refine-architecture/references/init.md +9 -16
- package/src/skf-refine-architecture/references/issue-detection.md +10 -25
- package/src/skf-refine-architecture/references/refinement-rules.md +4 -16
- package/src/skf-refine-architecture/references/report.md +13 -10
- package/src/skf-rename-skill/SKILL.md +11 -21
- package/src/skf-rename-skill/customize.toml +10 -0
- package/src/skf-rename-skill/references/execute.md +107 -78
- package/src/skf-rename-skill/references/exit-codes.md +12 -0
- package/src/skf-rename-skill/references/report.md +16 -8
- package/src/skf-rename-skill/references/select.md +69 -42
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -0
- package/src/skf-setup/SKILL.md +20 -12
- package/src/skf-setup/customize.toml +10 -0
- package/src/skf-setup/references/auto-index.md +9 -10
- package/src/skf-setup/references/ccc-index.md +14 -15
- package/src/skf-setup/references/detect-and-tier.md +6 -8
- package/src/skf-setup/references/report.md +22 -31
- package/src/skf-setup/references/tier-rules.md +2 -32
- package/src/skf-setup/references/write-config.md +9 -10
- package/src/skf-test-skill/SKILL.md +10 -8
- package/src/skf-test-skill/customize.toml +2 -0
- package/src/skf-test-skill/references/coherence-check.md +19 -31
- package/src/skf-test-skill/references/coverage-check.md +109 -75
- package/src/skf-test-skill/references/detect-mode.md +10 -41
- package/src/skf-test-skill/references/external-validators.md +11 -19
- package/src/skf-test-skill/references/init.md +38 -20
- package/src/skf-test-skill/references/migration-section-rules.md +4 -4
- package/src/skf-test-skill/references/report.md +60 -40
- package/src/skf-test-skill/references/score.md +32 -64
- package/src/skf-test-skill/references/scoring-rules.md +6 -62
- package/src/skf-test-skill/references/source-access-protocol.md +6 -6
- package/src/skf-test-skill/references/step-hard-gate.md +1 -3
- package/src/skf-test-skill/scripts/aggregate-coherence.py +276 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +359 -0
- package/src/skf-test-skill/scripts/combine-external-scores.py +190 -0
- package/src/skf-test-skill/scripts/compute-score.py +131 -1
- package/src/skf-test-skill/scripts/reconcile-coverage.py +327 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +251 -0
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +192 -0
- package/src/skf-update-skill/SKILL.md +17 -5
- package/src/skf-update-skill/customize.toml +14 -0
- package/src/skf-update-skill/references/detect-changes.md +19 -37
- package/src/skf-update-skill/references/health-check.md +3 -9
- package/src/skf-update-skill/references/init.md +39 -32
- package/src/skf-update-skill/references/manual-section-rules.md +1 -2
- package/src/skf-update-skill/references/merge-conflict-rules.md +1 -52
- package/src/skf-update-skill/references/merge.md +13 -57
- package/src/skf-update-skill/references/re-extract.md +12 -24
- package/src/skf-update-skill/references/report.md +14 -7
- package/src/skf-update-skill/references/validate.md +32 -30
- package/src/skf-update-skill/references/write.md +86 -51
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +167 -0
- package/src/skf-verify-stack/SKILL.md +11 -21
- package/src/skf-verify-stack/customize.toml +12 -3
- package/src/skf-verify-stack/references/coverage-patterns.md +1 -29
- package/src/skf-verify-stack/references/coverage.md +21 -10
- package/src/skf-verify-stack/references/exit-codes.md +14 -0
- package/src/skf-verify-stack/references/health-check.md +1 -1
- package/src/skf-verify-stack/references/init.md +20 -25
- package/src/skf-verify-stack/references/integration-verification-rules.md +10 -19
- package/src/skf-verify-stack/references/integrations.md +44 -49
- package/src/skf-verify-stack/references/report.md +28 -34
- package/src/skf-verify-stack/references/requirements.md +3 -3
- package/src/skf-verify-stack/references/synthesize.md +36 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +196 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +256 -0
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +258 -0
- package/src/skf-rename-skill/references/rebuild-context.md +0 -110
|
@@ -19,7 +19,7 @@ Analyzes a large repo or multi-service project to identify discrete skillable un
|
|
|
19
19
|
|
|
20
20
|
## Role
|
|
21
21
|
|
|
22
|
-
You are a source code analyst and decomposition architect collaborating with a developer onboarding an existing project
|
|
22
|
+
You are a source code analyst and decomposition architect collaborating with a developer onboarding an existing project, pairing your codebase-analysis and skill-scoping expertise with their domain knowledge.
|
|
23
23
|
|
|
24
24
|
## Workflow Rules
|
|
25
25
|
|
|
@@ -34,16 +34,16 @@ These rules apply to every step in this workflow:
|
|
|
34
34
|
| # | Step | File | Auto-proceed | Condition |
|
|
35
35
|
|---|------|------|--------------|-----------|
|
|
36
36
|
| 1 | Initialize | references/init.md | Yes | Always |
|
|
37
|
-
| 1a | Auto-Scope | references/step-auto-scope.md | Yes | `[auto]` mode only
|
|
37
|
+
| 1a | Auto-Scope | references/step-auto-scope.md | Yes | `[auto]` mode only — bypasses steps 2–6; owns pin resolution, coexistence detection, and the docs-only short-circuit |
|
|
38
38
|
| 1b | Continue (session resume) | references/continue.md | Yes | Always |
|
|
39
39
|
| 2 | Scan Project | references/scan-project.md | No (confirm) | Interactive mode only |
|
|
40
40
|
| 3 | Identify Units | references/identify-units.md | No (confirm) | Interactive mode only |
|
|
41
41
|
| 4 | Map & Detect | references/map-and-detect.md | Yes | Interactive mode only |
|
|
42
42
|
| 5 | Recommend | references/recommend.md | No (confirm) | Interactive mode only |
|
|
43
|
-
| 6 | Generate Briefs | references/generate-briefs.md |
|
|
43
|
+
| 6 | Generate Briefs | references/generate-briefs.md | No (confirm) | Interactive mode only |
|
|
44
44
|
| 7 | Workflow Health Check | references/health-check.md | Yes | Always |
|
|
45
45
|
|
|
46
|
-
**Auto mode path:**
|
|
46
|
+
**Auto mode path:** With `[auto]` present, init routes directly to step 1a. Step 1a may confirm N > 1 units (a monorepo splits into N briefs / N `brief_paths`, or merges to one), and routes docs-only targets to `references/auto-docs-only.md`.
|
|
47
47
|
|
|
48
48
|
**Shape detection reference:** `references/step-shape-detect.md` — loaded by step 1a as a reference doc (not a chained step).
|
|
49
49
|
|
|
@@ -51,41 +51,24 @@ These rules apply to every step in this workflow:
|
|
|
51
51
|
|
|
52
52
|
| Aspect | Detail |
|
|
53
53
|
|--------|--------|
|
|
54
|
-
| **Inputs** | project_path [required], scope_hint [optional]. `project_path`
|
|
55
|
-
| **Headless inputs** | `--project-path <path>` (skip Step 1 project-path prompt; accepts documentation URLs for docs-only mode), `--scope-hint <text>` (skip Step 1 scope-hint prompt), `--intent-hint <text>` (pre-supply analysis intent; drives recommendation ranking in Step 5), `--pin <version>` (pin to a specific version tag or branch; accepts semver tags, git tags, and branch names; when absent, resolves to the latest release tag) |
|
|
54
|
+
| **Inputs** | project_path [required], scope_hint [optional]. `project_path` is a GitHub repo URL or a local filesystem path. In `[auto]` mode it may also be a documentation URL — step 1a classifies the URL type and routes docs-only targets (see Stages row 1a). |
|
|
55
|
+
| **Headless inputs** | `--project-path <path>` (skip Step 1 project-path prompt; in `[auto]` mode also accepts documentation URLs for docs-only mode), `--scope-hint <text>` (skip Step 1 scope-hint prompt), `--intent-hint <text>` (pre-supply analysis intent; drives recommendation ranking in Step 5), `--pin <version>` (`[auto]` mode only — pin to a specific version tag or branch; accepts semver tags, git tags, and branch names; when absent, resolves to the latest release tag; interactive/headless runs use `--target-refs`/`--target-ref` instead) |
|
|
56
56
|
| **Headless flag** | `--headless` / `-H` flips every confirm gate to auto-proceed |
|
|
57
|
-
| **Auto flag** | `[auto]` bracket modifier — activates auto-scope mode (step 1a). Pipelines pass this as `AN[auto]`.
|
|
58
|
-
| **Gates** |
|
|
57
|
+
| **Auto flag** | `[auto]` bracket modifier — activates auto-scope mode (step 1a; see **Auto mode path** above). Pipelines pass this as `AN[auto]`. Requires `--project-path`. |
|
|
58
|
+
| **Gates** | steps 2/3/5: Confirm Gate [C]; step 6: Confirm Gate [Y] (write briefs) — all skipped in auto mode |
|
|
59
59
|
| **Outputs** | analysis-report.md, skill-brief.yaml files (one per recommended unit); final `SKF_ANALYZE_RESULT_JSON` line on stdout when `{headless_mode}` is true. In auto mode, the envelope includes `"mode":"auto"`. |
|
|
60
60
|
| **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true |
|
|
61
|
-
| **Exit codes** | See
|
|
61
|
+
| **Exit codes** | See `references/headless-contract.md` |
|
|
62
62
|
|
|
63
|
-
##
|
|
63
|
+
## Headless Result Contract
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
| Code | Meaning | Raised by |
|
|
68
|
-
| ---- | -------------------- | ------------------------------------------------------------------------------------------ |
|
|
69
|
-
| 0 | success / skipped / redirect | step 7 (terminal — health check completion); also covers coexistence `"skipped"` and `"redirect"` statuses from §0c |
|
|
70
|
-
| 2 | input-missing | step 1 §2-3 — required config absent (config.yaml not loadable, project path empty/invalid in headless mode); step 1 §2b — auto mode without `--project-path` |
|
|
71
|
-
| 3 | resolution-failure | step 1 §2 (`forge-tier.yaml` missing at `{sidecar_path}/forge-tier.yaml`); step 1 §3 (project path does not exist or remote URL inaccessible); step 1a §0a (docs-only URL unreachable); step 1a §0b (pin validation failure — `halt_reason: "pin-invalid"` when the supplied `--pin` does not match any tag or branch); step 1a §3 (shape detection script error, exit code 2) |
|
|
72
|
-
| 4 | write-failure | step 1 §6 (analysis report write failed); step 6 §5 (skill-brief.yaml write failed); step 6 §9 (result contract write failed) |
|
|
73
|
-
| 6 | user-cancelled | any interactive menu in steps 2/3/5/6 (user selected `[X]` Cancel and exit) |
|
|
74
|
-
|
|
75
|
-
## Result Contract (Headless)
|
|
76
|
-
|
|
77
|
-
When `{headless_mode}` is true, step 6 (interactive) or step 1a (auto) emits a single-line JSON envelope on **stdout** before chaining to step 7, and every HARD HALT emits the same envelope shape on **stderr** with `status: "error"`:
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
SKF_ANALYZE_RESULT_JSON: {"status":"success|error","report_path":"…|null","brief_paths":["…"],"unit_counts":{"confirmed":N,"skipped":N,"maybe":N},"exit_code":0,"halt_reason":null,"mode":"interactive|auto"}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
`status` is `"success"` on the terminal happy path, `"error"` on any HALT, `"redirect"` when coexistence detection routes to US (merge), or `"skipped"` when the user skips a conflicting target. `halt_reason` is one of: `null` (success), `"input-missing"`, `"forge-tier-missing"`, `"path-invalid"`, `"pin-invalid"`, `"write-failed"`, `"user-cancelled"`. `exit_code` matches the table above. `brief_paths` is an array of absolute paths to every generated `skill-brief.yaml` (empty array if none were generated). `unit_counts` reports confirmed/skipped/maybe counts from step 5's user decisions. `mode` is `"auto"` when the `[auto]` flag was active, `"interactive"` otherwise (omitting `mode` is equivalent to `"interactive"` for backward compatibility). The `coexistence` field (present when §0c triggers) is `"alongside"`, `"merge"`, or `"skip"`, indicating the user's coexistence decision. The `pinned_ref` and `pinned_version` fields (present when §0b resolves a pin) record the resolved git ref and extracted semver version for provenance tracking.
|
|
65
|
+
Headless/pipeline runs emit a single-line `SKF_ANALYZE_RESULT_JSON` envelope — on **stdout** for the terminal success path (step 6 or step 1a), on **stderr** with `status: "error"` for every HARD HALT — and exit with a stable code per failure class. The envelope shape, the `halt_reason` enum, and the exit-code table live in `references/headless-contract.md`; step files emit the concrete instance at each site.
|
|
84
66
|
|
|
85
67
|
## On Activation
|
|
86
68
|
|
|
87
69
|
1. Load config from `{project-root}/_bmad/skf/config.yaml` and resolve:
|
|
88
70
|
- `project_name`, `output_folder`, `user_name`, `communication_language`, `document_output_language`, `forge_data_folder`, `skills_output_folder`, `sidecar_path`
|
|
71
|
+
- If the config cannot be loaded, HARD HALT with exit code 2 (`input-missing`) per `references/headless-contract.md` — the workflow has no forge context to run against.
|
|
89
72
|
|
|
90
73
|
2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in preferences.yaml. Default: false.
|
|
91
74
|
|
|
@@ -104,13 +87,15 @@ SKF_ANALYZE_RESULT_JSON: {"status":"success|error","report_path":"…|null","bri
|
|
|
104
87
|
|
|
105
88
|
If the script fails or is missing, fall back to reading `{skill-root}/customize.toml` directly — the bundled defaults are an empty string for each path scalar.
|
|
106
89
|
|
|
107
|
-
Apply the path-scalar fallback now so stage files
|
|
90
|
+
Apply the path-scalar fallback now, so stage files reference the resolved variable with no conditional at the usage site. For each scalar, if the merged value is empty or absent, use the bundled default:
|
|
108
91
|
|
|
109
92
|
- `{unitDetectionHeuristicsPath}` ← `workflow.unit_detection_heuristics_path` if non-empty, else `references/unit-detection-heuristics.md`
|
|
110
93
|
- `{briefSchemaPath}` ← `workflow.brief_schema_path` if non-empty, else `assets/skill-brief-schema.md`
|
|
111
94
|
- `{analysisReportTemplatePath}` ← `workflow.analysis_report_template_path` if non-empty, else `templates/analysis-report-template.md`
|
|
112
|
-
- `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty string (
|
|
95
|
+
- `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty string (hook invocation skipped)
|
|
96
|
+
|
|
97
|
+
Stash all four as workflow-context variables. A non-empty value lets an org swap in a house-style copy (or wire a pipeline hook) without forking the skill.
|
|
113
98
|
|
|
114
|
-
|
|
99
|
+
Apply the array surfaces too: run `workflow.activation_steps_prepend` now, treat `workflow.persistent_facts` as standing context for the run (`file:`-prefixed entries load their file/glob contents as facts), then run `workflow.activation_steps_append` after activation.
|
|
115
100
|
|
|
116
101
|
4. Load, read the full file, and then execute `references/init.md` to begin the workflow.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# DO NOT EDIT -- overwritten on every update.
|
|
2
2
|
#
|
|
3
3
|
# Workflow customization surface for skf-analyze-source.
|
|
4
|
+
# Team overrides: _bmad/custom/skf-analyze-source.toml (under {project-root})
|
|
5
|
+
# Personal overrides: _bmad/custom/skf-analyze-source.user.toml (under {project-root})
|
|
4
6
|
|
|
5
7
|
[workflow]
|
|
6
8
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
nextStepFile: 'health-check.md'
|
|
3
|
+
outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
|
|
4
|
+
writeSkillBriefProbeOrder:
|
|
5
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-write-skill-brief.py'
|
|
6
|
+
- '{project-root}/src/shared/scripts/skf-write-skill-brief.py'
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<!-- Config: communicate in {communication_language}. -->
|
|
10
|
+
|
|
11
|
+
# Step 1a §0a: Docs-Only Short-Circuit
|
|
12
|
+
|
|
13
|
+
Reached from `step-auto-scope.md` §0c when the target is a documentation URL (not a GitHub repo or local path). It validates the URL, writes a minimal brief and analysis report, emits the result envelope, and chains directly to health-check — the standard auto-scope body (§1 through §11 in `step-auto-scope.md`) never runs for a docs-only target. `{coexistence_suffix}`, `{forge_tier}`, `{user_name}`, `{current_date}`, and the classification set upstream in §0/§0c carry into this file.
|
|
14
|
+
|
|
15
|
+
## MANDATORY SEQUENCE — §0a
|
|
16
|
+
|
|
17
|
+
### 1. Validate URL reachability
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
curl -sI --max-time 5 {url}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- On **2xx/3xx** response: URL is reachable. Continue.
|
|
24
|
+
- On **4xx/5xx**, DNS failure, or timeout: HARD HALT with exit code 3 (`resolution-failure`). Emit error message: `"Documentation URL unreachable: {url} — {status or error}"`, then the error envelope (shape in `references/headless-contract.md`) with `exit_code: 3`, `halt_reason: "resolution-failure"`, `mode: "auto"`, `source_type: "docs-only"`.
|
|
25
|
+
|
|
26
|
+
### 2. Derive skill name from URL domain
|
|
27
|
+
|
|
28
|
+
Extract the hostname from the URL (e.g., `docs.example.com` from `https://docs.example.com/guide/intro`), convert to kebab-case (replace `.` with `-`), yielding e.g. `docs-example-com`. If `{coexistence_suffix}` is non-empty, append it to the skill name (e.g., `docs-example-com-wiki`).
|
|
29
|
+
|
|
30
|
+
### 3. Write analysis report
|
|
31
|
+
|
|
32
|
+
Update {outputFile} with docs-only results. If the write fails, HARD HALT with exit code 4 (`write-failed`) per `references/headless-contract.md` (applies equally to the brief write in §4 and the result contract in §6).
|
|
33
|
+
|
|
34
|
+
**Update frontmatter:**
|
|
35
|
+
```yaml
|
|
36
|
+
stepsCompleted: ['init', 'auto-scope']
|
|
37
|
+
lastStep: 'auto-scope'
|
|
38
|
+
source_type: docs-only
|
|
39
|
+
confirmed_units:
|
|
40
|
+
- name: '{skill_name}'
|
|
41
|
+
shape: 'docs-only'
|
|
42
|
+
confidence: 1.0
|
|
43
|
+
export_count: 0
|
|
44
|
+
package_count: 0
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Append body section:**
|
|
48
|
+
```markdown
|
|
49
|
+
## Auto-Scope Analysis
|
|
50
|
+
|
|
51
|
+
**Mode:** auto (docs-only short-circuit)
|
|
52
|
+
**Source Type:** docs-only
|
|
53
|
+
**Documentation URL:** {url}
|
|
54
|
+
**Skill Name:** {skill_name}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 4. Write skill brief via canonical writer
|
|
58
|
+
|
|
59
|
+
**Resolve `{writeSkillBriefHelper}`** from `{writeSkillBriefProbeOrder}`; first existing path wins; HALT if neither resolves.
|
|
60
|
+
|
|
61
|
+
Create directory `{forge_data_folder}/{skill_name}/` if it does not exist.
|
|
62
|
+
|
|
63
|
+
Pipe the flat context JSON below into the resolved writer with the `--from-flat` flag:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"name": "{skill_name}",
|
|
68
|
+
"target_version": null,
|
|
69
|
+
"detected_version": null,
|
|
70
|
+
"source_type": "docs-only",
|
|
71
|
+
"source_repo": "{url}",
|
|
72
|
+
"language": "documentation",
|
|
73
|
+
"description": "Skill created from documentation at {url}",
|
|
74
|
+
"forge_tier": "{forge_tier}",
|
|
75
|
+
"created": "{current_date}",
|
|
76
|
+
"created_by": "{user_name}",
|
|
77
|
+
"scope_type": "docs-only",
|
|
78
|
+
"scope_include": [],
|
|
79
|
+
"scope_exclude": [],
|
|
80
|
+
"scope_notes": "Docs-only skill created from documentation URL",
|
|
81
|
+
"scope_rationale": null,
|
|
82
|
+
"scope_tier_a_include": null,
|
|
83
|
+
"scope_amendments": null,
|
|
84
|
+
"doc_urls": [{"url": "{url}", "label": "Primary Documentation"}],
|
|
85
|
+
"scripts_intent": null,
|
|
86
|
+
"assets_intent": null,
|
|
87
|
+
"source_authority": "community",
|
|
88
|
+
"target_ref": null,
|
|
89
|
+
"source_ref": null,
|
|
90
|
+
"version_resolved": "1.0.0"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
echo '<context-json>' | uv run {writeSkillBriefHelper} write --target {forge_data_folder}/{skill_name}/skill-brief.yaml --from-flat
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 5. Emit success envelope
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
SKF_ANALYZE_RESULT_JSON: {"status":"success","report_path":"{outputFile_path}","brief_paths":["{brief_path}"],"unit_counts":{"confirmed":1,"skipped":0,"maybe":0},"exit_code":0,"halt_reason":null,"mode":"auto","source_type":"docs-only"}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If `{coexistence_suffix}` is non-empty (i.e., [A]longside was selected in §0c), include `"coexistence":"alongside"` in the envelope.
|
|
105
|
+
|
|
106
|
+
The `source_type` field signals downstream consumers (BS) to skip repo-based enrichment.
|
|
107
|
+
|
|
108
|
+
### 6. Write result contract
|
|
109
|
+
|
|
110
|
+
Write the result contract per `shared/references/output-contract-schema.md`: the per-run record and latest copy, same as `step-auto-scope.md` §10.
|
|
111
|
+
|
|
112
|
+
If `{onCompleteCommand}` is non-empty, invoke it now with `--result-path={result_json_path}`.
|
|
113
|
+
|
|
114
|
+
### 7. Chain to health check
|
|
115
|
+
|
|
116
|
+
Load, read fully, then execute {nextStepFile} to run the shared workflow health check.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
|
|
3
3
|
nextStepOptions:
|
|
4
|
+
step 1a: 'step-auto-scope.md'
|
|
4
5
|
step 2: 'scan-project.md'
|
|
5
6
|
step 3: 'identify-units.md'
|
|
6
7
|
step 4: 'map-and-detect.md'
|
|
@@ -38,6 +39,7 @@ Load {outputFile} and read frontmatter:
|
|
|
38
39
|
- `forge_tier`
|
|
39
40
|
- `existing_skills`
|
|
40
41
|
- `confirmed_units`
|
|
42
|
+
- `mode` — `'auto'` when the report was produced by the auto-scope path; absent or any other value means interactive
|
|
41
43
|
|
|
42
44
|
### 3. Present Progress Summary
|
|
43
45
|
|
|
@@ -53,7 +55,11 @@ Load {outputFile} and read frontmatter:
|
|
|
53
55
|
|
|
54
56
|
### 4. Determine Next Step
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
**IF the report's `mode` is `'auto'`** (produced by the auto-scope path; reached here because the resume invocation did not carry `[auto]`): an auto analysis is a single idempotent pass, not a resumable interactive chain. Do not use the interactive table below.
|
|
59
|
+
- If `auto-scope` is in `stepsCompleted`, the auto analysis already completed — announce "**This auto analysis is already complete.** Would you like to start a new analysis?" and stop.
|
|
60
|
+
- Otherwise (an auto run interrupted before auto-scope finished), re-enter the auto path: load, read fully, then execute `step-auto-scope.md` (it reads the existing report frontmatter and re-runs cleanly). **STOP HERE.**
|
|
61
|
+
|
|
62
|
+
For interactive reports, map the last completed step to the next step file:
|
|
57
63
|
|
|
58
64
|
| Last Completed | Next Step |
|
|
59
65
|
|----------------|-----------|
|
|
@@ -76,16 +82,5 @@ lastContinued: '{current_date}'
|
|
|
76
82
|
|
|
77
83
|
"**Resuming from {next_step_name}...**"
|
|
78
84
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- After progress is confirmed, immediately load, read entire file, then execute the appropriate step from {nextStepOptions}
|
|
82
|
-
|
|
83
|
-
#### EXECUTION RULES:
|
|
84
|
-
|
|
85
|
-
- This is an auto-proceed continuation step
|
|
86
|
-
- Route directly to the next incomplete step
|
|
87
|
-
|
|
88
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
89
|
-
|
|
90
|
-
ONLY WHEN the progress state has been read, summarized to the user, and lastContinued updated will you load the appropriate next step file to resume the workflow.
|
|
85
|
+
Auto-proceed: immediately load, read the entire file, then execute the next incomplete step from {nextStepOptions}.
|
|
91
86
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
|
|
3
|
-
schemaFile: '
|
|
3
|
+
schemaFile: '{briefSchemaPath}'
|
|
4
4
|
validateBriefSchemaProbeOrder:
|
|
5
5
|
- '{project-root}/_bmad/skf/shared/scripts/skf-validate-brief-schema.py'
|
|
6
6
|
- '{project-root}/src/shared/scripts/skf-validate-brief-schema.py'
|
|
@@ -20,7 +20,7 @@ To generate a valid skill-brief.yaml file for each confirmed unit using the sche
|
|
|
20
20
|
- Generate only for units in confirmed_units — no extras, no omissions
|
|
21
21
|
- Do not modify recommendations or re-ask for confirmations
|
|
22
22
|
- Every generated field must trace back to data collected in steps 02-05
|
|
23
|
-
- Chains to the local health-check step via `{nextStepFile}` after completion — the user-facing summary is
|
|
23
|
+
- Chains to the local health-check step via `{nextStepFile}` after completion — the user-facing summary is not the terminal step
|
|
24
24
|
|
|
25
25
|
## MANDATORY SEQUENCE
|
|
26
26
|
|
|
@@ -40,7 +40,7 @@ Mark workflow complete and halt.
|
|
|
40
40
|
|
|
41
41
|
### 2. Generate Skill-Brief YAML Per Unit
|
|
42
42
|
|
|
43
|
-
For
|
|
43
|
+
For each unit in `confirmed_units`, construct a skill-brief.yaml using:
|
|
44
44
|
|
|
45
45
|
**Field mapping:**
|
|
46
46
|
|
|
@@ -74,7 +74,7 @@ YAML
|
|
|
74
74
|
|
|
75
75
|
The script returns JSON `{valid, errors[], warnings[], halt_reason, brief}` — the same validator and contract `skf-brief-skill` runs at consumption time, so a brief that passes here will not be rejected there for structural reasons. Apply the result:
|
|
76
76
|
|
|
77
|
-
- **`valid: false`** — the `errors[]` name the offending field (e.g. a `description` mis-indented under `scope:`, which leaves the required top-level `description` absent). Repair the assembled YAML and re-run the helper until `valid: true`.
|
|
77
|
+
- **`valid: false`** — the `errors[]` name the offending field (e.g. a `description` mis-indented under `scope:`, which leaves the required top-level `description` absent). Repair the assembled YAML and re-run the helper until `valid: true`. A brief is written only after it passes this gate.
|
|
78
78
|
- **`valid: true`** — carry any non-empty `warnings[]` into the §4 preview, then proceed.
|
|
79
79
|
|
|
80
80
|
This catches structural YAML errors where they are created, rather than letting them surface downstream as a HALT in `skf-brief-skill`'s ratify path.
|
|
@@ -84,13 +84,13 @@ This catches structural YAML errors where they are created, rather than letting
|
|
|
84
84
|
1. **Name uniqueness** — no duplicate names within the batch or existing skills
|
|
85
85
|
2. **Source accessible** — project_path exists
|
|
86
86
|
3. **Language recognized** — valid programming language identifier
|
|
87
|
-
4. **
|
|
88
|
-
|
|
87
|
+
4. **Forge tier match** — matches forge_tier from config
|
|
88
|
+
|
|
89
|
+
(The non-empty `scope.include` constraint — at least one glob pattern for every scope type except `docs-only` — is enforced deterministically by the §3a gate, so it is not re-checked here.)
|
|
89
90
|
|
|
90
91
|
**If any check fails:**
|
|
91
92
|
- Document the failure with specific field and reason
|
|
92
|
-
- Repair (3a structural errors) or present to user for correction (3b semantic issues) before writing
|
|
93
|
-
- Do NOT write invalid briefs
|
|
93
|
+
- Repair (3a structural errors) or present to user for correction (3b semantic issues) before writing — an invalid brief is not written
|
|
94
94
|
|
|
95
95
|
### 4. Present Generation Preview
|
|
96
96
|
|
|
@@ -113,6 +113,8 @@ This catches structural YAML errors where they are created, rather than letting
|
|
|
113
113
|
|
|
114
114
|
Wait for explicit user confirmation before writing files.
|
|
115
115
|
|
|
116
|
+
**GATE [default: Y]** — If `{headless_mode}` is true: auto-confirm [Y], write all briefs, and log: "headless: auto-write {count} briefs". Do not stall at this gate — it is the deliverable-producing step of a headless/pipeline run.
|
|
117
|
+
|
|
116
118
|
### 5. Write Files
|
|
117
119
|
|
|
118
120
|
**IF user confirms (Y):**
|
|
@@ -120,7 +122,7 @@ Wait for explicit user confirmation before writing files.
|
|
|
120
122
|
For each confirmed brief:
|
|
121
123
|
1. Create directory `{forge_data_folder}/{unit-name}/` if it does not exist
|
|
122
124
|
2. Write `skill-brief.yaml` to `{forge_data_folder}/{unit-name}/skill-brief.yaml` — write the exact YAML that passed the §3a schema gate verbatim; do not re-serialize, so the bytes on disk are the bytes that validated
|
|
123
|
-
3. Verify file was written
|
|
125
|
+
3. Verify the file was written; if the write fails, HARD HALT with exit code 4 (`write-failed`) per `references/headless-contract.md`
|
|
124
126
|
|
|
125
127
|
**IF user modifies (M):**
|
|
126
128
|
- Ask which brief and what to change
|
|
@@ -132,7 +134,7 @@ For each confirmed brief:
|
|
|
132
134
|
- Skip file writing, proceed to report update
|
|
133
135
|
|
|
134
136
|
**IF user cancels (X):**
|
|
135
|
-
- HARD HALT with exit code 6 (`user-cancelled`). Emit the
|
|
137
|
+
- HARD HALT with exit code 6 (`user-cancelled`). Emit the error envelope on stderr with `halt_reason: "user-cancelled"`, `brief_paths: []`, and `unit_counts` reflecting the confirmed/skipped/maybe state from step 5 (shape in `references/headless-contract.md`)
|
|
136
138
|
|
|
137
139
|
### 6. Determine Next Workflow Per Unit
|
|
138
140
|
|
|
@@ -204,7 +206,21 @@ To refine any brief, run the recommended next workflow. To re-analyze with diffe
|
|
|
204
206
|
|
|
205
207
|
### 9. Result Contract
|
|
206
208
|
|
|
207
|
-
Write the result contract per `shared/references/output-contract-schema.md`: the per-run record at `{forge_data_folder}/analyze-source-result-{YYYYMMDD-HHmmss}.json` (UTC timestamp, resolution to seconds) and a copy at `{forge_data_folder}/analyze-source-result-latest.json` (stable path for pipeline consumers — copy, not symlink). Include all generated `skill-brief.yaml` paths in `outputs` and brief counts in `summary`.
|
|
209
|
+
Write the result contract per `shared/references/output-contract-schema.md`: the per-run record at `{forge_data_folder}/analyze-source-result-{YYYYMMDD-HHmmss}.json` (UTC timestamp, resolution to seconds) and a copy at `{forge_data_folder}/analyze-source-result-latest.json` (stable path for pipeline consumers — copy, not symlink). Include all generated `skill-brief.yaml` paths in `outputs` and brief counts in `summary`. If the per-run record cannot be written, HARD HALT with exit code 4 (`write-failed`) per `references/headless-contract.md`.
|
|
210
|
+
|
|
211
|
+
### 9a. Emit Result Envelope
|
|
212
|
+
|
|
213
|
+
When `{headless_mode}` is true, emit the `SKF_ANALYZE_RESULT_JSON` envelope on **stdout** — the success signal for the interactive path, alongside §9's on-disk record (both are produced):
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
SKF_ANALYZE_RESULT_JSON: {"status":"success","report_path":"{outputFile_abs_path}","brief_paths":["{brief_path_1}",…,"{brief_path_N}"],"unit_counts":{"confirmed":N,"skipped":N,"maybe":N},"exit_code":0,"halt_reason":null,"mode":"interactive"}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
- `report_path` — absolute path to {outputFile}.
|
|
220
|
+
- `brief_paths` — every `skill-brief.yaml` written in §5 (empty array when the user skipped writing with [N]).
|
|
221
|
+
- `unit_counts` — confirmed/skipped counts from step 5 (`maybe` reserved; see `references/headless-contract.md`).
|
|
222
|
+
|
|
223
|
+
When `{headless_mode}` is false (interactive human run), skip this section — there is no pipeline consumer to signal.
|
|
208
224
|
|
|
209
225
|
### 9b. On-Complete Hook (pipeline integration)
|
|
210
226
|
|
|
@@ -224,5 +240,5 @@ If `{onCompleteCommand}` is empty, skip this section entirely (default behavior
|
|
|
224
240
|
|
|
225
241
|
### 10. Chain to Health Check
|
|
226
242
|
|
|
227
|
-
|
|
243
|
+
After the briefs are written (or skipped per user abort), the report updated, the summary presented, the result contract saved, and the on-complete hook invoked (or skipped per empty `{onCompleteCommand}`), load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step — continue past the summary even though it reads as final.
|
|
228
244
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Headless Result Contract & Exit Codes
|
|
2
|
+
|
|
3
|
+
Canonical headless/pipeline contract for skf-analyze-source. Step files emit the envelope and exit with the codes defined here.
|
|
4
|
+
|
|
5
|
+
## Result Envelope
|
|
6
|
+
|
|
7
|
+
When `{headless_mode}` is true, step 6 (interactive) or step 1a (auto) emits a single-line JSON envelope on **stdout** before chaining to step 7. Every HARD HALT emits the same envelope shape on **stderr** with `status: "error"`, using the exit code and `halt_reason` named at that HALT — so an automator branches on the failure class without grepping message text.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
SKF_ANALYZE_RESULT_JSON: {"status":"success|error|redirect|skipped","report_path":"…|null","brief_paths":["…"],"unit_counts":{"confirmed":N,"skipped":N,"maybe":N},"exit_code":0,"halt_reason":null,"mode":"interactive|auto"}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- `status` — `"success"` on the terminal happy path, `"error"` on any HALT, `"redirect"` when coexistence routes to US (merge), `"skipped"` when the user skips a conflicting target.
|
|
14
|
+
- `halt_reason` — one of `null` (success), `"input-missing"`, `"resolution-failure"`, `"pin-invalid"`, `"write-failed"`, `"user-cancelled"`.
|
|
15
|
+
- `exit_code` — matches the table below.
|
|
16
|
+
- `report_path` — absolute path to the analysis report, or `null` on an early HALT.
|
|
17
|
+
- `brief_paths` — array of absolute paths to every generated `skill-brief.yaml` (empty array if none).
|
|
18
|
+
- `unit_counts` — `confirmed` (units approved for briefs) and `skipped` (rejected in step 5, or the skipped target in coexistence §0c) counts; auto mode reports `confirmed:N, skipped:0`. `maybe` is a reserved slot, currently always `0`.
|
|
19
|
+
- `mode` — `"auto"` when the `[auto]` flag was active, `"interactive"` otherwise.
|
|
20
|
+
|
|
21
|
+
In auto mode the envelope also carries `coexistence` (the §0c decision) and, when a pin resolves, `pinned_ref`/`pinned_version` — `step-auto-scope.md` §0b/§0c define those field semantics. The docs-only path adds `source_type: "docs-only"`.
|
|
22
|
+
|
|
23
|
+
## Exit Codes
|
|
24
|
+
|
|
25
|
+
Every HARD HALT exits with a stable code so headless automators can branch on the failure class.
|
|
26
|
+
|
|
27
|
+
| Code | Meaning | Raised by |
|
|
28
|
+
| ---- | -------------------- | ------------------------------------------------------------------------------------------ |
|
|
29
|
+
| 0 | success / skipped / redirect | step 7 (terminal — health check completion); coexistence `"skipped"`/`"redirect"` statuses from §0c |
|
|
30
|
+
| 2 | input-missing | On Activation (config.yaml not loadable); step 1 §3 (project path empty/invalid in headless mode); step 1 §2b (auto mode without `--project-path`) |
|
|
31
|
+
| 3 | resolution-failure | step 1 §2 (`forge-tier.yaml` missing at `{sidecar_path}/forge-tier.yaml`); step 1 §3 (project path does not exist or remote URL inaccessible); step 1a §0a (docs-only URL unreachable); step 1a §0b (`halt_reason: "pin-invalid"` when the supplied `--pin` matches no tag or branch); step 1a §3 (shape detection script error, exit code 2) |
|
|
32
|
+
| 4 | write-failed | a failed write of the analysis report (step 1 §6 / step 1a §7 / §0a), a `skill-brief.yaml` (step 6 §5 / step 1a §8 / §0a), or the result contract (step 6 §9 / step 1a §10 / §0a) |
|
|
33
|
+
| 6 | user-cancelled | any interactive menu in steps 2/3/5/6 (user selected `[X]` Cancel and exit) |
|
|
@@ -16,8 +16,7 @@ Chain to the shared workflow self-improvement health check at `{nextStepFile}`.
|
|
|
16
16
|
## Rules
|
|
17
17
|
|
|
18
18
|
- No user-facing reports, file writes, or result contracts in this step — those belong in step 6
|
|
19
|
-
- Delegate directly to `{nextStepFile}` with no
|
|
20
|
-
- Do not attempt any other action between loading this step and executing `{nextStepFile}`
|
|
19
|
+
- Delegate directly to `{nextStepFile}` with no other action or commentary in between
|
|
21
20
|
|
|
22
21
|
## MANDATORY SEQUENCE
|
|
23
22
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'map-and-detect.md'
|
|
3
3
|
outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
|
|
4
|
-
heuristicsFile: '
|
|
4
|
+
heuristicsFile: '{unitDetectionHeuristicsPath}'
|
|
5
5
|
disqualifyCandidatesProbeOrder:
|
|
6
6
|
- '{project-root}/_bmad/skf/shared/scripts/skf-disqualify-candidates.py'
|
|
7
7
|
- '{project-root}/src/shared/scripts/skf-disqualify-candidates.py'
|
|
8
|
+
detectLanguageProbeOrder:
|
|
9
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-detect-language.py'
|
|
10
|
+
- '{project-root}/src/shared/scripts/skf-detect-language.py'
|
|
8
11
|
---
|
|
9
12
|
|
|
10
13
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -36,24 +39,13 @@ Load {heuristicsFile} for classification rules.
|
|
|
36
39
|
|
|
37
40
|
**Resolve `{disqualifyCandidatesHelper}`** from `{disqualifyCandidatesProbeOrder}`; first existing path wins. HALT if no candidate exists.
|
|
38
41
|
|
|
39
|
-
For
|
|
42
|
+
For each detected boundary from the scan, apply the classification rules from {heuristicsFile} (loaded in §1):
|
|
40
43
|
|
|
41
|
-
**Step A — Count detection signals:**
|
|
42
|
-
- Check strong signals (independent manifest, separate entry point, Docker config, distinct export surface, workspace member)
|
|
43
|
-
- Check moderate signals (directory depth, naming convention, separate tests, README, CI/CD reference)
|
|
44
|
-
- Check weak signals (large directory, comment boundaries, import clustering)
|
|
44
|
+
**Step A — Count detection signals:** tally the Strong / Moderate / Weak signals per its Detection Signals tables.
|
|
45
45
|
|
|
46
|
-
**Step B — Classify boundary type
|
|
47
|
-
- Service Boundary — independent deployable unit
|
|
48
|
-
- Package Boundary — workspace member or independently versioned
|
|
49
|
-
- Module Boundary — logical grouping within a package
|
|
50
|
-
- Library Boundary — third-party with significant project-specific usage
|
|
51
|
-
- Composite Boundary — ≥2 boundaries that only deliver value together (detected in §3b below; not assigned during initial per-boundary classification)
|
|
46
|
+
**Step B — Classify boundary type** per its Boundary Classification section. (Composite is detected separately in §3b below — not during this initial per-boundary pass.)
|
|
52
47
|
|
|
53
|
-
**Step C — Assign scope type
|
|
54
|
-
- `full-library` — entire codebase of the unit
|
|
55
|
-
- `specific-modules` — selected components or packages
|
|
56
|
-
- `public-api` — only exported interfaces
|
|
48
|
+
**Step C — Assign scope type** from that same section for the boundary's type.
|
|
57
49
|
|
|
58
50
|
**Step D — Run deterministic disqualification filter (script):**
|
|
59
51
|
|
|
@@ -87,9 +79,9 @@ Run the shared disqualification helper to apply the deterministic subset of the
|
|
|
87
79
|
- **Test-only** — test utilities with no production code
|
|
88
80
|
- **Already skilled** — exists in `existing_skills` list (recommend `update-skill` instead)
|
|
89
81
|
|
|
90
|
-
Remove any boundary that fails one of these LLM-judged rules from the working `kept` set and append it to `dropped[]` with the appropriate reason. Reasons recorded by the script (`too-few-files`, `too-low-loc`, `generated-code`, `auto-generated-tag`) are authoritative
|
|
82
|
+
Remove any boundary that fails one of these LLM-judged rules from the working `kept` set and append it to `dropped[]` with the appropriate reason. Reasons recorded by the script (`too-few-files`, `too-low-loc`, `generated-code`, `auto-generated-tag`) are authoritative — do not re-evaluate those rules manually.
|
|
91
83
|
|
|
92
|
-
**Qualification
|
|
84
|
+
**Qualification check:** Visually skim the script's `kept`/`dropped` decisions for sanity (e.g., a boundary you expected to qualify that landed in `dropped` — surface the script's `reason` and `context.first_match` to the user in §5 so they can override if the heuristic was wrong for this project).
|
|
93
85
|
|
|
94
86
|
### 3. Build Unit Classification Table
|
|
95
87
|
|
|
@@ -110,9 +102,7 @@ For disqualified candidates, note reason:
|
|
|
110
102
|
|
|
111
103
|
After building the classification table, apply the Composite Boundary detection heuristic from {heuristicsFile} against the qualifying units:
|
|
112
104
|
|
|
113
|
-
1. **Scan for merge candidates:** Among the qualifying units (from `kept[]`), find groups of ≥2 Package or Module boundaries that meet
|
|
114
|
-
- **Mutual hard dependency:** Every constituent imports from at least one other constituent in the group, AND no constituent's public API is self-contained
|
|
115
|
-
- **Shared integration surface:** Constituents share types/traits defined in one constituent but consumed by all others, AND the consuming constituents have no independent barrel
|
|
105
|
+
1. **Scan for merge candidates:** Among the qualifying units (from `kept[]`), find groups of ≥2 Package or Module boundaries that meet either Composite trigger — **Mutual hard dependency** or **Shared integration surface** — as defined in {heuristicsFile}'s Composite Boundary heuristic.
|
|
116
106
|
|
|
117
107
|
2. **If candidate groups are found**, propose each merge:
|
|
118
108
|
- Derive a composite name from the common namespace prefix or repo name
|
|
@@ -121,16 +111,23 @@ After building the classification table, apply the Composite Boundary detection
|
|
|
121
111
|
|
|
122
112
|
3. **If no candidate groups are found**, skip to §4.
|
|
123
113
|
|
|
124
|
-
**Merge does
|
|
114
|
+
**Merge does not fire for:** Units already flagged as Stack Skill Candidates in step 4 (map-and-detect §5) — those are multi-unit groupings that deliver value *separately* but are *also* useful together. Composite merges are for units that are *only* useful together (the key distinction). If a group of units is independently useful but commonly combined, it remains as separate units and is flagged as a stack skill candidate later.
|
|
125
115
|
|
|
126
116
|
**This step is a recommendation — not automatic.** Merges are presented to the user in §5 for confirmation (see "Composite Merge Proposals" below). If the user rejects a merge, the constituents remain as separate units in the classification table.
|
|
127
117
|
|
|
128
118
|
### 4. Detect Primary Language Per Unit
|
|
129
119
|
|
|
130
|
-
For each qualifying unit (including any approved composites from §3b),
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
120
|
+
For each qualifying unit (including any approved composites from §3b), detect the primary language deterministically via the shared helper — the single source of truth for the manifest→language rule table (no in-prose restatement, which drifts from the script's tsconfig JS-vs-TS and `build.gradle` Java-vs-Kotlin disambiguation).
|
|
121
|
+
|
|
122
|
+
**Resolve `{detectLanguageHelper}`** from `{detectLanguageProbeOrder}`; first existing path wins.
|
|
123
|
+
|
|
124
|
+
For each unit, pipe its file list — the `files` array built for that boundary in the §2 boundaries JSON — as the tree:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
echo '{"tree": [<unit files — forward-slash, repo-relative>]}' | uv run {detectLanguageHelper}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Read `.language` and `.confidence` for the unit. When confidence is low (the extension-frequency fallback fired — no manifest matched), surface it in §5 so the user can override the guess.
|
|
134
131
|
|
|
135
132
|
### 5. Present Classifications
|
|
136
133
|
|
|
@@ -195,16 +192,8 @@ Display: "**Select:** [C] Continue to Export Mapping and Integration Detection |
|
|
|
195
192
|
#### Menu Handling Logic:
|
|
196
193
|
|
|
197
194
|
- IF C: Save classifications to {outputFile}, update frontmatter, then load, read entire file, then execute {nextStepFile}
|
|
198
|
-
- IF X: HARD HALT with exit code 6 (`user-cancelled`). Emit the
|
|
195
|
+
- IF X: HARD HALT with exit code 6 (`user-cancelled`). Emit the error envelope on stderr with `halt_reason: "user-cancelled"` and counts/paths reflecting state at cancellation (shape in `references/headless-contract.md`)
|
|
199
196
|
- IF Any other: help user, then [Redisplay Menu Options](#7-present-menu-options)
|
|
200
197
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
- ALWAYS halt and wait for user input after presenting menu
|
|
204
|
-
- **GATE [default: C]** — If `{headless_mode}`: accept all classifications and auto-proceed, log: "headless: auto-accept unit classifications"
|
|
205
|
-
- ONLY proceed to next step when user selects 'C'
|
|
206
|
-
|
|
207
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
208
|
-
|
|
209
|
-
ONLY WHEN the Identified Units section has been appended to {outputFile} with complete classification tables, disqualification records, and language detection results, and frontmatter stepsCompleted has been updated, will you load and read fully {nextStepFile} to begin export mapping and integration detection.
|
|
198
|
+
**GATE [default: C]** — present the menu and wait for the user's choice. If `{headless_mode}`: accept all classifications and auto-proceed, log: "headless: auto-accept unit classifications".
|
|
210
199
|
|