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,5 +1,5 @@
|
|
|
1
1
|
# /// script
|
|
2
|
-
# requires-python = ">=3.
|
|
2
|
+
# requires-python = ">=3.11"
|
|
3
3
|
# dependencies = ["pyyaml"]
|
|
4
4
|
# ///
|
|
5
5
|
"""SKF Resolve Authoritative Files — §2a deterministic pre-prompt pipeline.
|
|
@@ -27,7 +27,7 @@ drift-prone parts. The helper consolidates them into one `resolve` call.
|
|
|
27
27
|
|
|
28
28
|
Subcommand:
|
|
29
29
|
resolve --source-root <path> --brief <brief.yaml-path>
|
|
30
|
-
[--preview-lines 20]
|
|
30
|
+
[--preview-lines 20] [--provenance-map <provenance-map.json>]
|
|
31
31
|
|
|
32
32
|
Output JSON (stdout):
|
|
33
33
|
|
|
@@ -35,10 +35,14 @@ Output JSON (stdout):
|
|
|
35
35
|
"status": "no-candidates" | "candidates-found",
|
|
36
36
|
"summary": {
|
|
37
37
|
"candidates_total": N,
|
|
38
|
+
"already_tracked_count": N,
|
|
38
39
|
"already_in_scope_count": N,
|
|
39
40
|
"pre_decided_count": N,
|
|
40
41
|
"unresolved_count": N
|
|
41
42
|
},
|
|
43
|
+
"already_tracked": [
|
|
44
|
+
{"path": "...", "heuristic": "llms.txt"}
|
|
45
|
+
],
|
|
42
46
|
"already_in_scope": [
|
|
43
47
|
{"path": "...", "heuristic": "llms.txt", "size_bytes": N,
|
|
44
48
|
"line_count": N, "content_hash": "sha256:..."}
|
|
@@ -53,13 +57,21 @@ Output JSON (stdout):
|
|
|
53
57
|
{"path": "...", "heuristic": "...", "size_bytes": N,
|
|
54
58
|
"line_count": N, "content_hash": "sha256:...",
|
|
55
59
|
"preview": "<first N lines as a string>",
|
|
56
|
-
"excluded_by_pattern": "<glob>" | "not matched by any scope.include"
|
|
60
|
+
"excluded_by_pattern": "<glob>" | "not matched by any scope.include",
|
|
61
|
+
"prior_action": null | "deferred-headless"}
|
|
57
62
|
]
|
|
58
63
|
}
|
|
59
64
|
|
|
60
65
|
Paths are emitted relative to `source-root`, forward-slash form
|
|
61
66
|
(cross-platform JSON convention — same as skf-detect-scripts-assets.py).
|
|
62
67
|
|
|
68
|
+
`already_tracked` semantics (update-skill's mirror of this protocol):
|
|
69
|
+
with `--provenance-map`, a candidate the map already names, in
|
|
70
|
+
`entries[].source_file` or `file_entries[].source_file`, is tracked:
|
|
71
|
+
change detection handles it, so it is listed here, with no hash, and in
|
|
72
|
+
no other bucket. Without `--provenance-map` the list is empty.
|
|
73
|
+
`candidates_total` counts every candidate, tracked ones included.
|
|
74
|
+
|
|
63
75
|
`pre_decided` semantics:
|
|
64
76
|
- `prior_action="promoted"` AND `should_add_to_promoted_docs=true` →
|
|
65
77
|
the path is in scope but the caller still needs to add it to
|
|
@@ -68,9 +80,18 @@ Paths are emitted relative to `source-root`, forward-slash form
|
|
|
68
80
|
- `prior_action="skipped"` → the user previously declined; caller
|
|
69
81
|
does nothing. Hash/size/lines are null (no need to read the file).
|
|
70
82
|
|
|
83
|
+
`unresolved` semantics: nobody has decided the path yet, so an
|
|
84
|
+
interactive run asks. `prior_action="deferred-headless"` means a headless
|
|
85
|
+
run already met the path and left the decision to the next interactive
|
|
86
|
+
run (an amendment with `action: "deferred-headless"`); a headless run
|
|
87
|
+
does not record it again. A `skipped` amendment whose reason is the
|
|
88
|
+
headless default, "headless: no user to prompt", was written that way by
|
|
89
|
+
a headless run before `deferred-headless` existed: no person declined
|
|
90
|
+
the file, so it counts as `deferred-headless` too.
|
|
91
|
+
|
|
71
92
|
Exit codes:
|
|
72
|
-
0
|
|
73
|
-
1
|
|
93
|
+
0 operation succeeded (any status)
|
|
94
|
+
1 user error (paths invalid, brief or provenance map unparseable)
|
|
74
95
|
"""
|
|
75
96
|
|
|
76
97
|
from __future__ import annotations
|
|
@@ -86,6 +107,21 @@ from typing import Iterable
|
|
|
86
107
|
import yaml
|
|
87
108
|
|
|
88
109
|
|
|
110
|
+
# skf-classify-changed-files.py loads this file for load_brief,
|
|
111
|
+
# extract_scope, glob_match, scope_match, normalize_rel_path and
|
|
112
|
+
# EXCLUDED_DIR_NAMES (its load_scope, the brief-scope test that
|
|
113
|
+
# skf-new-file-diff.py, skf-detect-scripts-assets.py --brief and
|
|
114
|
+
# skf-compare-file-hashes.py --brief load from it, reads the brief through
|
|
115
|
+
# them), skf-detect-registry.py for glob_match, load_brief
|
|
116
|
+
# and extract_scope, skf-extract-public-api.py for glob_match and
|
|
117
|
+
# parse_brief_yaml, and every other script that reads a skill brief
|
|
118
|
+
# (skf-validate-brief-schema.py, skf-provenance-gap-dispatch.py,
|
|
119
|
+
# skf-derive-assembly-shape.py, skf-write-skill-brief.py and skf-test-skill's
|
|
120
|
+
# load-coverage-inputs.py) for parse_brief_yaml, load-coverage-inputs.py
|
|
121
|
+
# also for _amendment_action: keep those names and what they take and
|
|
122
|
+
# return.
|
|
123
|
+
|
|
124
|
+
|
|
89
125
|
# --------------------------------------------------------------------------
|
|
90
126
|
# Heuristic list — case-insensitive basename match
|
|
91
127
|
# --------------------------------------------------------------------------
|
|
@@ -243,13 +279,30 @@ def scope_match(
|
|
|
243
279
|
# --------------------------------------------------------------------------
|
|
244
280
|
|
|
245
281
|
|
|
282
|
+
def parse_brief_yaml(text: str):
|
|
283
|
+
"""The one document a skill brief's YAML text holds, or None when it holds none.
|
|
284
|
+
|
|
285
|
+
SKF 1.x closed every brief with a trailing `---`, which YAML reads as a
|
|
286
|
+
second, empty document, so `yaml.safe_load` refuses such a brief. A
|
|
287
|
+
document that holds no value (empty, or an explicit null such as `~`) is
|
|
288
|
+
skipped wherever it stands; more than one document that holds a value is
|
|
289
|
+
refused with yaml.YAMLError, as is text that is not YAML.
|
|
290
|
+
"""
|
|
291
|
+
documents = [doc for doc in yaml.safe_load_all(text) if doc is not None]
|
|
292
|
+
if len(documents) > 1:
|
|
293
|
+
raise yaml.YAMLError(
|
|
294
|
+
f"a skill brief is a single document; this text holds {len(documents)}"
|
|
295
|
+
)
|
|
296
|
+
return documents[0] if documents else None
|
|
297
|
+
|
|
298
|
+
|
|
246
299
|
def load_brief(brief_path: Path) -> dict:
|
|
247
300
|
try:
|
|
248
301
|
text = brief_path.read_text(encoding="utf-8")
|
|
249
302
|
except OSError as exc:
|
|
250
303
|
raise ValueError(f"cannot read brief at {brief_path}: {exc}") from exc
|
|
251
304
|
try:
|
|
252
|
-
brief =
|
|
305
|
+
brief = parse_brief_yaml(text)
|
|
253
306
|
except yaml.YAMLError as exc:
|
|
254
307
|
raise ValueError(
|
|
255
308
|
f"brief at {brief_path} is not valid YAML: {exc}"
|
|
@@ -267,7 +320,8 @@ def extract_scope(brief: dict) -> tuple[list[str], list[str], dict[str, list[str
|
|
|
267
320
|
|
|
268
321
|
amendments_by_path maps each path to a list of actions seen, in the
|
|
269
322
|
order they appear in the brief (so reconcile() can pick most-recent
|
|
270
|
-
by iterating in reverse).
|
|
323
|
+
by iterating in reverse). A legacy headless skip is listed as
|
|
324
|
+
'deferred-headless' (see _amendment_action).
|
|
271
325
|
"""
|
|
272
326
|
scope = brief.get("scope") if isinstance(brief.get("scope"), dict) else {}
|
|
273
327
|
includes = scope.get("include") if isinstance(scope.get("include"), list) else []
|
|
@@ -279,8 +333,8 @@ def extract_scope(brief: dict) -> tuple[list[str], list[str], dict[str, list[str
|
|
|
279
333
|
if not isinstance(amend, dict):
|
|
280
334
|
continue
|
|
281
335
|
path = amend.get("path")
|
|
282
|
-
action = amend
|
|
283
|
-
if isinstance(path, str) and
|
|
336
|
+
action = _amendment_action(amend)
|
|
337
|
+
if isinstance(path, str) and action is not None:
|
|
284
338
|
by_path.setdefault(path, []).append(action)
|
|
285
339
|
|
|
286
340
|
# filter to strings only — schema requires strings but defensively guard
|
|
@@ -289,6 +343,48 @@ def extract_scope(brief: dict) -> tuple[list[str], list[str], dict[str, list[str
|
|
|
289
343
|
return includes, excludes, by_path
|
|
290
344
|
|
|
291
345
|
|
|
346
|
+
# --------------------------------------------------------------------------
|
|
347
|
+
# Provenance map: the files it already tracks
|
|
348
|
+
# --------------------------------------------------------------------------
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def normalize_rel_path(path: str) -> str:
|
|
352
|
+
"""A provenance or brief path in the form this helper emits: forward
|
|
353
|
+
slashes, no leading `./`."""
|
|
354
|
+
path = path.strip().replace("\\", "/")
|
|
355
|
+
while path.startswith("./"):
|
|
356
|
+
path = path[2:]
|
|
357
|
+
return path
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def load_tracked_files(provenance_path: Path) -> set[str]:
|
|
361
|
+
"""Every `entries[].source_file` and `file_entries[].source_file` of a
|
|
362
|
+
provenance map. Raises ValueError when the map cannot be read."""
|
|
363
|
+
try:
|
|
364
|
+
data = json.loads(provenance_path.read_text(encoding="utf-8"))
|
|
365
|
+
except OSError as exc:
|
|
366
|
+
raise ValueError(f"cannot read provenance map at {provenance_path}: {exc}") from exc
|
|
367
|
+
except ValueError as exc:
|
|
368
|
+
raise ValueError(
|
|
369
|
+
f"provenance map at {provenance_path} is not valid JSON: {exc}"
|
|
370
|
+
) from exc
|
|
371
|
+
if not isinstance(data, dict):
|
|
372
|
+
raise ValueError(
|
|
373
|
+
f"provenance map at {provenance_path} must be a JSON object; got "
|
|
374
|
+
f"{type(data).__name__}"
|
|
375
|
+
)
|
|
376
|
+
tracked: set[str] = set()
|
|
377
|
+
for key in ("entries", "file_entries"):
|
|
378
|
+
rows = data.get(key)
|
|
379
|
+
if not isinstance(rows, list):
|
|
380
|
+
continue
|
|
381
|
+
for row in rows:
|
|
382
|
+
source = row.get("source_file") if isinstance(row, dict) else None
|
|
383
|
+
if isinstance(source, str) and source.strip():
|
|
384
|
+
tracked.add(normalize_rel_path(source))
|
|
385
|
+
return tracked
|
|
386
|
+
|
|
387
|
+
|
|
292
388
|
# --------------------------------------------------------------------------
|
|
293
389
|
# File metadata: hash + size + lines + preview
|
|
294
390
|
# --------------------------------------------------------------------------
|
|
@@ -338,13 +434,28 @@ def load_preview(path: Path, *, max_lines: int) -> str:
|
|
|
338
434
|
|
|
339
435
|
_PROMOTED = "promoted"
|
|
340
436
|
_SKIPPED = "skipped"
|
|
437
|
+
_DEFERRED = "deferred-headless"
|
|
438
|
+
# The reason a headless run gave its automatic skip before deferred-headless
|
|
439
|
+
# existed. Such a skip was never a person's decision.
|
|
440
|
+
_LEGACY_HEADLESS_REASON = "headless: no user to prompt"
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def _amendment_action(amend: dict) -> str | None:
|
|
444
|
+
"""The action an amendment records, reading a legacy headless skip as a deferral."""
|
|
445
|
+
action = amend.get("action")
|
|
446
|
+
if not isinstance(action, str):
|
|
447
|
+
return None
|
|
448
|
+
reason = amend.get("reason")
|
|
449
|
+
if action == _SKIPPED and isinstance(reason, str) and reason.strip() == _LEGACY_HEADLESS_REASON:
|
|
450
|
+
return _DEFERRED
|
|
451
|
+
return action
|
|
341
452
|
|
|
342
453
|
|
|
343
454
|
def _latest_action(actions: list[str]) -> str | None:
|
|
344
455
|
"""Most-recent matching amendment wins. Returns 'promoted', 'skipped',
|
|
345
|
-
or None if no recognized action was seen."""
|
|
456
|
+
'deferred-headless', or None if no recognized action was seen."""
|
|
346
457
|
for action in reversed(actions):
|
|
347
|
-
if action in (_PROMOTED, _SKIPPED):
|
|
458
|
+
if action in (_PROMOTED, _SKIPPED, _DEFERRED):
|
|
348
459
|
return action
|
|
349
460
|
return None
|
|
350
461
|
|
|
@@ -354,17 +465,25 @@ def resolve(
|
|
|
354
465
|
brief_path: Path,
|
|
355
466
|
*,
|
|
356
467
|
preview_lines: int = 20,
|
|
468
|
+
provenance_map: Path | None = None,
|
|
357
469
|
) -> dict:
|
|
358
470
|
"""Run the §2a deterministic pipeline. See module docstring for output shape."""
|
|
359
471
|
brief = load_brief(brief_path)
|
|
360
472
|
includes, excludes, amendments_by_path = extract_scope(brief)
|
|
473
|
+
tracked = load_tracked_files(provenance_map) if provenance_map is not None else set()
|
|
361
474
|
|
|
475
|
+
already_tracked: list[dict] = []
|
|
362
476
|
already_in_scope: list[dict] = []
|
|
363
477
|
pre_decided: list[dict] = []
|
|
364
478
|
unresolved: list[dict] = []
|
|
365
479
|
|
|
366
480
|
for file_path, heuristic in iter_auth_doc_files(source_root):
|
|
367
481
|
rel = file_path.relative_to(source_root).as_posix()
|
|
482
|
+
if rel in tracked:
|
|
483
|
+
# The provenance map already names it: change detection handles
|
|
484
|
+
# it, and no decision is asked for.
|
|
485
|
+
already_tracked.append({"path": rel, "heuristic": heuristic})
|
|
486
|
+
continue
|
|
368
487
|
in_scope, excluded_by = scope_match(rel, includes, excludes)
|
|
369
488
|
prior_action = _latest_action(amendments_by_path.get(rel, []))
|
|
370
489
|
|
|
@@ -398,6 +517,7 @@ def resolve(
|
|
|
398
517
|
continue
|
|
399
518
|
|
|
400
519
|
if prior_action == _SKIPPED:
|
|
520
|
+
# A person declined the file; a headless deferral never lands here.
|
|
401
521
|
pre_decided.append({
|
|
402
522
|
"path": rel,
|
|
403
523
|
"heuristic": heuristic,
|
|
@@ -409,7 +529,8 @@ def resolve(
|
|
|
409
529
|
})
|
|
410
530
|
continue
|
|
411
531
|
|
|
412
|
-
#
|
|
532
|
+
# Out of scope and undecided (no amendment, or a headless deferral
|
|
533
|
+
# that waits for the next interactive run) → unresolved
|
|
413
534
|
unresolved.append({
|
|
414
535
|
"path": rel,
|
|
415
536
|
"heuristic": heuristic,
|
|
@@ -418,24 +539,28 @@ def resolve(
|
|
|
418
539
|
"content_hash": sha256_of_file(file_path),
|
|
419
540
|
"preview": load_preview(file_path, max_lines=preview_lines),
|
|
420
541
|
"excluded_by_pattern": excluded_by,
|
|
542
|
+
"prior_action": prior_action,
|
|
421
543
|
})
|
|
422
544
|
|
|
423
545
|
# Deterministic ordering for stable diffs / cache keys
|
|
546
|
+
already_tracked.sort(key=lambda r: r["path"])
|
|
424
547
|
already_in_scope.sort(key=lambda r: r["path"])
|
|
425
548
|
pre_decided.sort(key=lambda r: r["path"])
|
|
426
549
|
unresolved.sort(key=lambda r: r["path"])
|
|
427
550
|
|
|
428
551
|
candidates_total = (
|
|
429
|
-
len(already_in_scope) + len(pre_decided) + len(unresolved)
|
|
552
|
+
len(already_tracked) + len(already_in_scope) + len(pre_decided) + len(unresolved)
|
|
430
553
|
)
|
|
431
554
|
return {
|
|
432
555
|
"status": "candidates-found" if candidates_total > 0 else "no-candidates",
|
|
433
556
|
"summary": {
|
|
434
557
|
"candidates_total": candidates_total,
|
|
558
|
+
"already_tracked_count": len(already_tracked),
|
|
435
559
|
"already_in_scope_count": len(already_in_scope),
|
|
436
560
|
"pre_decided_count": len(pre_decided),
|
|
437
561
|
"unresolved_count": len(unresolved),
|
|
438
562
|
},
|
|
563
|
+
"already_tracked": already_tracked,
|
|
439
564
|
"already_in_scope": already_in_scope,
|
|
440
565
|
"pre_decided": pre_decided,
|
|
441
566
|
"unresolved": unresolved,
|
|
@@ -461,8 +586,17 @@ def _cmd_resolve(args: argparse.Namespace) -> int:
|
|
|
461
586
|
if args.preview_lines < 1:
|
|
462
587
|
print("error: --preview-lines must be >= 1", file=sys.stderr)
|
|
463
588
|
return 1
|
|
589
|
+
provenance_map = Path(args.provenance_map) if args.provenance_map else None
|
|
590
|
+
if provenance_map is not None and not provenance_map.is_file():
|
|
591
|
+
print(f"error: provenance map not found: {provenance_map}", file=sys.stderr)
|
|
592
|
+
return 1
|
|
464
593
|
try:
|
|
465
|
-
result = resolve(
|
|
594
|
+
result = resolve(
|
|
595
|
+
source_root,
|
|
596
|
+
brief_path,
|
|
597
|
+
preview_lines=args.preview_lines,
|
|
598
|
+
provenance_map=provenance_map,
|
|
599
|
+
)
|
|
466
600
|
except ValueError as exc:
|
|
467
601
|
print(f"error: {exc}", file=sys.stderr)
|
|
468
602
|
return 1
|
|
@@ -490,6 +624,13 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
490
624
|
default=20,
|
|
491
625
|
help="number of lines to capture for the prompt preview (default: 20)",
|
|
492
626
|
)
|
|
627
|
+
p.add_argument(
|
|
628
|
+
"--provenance-map",
|
|
629
|
+
help=(
|
|
630
|
+
"path to provenance-map.json: candidates it already tracks are "
|
|
631
|
+
"listed in already_tracked and in no other bucket"
|
|
632
|
+
),
|
|
633
|
+
)
|
|
493
634
|
p.set_defaults(func=_cmd_resolve)
|
|
494
635
|
return parser
|
|
495
636
|
|