bmad-module-skill-forge 2.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +49 -49
- package/docs/404.md +10 -8
- package/docs/_data/pinned.yaml +22 -13
- package/docs/_internal/STABILITY.md +58 -35
- package/docs/agents.md +39 -53
- package/docs/architecture.md +65 -51
- package/docs/bmad-synergy.md +53 -51
- package/docs/campaign.md +127 -75
- package/docs/concepts.md +34 -28
- package/docs/examples.md +70 -68
- package/docs/forge-auto.md +34 -31
- package/docs/getting-started.md +118 -57
- package/docs/how-it-works.md +25 -21
- package/docs/index.md +15 -15
- package/docs/skill-model.md +70 -59
- package/docs/troubleshooting.md +143 -18
- package/docs/verifying-a-skill.md +87 -57
- package/docs/why-skf.md +24 -22
- package/docs/workflows.md +274 -110
- package/package.json +18 -10
- package/src/forger/preferences.yaml +8 -1
- package/src/knowledge/agentskills-spec.md +2 -0
- package/src/knowledge/ccc-bridge.md +40 -24
- package/src/knowledge/confidence-tiers.md +9 -5
- package/src/knowledge/overview.md +3 -3
- package/src/knowledge/progressive-capability.md +8 -8
- package/src/knowledge/provenance-tracking.md +9 -5
- package/src/knowledge/qmd-registry.md +3 -3
- package/src/knowledge/skf-knowledge-index.csv +2 -2
- package/src/knowledge/skill-lifecycle.md +18 -11
- package/src/knowledge/split-body-strategy.md +0 -3
- package/src/knowledge/tool-resolution.md +4 -2
- package/src/knowledge/version-paths.md +101 -15
- package/src/module-help.csv +3 -3
- package/src/module.yaml +10 -0
- package/src/shared/data/ast-grep-recipes.yaml +608 -0
- package/src/shared/data/ide-context-files.json +30 -0
- package/src/shared/health-check.md +31 -59
- package/src/shared/references/description-guard-protocol.md +12 -9
- package/src/shared/references/feasibility-report-schema.md +19 -13
- package/src/shared/references/headless-gate-convention.md +55 -3
- package/src/shared/references/output-contract-schema.md +19 -8
- package/src/shared/references/pipeline-contracts.md +94 -29
- package/src/shared/references/tessl-review.md +77 -0
- package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
- package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
- package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
- package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
- package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
- package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
- package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
- package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
- package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
- package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
- package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
- package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
- package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
- package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
- package/src/shared/scripts/skf-atomic-write.py +233 -64
- package/src/shared/scripts/skf-build-change-manifest.py +2753 -28
- package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
- package/src/shared/scripts/skf-check-unit-records.py +184 -0
- package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
- package/src/shared/scripts/skf-classify-changed-files.py +772 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +267 -105
- package/src/shared/scripts/skf-count-imports.py +1867 -0
- package/src/shared/scripts/skf-count-tokens.py +1 -1
- package/src/shared/scripts/skf-derive-assembly-shape.py +21 -3
- package/src/shared/scripts/skf-description-guard.py +99 -11
- package/src/shared/scripts/skf-detect-docs.py +694 -2
- package/src/shared/scripts/skf-detect-language.py +486 -107
- package/src/shared/scripts/skf-detect-registry.py +887 -0
- package/src/shared/scripts/skf-detect-scripts-assets.py +197 -55
- package/src/shared/scripts/skf-detect-tools.py +209 -27
- package/src/shared/scripts/skf-detect-workspaces.py +506 -30
- package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
- package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
- package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
- package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
- package/src/shared/scripts/skf-extract-public-api.py +5247 -96
- package/src/shared/scripts/skf-extraction-inventory.py +1280 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +664 -0
- package/src/shared/scripts/skf-fetch-temporal.py +674 -0
- package/src/shared/scripts/skf-find-cycles.py +97 -29
- package/src/shared/scripts/skf-find-test-report.py +476 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +469 -205
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +700 -0
- package/src/shared/scripts/skf-hash-content.py +180 -20
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +161 -27
- package/src/shared/scripts/skf-manifest-ops.py +1 -1
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
- package/src/shared/scripts/skf-merge-doc-urls.py +143 -20
- package/src/shared/scripts/skf-names-present.py +221 -0
- package/src/shared/scripts/skf-pair-intersect.py +119 -28
- package/src/shared/scripts/skf-parse-gaps.py +1384 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-preflight.py +176 -28
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +64 -8
- package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
- package/src/shared/scripts/skf-quick-batch.py +774 -0
- package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
- package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
- package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
- package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
- package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
- package/src/shared/scripts/skf-resolve-authoritative-files.py +155 -14
- package/src/shared/scripts/skf-resolve-package.py +523 -106
- package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
- package/src/shared/scripts/skf-run-lock.py +577 -0
- package/src/shared/scripts/skf-scan-manifests.py +998 -57
- package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
- package/src/shared/scripts/skf-severity-classify.py +712 -108
- package/src/shared/scripts/skf-shape-detect.py +298 -204
- package/src/shared/scripts/skf-shard-body.py +9 -8
- package/src/shared/scripts/skf-skill-inventory.py +2412 -89
- package/src/shared/scripts/skf-skills-module.py +472 -0
- package/src/shared/scripts/skf-source-tree.py +1796 -0
- package/src/shared/scripts/skf-structural-diff.py +787 -121
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +120 -67
- package/src/shared/scripts/skf-update-run-state.py +624 -0
- package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
- package/src/shared/scripts/skf-validate-brief-schema.py +23 -2
- package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
- package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
- package/src/shared/scripts/skf-validate-output.py +712 -64
- package/src/shared/scripts/skf-validate-pins.py +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +116 -10
- package/src/shared/scripts/skf-verify-provenance-completeness.py +3945 -152
- package/src/shared/scripts/skf-write-skill-brief.py +406 -25
- package/src/shared/tool-requirements.yaml +201 -0
- package/src/skf-analyze-source/SKILL.md +41 -36
- package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
- package/src/skf-analyze-source/customize.toml +36 -24
- package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
- package/src/skf-analyze-source/references/continue.md +2 -13
- package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
- package/src/skf-analyze-source/references/generate-briefs.md +121 -55
- package/src/skf-analyze-source/references/headless-contract.md +42 -15
- package/src/skf-analyze-source/references/identify-units.md +96 -110
- package/src/skf-analyze-source/references/init.md +73 -71
- package/src/skf-analyze-source/references/map-and-detect.md +123 -105
- package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
- package/src/skf-analyze-source/references/recommend.md +51 -70
- package/src/skf-analyze-source/references/scan-project.md +60 -84
- package/src/skf-analyze-source/references/scan-root.md +39 -0
- package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
- package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
- package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
- package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
- package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
- package/src/skf-audit-skill/SKILL.md +43 -51
- package/src/skf-audit-skill/assets/drift-report-template.md +28 -3
- package/src/skf-audit-skill/customize.toml +41 -20
- package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
- package/src/skf-audit-skill/references/doc-drift.md +141 -0
- package/src/skf-audit-skill/references/headless-contract.md +29 -0
- package/src/skf-audit-skill/references/health-check.md +2 -0
- package/src/skf-audit-skill/references/init.md +149 -210
- package/src/skf-audit-skill/references/re-index.md +103 -110
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +34 -25
- package/src/skf-audit-skill/references/severity-classify.md +79 -65
- package/src/skf-audit-skill/references/severity-rules.md +15 -6
- package/src/skf-audit-skill/references/structural-diff.md +80 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +712 -0
- package/src/skf-brief-skill/SKILL.md +37 -26
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +18 -25
- package/src/skf-brief-skill/assets/skill-brief-schema.md +30 -23
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +144 -127
- package/src/skf-brief-skill/references/confirm-brief.md +11 -9
- package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
- package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
- package/src/skf-brief-skill/references/gather-intent.md +87 -182
- package/src/skf-brief-skill/references/headless-args.md +84 -16
- package/src/skf-brief-skill/references/health-check.md +1 -1
- package/src/skf-brief-skill/references/invocation-contract.md +18 -13
- package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
- package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
- package/src/skf-brief-skill/references/scope-definition.md +123 -47
- package/src/skf-brief-skill/references/step-auto-brief.md +26 -100
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +7 -10
- package/src/skf-brief-skill/references/write-brief.md +66 -57
- package/src/skf-campaign/SKILL.md +31 -34
- package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
- package/src/skf-campaign/customize.toml +47 -16
- package/src/skf-campaign/references/campaign-contracts.md +39 -29
- package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
- package/src/skf-campaign/references/health-check.md +7 -16
- package/src/skf-campaign/references/step-01-setup.md +46 -84
- package/src/skf-campaign/references/step-02-strategy.md +31 -30
- package/src/skf-campaign/references/step-03-pins.md +26 -18
- package/src/skf-campaign/references/step-04-provenance.md +24 -23
- package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
- package/src/skf-campaign/references/step-06-batch.md +41 -34
- package/src/skf-campaign/references/step-07-capstone.md +40 -25
- package/src/skf-campaign/references/step-08-verify.md +28 -29
- package/src/skf-campaign/references/step-09-refine.md +29 -30
- package/src/skf-campaign/references/step-10-export.md +48 -36
- package/src/skf-campaign/references/step-11-maintenance.md +31 -34
- package/src/skf-campaign/references/step-resume.md +37 -68
- package/src/skf-campaign/scripts/campaign-deps.py +57 -18
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
- package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
- package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
- package/src/skf-campaign/scripts/campaign-report.py +204 -37
- package/src/skf-campaign/scripts/campaign-state.py +1128 -0
- package/src/skf-campaign/scripts/campaign-status.py +10 -74
- package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
- package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
- package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
- package/src/skf-campaign/templates/campaign-report-template.md +5 -1
- package/src/skf-campaign/templates/kickoff-template.md +0 -14
- package/src/skf-create-skill/SKILL.md +27 -20
- package/src/skf-create-skill/assets/compile-assembly-rules.md +11 -8
- package/src/skf-create-skill/assets/skill-sections.md +21 -11
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +36 -58
- package/src/skf-create-skill/references/batch-mode.md +81 -0
- package/src/skf-create-skill/references/ccc-index-check.md +27 -0
- package/src/skf-create-skill/references/compile.md +119 -70
- package/src/skf-create-skill/references/component-extraction.md +113 -91
- package/src/skf-create-skill/references/enrich.md +41 -23
- package/src/skf-create-skill/references/entry-points-by-hand.md +37 -0
- package/src/skf-create-skill/references/extract.md +204 -162
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +11 -11
- package/src/skf-create-skill/references/extraction-patterns.md +588 -201
- package/src/skf-create-skill/references/generate-artifacts.md +145 -93
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +53 -36
- package/src/skf-create-skill/references/relabel-rule.md +12 -0
- package/src/skf-create-skill/references/report.md +37 -57
- package/src/skf-create-skill/references/source-resolution-protocols.md +58 -169
- package/src/skf-create-skill/references/step-auto-shard.md +20 -93
- package/src/skf-create-skill/references/step-doc-rot.md +44 -60
- package/src/skf-create-skill/references/step-doc-sources.md +28 -19
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
- package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
- package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
- package/src/skf-create-skill/references/validate.md +173 -99
- package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
- package/src/skf-create-stack-skill/SKILL.md +29 -56
- package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
- package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
- package/src/skf-create-stack-skill/customize.toml +23 -12
- package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
- package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
- package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
- package/src/skf-create-stack-skill/references/generate-output.md +138 -128
- package/src/skf-create-stack-skill/references/init.md +90 -32
- package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
- package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
- package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
- package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
- package/src/skf-create-stack-skill/references/report.md +39 -33
- package/src/skf-create-stack-skill/references/validate.md +20 -39
- package/src/skf-drop-skill/SKILL.md +28 -51
- package/src/skf-drop-skill/customize.toml +44 -30
- package/src/skf-drop-skill/references/execute.md +83 -146
- package/src/skf-drop-skill/references/health-check.md +2 -0
- package/src/skf-drop-skill/references/invocation-contract.md +64 -0
- package/src/skf-drop-skill/references/report.md +46 -30
- package/src/skf-drop-skill/references/select.md +122 -124
- package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
- package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
- package/src/skf-export-skill/SKILL.md +40 -62
- package/src/skf-export-skill/assets/managed-section-format.md +14 -50
- package/src/skf-export-skill/assets/snippet-format.md +3 -1
- package/src/skf-export-skill/customize.toml +42 -13
- package/src/skf-export-skill/references/generate-snippet.md +54 -46
- package/src/skf-export-skill/references/health-check.md +2 -0
- package/src/skf-export-skill/references/invocation-contract.md +15 -0
- package/src/skf-export-skill/references/load-skill.md +88 -62
- package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
- package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
- package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
- package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
- package/src/skf-export-skill/references/package.md +15 -73
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
- package/src/skf-export-skill/references/result-envelope.md +31 -16
- package/src/skf-export-skill/references/summary.md +41 -17
- package/src/skf-export-skill/references/token-report.md +4 -12
- package/src/skf-export-skill/references/update-context.md +118 -237
- package/src/skf-forger/SKILL.md +61 -37
- package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
- package/src/skf-forger/customize.toml +43 -0
- package/src/skf-forger/references/pipeline-mode.md +73 -18
- package/src/skf-forger/scripts/forge-status.py +299 -0
- package/src/skf-forger/scripts/parse-pipeline.py +322 -54
- package/src/skf-forger/scripts/pipeline-gate.py +428 -0
- package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
- package/src/skf-quick-skill/SKILL.md +54 -53
- package/src/skf-quick-skill/assets/skill-template.md +4 -2
- package/src/skf-quick-skill/customize.toml +51 -20
- package/src/skf-quick-skill/references/batch-mode.md +74 -21
- package/src/skf-quick-skill/references/compile.md +30 -31
- package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
- package/src/skf-quick-skill/references/finalize.md +69 -18
- package/src/skf-quick-skill/references/halt-contract.md +41 -29
- package/src/skf-quick-skill/references/health-check.md +5 -3
- package/src/skf-quick-skill/references/quick-extract.md +114 -45
- package/src/skf-quick-skill/references/registry-resolution.md +9 -64
- package/src/skf-quick-skill/references/resolve-target.md +116 -66
- package/src/skf-quick-skill/references/write-and-validate.md +79 -40
- package/src/skf-refine-architecture/SKILL.md +43 -53
- package/src/skf-refine-architecture/customize.toml +49 -20
- package/src/skf-refine-architecture/references/compile.md +97 -54
- package/src/skf-refine-architecture/references/exit-codes.md +30 -0
- package/src/skf-refine-architecture/references/finding-storage.md +21 -0
- package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
- package/src/skf-refine-architecture/references/improvements.md +14 -20
- package/src/skf-refine-architecture/references/init.md +98 -57
- package/src/skf-refine-architecture/references/issue-detection.md +32 -39
- package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
- package/src/skf-refine-architecture/references/report.md +65 -54
- package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
- package/src/skf-rename-skill/SKILL.md +19 -54
- package/src/skf-rename-skill/customize.toml +32 -26
- package/src/skf-rename-skill/references/execute.md +230 -184
- package/src/skf-rename-skill/references/exit-codes.md +7 -7
- package/src/skf-rename-skill/references/health-check.md +1 -7
- package/src/skf-rename-skill/references/invocation-contract.md +25 -0
- package/src/skf-rename-skill/references/report.md +63 -52
- package/src/skf-rename-skill/references/select.md +197 -115
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
- package/src/skf-setup/SKILL.md +26 -26
- package/src/skf-setup/customize.toml +14 -10
- package/src/skf-setup/references/auto-index.md +50 -63
- package/src/skf-setup/references/ccc-index.md +29 -90
- package/src/skf-setup/references/detect-and-tier.md +58 -67
- package/src/skf-setup/references/health-check.md +2 -0
- package/src/skf-setup/references/invocation-contract.md +14 -0
- package/src/skf-setup/references/report.md +43 -166
- package/src/skf-setup/references/tier-rules.md +5 -5
- package/src/skf-setup/references/write-config.md +34 -57
- package/src/skf-test-skill/SKILL.md +17 -57
- package/src/skf-test-skill/assets/output-section-formats.md +33 -34
- package/src/skf-test-skill/customize.toml +27 -13
- package/src/skf-test-skill/references/coherence-check.md +134 -62
- package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
- package/src/skf-test-skill/references/coverage-check.md +209 -264
- package/src/skf-test-skill/references/detect-mode.md +5 -5
- package/src/skf-test-skill/references/external-validators.md +94 -82
- package/src/skf-test-skill/references/health-check.md +6 -7
- package/src/skf-test-skill/references/init.md +164 -91
- package/src/skf-test-skill/references/invocation-contract.md +66 -0
- package/src/skf-test-skill/references/migration-section-rules.md +5 -2
- package/src/skf-test-skill/references/report.md +164 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +42 -155
- package/src/skf-test-skill/references/source-access-protocol.md +18 -94
- package/src/skf-test-skill/references/step-hard-gate.md +51 -33
- package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
- package/src/skf-test-skill/scripts/build-result-context.py +380 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
- package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
- package/src/skf-test-skill/scripts/compute-score.py +223 -45
- package/src/skf-test-skill/scripts/gap-ledger.py +1666 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +1198 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +547 -79
- package/src/skf-test-skill/scripts/score-signatures.py +479 -0
- package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +133 -56
- package/src/skf-test-skill/templates/test-report-template.md +21 -15
- package/src/skf-update-skill/SKILL.md +38 -25
- package/src/skf-update-skill/customize.toml +27 -12
- package/src/skf-update-skill/references/detect-changes.md +253 -223
- package/src/skf-update-skill/references/gap-driven.md +336 -0
- package/src/skf-update-skill/references/health-check.md +31 -5
- package/src/skf-update-skill/references/init.md +254 -84
- package/src/skf-update-skill/references/invocation-contract.md +12 -0
- package/src/skf-update-skill/references/manual-section-rules.md +6 -23
- package/src/skf-update-skill/references/merge.md +182 -49
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +102 -35
- package/src/skf-update-skill/references/write.md +357 -155
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +183 -46
- package/src/skf-verify-stack/SKILL.md +23 -42
- package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
- package/src/skf-verify-stack/customize.toml +55 -22
- package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
- package/src/skf-verify-stack/references/coverage.md +67 -64
- package/src/skf-verify-stack/references/exit-codes.md +21 -8
- package/src/skf-verify-stack/references/init.md +107 -62
- package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
- package/src/skf-verify-stack/references/integrations.md +106 -65
- package/src/skf-verify-stack/references/report.md +59 -42
- package/src/skf-verify-stack/references/requirements.md +32 -9
- package/src/skf-verify-stack/references/synthesize.md +53 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
- package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
- package/tools/cli/commands/install.js +11 -4
- package/tools/cli/commands/status.js +15 -3
- package/tools/cli/commands/update.js +11 -4
- package/tools/cli/lib/tool-check.js +320 -0
- package/tools/cli/lib/version-check.js +22 -9
- package/tools/cli/skf-cli.js +4 -1
- package/.gitattributes +0 -16
- package/.nvmrc +0 -1
- package/docs/_internal/RELEASING.md +0 -679
- package/release-audits/v1.0.0-launch-audit.md +0 -728
- package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
- package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
- package/src/skf-campaign/manifest.yaml +0 -15
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
- package/src/skf-create-skill/references/ecosystem-check.md +0 -74
- package/src/skf-drop-skill/references/headless-contract.md +0 -18
- package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
- package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
- package/src/skf-update-skill/references/validate.md +0 -124
- package/tools/validate-docs-drift.js +0 -233
- package/tools/validate-docs-links.js +0 -665
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# /// script
|
|
2
|
-
# requires-python = ">=3.
|
|
3
|
-
# dependencies = []
|
|
2
|
+
# requires-python = ">=3.11"
|
|
3
|
+
# dependencies = ["pyyaml"]
|
|
4
4
|
# ///
|
|
5
5
|
"""SKF Detect Scripts & Assets — file-level artifact detection for skill compilation.
|
|
6
6
|
|
|
@@ -22,11 +22,32 @@ CLI:
|
|
|
22
22
|
uv run skf-detect-scripts-assets.py detect <source-root> \\
|
|
23
23
|
[--scripts-intent detect|none] \\
|
|
24
24
|
[--assets-intent detect|none] \\
|
|
25
|
-
[--
|
|
25
|
+
[--brief <skill-brief.yaml>] \\
|
|
26
26
|
[--max-lines 500]
|
|
27
27
|
|
|
28
|
+
--brief keeps a file only when the skill brief's scope takes it, by the
|
|
29
|
+
one brief-scope test of skf-classify-changed-files.py (load_scope, loaded
|
|
30
|
+
from this folder only when --brief is given), which update-skill's
|
|
31
|
+
Category A and Category D and audit-skill's Script/Asset Drift use too:
|
|
32
|
+
the glob rules of skf-resolve-authoritative-files.py (`**` spans any
|
|
33
|
+
number of folders, `*` and `?` never cross a `/`), each `scope.include`
|
|
34
|
+
and `scope.exclude` pattern normalized (forward slashes, no leading `./`),
|
|
35
|
+
and a path in scope when an include matches it and no exclude does. With
|
|
36
|
+
an empty `scope.include`, a path is in scope when no exclude matches it
|
|
37
|
+
and its extension is one the brief's `language` uses. The test runs before
|
|
38
|
+
the script and asset rules. The brief's intents are not read here:
|
|
39
|
+
--scripts-intent and --assets-intent set them. A --brief that names no
|
|
40
|
+
file, one that cannot be read and an empty one (an unbound brief path)
|
|
41
|
+
exit 1, never an unscoped run. Without --brief every file is in scope.
|
|
42
|
+
|
|
28
43
|
Detection rules — scripts:
|
|
29
|
-
Directory convention: scripts/, bin/, tools/, cli/
|
|
44
|
+
Directory convention: scripts/, bin/, tools/, cli/ (at any depth). A
|
|
45
|
+
Python package's folder is code, not a script folder: a `.py` file
|
|
46
|
+
under such a folder that holds `__init__.py` is a script only with a
|
|
47
|
+
shebang, a top-level `if __name__ == "__main__":` block (either
|
|
48
|
+
comparison order, parentheses allowed, never a line inside a string)
|
|
49
|
+
or when it is the package's `__main__.py` (the `python -m` entry).
|
|
50
|
+
is_package_module() is that rule.
|
|
30
51
|
Shebang signals: #!/bin/bash, #!/usr/bin/env python|node|bash|sh, etc.
|
|
31
52
|
Entry point declarations: package.json `bin`, pyproject.toml [project.scripts]
|
|
32
53
|
CLI argument-parser imports are detected for the LLM-judgment tier only —
|
|
@@ -44,6 +65,13 @@ Exclusions:
|
|
|
44
65
|
Generated paths: dist/, build/, .webpack/, node_modules/, __pycache__/,
|
|
45
66
|
target/ (Rust), .next/, .nuxt/, out/, coverage/
|
|
46
67
|
|
|
68
|
+
file_kind() is the per-file rule: a script (is_script) before an asset
|
|
69
|
+
(asset_type), each asked only when its kind is on. detect() calls it with
|
|
70
|
+
its intents; skf-compare-file-hashes.py (audit-skill's Script/Asset Drift)
|
|
71
|
+
loads this file and walks with iter_files, is_binary_path,
|
|
72
|
+
entry_point_script_paths and file_kind, both kinds on, so audit-skill finds
|
|
73
|
+
the same new files update-skill's Category D finds through detect.
|
|
74
|
+
|
|
47
75
|
Size flag:
|
|
48
76
|
Files >max-lines (default 500) get size_flag="oversized" but are still
|
|
49
77
|
included — the caller decides whether to bundle them.
|
|
@@ -63,15 +91,18 @@ Confidence is always "T1-low" — file existence verified, content not
|
|
|
63
91
|
AST-analyzed. Matches the spec at extraction-patterns-tracing.md §Provenance.
|
|
64
92
|
|
|
65
93
|
Exit codes:
|
|
66
|
-
0
|
|
67
|
-
1
|
|
94
|
+
0 detection succeeded (including --scripts-intent=none --assets-intent=none)
|
|
95
|
+
1 user error (bad source root, malformed args, a --brief that names no
|
|
96
|
+
file, cannot be read or is empty, or a scope test that cannot be
|
|
97
|
+
loaded): one `error:` line on stderr
|
|
68
98
|
"""
|
|
69
99
|
|
|
70
100
|
from __future__ import annotations
|
|
71
101
|
|
|
72
102
|
import argparse
|
|
73
|
-
import
|
|
103
|
+
import ast
|
|
74
104
|
import hashlib
|
|
105
|
+
import importlib.util
|
|
75
106
|
import json
|
|
76
107
|
import re
|
|
77
108
|
import sys
|
|
@@ -182,18 +213,6 @@ def in_directory(path: Path, root: Path, dir_names: set[str]) -> bool:
|
|
|
182
213
|
return any(seg in dir_names for seg in relative_segments(path, root))
|
|
183
214
|
|
|
184
215
|
|
|
185
|
-
def matches_scope(path: Path, root: Path, scope_patterns: list[str]) -> bool:
|
|
186
|
-
"""Match `path` against scope-include glob patterns relative to root.
|
|
187
|
-
|
|
188
|
-
Forward-slash form so scope patterns like "scripts/*" match on Windows
|
|
189
|
-
too — fnmatch is byte-exact and won't normalize separators for us.
|
|
190
|
-
"""
|
|
191
|
-
if not scope_patterns:
|
|
192
|
-
return True
|
|
193
|
-
rel = path.relative_to(root).as_posix()
|
|
194
|
-
return any(fnmatch.fnmatch(rel, pattern) for pattern in scope_patterns)
|
|
195
|
-
|
|
196
|
-
|
|
197
216
|
# --------------------------------------------------------------------------
|
|
198
217
|
# Read helpers
|
|
199
218
|
# --------------------------------------------------------------------------
|
|
@@ -294,6 +313,8 @@ def _parse_package_json_bin(source_root: Path) -> Iterable[Path]:
|
|
|
294
313
|
data = json.loads(text)
|
|
295
314
|
except json.JSONDecodeError:
|
|
296
315
|
return ()
|
|
316
|
+
if not isinstance(data, dict): # valid JSON but no object (`[]`, `null`, a number): no `bin`
|
|
317
|
+
return ()
|
|
297
318
|
bin_field = data.get("bin")
|
|
298
319
|
if isinstance(bin_field, str):
|
|
299
320
|
candidates = [bin_field]
|
|
@@ -325,11 +346,72 @@ def _parse_pyproject_scripts(source_root: Path) -> Iterable[Path]:
|
|
|
325
346
|
return ()
|
|
326
347
|
|
|
327
348
|
|
|
349
|
+
# The fallback for a file that does not parse: a column-0 `if` comparing
|
|
350
|
+
# __name__ with "__main__", either way round, parentheses allowed.
|
|
351
|
+
_MAIN_BLOCK_RE = re.compile(
|
|
352
|
+
r"^if\s*\(?\s*(?:__name__\s*==\s*(['\"])__main__\1|(['\"])__main__\2\s*==\s*__name__)\s*\)?\s*:", re.M
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def in_package_script_dir(path: Path, source_root: Path) -> bool:
|
|
357
|
+
"""True when a script folder (SCRIPT_DIRS) over `path` holds
|
|
358
|
+
`__init__.py`: a Python package that happens to be named tools/, cli/,
|
|
359
|
+
bin/ or scripts/, whose modules are code."""
|
|
360
|
+
segments = relative_segments(path, source_root)
|
|
361
|
+
return any(
|
|
362
|
+
seg in SCRIPT_DIRS and source_root.joinpath(*segments[: i + 1], "__init__.py").is_file()
|
|
363
|
+
for i, seg in enumerate(segments)
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def has_shebang(path: Path) -> bool:
|
|
368
|
+
try:
|
|
369
|
+
with path.open("rb") as fh:
|
|
370
|
+
return fh.read(2) == b"#!"
|
|
371
|
+
except OSError:
|
|
372
|
+
return False
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def _is_main_test(test: ast.expr) -> bool:
|
|
376
|
+
"""`__name__ == "__main__"` or `"__main__" == __name__`."""
|
|
377
|
+
if not (isinstance(test, ast.Compare) and len(test.ops) == 1 and isinstance(test.ops[0], ast.Eq)):
|
|
378
|
+
return False
|
|
379
|
+
sides = (test.left, test.comparators[0])
|
|
380
|
+
return (any(isinstance(s, ast.Name) and s.id == "__name__" for s in sides)
|
|
381
|
+
and any(isinstance(s, ast.Constant) and s.value == "__main__" for s in sides))
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def has_main_block(path: Path) -> bool:
|
|
385
|
+
"""True when the file holds a top-level `if __name__ == "__main__":`
|
|
386
|
+
(either order, parenthesized or not). The file is parsed, so such a
|
|
387
|
+
line inside a string never counts; a file that does not parse is
|
|
388
|
+
matched line by line."""
|
|
389
|
+
text = read_text_safe(path)
|
|
390
|
+
if not text:
|
|
391
|
+
return False
|
|
392
|
+
try:
|
|
393
|
+
tree = ast.parse(text)
|
|
394
|
+
except (SyntaxError, ValueError):
|
|
395
|
+
return _MAIN_BLOCK_RE.search(text) is not None
|
|
396
|
+
return any(isinstance(node, ast.If) and _is_main_test(node.test) for node in tree.body)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def is_package_module(path: Path, source_root: Path) -> bool:
|
|
400
|
+
"""True when `path` is a module of a Python package named like a script
|
|
401
|
+
folder (in_package_script_dir): code, not a script, unless it runs on
|
|
402
|
+
its own (a shebang, a top-level `__main__` block, or the package's
|
|
403
|
+
`__main__.py`, which `python -m` runs)."""
|
|
404
|
+
return (path.suffix.lower() == ".py" and in_package_script_dir(path, source_root)
|
|
405
|
+
and path.name != "__main__.py" and not (has_shebang(path) or has_main_block(path)))
|
|
406
|
+
|
|
407
|
+
|
|
328
408
|
def is_script(path: Path, source_root: Path, *, entry_points: set[Path]) -> tuple[bool, str | None]:
|
|
329
409
|
"""Decide whether `path` is a script. Returns (is_script, shebang_lang)."""
|
|
330
410
|
if path.resolve() in entry_points:
|
|
331
411
|
return True, detect_shebang_language(path)
|
|
332
412
|
if in_directory(path, source_root, SCRIPT_DIRS):
|
|
413
|
+
if is_package_module(path, source_root):
|
|
414
|
+
return False, None
|
|
333
415
|
return True, detect_shebang_language(path)
|
|
334
416
|
shebang_lang = detect_shebang_language(path)
|
|
335
417
|
if shebang_lang is not None:
|
|
@@ -379,6 +461,25 @@ def asset_type(path: Path, source_root: Path) -> str | None:
|
|
|
379
461
|
return None
|
|
380
462
|
|
|
381
463
|
|
|
464
|
+
def file_kind(path: Path, source_root: Path, entry_points: set[Path], *,
|
|
465
|
+
scripts: bool = True, assets: bool = True) -> tuple[str, str | None] | None:
|
|
466
|
+
"""What `path` is: ("script", its shebang language or None), ("asset",
|
|
467
|
+
its asset type) or None. A script is never also an asset: is_script is
|
|
468
|
+
asked first, when `scripts` is on, then asset_type, when `assets` is on.
|
|
469
|
+
`entry_points` is entry_point_script_paths(source_root) (an empty set
|
|
470
|
+
when scripts are off). The kind strings are the ones
|
|
471
|
+
skf-classify-changed-files.py's Scope.wants takes."""
|
|
472
|
+
if scripts:
|
|
473
|
+
is_scr, shebang_lang = is_script(path, source_root, entry_points=entry_points)
|
|
474
|
+
if is_scr:
|
|
475
|
+
return "script", shebang_lang
|
|
476
|
+
if assets:
|
|
477
|
+
atype = asset_type(path, source_root)
|
|
478
|
+
if atype is not None:
|
|
479
|
+
return "asset", atype
|
|
480
|
+
return None
|
|
481
|
+
|
|
482
|
+
|
|
382
483
|
# --------------------------------------------------------------------------
|
|
383
484
|
# Purpose extraction
|
|
384
485
|
# --------------------------------------------------------------------------
|
|
@@ -474,10 +575,12 @@ def detect(
|
|
|
474
575
|
*,
|
|
475
576
|
scripts_intent: str = "detect",
|
|
476
577
|
assets_intent: str = "detect",
|
|
477
|
-
|
|
578
|
+
scope=None,
|
|
478
579
|
max_lines: int = 500,
|
|
479
580
|
) -> dict:
|
|
480
|
-
|
|
581
|
+
"""The inventories of `source_root`. `scope` is the brief's Scope
|
|
582
|
+
(skf-classify-changed-files.py load_scope, --brief): a file it does not
|
|
583
|
+
take is neither a script nor an asset. None takes every file."""
|
|
481
584
|
scripts_skipped = scripts_intent == "none"
|
|
482
585
|
assets_skipped = assets_intent == "none"
|
|
483
586
|
|
|
@@ -494,30 +597,27 @@ def detect(
|
|
|
494
597
|
files_scanned += 1
|
|
495
598
|
if is_binary_path(path):
|
|
496
599
|
continue
|
|
497
|
-
if not
|
|
600
|
+
if scope is not None and not scope.takes(path.relative_to(source_root).as_posix()):
|
|
498
601
|
continue
|
|
499
602
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
603
|
+
found = file_kind(path, source_root, entry_points,
|
|
604
|
+
scripts=not scripts_skipped, assets=not assets_skipped)
|
|
605
|
+
if found is None:
|
|
606
|
+
continue
|
|
607
|
+
kind, detail = found
|
|
608
|
+
if kind == "script":
|
|
609
|
+
scripts_inventory.append(
|
|
610
|
+
build_script_record(
|
|
611
|
+
path, source_root,
|
|
612
|
+
shebang_lang=detail, max_lines=max_lines,
|
|
510
613
|
)
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
assets_inventory.append(
|
|
517
|
-
build_asset_record(
|
|
518
|
-
path, source_root, atype=atype, max_lines=max_lines,
|
|
519
|
-
)
|
|
614
|
+
)
|
|
615
|
+
else:
|
|
616
|
+
assets_inventory.append(
|
|
617
|
+
build_asset_record(
|
|
618
|
+
path, source_root, atype=detail, max_lines=max_lines,
|
|
520
619
|
)
|
|
620
|
+
)
|
|
521
621
|
|
|
522
622
|
# Deterministic ordering for stable diffs / cacheability
|
|
523
623
|
scripts_inventory.sort(key=lambda r: r["source_file"])
|
|
@@ -541,28 +641,69 @@ def detect(
|
|
|
541
641
|
# --------------------------------------------------------------------------
|
|
542
642
|
|
|
543
643
|
|
|
644
|
+
_SIBLINGS: dict[str, object] = {}
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
def _sibling(filename: str):
|
|
648
|
+
"""A helper installed beside this script, loaded once as a module:
|
|
649
|
+
skf-classify-changed-files.py, whose load_scope is --brief's scope
|
|
650
|
+
test (it loads skf-resolve-authoritative-files.py beside it). Raises
|
|
651
|
+
whatever loading it raises."""
|
|
652
|
+
module = _SIBLINGS.get(filename)
|
|
653
|
+
if module is None:
|
|
654
|
+
path = Path(__file__).resolve().parent / filename
|
|
655
|
+
name = "skf_" + filename.removeprefix("skf-").removesuffix(".py").replace("-", "_")
|
|
656
|
+
spec = importlib.util.spec_from_file_location(name, path)
|
|
657
|
+
if spec is None or spec.loader is None or not path.is_file():
|
|
658
|
+
raise ImportError(f"{filename} not found beside {Path(__file__).name}")
|
|
659
|
+
module = importlib.util.module_from_spec(spec)
|
|
660
|
+
spec.loader.exec_module(module)
|
|
661
|
+
_SIBLINGS[filename] = module
|
|
662
|
+
return module
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
def _error(message: str) -> int:
|
|
666
|
+
"""`message` as one `error:` line on stderr (a YAML error spans several
|
|
667
|
+
lines: each line break and the space around it becomes one space); exit 1."""
|
|
668
|
+
print("error: " + re.sub(r"\s*[\r\n]\s*", " ", message.strip("\r\n")), file=sys.stderr)
|
|
669
|
+
return 1
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
def load_brief_scope(brief: str):
|
|
673
|
+
"""--brief's Scope. Raises ValueError for an empty value, a brief that
|
|
674
|
+
names no file or cannot be read, and a scope test that cannot be loaded
|
|
675
|
+
(a classifier or resolver missing, out of date or failing)."""
|
|
676
|
+
if not brief.strip():
|
|
677
|
+
raise ValueError("--brief is empty (an unbound brief path?): pass the brief, or leave --brief out")
|
|
678
|
+
try:
|
|
679
|
+
return _sibling("skf-classify-changed-files.py").load_scope(Path(brief))
|
|
680
|
+
except ValueError: # a brief it cannot find or read
|
|
681
|
+
raise
|
|
682
|
+
except Exception as exc: # whatever the scope test raises, the run reports it on one line
|
|
683
|
+
raise ValueError(f"cannot load the brief's scope test beside {Path(__file__).name}: {exc}; "
|
|
684
|
+
"re-install SKF") from exc
|
|
685
|
+
|
|
686
|
+
|
|
544
687
|
def _cmd_detect(args: argparse.Namespace) -> int:
|
|
545
688
|
source_root = Path(args.source_root).resolve()
|
|
546
689
|
if not source_root.is_dir():
|
|
547
|
-
|
|
548
|
-
return 1
|
|
549
|
-
scope_patterns = (
|
|
550
|
-
[s.strip() for s in args.scope_include.split(",") if s.strip()]
|
|
551
|
-
if args.scope_include
|
|
552
|
-
else []
|
|
553
|
-
)
|
|
690
|
+
return _error(f"source root not a directory: {source_root}")
|
|
554
691
|
if args.scripts_intent not in ("detect", "none"):
|
|
555
|
-
|
|
556
|
-
return 1
|
|
692
|
+
return _error("--scripts-intent must be detect|none")
|
|
557
693
|
if args.assets_intent not in ("detect", "none"):
|
|
558
|
-
|
|
559
|
-
|
|
694
|
+
return _error("--assets-intent must be detect|none")
|
|
695
|
+
scope = None
|
|
696
|
+
if args.brief is not None:
|
|
697
|
+
try:
|
|
698
|
+
scope = load_brief_scope(args.brief)
|
|
699
|
+
except ValueError as exc:
|
|
700
|
+
return _error(str(exc))
|
|
560
701
|
|
|
561
702
|
result = detect(
|
|
562
703
|
source_root,
|
|
563
704
|
scripts_intent=args.scripts_intent,
|
|
564
705
|
assets_intent=args.assets_intent,
|
|
565
|
-
|
|
706
|
+
scope=scope,
|
|
566
707
|
max_lines=args.max_lines,
|
|
567
708
|
)
|
|
568
709
|
json.dump(result, sys.stdout, indent=2)
|
|
@@ -589,9 +730,10 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
589
730
|
help="detect|none (default: detect)",
|
|
590
731
|
)
|
|
591
732
|
p.add_argument(
|
|
592
|
-
"--
|
|
733
|
+
"--brief",
|
|
593
734
|
default=None,
|
|
594
|
-
|
|
735
|
+
metavar="BRIEF",
|
|
736
|
+
help="the skill brief (skill-brief.yaml): detect only in the files its scope takes",
|
|
595
737
|
)
|
|
596
738
|
p.add_argument(
|
|
597
739
|
"--max-lines",
|