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.
Files changed (235) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.nvmrc +1 -1
  3. package/docs/_data/pinned.yaml +1 -1
  4. package/package.json +2 -2
  5. package/src/knowledge/skill-lifecycle.md +1 -1
  6. package/src/module-help.csv +2 -2
  7. package/src/shared/scripts/skf-comention-pairs.py +350 -0
  8. package/src/shared/scripts/skf-count-tokens.py +222 -0
  9. package/src/shared/scripts/skf-detect-docs.py +232 -1
  10. package/src/shared/scripts/skf-detect-language.py +77 -0
  11. package/src/shared/scripts/skf-detect-tools.py +105 -2
  12. package/src/shared/scripts/skf-enumerate-stack-skills.py +111 -2
  13. package/src/shared/scripts/skf-find-cycles.py +246 -0
  14. package/src/shared/scripts/skf-hash-content.py +487 -2
  15. package/src/shared/scripts/skf-manifest-ops.py +67 -1
  16. package/src/shared/scripts/skf-rebuild-managed-sections.py +180 -0
  17. package/src/shared/scripts/skf-recommend-scope-type.py +1 -2
  18. package/src/shared/scripts/skf-render-metadata-stats.py +499 -0
  19. package/src/shared/scripts/skf-rewrite-skill-name.py +308 -0
  20. package/src/shared/scripts/skf-shard-body.py +461 -0
  21. package/src/shared/scripts/skf-skill-inventory.py +139 -3
  22. package/src/shared/scripts/skf-structural-diff.py +307 -67
  23. package/src/shared/scripts/skf-validate-brief-schema.py +39 -1
  24. package/src/shared/scripts/skf-validate-feasibility-report.py +234 -0
  25. package/src/shared/scripts/skf-validate-frontmatter.py +17 -12
  26. package/src/shared/scripts/skf-validate-output.py +443 -10
  27. package/src/shared/scripts/skf-validate-pins.py +1 -1
  28. package/src/shared/scripts/skf-verify-no-trace.py +214 -0
  29. package/src/shared/scripts/skf-verify-provenance-completeness.py +439 -0
  30. package/src/skf-analyze-source/SKILL.md +17 -32
  31. package/src/skf-analyze-source/customize.toml +2 -0
  32. package/src/skf-analyze-source/references/auto-docs-only.md +116 -0
  33. package/src/skf-analyze-source/references/continue.md +8 -13
  34. package/src/skf-analyze-source/references/generate-briefs.md +28 -12
  35. package/src/skf-analyze-source/references/headless-contract.md +33 -0
  36. package/src/skf-analyze-source/references/health-check.md +1 -2
  37. package/src/skf-analyze-source/references/identify-units.md +25 -36
  38. package/src/skf-analyze-source/references/init.md +12 -25
  39. package/src/skf-analyze-source/references/map-and-detect.md +8 -20
  40. package/src/skf-analyze-source/references/recommend.md +4 -14
  41. package/src/skf-analyze-source/references/scan-project.md +3 -11
  42. package/src/skf-analyze-source/references/step-auto-scope.md +42 -180
  43. package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -2
  44. package/src/skf-audit-skill/SKILL.md +9 -6
  45. package/src/skf-audit-skill/customize.toml +2 -0
  46. package/src/skf-audit-skill/references/init.md +58 -32
  47. package/src/skf-audit-skill/references/re-index.md +15 -34
  48. package/src/skf-audit-skill/references/report.md +11 -58
  49. package/src/skf-audit-skill/references/semantic-diff.md +4 -22
  50. package/src/skf-audit-skill/references/severity-classify.md +53 -87
  51. package/src/skf-audit-skill/references/step-doc-drift.md +49 -19
  52. package/src/skf-audit-skill/references/structural-diff.md +43 -68
  53. package/src/skf-brief-skill/SKILL.md +7 -36
  54. package/src/skf-brief-skill/assets/scope-templates.md +1 -1
  55. package/src/skf-brief-skill/customize.toml +14 -0
  56. package/src/skf-brief-skill/references/analyze-target.md +6 -14
  57. package/src/skf-brief-skill/references/confirm-brief.md +2 -14
  58. package/src/skf-brief-skill/references/draft-checkpoint.md +8 -8
  59. package/src/skf-brief-skill/references/gather-intent.md +19 -22
  60. package/src/skf-brief-skill/references/headless-args.md +1 -1
  61. package/src/skf-brief-skill/references/health-check.md +1 -22
  62. package/src/skf-brief-skill/references/invocation-contract.md +37 -0
  63. package/src/skf-brief-skill/references/scope-definition.md +4 -14
  64. package/src/skf-brief-skill/references/step-auto-brief.md +1 -5
  65. package/src/skf-brief-skill/references/step-auto-validate.md +1 -5
  66. package/src/skf-brief-skill/references/version-resolution.md +1 -1
  67. package/src/skf-brief-skill/references/write-brief.md +17 -10
  68. package/src/skf-campaign/SKILL.md +15 -84
  69. package/src/skf-campaign/customize.toml +2 -0
  70. package/src/skf-campaign/manifest.yaml +4 -0
  71. package/src/skf-campaign/references/campaign-contracts.md +67 -0
  72. package/src/skf-campaign/references/campaign-directive-spec.md +14 -103
  73. package/src/skf-campaign/references/step-01-setup.md +4 -5
  74. package/src/skf-campaign/references/step-02-strategy.md +8 -3
  75. package/src/skf-campaign/references/step-03-pins.md +1 -1
  76. package/src/skf-campaign/references/step-04-provenance.md +1 -1
  77. package/src/skf-campaign/references/step-05-skill-loop.md +1 -1
  78. package/src/skf-campaign/references/step-06-batch.md +7 -6
  79. package/src/skf-campaign/references/step-11-maintenance.md +2 -2
  80. package/src/skf-campaign/references/step-resume.md +9 -8
  81. package/src/skf-campaign/scripts/campaign-deps.py +10 -1
  82. package/src/skf-campaign/scripts/campaign-render-batch.py +199 -0
  83. package/src/skf-campaign/scripts/campaign-status.py +162 -0
  84. package/src/skf-campaign/templates/campaign-brief-template.yaml +1 -1
  85. package/src/skf-create-skill/SKILL.md +14 -3
  86. package/src/skf-create-skill/assets/compile-assembly-rules.md +17 -38
  87. package/src/skf-create-skill/assets/skill-sections.md +9 -100
  88. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +4 -13
  89. package/src/skf-create-skill/customize.toml +13 -0
  90. package/src/skf-create-skill/references/authoritative-files-protocol.md +7 -7
  91. package/src/skf-create-skill/references/compile.md +34 -47
  92. package/src/skf-create-skill/references/component-extraction.md +8 -35
  93. package/src/skf-create-skill/references/ecosystem-check.md +9 -25
  94. package/src/skf-create-skill/references/enrich.md +4 -17
  95. package/src/skf-create-skill/references/extract.md +14 -29
  96. package/src/skf-create-skill/references/extraction-patterns-tracing.md +1 -1
  97. package/src/skf-create-skill/references/extraction-patterns.md +7 -7
  98. package/src/skf-create-skill/references/generate-artifacts.md +9 -23
  99. package/src/skf-create-skill/references/health-check.md +1 -1
  100. package/src/skf-create-skill/references/load-brief.md +16 -18
  101. package/src/skf-create-skill/references/report.md +12 -15
  102. package/src/skf-create-skill/references/source-resolution-protocols.md +3 -3
  103. package/src/skf-create-skill/references/step-auto-shard.md +52 -25
  104. package/src/skf-create-skill/references/step-doc-rot.md +30 -12
  105. package/src/skf-create-skill/references/step-doc-sources.md +2 -2
  106. package/src/skf-create-skill/references/sub/ccc-discover.md +2 -13
  107. package/src/skf-create-skill/references/sub/fetch-docs.md +8 -50
  108. package/src/skf-create-skill/references/sub/fetch-temporal.md +5 -20
  109. package/src/skf-create-skill/references/tier-degradation-rules.md +6 -8
  110. package/src/skf-create-skill/references/validate.md +59 -28
  111. package/src/skf-create-skill/scripts/scan-doc-rot.py +245 -0
  112. package/src/skf-create-stack-skill/SKILL.md +15 -9
  113. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +1 -1
  114. package/src/skf-create-stack-skill/customize.toml +10 -0
  115. package/src/skf-create-stack-skill/references/compile-stack.md +7 -8
  116. package/src/skf-create-stack-skill/references/compose-mode-rules.md +2 -13
  117. package/src/skf-create-stack-skill/references/detect-integrations.md +49 -54
  118. package/src/skf-create-stack-skill/references/detect-manifests.md +37 -30
  119. package/src/skf-create-stack-skill/references/generate-output.md +24 -75
  120. package/src/skf-create-stack-skill/references/init.md +9 -81
  121. package/src/skf-create-stack-skill/references/manifest-patterns.md +5 -35
  122. package/src/skf-create-stack-skill/references/parallel-extract.md +12 -27
  123. package/src/skf-create-stack-skill/references/rank-and-confirm.md +6 -6
  124. package/src/skf-create-stack-skill/references/report.md +27 -62
  125. package/src/skf-create-stack-skill/references/validate.md +35 -31
  126. package/src/skf-drop-skill/SKILL.md +20 -23
  127. package/src/skf-drop-skill/customize.toml +10 -0
  128. package/src/skf-drop-skill/references/execute.md +51 -31
  129. package/src/skf-drop-skill/references/headless-contract.md +18 -0
  130. package/src/skf-drop-skill/references/health-check.md +1 -13
  131. package/src/skf-drop-skill/references/report.md +42 -10
  132. package/src/skf-drop-skill/references/select.md +88 -48
  133. package/src/skf-drop-skill/scripts/dir-sizes.py +116 -0
  134. package/src/skf-export-skill/SKILL.md +17 -14
  135. package/src/skf-export-skill/assets/managed-section-format.md +2 -5
  136. package/src/skf-export-skill/customize.toml +10 -6
  137. package/src/skf-export-skill/references/generate-snippet.md +21 -35
  138. package/src/skf-export-skill/references/load-skill.md +44 -42
  139. package/src/skf-export-skill/references/multi-skill-mode.md +1 -1
  140. package/src/skf-export-skill/references/orphan-context-detection.md +11 -3
  141. package/src/skf-export-skill/references/package.md +27 -33
  142. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +24 -5
  143. package/src/skf-export-skill/references/result-envelope.md +28 -0
  144. package/src/skf-export-skill/references/summary.md +11 -5
  145. package/src/skf-export-skill/references/token-report.md +42 -24
  146. package/src/skf-export-skill/references/update-context.md +32 -33
  147. package/src/skf-forger/SKILL.md +27 -39
  148. package/src/skf-forger/references/pipeline-mode.md +34 -0
  149. package/src/skf-forger/scripts/parse-pipeline.py +270 -0
  150. package/src/skf-quick-skill/SKILL.md +10 -60
  151. package/src/skf-quick-skill/customize.toml +9 -0
  152. package/src/skf-quick-skill/references/batch-mode.md +6 -4
  153. package/src/skf-quick-skill/references/compile.md +15 -52
  154. package/src/skf-quick-skill/references/ecosystem-check.md +5 -20
  155. package/src/skf-quick-skill/references/finalize.md +12 -6
  156. package/src/skf-quick-skill/references/halt-contract.md +54 -0
  157. package/src/skf-quick-skill/references/health-check.md +3 -4
  158. package/src/skf-quick-skill/references/quick-extract.md +7 -18
  159. package/src/skf-quick-skill/references/registry-resolution.md +1 -23
  160. package/src/skf-quick-skill/references/resolve-target.md +27 -34
  161. package/src/skf-quick-skill/references/write-and-validate.md +10 -25
  162. package/src/skf-refine-architecture/SKILL.md +14 -7
  163. package/src/skf-refine-architecture/customize.toml +9 -0
  164. package/src/skf-refine-architecture/references/compile.md +9 -7
  165. package/src/skf-refine-architecture/references/gap-analysis.md +21 -50
  166. package/src/skf-refine-architecture/references/health-check.md +1 -1
  167. package/src/skf-refine-architecture/references/improvements.md +9 -25
  168. package/src/skf-refine-architecture/references/init.md +9 -16
  169. package/src/skf-refine-architecture/references/issue-detection.md +10 -25
  170. package/src/skf-refine-architecture/references/refinement-rules.md +4 -16
  171. package/src/skf-refine-architecture/references/report.md +13 -10
  172. package/src/skf-rename-skill/SKILL.md +11 -21
  173. package/src/skf-rename-skill/customize.toml +10 -0
  174. package/src/skf-rename-skill/references/execute.md +107 -78
  175. package/src/skf-rename-skill/references/exit-codes.md +12 -0
  176. package/src/skf-rename-skill/references/report.md +16 -8
  177. package/src/skf-rename-skill/references/select.md +69 -42
  178. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -0
  179. package/src/skf-setup/SKILL.md +20 -12
  180. package/src/skf-setup/customize.toml +10 -0
  181. package/src/skf-setup/references/auto-index.md +9 -10
  182. package/src/skf-setup/references/ccc-index.md +14 -15
  183. package/src/skf-setup/references/detect-and-tier.md +6 -8
  184. package/src/skf-setup/references/report.md +22 -31
  185. package/src/skf-setup/references/tier-rules.md +2 -32
  186. package/src/skf-setup/references/write-config.md +9 -10
  187. package/src/skf-test-skill/SKILL.md +10 -8
  188. package/src/skf-test-skill/customize.toml +2 -0
  189. package/src/skf-test-skill/references/coherence-check.md +19 -31
  190. package/src/skf-test-skill/references/coverage-check.md +109 -75
  191. package/src/skf-test-skill/references/detect-mode.md +10 -41
  192. package/src/skf-test-skill/references/external-validators.md +11 -19
  193. package/src/skf-test-skill/references/init.md +38 -20
  194. package/src/skf-test-skill/references/migration-section-rules.md +4 -4
  195. package/src/skf-test-skill/references/report.md +60 -40
  196. package/src/skf-test-skill/references/score.md +32 -64
  197. package/src/skf-test-skill/references/scoring-rules.md +6 -62
  198. package/src/skf-test-skill/references/source-access-protocol.md +6 -6
  199. package/src/skf-test-skill/references/step-hard-gate.md +1 -3
  200. package/src/skf-test-skill/scripts/aggregate-coherence.py +276 -0
  201. package/src/skf-test-skill/scripts/check-metadata-coherence.py +359 -0
  202. package/src/skf-test-skill/scripts/combine-external-scores.py +190 -0
  203. package/src/skf-test-skill/scripts/compute-score.py +131 -1
  204. package/src/skf-test-skill/scripts/reconcile-coverage.py +327 -0
  205. package/src/skf-test-skill/scripts/validate-inventory.py +251 -0
  206. package/src/skf-test-skill/scripts/verify-declared-numerator.py +192 -0
  207. package/src/skf-update-skill/SKILL.md +17 -5
  208. package/src/skf-update-skill/customize.toml +14 -0
  209. package/src/skf-update-skill/references/detect-changes.md +19 -37
  210. package/src/skf-update-skill/references/health-check.md +3 -9
  211. package/src/skf-update-skill/references/init.md +39 -32
  212. package/src/skf-update-skill/references/manual-section-rules.md +1 -2
  213. package/src/skf-update-skill/references/merge-conflict-rules.md +1 -52
  214. package/src/skf-update-skill/references/merge.md +13 -57
  215. package/src/skf-update-skill/references/re-extract.md +12 -24
  216. package/src/skf-update-skill/references/report.md +14 -7
  217. package/src/skf-update-skill/references/validate.md +32 -30
  218. package/src/skf-update-skill/references/write.md +86 -51
  219. package/src/skf-update-skill/scripts/skf-new-file-diff.py +167 -0
  220. package/src/skf-verify-stack/SKILL.md +11 -21
  221. package/src/skf-verify-stack/customize.toml +12 -3
  222. package/src/skf-verify-stack/references/coverage-patterns.md +1 -29
  223. package/src/skf-verify-stack/references/coverage.md +21 -10
  224. package/src/skf-verify-stack/references/exit-codes.md +14 -0
  225. package/src/skf-verify-stack/references/health-check.md +1 -1
  226. package/src/skf-verify-stack/references/init.md +20 -25
  227. package/src/skf-verify-stack/references/integration-verification-rules.md +10 -19
  228. package/src/skf-verify-stack/references/integrations.md +44 -49
  229. package/src/skf-verify-stack/references/report.md +28 -34
  230. package/src/skf-verify-stack/references/requirements.md +3 -3
  231. package/src/skf-verify-stack/references/synthesize.md +36 -39
  232. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +196 -0
  233. package/src/skf-verify-stack/scripts/skf-report-delta.py +256 -0
  234. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +258 -0
  235. package/src/skf-rename-skill/references/rebuild-context.md +0 -110
@@ -16,10 +16,23 @@ Actions:
16
16
  clear — Remove managed section entirely (markers + content)
17
17
  insert — Insert managed section if not present (at end of file)
18
18
  check — Check if managed section exists, report status
19
+
20
+ Query actions (read-only, take positional file lists instead of <file> <action>):
21
+ orphan-detect <context-file>... --exported-skills a,b
22
+ — Parse `[skill-name v...]` rows across one or more context
23
+ files, drop rows whose skill_name is in the exported set,
24
+ and report the survivors (deduped by (skill_name, version),
25
+ with verbatim snippet_text and sorted source_files provenance)
26
+ as `orphan_managed_rows`.
27
+ root-probe <snippet-file>... --reference-root .claude/skills/
28
+ — Read each snippet's first line, parse its `root:` prefix
29
+ (trailing `{skill-name}/` stripped), collect the unique
30
+ `observed_prefixes`, and flag `mismatch` against the reference.
19
31
  """
20
32
 
21
33
  from __future__ import annotations
22
34
 
35
+ import argparse
23
36
  import json
24
37
  import os
25
38
  import re
@@ -34,6 +47,16 @@ MARKER_PATTERN = re.compile(
34
47
  re.DOTALL,
35
48
  )
36
49
 
50
+ # A managed-section skill row header: `[skill-name v1.2.3]…`, optionally
51
+ # prefixed by the format's leading `|`. Requires a ` v<version>` inside the
52
+ # brackets so the section header `[SKF Skills]|{n} skills|{m} stack` (no ` v`)
53
+ # is never mistaken for a skill row.
54
+ ROW_HEADER_PATTERN = re.compile(
55
+ r"^\|?\[(?P<name>[^\]]+?) v(?P<version>[^\]\s]+)\]"
56
+ )
57
+ # The `root:` field of a snippet's first line: `…|root: {prefix}{skill-name}/`.
58
+ SNIPPET_ROOT_PATTERN = re.compile(r"root:\s*(?P<root>\S.*?)\s*$")
59
+
37
60
 
38
61
  def read_context_file(file_path):
39
62
  """Read a context file. Returns (content, None) or (None, error)."""
@@ -222,7 +245,164 @@ def cmd_insert(file_path, new_content):
222
245
  return {"status": "ok", "action": "inserted", "bytes_written": len(updated)}
223
246
 
224
247
 
248
+ def _is_row_separator(line):
249
+ """A blank/separator line between snippets: bare `|` or empty."""
250
+ return line.strip() in ("", "|")
251
+
252
+
253
+ def parse_managed_rows(body):
254
+ """Split the between-marker `body` into skill rows.
255
+
256
+ Returns a list of {skill_name, version, snippet_text} dicts, one per
257
+ `[skill-name v...]` header found. `snippet_text` is the header line plus its
258
+ continuation lines, captured verbatim (byte-preserved) up to — but not
259
+ including — the next bare-`|` separator, the next row header, or end of body.
260
+ Non-row lines (the `[SKF Skills]` header, the IMPORTANT preamble) are skipped.
261
+ """
262
+ lines = body.split("\n")
263
+ rows = []
264
+ i = 0
265
+ n = len(lines)
266
+ while i < n:
267
+ m = ROW_HEADER_PATTERN.match(lines[i])
268
+ if not m:
269
+ i += 1
270
+ continue
271
+ start = i
272
+ i += 1
273
+ while i < n and not ROW_HEADER_PATTERN.match(lines[i]) and not _is_row_separator(lines[i]):
274
+ i += 1
275
+ rows.append(
276
+ {
277
+ "skill_name": m.group("name"),
278
+ "version": m.group("version"),
279
+ "snippet_text": "\n".join(lines[start:i]),
280
+ }
281
+ )
282
+ return rows
283
+
284
+
285
+ def cmd_orphan_detect(context_files, exported_skills):
286
+ """Detect managed-section rows absent from the exported skill set.
287
+
288
+ Scans every context file that exists and has a managed section, parses its
289
+ skill rows, drops those whose skill_name is in `exported_skills`, and
290
+ accumulates the survivors keyed by (skill_name, version). The first-seen
291
+ snippet_text wins; each file the row appears in is added to source_files.
292
+ Deterministic: rows sorted by (skill_name, version), source_files sorted.
293
+ """
294
+ exported = {s.strip() for s in exported_skills.split(",") if s.strip()}
295
+ orphans = {} # (name, version) -> {skill_name, version, snippet_text, source_files:set}
296
+ for cf in context_files:
297
+ content, err = read_context_file(cf)
298
+ if err:
299
+ continue # missing file — no orphans by definition
300
+ match = find_managed_section(content)
301
+ if not match:
302
+ continue # no managed section — no orphans
303
+ for row in parse_managed_rows(match.group(2)):
304
+ if row["skill_name"] in exported:
305
+ continue # not an orphan — it is being (re)exported
306
+ key = (row["skill_name"], row["version"])
307
+ if key in orphans:
308
+ orphans[key]["source_files"].add(cf) # keep first-seen snippet_text
309
+ else:
310
+ orphans[key] = {
311
+ "skill_name": row["skill_name"],
312
+ "version": row["version"],
313
+ "snippet_text": row["snippet_text"],
314
+ "source_files": {cf},
315
+ }
316
+ orphan_rows = [
317
+ {
318
+ "skill_name": v["skill_name"],
319
+ "version": v["version"],
320
+ "snippet_text": v["snippet_text"],
321
+ "source_files": sorted(v["source_files"]),
322
+ }
323
+ for _, v in sorted(orphans.items())
324
+ ]
325
+ return {"status": "ok", "orphan_managed_rows": orphan_rows}
326
+
327
+
328
+ def cmd_root_probe(snippet_files, reference_root):
329
+ """Observe snippet root prefixes and flag mismatch against a reference.
330
+
331
+ Reads the first line of each snippet that exists, parses its `root:` value,
332
+ strips the trailing `{skill-name}/` to recover the prefix, and collects the
333
+ unique prefixes. `mismatch` is True when any observed prefix differs from
334
+ `reference_root`. Deterministic: observed_prefixes sorted.
335
+ """
336
+ observed = set()
337
+ for sf in snippet_files:
338
+ content, err = read_context_file(sf)
339
+ if err:
340
+ continue # missing snippet — skip
341
+ first_line = content.split("\n", 1)[0]
342
+ header = ROW_HEADER_PATTERN.match(first_line)
343
+ root_match = SNIPPET_ROOT_PATTERN.search(first_line)
344
+ if not root_match:
345
+ continue # no root: field — skip
346
+ root_value = root_match.group("root")
347
+ prefix = root_value
348
+ if header:
349
+ suffix = header.group("name") + "/"
350
+ if root_value.endswith(suffix):
351
+ prefix = root_value[: -len(suffix)]
352
+ observed.add(prefix)
353
+ observed_prefixes = sorted(observed)
354
+ return {
355
+ "status": "ok",
356
+ "reference_root": reference_root,
357
+ "observed_prefixes": observed_prefixes,
358
+ "mismatch": any(p != reference_root for p in observed_prefixes),
359
+ }
360
+
361
+
362
+ def _run_query_action(argv):
363
+ """Dispatch the read-only query actions (orphan-detect / root-probe).
364
+
365
+ These take a positional file list rather than the legacy `<file> <action>`
366
+ shape, so they are parsed with argparse and routed here before the legacy
367
+ path. Returns (result_dict, exit_code).
368
+ """
369
+ action = argv[0]
370
+ if action == "orphan-detect":
371
+ parser = argparse.ArgumentParser(
372
+ prog="skf-rebuild-managed-sections.py orphan-detect",
373
+ description="Detect managed-section rows absent from the exported skill set.",
374
+ )
375
+ parser.add_argument("context_files", nargs="+", help="Context file paths to scan")
376
+ parser.add_argument(
377
+ "--exported-skills",
378
+ default="",
379
+ help="Comma-separated skill names being exported (excluded from orphans)",
380
+ )
381
+ args = parser.parse_args(argv[1:])
382
+ return cmd_orphan_detect(args.context_files, args.exported_skills), 0
383
+ # action == "root-probe"
384
+ parser = argparse.ArgumentParser(
385
+ prog="skf-rebuild-managed-sections.py root-probe",
386
+ description="Observe snippet root prefixes and flag mismatch against a reference.",
387
+ )
388
+ parser.add_argument("snippet_files", nargs="+", help="Snippet file paths to probe")
389
+ parser.add_argument(
390
+ "--reference-root",
391
+ required=True,
392
+ help="Reference skill root prefix to compare observed prefixes against",
393
+ )
394
+ args = parser.parse_args(argv[1:])
395
+ return cmd_root_probe(args.snippet_files, args.reference_root), 0
396
+
397
+
225
398
  def main():
399
+ # Query actions take a positional file list, so they are action-first
400
+ # (`orphan-detect <file>...`) rather than the legacy `<file> <action>` shape.
401
+ if len(sys.argv) >= 2 and sys.argv[1] in ("orphan-detect", "root-probe"):
402
+ result, code = _run_query_action(sys.argv[1:])
403
+ print(json.dumps(result, indent=2))
404
+ sys.exit(code)
405
+
226
406
  if len(sys.argv) < 3:
227
407
  print("Usage: python3 skf-rebuild-managed-sections.py <context-file> <action> [--content <text>]", file=sys.stderr)
228
408
  print("Actions: read, replace, clear, insert, check", file=sys.stderr)
@@ -15,7 +15,7 @@ The five-rule ladder (apply in order, first match wins):
15
15
  entries or `Component[]` annotation when contents available;
16
16
  presence-only when contents not available)
17
17
  2. reference-app — intent text mentions wiring / integration / starter
18
- / lifecycle / build-config keywords, OR analysis flagged as demo/example
18
+ / build-config keywords, OR analysis flagged as demo/example
19
19
  3. specific-modules — intent names a specific subset ("just the X",
20
20
  "only the Y") OR module_count >= 6
21
21
  4. public-api — export_count <= 8 AND intent mentions "the API",
@@ -71,7 +71,6 @@ REFERENCE_APP_KEYWORDS = (
71
71
  "integration example",
72
72
  "integration sample",
73
73
  "starter",
74
- "lifecycle",
75
74
  "build config",
76
75
  "build-config",
77
76
  "demo app",