bmad-module-skill-forge 2.2.0 → 3.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 +135 -18
- package/docs/verifying-a-skill.md +83 -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 +2 -2
- 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 +32 -12
- 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 +30 -14
- package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
- 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 +694 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
- 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 +3 -2
- 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 +1 -1
- 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 +4084 -85
- package/src/shared/scripts/skf-extraction-inventory.py +746 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +539 -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 +444 -203
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +661 -0
- package/src/shared/scripts/skf-hash-content.py +166 -12
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +159 -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 +1 -1
- 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 +161 -27
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
- 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 +128 -13
- 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 +670 -119
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +5 -5
- 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 +4 -1
- 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 +2919 -54
- package/src/shared/scripts/skf-write-skill-brief.py +367 -19
- 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 +27 -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/init.md +148 -210
- package/src/skf-audit-skill/references/re-index.md +96 -108
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +27 -18
- 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 +75 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
- package/src/skf-brief-skill/SKILL.md +36 -25
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +17 -24
- package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +142 -125
- package/src/skf-brief-skill/references/confirm-brief.md +10 -8
- 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 +24 -80
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +3 -2
- 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 +6 -5
- package/src/skf-create-skill/assets/skill-sections.md +15 -5
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
- 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 +107 -29
- 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 +20 -0
- package/src/skf-create-skill/references/extract.md +200 -161
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
- package/src/skf-create-skill/references/extraction-patterns.md +584 -196
- 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 +28 -59
- package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
- 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 +79 -146
- 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 +118 -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 +217 -254
- 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 +163 -88
- 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 +162 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +41 -155
- package/src/skf-test-skill/references/source-access-protocol.md +19 -92
- 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 +287 -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 +1381 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
- package/src/skf-test-skill/scripts/score-signatures.py +459 -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 +127 -52
- 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 +233 -222
- 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 +250 -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 +180 -47
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +100 -35
- package/src/skf-update-skill/references/write.md +331 -149
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
- 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,16 +1,45 @@
|
|
|
1
1
|
# /// script
|
|
2
|
-
# requires-python = ">=3.
|
|
2
|
+
# requires-python = ">=3.11"
|
|
3
3
|
# dependencies = ["pyyaml"]
|
|
4
4
|
# ///
|
|
5
|
-
"""Campaign Report
|
|
5
|
+
"""Campaign Report: generate a markdown report from campaign state + template.
|
|
6
6
|
|
|
7
7
|
CLI:
|
|
8
8
|
uv run campaign-report.py \
|
|
9
|
-
--state-file <path> --template-file <path> --output-file <path>
|
|
9
|
+
--state-file <path> --template-file <path> --output-file <path> \
|
|
10
|
+
[--context-file <path> [--decision-log <path>]]
|
|
10
11
|
|
|
11
12
|
Output (JSON on stdout):
|
|
12
13
|
{"status":"success","report_path":"...","skills_completed":N,"skills_failed":N,
|
|
13
|
-
"quality_scores":{"skill":score,...},"duration":"..."
|
|
14
|
+
"quality_scores":{"skill":score,...},"duration":"...",
|
|
15
|
+
"export_verdicts":{"skill":"pass|fallback|fail",...},"skills_excluded":["skill",...],
|
|
16
|
+
"skills_exported":["skill",...],
|
|
17
|
+
"export_failures":[{"skill","halt_reason","exit_code"},...]}
|
|
18
|
+
|
|
19
|
+
`export_verdicts` holds each completed skill's quality-gate verdict at Export
|
|
20
|
+
and `skills_excluded` the completed skills the gate kept from export, both
|
|
21
|
+
from campaign-quality-gate.py classify (the rule step-10 applies, the state's
|
|
22
|
+
directive included), so a headless caller sees which completed skills were
|
|
23
|
+
not exported. Both are null when the gate cannot be applied (an invalid gate
|
|
24
|
+
or an unreadable directive), and the report says so.
|
|
25
|
+
|
|
26
|
+
`skills_exported` and `export_failures` are what Export did: the `export`
|
|
27
|
+
outcome campaign-state.py recorded for each skill after its skf-export-skill
|
|
28
|
+
call, an exported skill by name and a failed one with that call's
|
|
29
|
+
halt_reason and exit code. Both are null when the Export stage did not run
|
|
30
|
+
(`campaign.current_stage` below 9). The report's Export Gate table shows the
|
|
31
|
+
same outcome per skill in its Export column.
|
|
32
|
+
|
|
33
|
+
--context-file also writes the payload skf-emit-result-envelope.py turns into
|
|
34
|
+
the campaign's SKF_CAMPAIGN_RESULT_JSON line (schemas/
|
|
35
|
+
skf-campaign-result-envelope.v1.json): the result above, with the report as
|
|
36
|
+
`campaign_report_path` and --decision-log as `decision_log`. When the report
|
|
37
|
+
cannot be written it still writes one, the degraded finish: `status` error,
|
|
38
|
+
`halt_reason` report-failure, no report path, and the counts and scores the
|
|
39
|
+
state gives (none when it cannot be read). So step 11 stages nothing by hand
|
|
40
|
+
on either path. It first removes the payload an earlier run left, so a
|
|
41
|
+
payload that cannot be written leaves no file and step 11 takes its fallback
|
|
42
|
+
instead of an earlier run's envelope.
|
|
14
43
|
|
|
15
44
|
Exit codes:
|
|
16
45
|
0 success
|
|
@@ -20,6 +49,8 @@ Exit codes:
|
|
|
20
49
|
from __future__ import annotations
|
|
21
50
|
|
|
22
51
|
import argparse
|
|
52
|
+
import contextlib
|
|
53
|
+
import importlib.util
|
|
23
54
|
import json
|
|
24
55
|
import os
|
|
25
56
|
import sys
|
|
@@ -29,6 +60,8 @@ from typing import Any, Dict, List, Optional
|
|
|
29
60
|
|
|
30
61
|
import yaml
|
|
31
62
|
|
|
63
|
+
GATE_SCRIPT = Path(__file__).resolve().with_name("campaign-quality-gate.py")
|
|
64
|
+
|
|
32
65
|
|
|
33
66
|
def _emit_error(message: str, code: str) -> None:
|
|
34
67
|
json.dump({"error": message, "code": code}, sys.stderr)
|
|
@@ -65,7 +98,81 @@ def _format_duration(start: Optional[datetime], end: Optional[datetime]) -> str:
|
|
|
65
98
|
return f"{seconds}s"
|
|
66
99
|
|
|
67
100
|
|
|
68
|
-
def
|
|
101
|
+
def _export_classification(state: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
102
|
+
"""campaign-quality-gate.py classify for the state, or None when the gate cannot be applied."""
|
|
103
|
+
spec = importlib.util.spec_from_file_location("campaign_quality_gate", GATE_SCRIPT)
|
|
104
|
+
gate = importlib.util.module_from_spec(spec)
|
|
105
|
+
spec.loader.exec_module(gate)
|
|
106
|
+
campaign = state.get("campaign") or {}
|
|
107
|
+
try:
|
|
108
|
+
return gate.classify(state, gate.read_directive(campaign.get("directive_path")))
|
|
109
|
+
except (gate.GateError, KeyError, TypeError, AttributeError):
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _export_record(skill: Any) -> Optional[Dict[str, Any]]:
|
|
114
|
+
"""The `export` outcome campaign-state.py recorded for a skill, or None."""
|
|
115
|
+
record = skill.get("export") if isinstance(skill, dict) else None
|
|
116
|
+
return record if isinstance(record, dict) and record.get("status") in ("exported", "failed") else None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _export_cell(record: Optional[Dict[str, Any]], verdict: str) -> str:
|
|
120
|
+
if record is None:
|
|
121
|
+
return "not exported" if verdict == "fail" else "N/A"
|
|
122
|
+
if record["status"] == "exported":
|
|
123
|
+
return "exported"
|
|
124
|
+
why = record.get("halt_reason") or (
|
|
125
|
+
f"exit {record['exit_code']}" if record.get("exit_code") is not None else "no exit code")
|
|
126
|
+
return f"failed ({why})"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _export_outcomes(state: Any) -> Dict[str, Any]:
|
|
130
|
+
"""What Export did, from each skill's recorded `export`; both null before stage 9 ran."""
|
|
131
|
+
campaign = state.get("campaign") if isinstance(state, dict) else None
|
|
132
|
+
stage = campaign.get("current_stage") if isinstance(campaign, dict) else None
|
|
133
|
+
if not isinstance(stage, int) or isinstance(stage, bool) or stage < 9:
|
|
134
|
+
return {"skills_exported": None, "export_failures": None}
|
|
135
|
+
skills = state.get("skills")
|
|
136
|
+
exported, failures = [], []
|
|
137
|
+
for skill in skills if isinstance(skills, list) else []:
|
|
138
|
+
record = _export_record(skill)
|
|
139
|
+
if record is None or not skill.get("name"):
|
|
140
|
+
continue
|
|
141
|
+
if record["status"] == "exported":
|
|
142
|
+
exported.append(skill["name"])
|
|
143
|
+
else:
|
|
144
|
+
failures.append({"skill": skill["name"], "halt_reason": record.get("halt_reason"),
|
|
145
|
+
"exit_code": record.get("exit_code")})
|
|
146
|
+
return {"skills_exported": exported, "export_failures": failures}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _export_gate_section(
|
|
150
|
+
classification: Optional[Dict[str, Any]], state: Optional[Dict[str, Any]] = None
|
|
151
|
+
) -> str:
|
|
152
|
+
if classification is None:
|
|
153
|
+
return "The quality gate could not be applied to the completed skills (see the decision log)."
|
|
154
|
+
rows = classification["skills"]
|
|
155
|
+
if not rows:
|
|
156
|
+
return "No completed skills."
|
|
157
|
+
records = {s.get("name"): _export_record(s) for s in (state or {}).get("skills") or [] if isinstance(s, dict)}
|
|
158
|
+
lines = ["| Skill | Quality Score | Gate | Export |", "|-------|---------------|------|--------|"]
|
|
159
|
+
for row in rows:
|
|
160
|
+
score = row["quality_score"] if row["quality_score"] is not None else "N/A"
|
|
161
|
+
export = _export_cell(records.get(row["name"]), row["verdict"])
|
|
162
|
+
lines.append(f"| {row['name']} | {score} | {row['verdict']} | {export} |")
|
|
163
|
+
excluded = classification["excluded"]
|
|
164
|
+
if excluded:
|
|
165
|
+
listed = ", ".join(
|
|
166
|
+
f"{e['name']} ({e['quality_score'] if e['quality_score'] is not None else 'N/A'}: {e['reason']})"
|
|
167
|
+
for e in excluded
|
|
168
|
+
)
|
|
169
|
+
lines += ["", f"**Not exported (below the quality gate):** {listed}"]
|
|
170
|
+
return "\n".join(lines)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _compute_aggregates(
|
|
174
|
+
state: Dict[str, Any], classification: Optional[Dict[str, Any]] = None
|
|
175
|
+
) -> Dict[str, Any]:
|
|
69
176
|
campaign = state.get("campaign", {})
|
|
70
177
|
skills: List[Dict[str, Any]] = state.get("skills", [])
|
|
71
178
|
|
|
@@ -141,6 +248,8 @@ def _compute_aggregates(state: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
141
248
|
failed_skipped_lines.append("No skills in campaign.")
|
|
142
249
|
|
|
143
250
|
quality_gate = campaign.get("quality_gate", {})
|
|
251
|
+
if classification is None:
|
|
252
|
+
classification = _export_classification(state)
|
|
144
253
|
|
|
145
254
|
return {
|
|
146
255
|
"campaign_name": campaign.get("name", ""),
|
|
@@ -163,72 +272,125 @@ def _compute_aggregates(state: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
163
272
|
"workarounds_list": "\n".join(workarounds_list_items),
|
|
164
273
|
"duration_table": "\n".join(duration_table_rows),
|
|
165
274
|
"failed_skipped_section": "\n".join(failed_skipped_lines),
|
|
275
|
+
"export_gate_section": _export_gate_section(classification, state),
|
|
166
276
|
}
|
|
167
277
|
|
|
168
278
|
|
|
169
|
-
def
|
|
279
|
+
def _counts(state: Any) -> Dict[str, Any]:
|
|
280
|
+
"""The completed and failed counts and the completed skills' scores."""
|
|
281
|
+
skills = state.get("skills", []) if isinstance(state, dict) else []
|
|
282
|
+
skills = [s for s in skills if isinstance(s, dict)] if isinstance(skills, list) else []
|
|
283
|
+
return {
|
|
284
|
+
"skills_completed": sum(1 for s in skills if s.get("status") == "completed"),
|
|
285
|
+
"skills_failed": sum(1 for s in skills if s.get("status") == "failed"),
|
|
286
|
+
"quality_scores": {
|
|
287
|
+
s["name"]: s["quality_score"]
|
|
288
|
+
for s in skills
|
|
289
|
+
if s.get("status") == "completed" and s.get("quality_score") is not None and s.get("name")
|
|
290
|
+
},
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _write_context(path: Optional[str], payload: Dict[str, Any]) -> None:
|
|
295
|
+
"""Write the emitter payload; a failed write leaves step 11 its fallback."""
|
|
296
|
+
if not path:
|
|
297
|
+
return
|
|
298
|
+
try:
|
|
299
|
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
300
|
+
Path(path).write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
|
|
301
|
+
except OSError as exc:
|
|
302
|
+
_emit_error(f"Failed to write the envelope context: {exc}", "CONTEXT_WRITE_ERROR")
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def run(
|
|
306
|
+
state_file: str,
|
|
307
|
+
template_file: str,
|
|
308
|
+
output_file: str,
|
|
309
|
+
context_file: Optional[str] = None,
|
|
310
|
+
decision_log: Optional[str] = None,
|
|
311
|
+
) -> int:
|
|
170
312
|
state_path = Path(state_file)
|
|
171
313
|
template_path = Path(template_file)
|
|
172
314
|
output_path = Path(output_file)
|
|
173
|
-
|
|
174
|
-
if
|
|
175
|
-
|
|
315
|
+
state: Any = None
|
|
316
|
+
if context_file:
|
|
317
|
+
with contextlib.suppress(OSError):
|
|
318
|
+
Path(context_file).unlink(missing_ok=True)
|
|
319
|
+
|
|
320
|
+
def fail(message: str, code: str) -> int:
|
|
321
|
+
_emit_error(message, code)
|
|
322
|
+
_write_context(context_file, {
|
|
323
|
+
"status": "error",
|
|
324
|
+
"halt_reason": "report-failure",
|
|
325
|
+
**_counts(state),
|
|
326
|
+
**_export_outcomes(state),
|
|
327
|
+
"campaign_report_path": None,
|
|
328
|
+
"decision_log": decision_log,
|
|
329
|
+
})
|
|
176
330
|
return 2
|
|
177
331
|
|
|
178
|
-
if not
|
|
179
|
-
|
|
180
|
-
return 2
|
|
332
|
+
if not state_path.is_file():
|
|
333
|
+
return fail(f"State file not found: {state_file}", "STATE_NOT_FOUND")
|
|
181
334
|
|
|
182
335
|
try:
|
|
183
336
|
state = _load_yaml(state_path)
|
|
184
337
|
except Exception as exc:
|
|
185
|
-
|
|
186
|
-
return 2
|
|
338
|
+
return fail(f"Failed to parse state file: {exc}", "STATE_PARSE_ERROR")
|
|
187
339
|
|
|
188
340
|
if not isinstance(state, dict):
|
|
189
|
-
|
|
190
|
-
|
|
341
|
+
return fail("State file root is not a mapping", "INVALID_STATE")
|
|
342
|
+
|
|
343
|
+
# Read after the state, so a degraded payload still carries its counts.
|
|
344
|
+
if not template_path.is_file():
|
|
345
|
+
return fail(f"Template file not found: {template_file}", "TEMPLATE_NOT_FOUND")
|
|
191
346
|
|
|
192
347
|
try:
|
|
193
348
|
template = template_path.read_text(encoding="utf-8")
|
|
194
349
|
except Exception as exc:
|
|
195
|
-
|
|
196
|
-
return 2
|
|
350
|
+
return fail(f"Failed to read template file: {exc}", "TEMPLATE_READ_ERROR")
|
|
197
351
|
|
|
198
352
|
try:
|
|
199
|
-
|
|
353
|
+
classification = _export_classification(state)
|
|
354
|
+
aggregates = _compute_aggregates(state, classification)
|
|
200
355
|
except Exception as exc:
|
|
201
|
-
|
|
202
|
-
return 2
|
|
356
|
+
return fail(f"Failed to compute report aggregates: {exc}", "AGGREGATE_ERROR")
|
|
203
357
|
|
|
204
358
|
report = template
|
|
205
359
|
for key, value in aggregates.items():
|
|
206
360
|
report = report.replace("{{" + key + "}}", value)
|
|
207
361
|
|
|
208
|
-
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
209
362
|
try:
|
|
363
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
210
364
|
output_path.write_text(report, encoding="utf-8")
|
|
211
365
|
except Exception as exc:
|
|
212
|
-
|
|
213
|
-
return 2
|
|
214
|
-
|
|
215
|
-
skills = state.get("skills", [])
|
|
216
|
-
completed_count = sum(1 for s in skills if s.get("status") == "completed")
|
|
217
|
-
failed_count = sum(1 for s in skills if s.get("status") == "failed")
|
|
218
|
-
quality_scores = {
|
|
219
|
-
s["name"]: s["quality_score"]
|
|
220
|
-
for s in skills
|
|
221
|
-
if s.get("status") == "completed" and s.get("quality_score") is not None
|
|
222
|
-
}
|
|
366
|
+
return fail(f"Failed to write report: {exc}", "WRITE_ERROR")
|
|
223
367
|
|
|
224
368
|
result = {
|
|
225
369
|
"status": "success",
|
|
226
370
|
"report_path": output_path.as_posix(),
|
|
227
|
-
|
|
228
|
-
"skills_failed": failed_count,
|
|
229
|
-
"quality_scores": quality_scores,
|
|
371
|
+
**_counts(state),
|
|
230
372
|
"duration": aggregates["duration"],
|
|
373
|
+
"export_verdicts": (
|
|
374
|
+
None if classification is None else {r["name"]: r["verdict"] for r in classification["skills"]}
|
|
375
|
+
),
|
|
376
|
+
"skills_excluded": (
|
|
377
|
+
None if classification is None else [e["name"] for e in classification["excluded"]]
|
|
378
|
+
),
|
|
379
|
+
**_export_outcomes(state),
|
|
231
380
|
}
|
|
381
|
+
_write_context(context_file, {
|
|
382
|
+
"status": "success",
|
|
383
|
+
"skills_completed": result["skills_completed"],
|
|
384
|
+
"skills_failed": result["skills_failed"],
|
|
385
|
+
"quality_scores": result["quality_scores"],
|
|
386
|
+
"export_verdicts": result["export_verdicts"],
|
|
387
|
+
"skills_excluded": result["skills_excluded"],
|
|
388
|
+
"skills_exported": result["skills_exported"],
|
|
389
|
+
"export_failures": result["export_failures"],
|
|
390
|
+
"campaign_report_path": result["report_path"],
|
|
391
|
+
"decision_log": decision_log,
|
|
392
|
+
"duration": result["duration"],
|
|
393
|
+
})
|
|
232
394
|
json.dump(result, sys.stdout, separators=(",", ":"))
|
|
233
395
|
sys.stdout.write("\n")
|
|
234
396
|
return 0
|
|
@@ -241,8 +403,13 @@ def main() -> int:
|
|
|
241
403
|
parser.add_argument("--state-file", required=True, help="Path to _campaign-state.yaml")
|
|
242
404
|
parser.add_argument("--template-file", required=True, help="Path to campaign-report-template.md")
|
|
243
405
|
parser.add_argument("--output-file", required=True, help="Path to write the generated report")
|
|
406
|
+
parser.add_argument(
|
|
407
|
+
"--context-file",
|
|
408
|
+
help="Also write the SKF_CAMPAIGN_RESULT_JSON payload for skf-emit-result-envelope.py here",
|
|
409
|
+
)
|
|
410
|
+
parser.add_argument("--decision-log", help="Path to _campaign-decision-log.md, for the payload")
|
|
244
411
|
args = parser.parse_args()
|
|
245
|
-
return run(args.state_file, args.template_file, args.output_file)
|
|
412
|
+
return run(args.state_file, args.template_file, args.output_file, args.context_file, args.decision_log)
|
|
246
413
|
|
|
247
414
|
|
|
248
415
|
if __name__ == "__main__":
|