pi-dev-team 0.2.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/LICENSE +21 -0
- package/PORTING.md +134 -0
- package/README.md +207 -0
- package/UPSTREAM.json +64 -0
- package/agents/Explore.md +15 -0
- package/agents/a11y-review.md +118 -0
- package/agents/adr-author.md +70 -0
- package/agents/ai-provenance-review.md +120 -0
- package/agents/angular-reactivity-review.md +95 -0
- package/agents/arch-review.md +135 -0
- package/agents/architect.md +78 -0
- package/agents/autoship-batch-proposer.md +69 -0
- package/agents/claude-setup-review.md +136 -0
- package/agents/codebase-recon.md +184 -0
- package/agents/component-architecture-review.md +119 -0
- package/agents/concurrency-review.md +109 -0
- package/agents/correctness-review.md +290 -0
- package/agents/data-flow-tracer.md +120 -0
- package/agents/doc-review.md +165 -0
- package/agents/domain-review.md +136 -0
- package/agents/general-purpose.md +10 -0
- package/agents/gherkin-quality-critic.md +113 -0
- package/agents/js-fp-review.md +114 -0
- package/agents/mutation-kill.md +684 -0
- package/agents/naming-review.md +142 -0
- package/agents/orchestrator.md +339 -0
- package/agents/performance-review.md +105 -0
- package/agents/plan-review-acceptance.md +115 -0
- package/agents/plan-review-design.md +90 -0
- package/agents/plan-review-parallelization.md +84 -0
- package/agents/plan-review-strategic.md +96 -0
- package/agents/plan-review-ux.md +110 -0
- package/agents/platform-engineer.md +64 -0
- package/agents/product-manager.md +68 -0
- package/agents/progress-guardian.md +79 -0
- package/agents/qa-engineer.md +289 -0
- package/agents/quality-reviewer.md +132 -0
- package/agents/react-reactivity-review.md +102 -0
- package/agents/refactor-opportunity-review.md +128 -0
- package/agents/security-engineer.md +60 -0
- package/agents/security-review.md +218 -0
- package/agents/session-analysis.md +95 -0
- package/agents/software-engineer.md +105 -0
- package/agents/spec-compliance-review.md +100 -0
- package/agents/spec-reviewer.md +114 -0
- package/agents/structure-review.md +146 -0
- package/agents/tech-writer.md +84 -0
- package/agents/test-review.md +246 -0
- package/agents/test-smell-review.md +188 -0
- package/agents/token-efficiency-review.md +139 -0
- package/agents/ui-ux-designer.md +54 -0
- package/agents/vue-reactivity-review.md +95 -0
- package/bin/__pycache__/claudecpython-314.pyc +0 -0
- package/bin/claude +258 -0
- package/docs/upstream/.pages +1 -0
- package/docs/upstream/CHANGELOG.md +2586 -0
- package/docs/upstream/README.md +155 -0
- package/docs/upstream/agent-architecture.md +214 -0
- package/docs/upstream/agent_info.md +187 -0
- package/docs/upstream/artifact-migration.md +124 -0
- package/docs/upstream/code-intelligence-nudge.md +149 -0
- package/docs/upstream/code-review-process.md +294 -0
- package/docs/upstream/concurrent-use.md +73 -0
- package/docs/upstream/context-management.md +111 -0
- package/docs/upstream/developer-notes.md +280 -0
- package/docs/upstream/diagrams/architecture-overview.svg +101 -0
- package/docs/upstream/diagrams/review-dispatch.svg +139 -0
- package/docs/upstream/diagrams/team-agents.svg +128 -0
- package/docs/upstream/diagrams/test-improve-flow.svg +166 -0
- package/docs/upstream/diagrams/workflow-linear.svg +66 -0
- package/docs/upstream/diagrams/workflow-three-phase.svg +200 -0
- package/docs/upstream/eval-maintenance.md +95 -0
- package/docs/upstream/eval-running-guide.md +147 -0
- package/docs/upstream/eval-system.md +291 -0
- package/docs/upstream/session-review-oss-complements.md +75 -0
- package/docs/upstream/session-review.md +212 -0
- package/docs/upstream/skills.md +188 -0
- package/docs/upstream/team-structure.md +21 -0
- package/docs/upstream/telemetry-ci-access.md +129 -0
- package/docs/upstream/telemetry-repo-security.md +120 -0
- package/docs/upstream/test-evaluation.md +277 -0
- package/docs/upstream/test-improve.md +154 -0
- package/docs/upstream/triage-workflow.md +282 -0
- package/docs/upstream/workflows.md +289 -0
- package/extensions/dev-team/index.ts +539 -0
- package/extensions/dev-team/lib/agents.ts +272 -0
- package/extensions/dev-team/lib/ai-credits.ts +92 -0
- package/extensions/dev-team/lib/autocompact.ts +81 -0
- package/extensions/dev-team/lib/child-run.ts +102 -0
- package/extensions/dev-team/lib/config.ts +236 -0
- package/extensions/dev-team/lib/gh-command.ts +103 -0
- package/extensions/dev-team/lib/github-style.ts +307 -0
- package/extensions/dev-team/lib/hooks.ts +350 -0
- package/extensions/dev-team/lib/metrics.ts +115 -0
- package/extensions/dev-team/lib/safe-read.ts +49 -0
- package/extensions/dev-team/lib/session-files.ts +57 -0
- package/extensions/dev-team/lib/session-spend.ts +123 -0
- package/extensions/dev-team/lib/shell-scan.ts +205 -0
- package/extensions/dev-team/lib/skills.ts +213 -0
- package/extensions/dev-team/lib/subagent-render.ts +245 -0
- package/extensions/dev-team/lib/subagent-types.ts +164 -0
- package/extensions/dev-team/lib/subagent.ts +596 -0
- package/extensions/dev-team/lib/terminal-text.ts +54 -0
- package/extensions/dev-team/lib/tools-misc.ts +152 -0
- package/extensions/dev-team/lib/transcript.ts +110 -0
- package/extensions/dev-team/lib/trust.ts +52 -0
- package/extensions/dev-team/lib/usage-breakdown.ts +176 -0
- package/extensions/dev-team/lib/usage-chart.ts +153 -0
- package/extensions/dev-team/lib/usage-command.ts +107 -0
- package/extensions/dev-team/lib/usage-history.ts +203 -0
- package/extensions/dev-team/lib/usage-render.ts +225 -0
- package/extensions/dev-team/lib/usage-split-bar.ts +127 -0
- package/extensions/dev-team/lib/usage-state.ts +116 -0
- package/extensions/dev-team/lib/usage-text.ts +159 -0
- package/extensions/dev-team/lib/usage-view.ts +109 -0
- package/hooks/__pycache__/refactor_test_freeze_guard.cpython-314.pyc +0 -0
- package/hooks/agent_dispatch_ledger.py +190 -0
- package/hooks/autocompact_setup_nudge.py +99 -0
- package/hooks/bash_retry_guard.py +228 -0
- package/hooks/boundary_events_write_guard.py +352 -0
- package/hooks/code_intelligence_nudge.py +293 -0
- package/hooks/code_intelligence_turn_mark.py +317 -0
- package/hooks/codegraph_bootstrap.py +139 -0
- package/hooks/contract_version_guard.py +362 -0
- package/hooks/cost_meter.py +106 -0
- package/hooks/destructive-commands.json +62 -0
- package/hooks/destructive_guard.py +477 -0
- package/hooks/eval_compliance_check.py +440 -0
- package/hooks/guards.json +17 -0
- package/hooks/hooks.json +323 -0
- package/hooks/internal_double_gate.py +296 -0
- package/hooks/js_fp_review.py +212 -0
- package/hooks/knowledge_index.py +119 -0
- package/hooks/lib/__pycache__/artifact_paths.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/atomic_state.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/autocompact_config.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/boundary_events.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/doc_classification.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/gh_pr_create_detect.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/git_safe_diff.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/instrument_log.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/metrics_query.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/plugin_version.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/pre_commit_doc_classifier.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_agent_registry.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_gate_corroboration.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_gate_hash.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_verdicts.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/stdin_json.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/stryker_invocation.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/telemetry_consent.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/test_file_classify.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/token_efficiency_limits.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/verify_guard_state.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/xunit_v3_operator_gate.cpython-314.pyc +0 -0
- package/hooks/lib/agent_skill_hints.py +74 -0
- package/hooks/lib/artifact_paths.py +263 -0
- package/hooks/lib/atomic_state.py +557 -0
- package/hooks/lib/autocompact_config.py +103 -0
- package/hooks/lib/autoship_log.py +106 -0
- package/hooks/lib/banned_scripts_policy.py +51 -0
- package/hooks/lib/boundary_events.py +436 -0
- package/hooks/lib/build_knowledge_index.py +504 -0
- package/hooks/lib/build_skills_index.py +361 -0
- package/hooks/lib/build_state.py +116 -0
- package/hooks/lib/classify_ship_outcome.py +126 -0
- package/hooks/lib/config_changelog_schema.py +115 -0
- package/hooks/lib/cost_meter.py +955 -0
- package/hooks/lib/doc_classification.py +116 -0
- package/hooks/lib/gh_pr_create_detect.py +136 -0
- package/hooks/lib/git_safe_diff.py +123 -0
- package/hooks/lib/instrument_log.py +66 -0
- package/hooks/lib/iteration_journal_gate.py +197 -0
- package/hooks/lib/knowledge_index_paths.py +88 -0
- package/hooks/lib/mcp_json_repowise.py +177 -0
- package/hooks/lib/metrics_query.py +202 -0
- package/hooks/lib/minimal_yaml.py +434 -0
- package/hooks/lib/plugin_version.py +142 -0
- package/hooks/lib/pre_commit_detect.py +537 -0
- package/hooks/lib/pre_commit_doc_classifier.py +126 -0
- package/hooks/lib/pricing.py +118 -0
- package/hooks/lib/report_pdf.py +371 -0
- package/hooks/lib/review_agent_registry.py +142 -0
- package/hooks/lib/review_dispatch_ledger.py +101 -0
- package/hooks/lib/review_gate_corroboration.py +521 -0
- package/hooks/lib/review_gate_hash.py +252 -0
- package/hooks/lib/review_gate_normalized_hash.py +1115 -0
- package/hooks/lib/review_verdicts.py +301 -0
- package/hooks/lib/run_report.py +160 -0
- package/hooks/lib/skill_categories.yaml +125 -0
- package/hooks/lib/stdin_json.py +57 -0
- package/hooks/lib/stryker_invocation.py +102 -0
- package/hooks/lib/telemetry_consent.py +41 -0
- package/hooks/lib/telemetry_report.py +108 -0
- package/hooks/lib/test_file_classify.py +160 -0
- package/hooks/lib/token_efficiency_limits.py +51 -0
- package/hooks/lib/turn_identity.py +77 -0
- package/hooks/lib/verify_guard_state.py +110 -0
- package/hooks/lib/workflow_state.py +206 -0
- package/hooks/lib/xunit_v3_operator_gate.py +596 -0
- package/hooks/mcp_json_repowise_nudge.py +74 -0
- package/hooks/mutation_adapters/__init__.py +7 -0
- package/hooks/mutation_adapters/__pycache__/__init__.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/lib.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/mutmut.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/pitest.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/stryker.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/stryker_net.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/lib.py +478 -0
- package/hooks/mutation_adapters/mutmut.py +188 -0
- package/hooks/mutation_adapters/pitest.py +266 -0
- package/hooks/mutation_adapters/stryker.py +157 -0
- package/hooks/mutation_adapters/stryker_net.py +264 -0
- package/hooks/mutation_gate.py +193 -0
- package/hooks/mutation_testing_smoke_gate.py +371 -0
- package/hooks/pending_review_notify.py +121 -0
- package/hooks/phase_marker.py +138 -0
- package/hooks/post_compact_state_reinject.py +180 -0
- package/hooks/post_format.py +115 -0
- package/hooks/pre_commit_knowledge_index.py +128 -0
- package/hooks/pre_commit_review.py +66 -0
- package/hooks/pre_pr_review.py +694 -0
- package/hooks/pre_tool_guard.py +405 -0
- package/hooks/py.sh +73 -0
- package/hooks/refactor-bash-write-patterns.json +29 -0
- package/hooks/refactor_test_bash_guard.py +253 -0
- package/hooks/refactor_test_freeze_guard.py +139 -0
- package/hooks/refactor_test_revert_guard.py +186 -0
- package/hooks/repo_review_nudge.py +287 -0
- package/hooks/review_verdict_recorder.py +464 -0
- package/hooks/scan_bash_command_for_banned_scripts.py +428 -0
- package/hooks/scan_worktree_for_banned_scripts.py +238 -0
- package/hooks/session_learning_trigger.py +248 -0
- package/hooks/skills_index.py +126 -0
- package/hooks/stryker_xunit_shim_guard.py +571 -0
- package/hooks/subagent_completion_guard.py +309 -0
- package/hooks/subagent_skill_context.py +139 -0
- package/hooks/task_completion_metrics.py +216 -0
- package/hooks/tdd_guard.py +229 -0
- package/hooks/telemetry.py +341 -0
- package/hooks/token_efficiency_review.py +194 -0
- package/hooks/verify_guard.py +183 -0
- package/hooks/verify_guard_edit_marker.py +73 -0
- package/hooks/version_check.py +173 -0
- package/knowledge/accepted-risks-schema.md +98 -0
- package/knowledge/adr-decision-criteria.md +64 -0
- package/knowledge/adversarial-review-protocol.md +139 -0
- package/knowledge/agent-registry.md +228 -0
- package/knowledge/agent-review-methodology.md +80 -0
- package/knowledge/ai-friendly-repo-guidelines.md +67 -0
- package/knowledge/architecture-assessment.md +96 -0
- package/knowledge/artifact-lifecycle.md +57 -0
- package/knowledge/cd-maturity-model.md +82 -0
- package/knowledge/cd-test-architecture.md +190 -0
- package/knowledge/ci-cd-file-scope.md +24 -0
- package/knowledge/codegraph-vs-graphify.md +192 -0
- package/knowledge/component-test-patterns.md +139 -0
- package/knowledge/database-change-management.md +80 -0
- package/knowledge/database-test-patterns.md +79 -0
- package/knowledge/decision-defaults.md +88 -0
- package/knowledge/dependency-breaking-techniques.md +116 -0
- package/knowledge/deployment-pipeline.md +86 -0
- package/knowledge/design-smells.md +122 -0
- package/knowledge/directory-enumeration.md +38 -0
- package/knowledge/domain-modeling.md +123 -0
- package/knowledge/evidence-bundle.md +90 -0
- package/knowledge/exploratory-testing-field-guide.md +122 -0
- package/knowledge/failure-routing.md +28 -0
- package/knowledge/fixture-construction.md +56 -0
- package/knowledge/frontend-component-architecture.md +139 -0
- package/knowledge/gherkin-quality-review-dispatch.md +135 -0
- package/knowledge/index.json +6766 -0
- package/knowledge/internal-collaborator-doubling.md +101 -0
- package/knowledge/legacy-test-strategy.md +71 -0
- package/knowledge/long-run-waiting.md +66 -0
- package/knowledge/microservice-testing.md +71 -0
- package/knowledge/model-pricing.json +23 -0
- package/knowledge/mutation-score-formulas.md +60 -0
- package/knowledge/object-calisthenics.md +147 -0
- package/knowledge/oracle-provenance.md +94 -0
- package/knowledge/orchestrator-script-implementation.md +185 -0
- package/knowledge/owasp-detection.md +148 -0
- package/knowledge/plan-review-rubric.md +56 -0
- package/knowledge/proxy-connectivity.md +62 -0
- package/knowledge/reactive-effect-patterns.md +73 -0
- package/knowledge/recon-inventory-excludes.txt +32 -0
- package/knowledge/references/bdd-value-guide.md +61 -0
- package/knowledge/references/csharp-http-client-testing.md +264 -0
- package/knowledge/release-strategies.md +74 -0
- package/knowledge/report-output-location.md +117 -0
- package/knowledge/report-pdf-integration.md +63 -0
- package/knowledge/report-print.css +129 -0
- package/knowledge/report-template.md +114 -0
- package/knowledge/report-to-pdf.md +69 -0
- package/knowledge/request-processing-flow.md +63 -0
- package/knowledge/result-verification.md +52 -0
- package/knowledge/review-agent-output-contract.md +121 -0
- package/knowledge/review-lens-classification.md +113 -0
- package/knowledge/review-rubric.md +62 -0
- package/knowledge/review-template.md +104 -0
- package/knowledge/rule-fixtures/A02.insecure-random-js/negative.js +1 -0
- package/knowledge/rule-fixtures/A02.insecure-random-js/positive.js +1 -0
- package/knowledge/rule-fixtures/A02.weak-hashing-md5/negative.py +1 -0
- package/knowledge/rule-fixtures/A02.weak-hashing-md5/positive.py +1 -0
- package/knowledge/rule-fixtures/A03.command-injection/negative.js +1 -0
- package/knowledge/rule-fixtures/A03.command-injection/positive.js +1 -0
- package/knowledge/rule-fixtures/A03.sql-injection/negative.js +1 -0
- package/knowledge/rule-fixtures/A03.sql-injection/positive.js +1 -0
- package/knowledge/rule-fixtures/A03.xss-innerhtml/negative.js +1 -0
- package/knowledge/rule-fixtures/A03.xss-innerhtml/positive.js +1 -0
- package/knowledge/rule-fixtures/A05.cors-wildcard/negative.js +1 -0
- package/knowledge/rule-fixtures/A05.cors-wildcard/positive.js +1 -0
- package/knowledge/rule-fixtures/A05.default-credentials/negative.js +1 -0
- package/knowledge/rule-fixtures/A05.default-credentials/positive.js +1 -0
- package/knowledge/rule-fixtures/A07.jwt-alg-none/negative.js +1 -0
- package/knowledge/rule-fixtures/A07.jwt-alg-none/positive.js +1 -0
- package/knowledge/rule-fixtures/A08.binary-formatter/negative.cs +1 -0
- package/knowledge/rule-fixtures/A08.binary-formatter/positive.cs +1 -0
- package/knowledge/rule-fixtures/A08.js-eval/negative.js +1 -0
- package/knowledge/rule-fixtures/A08.js-eval/positive.js +1 -0
- package/knowledge/rule-fixtures/A08.object-input-stream/negative.java +1 -0
- package/knowledge/rule-fixtures/A08.object-input-stream/positive.java +1 -0
- package/knowledge/schemas/disposition-register-v1.json +65 -0
- package/knowledge/schemas/recon-envelope-v1.json +198 -0
- package/knowledge/schemas/unified-finding-v1.json +72 -0
- package/knowledge/security-primitives-contract.md +301 -0
- package/knowledge/security-review-rule-map.yaml +107 -0
- package/knowledge/skills-registry.md +72 -0
- package/knowledge/task-size-classifier.md +103 -0
- package/knowledge/telemetry-schema.md +881 -0
- package/knowledge/test-automation-maturity.md +56 -0
- package/knowledge/test-automation-principles.md +71 -0
- package/knowledge/test-cadence-tradeoffs.md +68 -0
- package/knowledge/test-doubles.md +105 -0
- package/knowledge/test-file-indicators.md +22 -0
- package/knowledge/test-layer-gates.md +35 -0
- package/knowledge/test-matrix-examples/django-batch.md +24 -0
- package/knowledge/test-matrix-examples/dotnet-grpc-fronting-api.md +90 -0
- package/knowledge/test-matrix-examples/dotnet-http-consumer.md +131 -0
- package/knowledge/test-matrix-examples/react-node-spa.md +24 -0
- package/knowledge/test-matrix-examples/spring-boot-service.md +25 -0
- package/knowledge/test-matrix-examples/ssr-htmx.md +24 -0
- package/knowledge/test-organization.md +70 -0
- package/knowledge/test-pyramid.md +84 -0
- package/knowledge/test-refactoring.md +67 -0
- package/knowledge/test-review-division-of-labor.md +85 -0
- package/knowledge/test-smells.md +80 -0
- package/knowledge/test-stack-profiles/bdd-frameworks.md +235 -0
- package/knowledge/test-stack-profiles/django.md +13 -0
- package/knowledge/test-stack-profiles/dotnet.md +18 -0
- package/knowledge/test-stack-profiles/go.md +16 -0
- package/knowledge/test-stack-profiles/node.md +16 -0
- package/knowledge/test-stack-profiles/react.md +12 -0
- package/knowledge/test-stack-profiles/spring-boot.md +16 -0
- package/knowledge/test-stack-profiles/ssr-htmx.md +14 -0
- package/knowledge/test-stack-profiles/vue.md +12 -0
- package/knowledge/test-strategy.md +70 -0
- package/knowledge/testability-patterns.md +240 -0
- package/knowledge/testing-quadrants.md +44 -0
- package/knowledge/testing-techniques/approval.md +15 -0
- package/knowledge/testing-techniques/chaos.md +17 -0
- package/knowledge/testing-techniques/fuzz.md +15 -0
- package/knowledge/testing-techniques/property-based.md +15 -0
- package/knowledge/testing-techniques/schema-validation.md +15 -0
- package/knowledge/testing-techniques/screenshot.md +15 -0
- package/knowledge/three-phase-workflow.md +198 -0
- package/knowledge/value-patterns.md +55 -0
- package/knowledge/verification-mode.md +116 -0
- package/knowledge/virtual-service-libraries.md +75 -0
- package/knowledge/wave-consolidation-guidance.md +21 -0
- package/overrides/agents/Explore.md +15 -0
- package/overrides/agents/general-purpose.md +10 -0
- package/overrides/notes/autoship.md +6 -0
- package/overrides/notes/issues-from-assessment.md +3 -0
- package/overrides/notes/issues-from-plan.md +3 -0
- package/overrides/notes/mutation-night-watch.md +3 -0
- package/overrides/notes/mutation-testing.md +3 -0
- package/overrides/notes/pr.md +7 -0
- package/overrides/notes/project-init.md +6 -0
- package/overrides/notes/setup.md +13 -0
- package/overrides/notes/specs.md +3 -0
- package/overrides/skills/headless-run/SKILL.md +45 -0
- package/overrides/skills/upgrade/SKILL.md +30 -0
- package/overrides/skills/version/SKILL.md +25 -0
- package/package.json +36 -0
- package/scripts/authoring_digest.py +93 -0
- package/scripts/autoship_discover.py +121 -0
- package/scripts/autoship_group.py +409 -0
- package/scripts/autoship_proposals.py +494 -0
- package/scripts/autoship_queue.py +291 -0
- package/scripts/autoship_reclaim.py +495 -0
- package/scripts/build_jobs.py +108 -0
- package/scripts/build_rollback_point.py +240 -0
- package/scripts/build_slice_scope.py +157 -0
- package/scripts/build_wave.py +109 -0
- package/scripts/build_wave_reconcile.py +252 -0
- package/scripts/build_worktree_baseref.py +113 -0
- package/scripts/check_agent_scope.py +117 -0
- package/scripts/check_agent_tool_mapping.py +213 -0
- package/scripts/check_review_agent_mcp_tools.py +317 -0
- package/scripts/check_security_assessment_mcp_tools.py +165 -0
- package/scripts/checkpoint_abort.py +502 -0
- package/scripts/claude_setup_review.py +438 -0
- package/scripts/codebase_recon.py +556 -0
- package/scripts/coverage_config.py +623 -0
- package/scripts/coverage_delta_steering.py +330 -0
- package/scripts/coverage_discovery_dotnet.py +315 -0
- package/scripts/coverage_discovery_java.py +742 -0
- package/scripts/coverage_discovery_js.py +546 -0
- package/scripts/coverage_gap_ranking.py +556 -0
- package/scripts/coverage_readiness.py +455 -0
- package/scripts/coverage_report_parse.py +521 -0
- package/scripts/detect_bdd_convention.py +252 -0
- package/scripts/eval_ablation.py +376 -0
- package/scripts/gherkin_analysis_coverage_gate.py +306 -0
- package/scripts/gherkin_cross_feature_duplicate_titles_gate.py +173 -0
- package/scripts/gherkin_effectiveness_rollup.py +238 -0
- package/scripts/gherkin_failure_path_gate.py +206 -0
- package/scripts/gherkin_feature_merge.py +720 -0
- package/scripts/gherkin_stub_gate.py +163 -0
- package/scripts/gherkin_stub_merge.py +479 -0
- package/scripts/git_origin_host.py +88 -0
- package/scripts/install-java-static-analysis.py +110 -0
- package/scripts/issue_deps.py +74 -0
- package/scripts/lib/_bdd_markers.py +28 -0
- package/scripts/lib/_gherkin_text.py +93 -0
- package/scripts/lib/_vendored_tree.py +70 -0
- package/scripts/lib/autoship_state.py +397 -0
- package/scripts/lib/claude_md_guard.py +226 -0
- package/scripts/lib/deterministic_recon.py +446 -0
- package/scripts/lib/mcp_tool_grants.py +211 -0
- package/scripts/lib/plan_parse.py +386 -0
- package/scripts/lib/review_result.py +84 -0
- package/scripts/lib/review_roster.py +86 -0
- package/scripts/lib/session_log/__init__.py +34 -0
- package/scripts/lib/session_log/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/lib/session_log/__pycache__/records.cpython-314.pyc +0 -0
- package/scripts/lib/session_log/classify.py +231 -0
- package/scripts/lib/session_log/corrections.py +194 -0
- package/scripts/lib/session_log/discovery.py +108 -0
- package/scripts/lib/session_log/records.py +218 -0
- package/scripts/lib/session_log/redact.py +76 -0
- package/scripts/lib/session_log/signals.py +373 -0
- package/scripts/lib/session_report_downstream.py +614 -0
- package/scripts/lib/session_report_maintainer.py +1273 -0
- package/scripts/lib/session_report_shared.py +262 -0
- package/scripts/lib/settings_hook_guard.py +157 -0
- package/scripts/lib/slug.py +33 -0
- package/scripts/lib/stub_extractors/__init__.py +82 -0
- package/scripts/lib/stub_extractors/_common.py +328 -0
- package/scripts/lib/stub_extractors/csharp.py +19 -0
- package/scripts/lib/stub_extractors/go.py +173 -0
- package/scripts/lib/stub_extractors/java.py +18 -0
- package/scripts/lib/stub_extractors/jsts.py +126 -0
- package/scripts/mutation_stack_sections.py +149 -0
- package/scripts/mutation_yield_steering.py +345 -0
- package/scripts/orchestrator.py +895 -0
- package/scripts/plan_gherkin_export.py +227 -0
- package/scripts/plan_waves.py +208 -0
- package/scripts/pr_close_keyword_lint.py +108 -0
- package/scripts/progress_guardian.py +888 -0
- package/scripts/recon_inventory.py +273 -0
- package/scripts/review_findings_log.py +93 -0
- package/scripts/run_invariants.py +124 -0
- package/scripts/select_lenses.py +640 -0
- package/scripts/session_report.py +486 -0
- package/scripts/set_autocompact_env.py +221 -0
- package/scripts/ship_resume_guard.py +135 -0
- package/scripts/ship_review_gate.py +63 -0
- package/scripts/specs_convention_marker.py +103 -0
- package/scripts/test_improve_resume.py +277 -0
- package/scripts/test_review_mechanics.py +958 -0
- package/scripts/token_efficiency_review.py +322 -0
- package/scripts/verdict_scope.py +285 -0
- package/scripts/verify_gherkin_quality_critic_isolation.py +296 -0
- package/scripts/verify_tier.py +157 -0
- package/skills/adr-tools/SKILL.md +118 -0
- package/skills/agent-readiness/SKILL.md +105 -0
- package/skills/agent-readiness/ai_friendly_analyzers.py +326 -0
- package/skills/agent-readiness/scanner.py +441 -0
- package/skills/agent-readiness/scorecard.yaml +88 -0
- package/skills/api-design/SKILL.md +115 -0
- package/skills/apply-fixes/SKILL.md +171 -0
- package/skills/apply-test-doubles/SKILL.md +321 -0
- package/skills/artifact-lifecycle/SKILL.md +127 -0
- package/skills/autoship/SKILL.md +1124 -0
- package/skills/benchmark/SKILL.md +105 -0
- package/skills/branch-workflow/SKILL.md +89 -0
- package/skills/browse/SKILL.md +184 -0
- package/skills/browser-testing/SKILL.md +62 -0
- package/skills/browser-testing/references/playwright-patterns.md +216 -0
- package/skills/build/SKILL.md +422 -0
- package/skills/build/references/static-self-heal.md +245 -0
- package/skills/careful/SKILL.md +72 -0
- package/skills/cd-test-architecture/SKILL.md +371 -0
- package/skills/ci-debugging/SKILL.md +105 -0
- package/skills/co-evolution-audit/SKILL.md +269 -0
- package/skills/code-review/SKILL.md +1015 -0
- package/skills/code-review/examples/aggregated-sample.json +56 -0
- package/skills/code-review/examples/sample-report.md +41 -0
- package/skills/code-review/output-format.md +478 -0
- package/skills/code-review/scripts/activation.py +86 -0
- package/skills/code-review/scripts/change_impact.py +357 -0
- package/skills/code-review/scripts/change_shape.py +372 -0
- package/skills/code-review/scripts/change_size.py +212 -0
- package/skills/code-review/scripts/changed_file_list.py +141 -0
- package/skills/code-review/scripts/closing_pass.py +187 -0
- package/skills/code-review/scripts/consolidate.py +277 -0
- package/skills/code-review/scripts/contract_failure_report.py +185 -0
- package/skills/code-review/scripts/dispatch_reconcile.py +66 -0
- package/skills/code-review/scripts/dispatch_waves.py +164 -0
- package/skills/code-review/scripts/finding_signature.py +446 -0
- package/skills/code-review/scripts/ledger.py +283 -0
- package/skills/code-review/scripts/partition.py +169 -0
- package/skills/code-review/scripts/render_tiered_findings.py +274 -0
- package/skills/code-review/scripts/repo_invariants.py +1066 -0
- package/skills/code-review/scripts/review_context_pack.py +306 -0
- package/skills/code-review/scripts/review_round_log.py +345 -0
- package/skills/code-review/scripts/review_value_coverage.py +297 -0
- package/skills/code-review/scripts/validate_review_output.py +467 -0
- package/skills/code-review/sliced-mode.md +205 -0
- package/skills/competitive-analysis/SKILL.md +191 -0
- package/skills/context-loading-protocol/SKILL.md +157 -0
- package/skills/continue/SKILL.md +90 -0
- package/skills/cost-report/SKILL.md +178 -0
- package/skills/coverage-baseline/SKILL.md +335 -0
- package/skills/coverage-baseline/references/multi-project-discovery.md +202 -0
- package/skills/coverage-delta/SKILL.md +181 -0
- package/skills/coverage-delta/references/mutation-gate.md +70 -0
- package/skills/design-doc/SKILL.md +95 -0
- package/skills/design-interrogation/SKILL.md +89 -0
- package/skills/design-it-twice/SKILL.md +91 -0
- package/skills/docker-image-audit/SKILL.md +108 -0
- package/skills/docker-image-audit/references/install-guide.md +64 -0
- package/skills/docker-image-audit/references/report-template.md +73 -0
- package/skills/docker-image-create/SKILL.md +185 -0
- package/skills/domain-analysis/SKILL.md +183 -0
- package/skills/domain-driven-design/SKILL.md +194 -0
- package/skills/exploratory-testing/SKILL.md +108 -0
- package/skills/explore/SKILL.md +51 -0
- package/skills/farley-score/SKILL.md +165 -0
- package/skills/feature-file-validation/SKILL.md +78 -0
- package/skills/feature-file-validation/references/validation-rules.md +115 -0
- package/skills/feedback-learning/SKILL.md +414 -0
- package/skills/fix/SKILL.md +450 -0
- package/skills/freeze/SKILL.md +68 -0
- package/skills/frontend-architecture/SKILL.md +113 -0
- package/skills/gherkin-derive/SKILL.md +630 -0
- package/skills/gherkin-public/SKILL.md +266 -0
- package/skills/governance-compliance/SKILL.md +150 -0
- package/skills/guard/SKILL.md +75 -0
- package/skills/handoff/SKILL.md +139 -0
- package/skills/handoff/references/summary-templates.md +242 -0
- package/skills/harness-audit/SKILL.md +751 -0
- package/skills/harness-audit/scripts/lesson_validate.py +386 -0
- package/skills/harness-audit/scripts/redundancy_criterion.py +188 -0
- package/skills/headless-run/SKILL.md +45 -0
- package/skills/headless-run/scripts/isolated_dispatch.py +381 -0
- package/skills/help/SKILL.md +72 -0
- package/skills/hexagonal-architecture/SKILL.md +85 -0
- package/skills/human-oversight-protocol/SKILL.md +224 -0
- package/skills/issues-from-assessment/SKILL.md +223 -0
- package/skills/issues-from-plan/SKILL.md +133 -0
- package/skills/legacy-code/SKILL.md +132 -0
- package/skills/mermaid-diagramming/SKILL.md +120 -0
- package/skills/mutation-night-watch/SKILL.md +154 -0
- package/skills/mutation-night-watch/references/scheduling.md +135 -0
- package/skills/mutation-testing/SKILL.md +396 -0
- package/skills/mutation-testing/references/languages/csharp-stryker-net.md +676 -0
- package/skills/mutation-testing/references/languages/go-go-mutesting.md +95 -0
- package/skills/mutation-testing/references/languages/java-pitest.md +77 -0
- package/skills/mutation-testing/references/languages/javascript-stryker.md +188 -0
- package/skills/mutation-testing/references/languages/python-mutmut.md +97 -0
- package/skills/mutation-testing/references/time-estimation.md +34 -0
- package/skills/mutation-testing/references/tool-detection.md +15 -0
- package/skills/mutation-testing/references/workflow-callers.md +23 -0
- package/skills/mutation-testing/scripts/__pycache__/xunit_v3_feature_detector.cpython-314.pyc +0 -0
- package/skills/mutation-testing/scripts/csharp_stryker_net_slice_runner.py +635 -0
- package/skills/mutation-testing/scripts/csharp_stryker_net_status_loop.py +525 -0
- package/skills/mutation-testing/scripts/csharp_stryker_net_wrapper.py +681 -0
- package/skills/mutation-testing/scripts/mutation_baseline_reuse.py +292 -0
- package/skills/mutation-testing/scripts/mutation_exclude_policy.py +268 -0
- package/skills/mutation-testing/scripts/mutation_feasibility_gate.py +463 -0
- package/skills/mutation-testing/scripts/mutation_kill_headless.py +331 -0
- package/skills/mutation-testing/scripts/mutation_kill_insert.py +199 -0
- package/skills/mutation-testing/scripts/mutation_kill_insert_python.py +150 -0
- package/skills/mutation-testing/scripts/mutation_kill_loop.py +869 -0
- package/skills/mutation-testing/scripts/mutation_kill_loop_python.py +949 -0
- package/skills/mutation-testing/scripts/mutation_kill_retry.py +592 -0
- package/skills/mutation-testing/scripts/mutation_kill_shared.py +620 -0
- package/skills/mutation-testing/scripts/mutation_nightwatch.py +462 -0
- package/skills/mutation-testing/scripts/mutation_nightwatch_stacks.py +425 -0
- package/skills/mutation-testing/scripts/mutation_report.py +743 -0
- package/skills/mutation-testing/scripts/mutation_report_cli.py +175 -0
- package/skills/mutation-testing/scripts/mutation_safety_gate.py +69 -0
- package/skills/mutation-testing/scripts/stryker_shard_pipeline.py +847 -0
- package/skills/mutation-testing/scripts/stryker_shard_setup.py +440 -0
- package/skills/mutation-testing/scripts/stryker_timeout_retry.py +142 -0
- package/skills/mutation-testing/scripts/xunit_v3_feature_detector.py +341 -0
- package/skills/performance-benchmark/SKILL.md +174 -0
- package/skills/performance-benchmark/examples/report-format.md +43 -0
- package/skills/performance-benchmark/references/benchmark-script.md +169 -0
- package/skills/performance-metrics/SKILL.md +265 -0
- package/skills/plan/SKILL.md +199 -0
- package/skills/plan/references/gherkin-persistence.md +43 -0
- package/skills/plan/references/plan-template.md +182 -0
- package/skills/pr/SKILL.md +289 -0
- package/skills/pr/scripts/gate_retry_state.py +368 -0
- package/skills/project-init/README.md +141 -0
- package/skills/project-init/SKILL.md +1197 -0
- package/skills/project-init/evals/evals.json +200 -0
- package/skills/project-init/references/capability-tools.md +55 -0
- package/skills/project-init/references/configs.md +221 -0
- package/skills/property-based-testing/SKILL.md +121 -0
- package/skills/property-based-testing/fixtures/invariant_fixture.py +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/README.md +42 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/LICENSE +21 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/README.md +263 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.js +12147 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/package.json +3 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/types57/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.js +12011 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/rolldown-runtime-D7D4PA-g.js +13 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/types57/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/package.json +94 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/LICENSE +21 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/README.md +168 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/RandomGenerator-DcXj09Ch.d.ts +14 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.js +38 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.js +18 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.js +22 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.js +134 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/RandomGenerator-DcXj09Ch.d.ts +14 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.js +37 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.js +17 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.js +21 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.js +133 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.js +44 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.js +90 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.js +80 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.js +78 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/package.json +3 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.d.ts +16 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.d.ts +2 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.js +8 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.d.ts +12 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.js +9 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.js +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.js +46 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.js +92 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.js +82 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.js +80 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.d.ts +16 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.d.ts +2 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.js +9 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.d.ts +12 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.js +10 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.js +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/package.json +133 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/package-lock.json +1179 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/package.json +14 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.js +29 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.properties.test.js +16 -0
- package/skills/property-based-testing/fixtures/no_property_fixture.py +10 -0
- package/skills/property-based-testing/fixtures/roundtrip_fixture.py +16 -0
- package/skills/property-based-testing/references/languages/javascript.md +54 -0
- package/skills/property-based-testing/scripts/detect_and_dispatch.py +80 -0
- package/skills/property-based-testing/scripts/hypothesis_scaffold.py +276 -0
- package/skills/proxy-resilience/SKILL.md +84 -0
- package/skills/quality-gate-pipeline/SKILL.md +184 -0
- package/skills/quality-targets-converge/SKILL.md +254 -0
- package/skills/repo-review/SKILL.md +159 -0
- package/skills/report-pdf/SKILL.md +66 -0
- package/skills/review/SKILL.md +47 -0
- package/skills/review-agent/SKILL.md +152 -0
- package/skills/review-summary/SKILL.md +73 -0
- package/skills/run-report/SKILL.md +70 -0
- package/skills/semantic-duplication-scan/SKILL.md +337 -0
- package/skills/semantic-scan/SKILL.md +53 -0
- package/skills/semgrep-analyze/SKILL.md +139 -0
- package/skills/setup/SKILL.md +1122 -0
- package/skills/ship/SKILL.md +240 -0
- package/skills/source-verification/SKILL.md +210 -0
- package/skills/source-verification/scripts/claim_extractor.py +155 -0
- package/skills/specs/.size-baseline.json +4 -0
- package/skills/specs/SKILL.md +243 -0
- package/skills/specs/references/completeness-checklist.md +83 -0
- package/skills/specs/references/extraction.md +58 -0
- package/skills/specs/references/glossary.md +59 -0
- package/skills/specs/references/persistence.md +115 -0
- package/skills/specs/references/predictability-check.md +77 -0
- package/skills/static-analysis-integration/SKILL.md +235 -0
- package/skills/static-analysis-integration/adapters/_envelope.py +26 -0
- package/skills/static-analysis-integration/adapters/jscpd-adapter.py +66 -0
- package/skills/static-analysis-integration/adapters/lizard-adapter.py +81 -0
- package/skills/static-analysis-integration/adapters/mypy-adapter.py +50 -0
- package/skills/static-analysis-integration/adapters/mypy-src-layout.py +93 -0
- package/skills/static-analysis-integration/adapters/security-review-adapter.py +212 -0
- package/skills/static-analysis-integration/maintenance.md +23 -0
- package/skills/static-analysis-integration/references/language-setup.md +228 -0
- package/skills/static-analysis-integration/references/sarif-parser.md +124 -0
- package/skills/static-analysis-integration/references/security-review-adapter.md +118 -0
- package/skills/static-analysis-integration/references/tool-configs.md +617 -0
- package/skills/static-analysis-integration/rulesets/pmd-quickstart.xml +24 -0
- package/skills/stryker-xunit-v2-shim/SKILL.md +274 -0
- package/skills/stryker-xunit-v2-shim/references/shim-howto.md +256 -0
- package/skills/stryker-xunit-v2-shim/scripts/generate_shim.py +143 -0
- package/skills/systematic-debugging/SKILL.md +130 -0
- package/skills/telemetry/SKILL.md +75 -0
- package/skills/test-audit-disable/SKILL.md +129 -0
- package/skills/test-design/SKILL.md +177 -0
- package/skills/test-design/scripts/__pycache__/internal_double_detector.cpython-314.pyc +0 -0
- package/skills/test-design/scripts/internal_double_detector.py +631 -0
- package/skills/test-design-advisor/SKILL.md +166 -0
- package/skills/test-driven-development/SKILL.md +169 -0
- package/skills/test-health/SKILL.md +262 -0
- package/skills/test-improve/SKILL.md +239 -0
- package/skills/test-improve/references/phase-0-approach-contract.md +228 -0
- package/skills/test-improve/references/phase-1-analyze.md +131 -0
- package/skills/test-improve/references/phase-2-baseline.md +121 -0
- package/skills/test-improve/references/phase-3-derive-gherkin.md +53 -0
- package/skills/test-improve/references/phase-4-plan-fixes.md +34 -0
- package/skills/test-improve/references/phase-5-improve.md +215 -0
- package/skills/test-improve/references/phase-6-refactor-decision.md +45 -0
- package/skills/test-improve/references/phase-7-refactor.md +44 -0
- package/skills/test-improve/references/phase-8-validate.md +66 -0
- package/skills/test-improve/references/phase-9-close-out-prompt.md +11 -0
- package/skills/test-improve/references/phase-9-report.md +62 -0
- package/skills/test-improve/references/review-loop.md +92 -0
- package/skills/test-improve/templates/executive-summary.md +123 -0
- package/skills/threat-modeling/SKILL.md +108 -0
- package/skills/triage/SKILL.md +211 -0
- package/skills/ubiquitous-language/SKILL.md +192 -0
- package/skills/ubiquitous-language/scripts/collect_domain_signals.py +300 -0
- package/skills/unfreeze/SKILL.md +37 -0
- package/skills/upgrade/SKILL.md +31 -0
- package/skills/upgrade/scripts/check_version_drift.py +113 -0
- package/skills/upgrade/scripts/enable_autoupdate.py +149 -0
- package/skills/version/SKILL.md +25 -0
- package/sync/__pycache__/sync_upstream.cpython-314.pyc +0 -0
- package/sync/sync_upstream.py +293 -0
- package/templates/ACCEPTED-RISKS.md.tmpl +46 -0
- package/templates/agents/agent-template.md +151 -0
- package/templates/agents/angular-testing.md +66 -0
- package/templates/agents/csharp-quality.md +63 -0
- package/templates/agents/esm-enforcer.md +52 -0
- package/templates/agents/front-end-testing.md +65 -0
- package/templates/agents/go-quality.md +65 -0
- package/templates/agents/python-quality.md +62 -0
- package/templates/agents/react-testing.md +61 -0
- package/templates/agents/ts-enforcer.md +60 -0
- package/templates/agents/twelve-factor-audit.md +49 -0
- package/tools/entropy-check.py +250 -0
- package/tools/model-hash-verify.py +213 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""gherkin_effectiveness_rollup.py — roll up gherkin-derive scenario data
|
|
3
|
+
against the coverage/mutation measurements the plugin already computes,
|
|
4
|
+
so there is a signal on whether BDD-derived tests catch more real defects
|
|
5
|
+
than ad hoc ones (issue #1296).
|
|
6
|
+
|
|
7
|
+
Today `/gherkin-derive` writes a surface inventory (`gherkin.md`) and
|
|
8
|
+
`/gherkin-public` writes a scenario→Story map (`gherkin-bindings.json`), while
|
|
9
|
+
`/coverage-baseline`, `/coverage-delta`, and the mutation baseline/history
|
|
10
|
+
files separately track coverage and mutation-survivor counts. Nothing
|
|
11
|
+
correlates the two. This script reads whatever of those files exist for one
|
|
12
|
+
workflow run and emits one JSONL record per discovered scenario to
|
|
13
|
+
`.claude/metrics/gherkin-derive-effectiveness.jsonl` (append-only, per the
|
|
14
|
+
`performance-metrics` skill's convention).
|
|
15
|
+
|
|
16
|
+
**Attribution granularity is honest, not exact.** No file in this plugin
|
|
17
|
+
today maps an individual scenario to the specific test(s) that exercise it
|
|
18
|
+
at the mutation/coverage level — `gherkin-bindings.json` maps a scenario to a
|
|
19
|
+
*Story* (which may bind several tests), and coverage/mutation deltas are
|
|
20
|
+
measured per-file or repo-wide, not per-scenario. This script therefore
|
|
21
|
+
reports the best available repo/workflow-level coverage and mutation deltas
|
|
22
|
+
alongside each scenario's provenance and binding mode, and does NOT claim a
|
|
23
|
+
delta is caused solely by that scenario's test. Treat the emitted
|
|
24
|
+
`coverage_delta` / `mutation_delta` fields as workflow-level context for the
|
|
25
|
+
scenario, not as isolated per-scenario attribution.
|
|
26
|
+
|
|
27
|
+
The surface-inventory table format is not fixed by `/gherkin-derive` today,
|
|
28
|
+
so parsing is deliberately lenient: any markdown table under the file is
|
|
29
|
+
scanned for columns whose header contains "surface", "source", "provenance",
|
|
30
|
+
or "mode" (case-insensitive); a file with no such table yields a warning on
|
|
31
|
+
stderr and zero scenario records, rather than crashing.
|
|
32
|
+
|
|
33
|
+
Stdlib-only. (ADR 0014/0015).
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
import argparse
|
|
39
|
+
import json
|
|
40
|
+
import re
|
|
41
|
+
import sys
|
|
42
|
+
from pathlib import Path
|
|
43
|
+
|
|
44
|
+
_HOOKS_LIB_DIR = Path(__file__).resolve().parent.parent / "hooks" / "lib"
|
|
45
|
+
if str(_HOOKS_LIB_DIR) not in sys.path:
|
|
46
|
+
sys.path.insert(0, str(_HOOKS_LIB_DIR))
|
|
47
|
+
|
|
48
|
+
import artifact_paths
|
|
49
|
+
from atomic_state import append_line_locked
|
|
50
|
+
|
|
51
|
+
_TABLE_ROW_RE = re.compile(r"^\s*\|(.+)\|\s*$")
|
|
52
|
+
_SEPARATOR_CELL_RE = re.compile(r"^\s*:?-{2,}:?\s*$")
|
|
53
|
+
|
|
54
|
+
# Header keywords this parser recognizes, mapped to the output field name.
|
|
55
|
+
_COLUMN_KEYWORDS: dict[str, str] = {
|
|
56
|
+
"surface": "surface",
|
|
57
|
+
"source": "discovery_source",
|
|
58
|
+
"provenance": "provenance",
|
|
59
|
+
"mode": "binding_mode",
|
|
60
|
+
"file": "files",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class RollupWarning(Exception):
|
|
65
|
+
"""Non-fatal condition worth surfacing on stderr; callers keep going."""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _split_row(line: str) -> list[str]:
|
|
69
|
+
return [cell.strip() for cell in line.strip().strip("|").split("|")]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def parse_surface_table(text: str) -> list[dict[str, str]]:
|
|
73
|
+
"""Return one dict per data row of the first markdown table whose header
|
|
74
|
+
matches at least one column in `_COLUMN_KEYWORDS`. Returns [] if no such
|
|
75
|
+
table is found."""
|
|
76
|
+
lines = text.splitlines()
|
|
77
|
+
i = 0
|
|
78
|
+
while i < len(lines) - 1:
|
|
79
|
+
header_match = _TABLE_ROW_RE.match(lines[i])
|
|
80
|
+
sep_match = _TABLE_ROW_RE.match(lines[i + 1]) if header_match else None
|
|
81
|
+
if header_match and sep_match:
|
|
82
|
+
sep_cells = _split_row(lines[i + 1])
|
|
83
|
+
if all(_SEPARATOR_CELL_RE.match(c) for c in sep_cells if c):
|
|
84
|
+
header_cells = [c.lower() for c in _split_row(lines[i])]
|
|
85
|
+
field_for_col = {}
|
|
86
|
+
for idx, cell in enumerate(header_cells):
|
|
87
|
+
for keyword, field in _COLUMN_KEYWORDS.items():
|
|
88
|
+
if keyword in cell:
|
|
89
|
+
field_for_col[idx] = field
|
|
90
|
+
break
|
|
91
|
+
if field_for_col:
|
|
92
|
+
rows: list[dict[str, str]] = []
|
|
93
|
+
j = i + 2
|
|
94
|
+
while j < len(lines) and _TABLE_ROW_RE.match(lines[j]):
|
|
95
|
+
cells = _split_row(lines[j])
|
|
96
|
+
row = {
|
|
97
|
+
field: cells[idx]
|
|
98
|
+
for idx, field in field_for_col.items()
|
|
99
|
+
if idx < len(cells)
|
|
100
|
+
}
|
|
101
|
+
if row:
|
|
102
|
+
rows.append(row)
|
|
103
|
+
j += 1
|
|
104
|
+
return rows
|
|
105
|
+
i += 1
|
|
106
|
+
return []
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def load_scenarios(gherkin_md: Path | None) -> list[dict[str, str]]:
|
|
110
|
+
if gherkin_md is None:
|
|
111
|
+
return []
|
|
112
|
+
if not gherkin_md.is_file():
|
|
113
|
+
raise RollupWarning(f"surface inventory not found: {gherkin_md}")
|
|
114
|
+
rows = parse_surface_table(gherkin_md.read_text(encoding="utf-8"))
|
|
115
|
+
if not rows:
|
|
116
|
+
raise RollupWarning(f"no recognizable surface table in: {gherkin_md}")
|
|
117
|
+
return rows
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def load_json(path: Path | None) -> dict | None:
|
|
121
|
+
if path is None:
|
|
122
|
+
return None
|
|
123
|
+
if not path.is_file():
|
|
124
|
+
return None
|
|
125
|
+
with path.open(encoding="utf-8") as fh:
|
|
126
|
+
return json.load(fh)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def load_bindings(bindings_json: Path | None) -> dict[str, object]:
|
|
130
|
+
data = load_json(bindings_json)
|
|
131
|
+
return data if isinstance(data, dict) else {}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def scenario_key(surface: str) -> str:
|
|
135
|
+
"""Best-effort key to look up a surface in `gherkin-bindings.json`, which
|
|
136
|
+
is keyed `<feature-file>::<scenario-name>`. The inventory table has no
|
|
137
|
+
fixed scenario-name column, so this matches by surface/feature-file
|
|
138
|
+
prefix rather than requiring an exact key."""
|
|
139
|
+
return surface.strip()
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def coverage_delta(baseline: dict | None, current: dict | None) -> dict | None:
|
|
143
|
+
if not baseline or not current:
|
|
144
|
+
return None
|
|
145
|
+
delta = {}
|
|
146
|
+
for field in ("line_pct", "branch_pct"):
|
|
147
|
+
b, c = baseline.get(field), current.get(field)
|
|
148
|
+
if isinstance(b, (int, float)) and isinstance(c, (int, float)):
|
|
149
|
+
delta[field] = round(c - b, 2)
|
|
150
|
+
return delta or None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def mutation_delta(baseline: dict | None, current: dict | None) -> dict | None:
|
|
154
|
+
if not baseline or not current:
|
|
155
|
+
return None
|
|
156
|
+
b, c = baseline.get("survivors_after"), current.get("survivors_after")
|
|
157
|
+
if isinstance(b, (int, float)) and isinstance(c, (int, float)):
|
|
158
|
+
return {"survivors_after_delta": c - b}
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def build_records(
|
|
163
|
+
scenarios: list[dict[str, str]],
|
|
164
|
+
bindings: dict[str, object],
|
|
165
|
+
cov_delta: dict | None,
|
|
166
|
+
mut_delta: dict | None,
|
|
167
|
+
) -> list[dict]:
|
|
168
|
+
records = []
|
|
169
|
+
for row in scenarios:
|
|
170
|
+
surface = row.get("surface", "")
|
|
171
|
+
record = {
|
|
172
|
+
"surface": surface or None,
|
|
173
|
+
"discovery_source": row.get("discovery_source"),
|
|
174
|
+
"provenance": row.get("provenance"),
|
|
175
|
+
"binding_mode": row.get("binding_mode"),
|
|
176
|
+
"bound_story": bindings.get(scenario_key(surface)),
|
|
177
|
+
"coverage_delta": cov_delta,
|
|
178
|
+
"mutation_delta": mut_delta,
|
|
179
|
+
}
|
|
180
|
+
records.append(record)
|
|
181
|
+
return records
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def append_jsonl(records: list[dict], out_path: Path) -> int:
|
|
185
|
+
"""Append each record as one JSON line, serialized via
|
|
186
|
+
`atomic_state.append_line_locked` (#1901) so two concurrent rollup runs
|
|
187
|
+
writing to the same stream cannot interleave their bytes into one
|
|
188
|
+
corrupted line — matching the pattern #1896 applied to the plugin's
|
|
189
|
+
other `.claude/metrics/*.jsonl` appenders. `fail_open=False` re-raises a
|
|
190
|
+
write error after the lock releases rather than swallowing it, matching
|
|
191
|
+
this function's previous behavior (a bare `open()`/`write()` that
|
|
192
|
+
propagated any OSError to the caller)."""
|
|
193
|
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
194
|
+
for record in records:
|
|
195
|
+
line = json.dumps(record, sort_keys=True) + "\n"
|
|
196
|
+
append_line_locked(out_path, line, fail_open=False)
|
|
197
|
+
return len(records)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def main(argv: list[str] | None = None) -> int:
|
|
201
|
+
# Resolved per-invocation (not at import time): shells out to git via
|
|
202
|
+
# artifact_paths.metrics_dir(), and freezing that at module-import time
|
|
203
|
+
# would pin the resolved root to whatever cwd happened to be active
|
|
204
|
+
# during import (e.g. test collection), not the invocation's cwd.
|
|
205
|
+
default_out = artifact_paths.metrics_dir() / "gherkin-derive-effectiveness.jsonl"
|
|
206
|
+
|
|
207
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
208
|
+
parser.add_argument("--gherkin-md", type=Path, help="surface inventory markdown (gherkin.md)")
|
|
209
|
+
parser.add_argument("--bindings-json", type=Path, help="gherkin-bindings.json, if present")
|
|
210
|
+
parser.add_argument("--baseline-coverage", type=Path, help="baseline-coverage.json")
|
|
211
|
+
parser.add_argument("--current-coverage", type=Path, help="latest coverage measurement (same shape as baseline-coverage.json)")
|
|
212
|
+
parser.add_argument("--baseline-mutation", type=Path, help="baseline-mutation.json")
|
|
213
|
+
parser.add_argument("--current-mutation", type=Path, help="latest mutation measurement (same shape as baseline-mutation.json)")
|
|
214
|
+
parser.add_argument("--out", type=Path, default=default_out, help=f"output JSONL path (default: {default_out})")
|
|
215
|
+
args = parser.parse_args(argv)
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
scenarios = load_scenarios(args.gherkin_md)
|
|
219
|
+
except RollupWarning as exc:
|
|
220
|
+
print(f"gherkin_effectiveness_rollup: {exc}", file=sys.stderr)
|
|
221
|
+
scenarios = []
|
|
222
|
+
|
|
223
|
+
if not scenarios:
|
|
224
|
+
print("gherkin_effectiveness_rollup: no scenarios to roll up; nothing written", file=sys.stderr)
|
|
225
|
+
return 0
|
|
226
|
+
|
|
227
|
+
bindings = load_bindings(args.bindings_json)
|
|
228
|
+
cov_delta = coverage_delta(load_json(args.baseline_coverage), load_json(args.current_coverage))
|
|
229
|
+
mut_delta = mutation_delta(load_json(args.baseline_mutation), load_json(args.current_mutation))
|
|
230
|
+
|
|
231
|
+
records = build_records(scenarios, bindings, cov_delta, mut_delta)
|
|
232
|
+
count = append_jsonl(records, args.out)
|
|
233
|
+
print(f"gherkin_effectiveness_rollup: wrote {count} record(s) to {args.out}")
|
|
234
|
+
return 0
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
if __name__ == "__main__":
|
|
238
|
+
sys.exit(main())
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""gherkin_failure_path_gate.py — flag Feature: blocks with no failure-path
|
|
3
|
+
scenario (issue #1420).
|
|
4
|
+
|
|
5
|
+
Mirrors `gherkin_stub_gate.py`'s shape: scans `.feature` files under one or
|
|
6
|
+
more directories, parses each `Feature:` block's scenarios, and flags any
|
|
7
|
+
block whose scenarios (title + step text, case-insensitive) match none of a
|
|
8
|
+
keyword list. This is a deliberately simple, best-effort heuristic, not a
|
|
9
|
+
semantic classifier — both false negatives (a genuine failure scenario
|
|
10
|
+
phrased without any listed keyword) and false positives (a happy-path
|
|
11
|
+
scenario coincidentally containing a listed substring, e.g. "does not exceed
|
|
12
|
+
the limit") are possible and accepted; `--keyword`/`--extra-keyword` let a
|
|
13
|
+
repo tune the list.
|
|
14
|
+
|
|
15
|
+
Stdlib-only. (ADR 0014/0015).
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
python3 gherkin_failure_path_gate.py --dir <dir> [--dir <dir> ...] [--json]
|
|
19
|
+
python3 gherkin_failure_path_gate.py --dir features --extra-keyword declined
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import argparse
|
|
25
|
+
import json
|
|
26
|
+
import sys
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
_HERE = Path(__file__).resolve().parent
|
|
30
|
+
sys.path.insert(0, str(_HERE / "lib"))
|
|
31
|
+
|
|
32
|
+
from _gherkin_text import FEATURE_PREFIX as _FEATURE_PREFIX
|
|
33
|
+
from _gherkin_text import SCENARIO_OUTLINE_PREFIX as _SCENARIO_OUTLINE_PREFIX
|
|
34
|
+
from _gherkin_text import SCENARIO_PREFIX as _SCENARIO_PREFIX
|
|
35
|
+
from _gherkin_text import safe_for_terminal as _safe_for_terminal
|
|
36
|
+
from _gherkin_text import stripped as _stripped
|
|
37
|
+
from _gherkin_text import trim_trailing_tag_run as _trim_trailing_tag_run
|
|
38
|
+
from _vendored_tree import find_files as _find_files
|
|
39
|
+
|
|
40
|
+
# Entries are literal substrings, not stems — "exceeds" does not match
|
|
41
|
+
# "exceed" — matching gherkin_feature_merge.py's `is_stale` in spirit (a
|
|
42
|
+
# deliberately simple, best-effort check, not a semantic classifier). A
|
|
43
|
+
# cleanup pass "fixing" what looks like a stray verb-form mismatch would
|
|
44
|
+
# silently change gate behavior: the documented false-positive test
|
|
45
|
+
# (test_extra_keyword_can_produce_a_documented_false_positive) specifically
|
|
46
|
+
# relies on "exceed" being absent from this list by default. "exceeds" is
|
|
47
|
+
# the intended default per issue #1420 — the false positive it enables (a
|
|
48
|
+
# scenario using "exceed" instead) is accepted and demonstrated by that
|
|
49
|
+
# same test via --extra-keyword, not an oversight.
|
|
50
|
+
DEFAULT_KEYWORDS = (
|
|
51
|
+
"invalid",
|
|
52
|
+
"error",
|
|
53
|
+
"fail",
|
|
54
|
+
"unauthorized",
|
|
55
|
+
"not found",
|
|
56
|
+
"denied",
|
|
57
|
+
"timeout",
|
|
58
|
+
"exceeds",
|
|
59
|
+
"missing",
|
|
60
|
+
"malformed",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def find_feature_files(directories: list) -> list:
|
|
65
|
+
"""Return every `.feature` file under `directories`, pruning vendored
|
|
66
|
+
trees, sorted for deterministic output."""
|
|
67
|
+
return _find_files(directories, lambda path: path.suffix == ".feature")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def parse_features(text: str, path) -> list:
|
|
71
|
+
"""Return one entry per `Feature:` block: {file, feature_title, line,
|
|
72
|
+
scenario_titles, scenario_text} — scenario_text is every non-header line
|
|
73
|
+
in the block, used for keyword matching against step text as well as
|
|
74
|
+
titles. `file` is set here from `path` (a caller no longer patches it in
|
|
75
|
+
afterward) so a feature dict is never partially constructed — the
|
|
76
|
+
"title" key is also named `feature_title` here to match every other
|
|
77
|
+
consumer of this concept (`gherkin_feature_merge.py`'s `--feature-title`,
|
|
78
|
+
and this module's own finding dict below)."""
|
|
79
|
+
lines = text.splitlines(keepends=True)
|
|
80
|
+
features = []
|
|
81
|
+
header_indices = [
|
|
82
|
+
i for i, line in enumerate(lines) if _stripped(line).strip().startswith(_FEATURE_PREFIX)
|
|
83
|
+
]
|
|
84
|
+
for idx, header_index in enumerate(header_indices):
|
|
85
|
+
title = _stripped(lines[header_index]).strip()[len(_FEATURE_PREFIX) :].strip()
|
|
86
|
+
end_index = header_indices[idx + 1] if idx + 1 < len(header_indices) else len(lines)
|
|
87
|
+
# A `@tag`/blank-line run immediately preceding the next Feature:
|
|
88
|
+
# header belongs to that next block, not this one. Without this, a
|
|
89
|
+
# tag like `@error-handling` on the *following* Feature block leaks
|
|
90
|
+
# into this block's scenario_text, and a keyword match against that
|
|
91
|
+
# leaked tag can make this block pass the gate even though it has no
|
|
92
|
+
# failure-path scenario of its own.
|
|
93
|
+
end_index = _trim_trailing_tag_run(lines, header_index, end_index)
|
|
94
|
+
body = lines[header_index + 1 : end_index]
|
|
95
|
+
scenario_titles = []
|
|
96
|
+
for line in body:
|
|
97
|
+
stripped = _stripped(line).strip()
|
|
98
|
+
if stripped.startswith(_SCENARIO_OUTLINE_PREFIX):
|
|
99
|
+
scenario_titles.append(stripped[len(_SCENARIO_OUTLINE_PREFIX) :].strip())
|
|
100
|
+
elif stripped.startswith(_SCENARIO_PREFIX):
|
|
101
|
+
scenario_titles.append(stripped[len(_SCENARIO_PREFIX) :].strip())
|
|
102
|
+
features.append(
|
|
103
|
+
{
|
|
104
|
+
"file": str(path),
|
|
105
|
+
"feature_title": title,
|
|
106
|
+
"line": header_index + 1,
|
|
107
|
+
"scenario_titles": scenario_titles,
|
|
108
|
+
"scenario_text": "".join(body),
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
return features
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def find_missing_failure_path(features: list, keywords) -> list:
|
|
115
|
+
"""Return {file, line, feature_title} for every feature with zero
|
|
116
|
+
scenarios (title + step text, case-insensitive) matching `keywords`."""
|
|
117
|
+
findings = []
|
|
118
|
+
lowered_keywords = [k.lower() for k in keywords]
|
|
119
|
+
for feature in features:
|
|
120
|
+
haystack = (feature["scenario_text"] + " " + " ".join(feature["scenario_titles"])).lower()
|
|
121
|
+
if not any(keyword in haystack for keyword in lowered_keywords):
|
|
122
|
+
findings.append(
|
|
123
|
+
{
|
|
124
|
+
"file": feature["file"],
|
|
125
|
+
"line": feature["line"],
|
|
126
|
+
"feature_title": feature["feature_title"],
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
return findings
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def main(argv: list | None = None) -> int:
|
|
133
|
+
parser = argparse.ArgumentParser(
|
|
134
|
+
prog="gherkin_failure_path_gate.py",
|
|
135
|
+
description="Flag Feature: blocks with no failure-path scenario.",
|
|
136
|
+
)
|
|
137
|
+
parser.add_argument("--dir", dest="dirs", action="append", type=Path, required=True)
|
|
138
|
+
parser.add_argument("--json", action="store_true")
|
|
139
|
+
parser.add_argument(
|
|
140
|
+
"--keyword",
|
|
141
|
+
dest="keywords",
|
|
142
|
+
action="append",
|
|
143
|
+
help=(
|
|
144
|
+
"Discard the default keyword list and use only the --keyword "
|
|
145
|
+
"value(s) given (repeatable) — this REPLACES the defaults, it "
|
|
146
|
+
"does not add to them. To add one term on top of the defaults, "
|
|
147
|
+
"use --extra-keyword instead."
|
|
148
|
+
),
|
|
149
|
+
)
|
|
150
|
+
parser.add_argument(
|
|
151
|
+
"--extra-keyword",
|
|
152
|
+
dest="extra_keywords",
|
|
153
|
+
action="append",
|
|
154
|
+
default=[],
|
|
155
|
+
help="Add to the default keyword list (repeatable).",
|
|
156
|
+
)
|
|
157
|
+
args = parser.parse_args(argv)
|
|
158
|
+
|
|
159
|
+
keywords = list(args.keywords) if args.keywords else list(DEFAULT_KEYWORDS)
|
|
160
|
+
keywords.extend(args.extra_keywords)
|
|
161
|
+
|
|
162
|
+
files = find_feature_files(args.dirs)
|
|
163
|
+
|
|
164
|
+
if not files:
|
|
165
|
+
# A --dir that doesn't exist (or resolves to zero .feature files)
|
|
166
|
+
# used to fall through to "OK: 0 Feature block(s) scanned, all have
|
|
167
|
+
# a failure-path scenario" below — an affirmative all-clear for zero
|
|
168
|
+
# evidence. --dir is not always typed by a human: gherkin-derive
|
|
169
|
+
# composes it from a probe of the target repo, so a gate that can't
|
|
170
|
+
# find anything to scan must say so distinctly, not pass.
|
|
171
|
+
dirs_display = ", ".join(str(d) for d in args.dirs)
|
|
172
|
+
message = f"no .feature files found under {dirs_display} — gate did not run"
|
|
173
|
+
if args.json:
|
|
174
|
+
print(json.dumps({"scanned": [], "findings": [], "warning": message}, indent=2))
|
|
175
|
+
else:
|
|
176
|
+
# --dir is composed by gherkin-derive from a probe of the target
|
|
177
|
+
# repo, not always typed by a human — the same untrusted-path
|
|
178
|
+
# class as a scanned file's path, sanitized the same way.
|
|
179
|
+
print(f"WARN: no .feature files found under {_safe_for_terminal(dirs_display)} — gate did not run")
|
|
180
|
+
return 2
|
|
181
|
+
|
|
182
|
+
all_features = []
|
|
183
|
+
for path in files:
|
|
184
|
+
text = path.read_text(encoding="utf-8", errors="replace")
|
|
185
|
+
all_features.extend(parse_features(text, path))
|
|
186
|
+
|
|
187
|
+
findings = find_missing_failure_path(all_features, keywords)
|
|
188
|
+
|
|
189
|
+
if args.json:
|
|
190
|
+
print(json.dumps({"scanned": [str(f) for f in files], "findings": findings}, indent=2))
|
|
191
|
+
return 1 if findings else 0
|
|
192
|
+
|
|
193
|
+
if findings:
|
|
194
|
+
print(f"FAIL: {len(findings)} Feature block(s) missing a failure-path scenario:")
|
|
195
|
+
for entry in findings:
|
|
196
|
+
path = _safe_for_terminal(entry["file"])
|
|
197
|
+
title = _safe_for_terminal(entry["feature_title"])
|
|
198
|
+
print(f" - {path}:{entry['line']} — {title}")
|
|
199
|
+
return 1
|
|
200
|
+
|
|
201
|
+
print(f"OK: {len(all_features)} Feature block(s) scanned, all have a failure-path scenario.")
|
|
202
|
+
return 0
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
if __name__ == "__main__": # pragma: no cover
|
|
206
|
+
sys.exit(main())
|