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,163 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""gherkin_stub_gate.py — fail closed while bdd-runner step definitions are
|
|
3
|
+
still pending (issue #1391).
|
|
4
|
+
|
|
5
|
+
`bdd-runner` mode wires a real native Gherkin parser (cucumber-js, Reqnroll,
|
|
6
|
+
cucumber-jvm, godog) and `gherkin-derive/SKILL.md` Step 4 generates **pending**
|
|
7
|
+
step-definition stubs so the suite compiles and fails intentionally (red
|
|
8
|
+
before green) — that scaffolding step is correct on its own. Choosing
|
|
9
|
+
`bdd-runner` mode is a decision to end up with fully executing, Gherkin-bound
|
|
10
|
+
tests, not a decision to scaffold placeholders that may or may not get
|
|
11
|
+
finished. This script is the completion gate: it greps the step-definition
|
|
12
|
+
files for the per-language pending marker and fails, listing every remaining
|
|
13
|
+
file:line, when any stub was never filled in.
|
|
14
|
+
|
|
15
|
+
Per-language pending markers (`gherkin-derive/SKILL.md` Step 4's table,
|
|
16
|
+
reused here — not re-derived). The extension -> (language label, markers)
|
|
17
|
+
table itself lives in `lib/_bdd_markers.py` (issue #1421 bug 5) — shared with
|
|
18
|
+
`lib/stub_extractors/__init__.py`, which needs the same mapping and used to
|
|
19
|
+
reach up into this module's `_MARKERS_BY_EXT` via a `sys.path` layer
|
|
20
|
+
inversion to get it. C# carries two markers: `PendingStepException`
|
|
21
|
+
is Reqnroll's current auto-suggested stub, and `StepIsPending()` is its
|
|
22
|
+
deprecated-since-3.3.4 predecessor — still recognized so an older or
|
|
23
|
+
not-yet-regenerated stub isn't a false negative
|
|
24
|
+
(`knowledge/test-stack-profiles/bdd-frameworks.md`):
|
|
25
|
+
|
|
26
|
+
| Language | Framework | Pending marker(s) |
|
|
27
|
+
|----------|-------------------------------------|----------------------------------------------|
|
|
28
|
+
| JS/TS | Cucumber.js | `this.pending()` |
|
|
29
|
+
| Java | Cucumber-JVM | `PendingException` |
|
|
30
|
+
| C# | Reqnroll (xUnit/NUnit/MSTest) | `PendingStepException`, `StepIsPending()` |
|
|
31
|
+
| Go | Godog | `godog.ErrPending` |
|
|
32
|
+
|
|
33
|
+
The language for a given step-definition file is resolved from its
|
|
34
|
+
extension, matched **case-insensitively** — `.js`/`.ts`/`.mjs`/`.cjs` →
|
|
35
|
+
JS/TS, `.java` → Java, `.cs` → C#, `.go` → Go. Files with an unrecognized
|
|
36
|
+
extension are skipped (not every file under a step-definitions directory is
|
|
37
|
+
necessarily a step-definition file). Vendored/generated trees
|
|
38
|
+
(`.git`, `node_modules`, `vendor`, `dist`, `build`, and virtualenv
|
|
39
|
+
directories) are pruned during the scan — the same exclusion set
|
|
40
|
+
`detect_bdd_convention.py` uses — so a stray dependency tree under a scanned
|
|
41
|
+
directory is never walked or grepped — via the shared `_vendored_tree.py`
|
|
42
|
+
helper (issue #1420), also used by `detect_bdd_convention.py` and
|
|
43
|
+
`gherkin_failure_path_gate.py`.
|
|
44
|
+
|
|
45
|
+
Stdlib-only. (ADR 0014/0015).
|
|
46
|
+
|
|
47
|
+
Usage:
|
|
48
|
+
python3 gherkin_stub_gate.py --dir <step-definitions-dir> [--dir <dir> ...]
|
|
49
|
+
python3 gherkin_stub_gate.py --dir features/test-improve/my-slug --json
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
from __future__ import annotations
|
|
53
|
+
|
|
54
|
+
import argparse
|
|
55
|
+
import json
|
|
56
|
+
import sys
|
|
57
|
+
from pathlib import Path
|
|
58
|
+
|
|
59
|
+
_HERE = Path(__file__).resolve().parent
|
|
60
|
+
sys.path.insert(0, str(_HERE / "lib"))
|
|
61
|
+
|
|
62
|
+
from _bdd_markers import MARKERS_BY_EXT as _MARKERS_BY_EXT
|
|
63
|
+
from _gherkin_text import safe_for_terminal as _safe_for_terminal
|
|
64
|
+
from _vendored_tree import find_files as _find_files
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def find_step_definition_files(directories: list[Path]) -> list[Path]:
|
|
68
|
+
"""Return every file under `directories` whose extension is a known
|
|
69
|
+
step-definition language (matched case-insensitively), pruning vendored
|
|
70
|
+
trees, sorted for deterministic output."""
|
|
71
|
+
return _find_files(directories, lambda path: path.suffix.lower() in _MARKERS_BY_EXT)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _matching_marker(line: str, markers: tuple) -> str | None:
|
|
75
|
+
"""Return the first marker in `markers` that occurs in `line`, or
|
|
76
|
+
`None` — the innermost scan of `find_pending_stubs`, extracted so that
|
|
77
|
+
function stays at 2 levels of nesting instead of 4."""
|
|
78
|
+
return next((marker for marker in markers if marker in line), None)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def find_pending_stubs(files: list[Path]) -> list[dict]:
|
|
82
|
+
"""Return one entry per pending-marker occurrence: {file, line, language, text}."""
|
|
83
|
+
pending: list[dict] = []
|
|
84
|
+
for path in files:
|
|
85
|
+
language, markers = _MARKERS_BY_EXT[path.suffix.lower()]
|
|
86
|
+
text = path.read_text(encoding="utf-8", errors="replace")
|
|
87
|
+
for line_no, line in enumerate(text.splitlines(), start=1):
|
|
88
|
+
marker = _matching_marker(line, markers)
|
|
89
|
+
if marker is not None:
|
|
90
|
+
pending.append(
|
|
91
|
+
{
|
|
92
|
+
"file": str(path),
|
|
93
|
+
"line": line_no,
|
|
94
|
+
"language": language,
|
|
95
|
+
"marker": marker,
|
|
96
|
+
"text": line.strip(),
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
return pending
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def main(argv: list[str] | None = None) -> int:
|
|
103
|
+
parser = argparse.ArgumentParser(
|
|
104
|
+
prog="gherkin_stub_gate.py",
|
|
105
|
+
description=(
|
|
106
|
+
"Fail closed when any bdd-runner step-definition file still "
|
|
107
|
+
"carries a pending-stub marker."
|
|
108
|
+
),
|
|
109
|
+
)
|
|
110
|
+
parser.add_argument(
|
|
111
|
+
"--dir",
|
|
112
|
+
dest="dirs",
|
|
113
|
+
action="append",
|
|
114
|
+
type=Path,
|
|
115
|
+
required=True,
|
|
116
|
+
help="Step-definitions directory to scan (repeatable).",
|
|
117
|
+
)
|
|
118
|
+
parser.add_argument("--json", action="store_true", help="machine-readable output")
|
|
119
|
+
args = parser.parse_args(argv)
|
|
120
|
+
|
|
121
|
+
files = find_step_definition_files(args.dirs)
|
|
122
|
+
|
|
123
|
+
if not files:
|
|
124
|
+
# Mirrors gherkin_failure_path_gate.py's identical fix: a --dir that
|
|
125
|
+
# doesn't exist (or resolves to zero step-definition files) used to
|
|
126
|
+
# silently report "OK: 0 ... scanned, no pending stubs remain" — an
|
|
127
|
+
# affirmative all-clear for zero evidence. --dir is composed by
|
|
128
|
+
# gherkin-derive from a probe of the target repo, not always typed
|
|
129
|
+
# by a human, so a gate that scanned nothing must say so distinctly.
|
|
130
|
+
dirs_display = ", ".join(str(d) for d in args.dirs)
|
|
131
|
+
message = f"no step-definition files found under {dirs_display} — gate did not run"
|
|
132
|
+
if args.json:
|
|
133
|
+
print(json.dumps({"scanned": [], "pending": [], "warning": message}, indent=2))
|
|
134
|
+
else:
|
|
135
|
+
# --dir is composed by gherkin-derive from a probe of the target
|
|
136
|
+
# repo, not always typed by a human — the same untrusted-path
|
|
137
|
+
# class as a scanned file's path, sanitized the same way.
|
|
138
|
+
print(
|
|
139
|
+
f"WARN: no step-definition files found under "
|
|
140
|
+
f"{_safe_for_terminal(dirs_display)} — gate did not run"
|
|
141
|
+
)
|
|
142
|
+
return 2
|
|
143
|
+
|
|
144
|
+
pending = find_pending_stubs(files)
|
|
145
|
+
|
|
146
|
+
if args.json:
|
|
147
|
+
print(json.dumps({"scanned": [str(f) for f in files], "pending": pending}, indent=2))
|
|
148
|
+
return 1 if pending else 0
|
|
149
|
+
|
|
150
|
+
if pending:
|
|
151
|
+
print(f"FAIL: {len(pending)} pending step definition(s) — bdd-runner mode is not done:")
|
|
152
|
+
for entry in pending:
|
|
153
|
+
path = _safe_for_terminal(entry["file"])
|
|
154
|
+
text = _safe_for_terminal(entry["text"])
|
|
155
|
+
print(f" - {path}:{entry['line']} ({entry['language']}) — {text}")
|
|
156
|
+
return 1
|
|
157
|
+
|
|
158
|
+
print(f"OK: {len(files)} step-definition file(s) scanned, no pending stubs remain.")
|
|
159
|
+
return 0
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
if __name__ == "__main__": # pragma: no cover
|
|
163
|
+
sys.exit(main())
|
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""gherkin_stub_merge.py — merge newly-derived step-definition stubs into an
|
|
3
|
+
existing step-definition file without clobbering an already-implemented step
|
|
4
|
+
(issue #1421).
|
|
5
|
+
|
|
6
|
+
`gherkin-derive`'s `bdd-runner` mode used to regenerate step-definition stubs
|
|
7
|
+
unconditionally on every run, silently discarding any step a human (or
|
|
8
|
+
`/build`) had already implemented. This module gives it a safe alternative,
|
|
9
|
+
mirroring `gherkin_feature_merge.py`'s read-before-write/merge discipline:
|
|
10
|
+
parse the existing file via `scripts/lib/stub_extractors` (one
|
|
11
|
+
lexically-aware, brace-balance-bounded extractor per language), skip any
|
|
12
|
+
candidate whose step-pattern text already exists there — regardless of
|
|
13
|
+
whether that existing binding is pending or already implemented — and append
|
|
14
|
+
only genuinely-new candidates as pending stubs after the last existing
|
|
15
|
+
binding. An existing binding's body is never rewritten or reordered.
|
|
16
|
+
|
|
17
|
+
`stub_extractors.parse_existing_steps` refuses to guess a span when a file's
|
|
18
|
+
brackets don't lexically balance, or a marker has no attached, boundable
|
|
19
|
+
body — reported as one of two structural-error sentinels
|
|
20
|
+
(`unbalanced-braces`, `dangling-annotation`, re-exported here), plus
|
|
21
|
+
`unsafe-path` at this script's own level for a `--existing` path containing a
|
|
22
|
+
`..` component, `malformed-candidates` when the `--candidates` scratch
|
|
23
|
+
file itself can't be bounded, `unreadable-candidates` when that file is
|
|
24
|
+
missing or can't be read at all, and `unsupported-extension` for an `--ext`
|
|
25
|
+
naming no known step-definition language. Every error leaves the existing
|
|
26
|
+
file completely untouched.
|
|
27
|
+
|
|
28
|
+
Stdlib-only. (ADR 0014/0015).
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
python3 gherkin_stub_merge.py merge --existing <path> --candidates <path> \
|
|
32
|
+
--ext <.js|.ts|.mjs|.cjs|.java|.cs|.go> [--dry-run] [--json]
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
from __future__ import annotations
|
|
36
|
+
|
|
37
|
+
import argparse
|
|
38
|
+
import json
|
|
39
|
+
import os
|
|
40
|
+
import sys
|
|
41
|
+
import tempfile
|
|
42
|
+
from dataclasses import dataclass
|
|
43
|
+
from pathlib import Path
|
|
44
|
+
|
|
45
|
+
_HERE = Path(__file__).resolve().parent
|
|
46
|
+
sys.path.insert(0, str(_HERE / "lib"))
|
|
47
|
+
|
|
48
|
+
from _gherkin_text import safe_for_terminal as _safe_for_terminal
|
|
49
|
+
from stub_extractors import (
|
|
50
|
+
ERROR_DANGLING_ANNOTATION, # noqa: F401
|
|
51
|
+
ERROR_UNBALANCED_BRACES, # noqa: F401
|
|
52
|
+
parse_existing_steps,
|
|
53
|
+
)
|
|
54
|
+
from stub_extractors import go as _go_extractor
|
|
55
|
+
|
|
56
|
+
# This script's own error sentinels — distinct from the two structural
|
|
57
|
+
# sentinels stub_extractors returns (re-exported above), the same split
|
|
58
|
+
# gherkin_feature_merge.py makes between its own ERROR_UNSAFE_PATH/
|
|
59
|
+
# ERROR_MALFORMED_CANDIDATES and the parser's ERROR_FEATURE_NOT_FOUND/
|
|
60
|
+
# ERROR_MALFORMED_FEATURE_BLOCK.
|
|
61
|
+
ERROR_UNSAFE_PATH = "unsafe-path"
|
|
62
|
+
ERROR_MALFORMED_CANDIDATES = "malformed-candidates"
|
|
63
|
+
# issue #1421 bug 6: a missing/unreadable --candidates path and an
|
|
64
|
+
# unrecognized --ext (argparse has no `choices=` for it) used to escape
|
|
65
|
+
# _cmd_merge as raw, uncaught Python exceptions instead of one of these
|
|
66
|
+
# sentinels through the same exit-2 --json contract every other structural
|
|
67
|
+
# problem uses.
|
|
68
|
+
ERROR_UNREADABLE_CANDIDATES = "unreadable-candidates"
|
|
69
|
+
ERROR_UNSUPPORTED_EXTENSION = "unsupported-extension"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class StepCandidate:
|
|
74
|
+
"""One newly-derived step-definition stub to merge in — pre-composed,
|
|
75
|
+
language-appropriate source text (the caller, `gherkin-derive/SKILL.md`
|
|
76
|
+
Step 4, is responsible for its exact shape), plus the step-pattern text
|
|
77
|
+
used to detect whether it already exists.
|
|
78
|
+
|
|
79
|
+
`decl_text` is Go-only (`None` for JS/TS, Java, C#): Go's registration
|
|
80
|
+
call and the top-level function it references are non-adjacent source
|
|
81
|
+
regions, so `text` (the registration call alone) is insufficient on its
|
|
82
|
+
own — `decl_text` carries the function declaration that must be spliced
|
|
83
|
+
in at a different, top-level-safe position (see `merge_steps`).
|
|
84
|
+
`parse_candidate_steps` populates it automatically from a `--candidates`
|
|
85
|
+
scratch file; a caller building `StepCandidate` by hand for Go must
|
|
86
|
+
supply it explicitly or the merged file will fail to compile."""
|
|
87
|
+
|
|
88
|
+
pattern: str
|
|
89
|
+
text: str
|
|
90
|
+
decl_text: str | None = None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass
|
|
94
|
+
class MergeResult:
|
|
95
|
+
text: str
|
|
96
|
+
added_patterns: list
|
|
97
|
+
skipped_duplicate_patterns: list
|
|
98
|
+
error: str | None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _dedupe_candidates(candidates: list) -> tuple:
|
|
102
|
+
"""Return `(deduped_candidates, self_duplicate_patterns)`. Two candidates
|
|
103
|
+
sharing a trimmed pattern would otherwise both be appended, mirroring the
|
|
104
|
+
identical fix `gherkin_feature_merge._dedupe_candidate_units` applies to
|
|
105
|
+
scenario titles."""
|
|
106
|
+
seen = set()
|
|
107
|
+
deduped = []
|
|
108
|
+
duplicates = []
|
|
109
|
+
for candidate in candidates:
|
|
110
|
+
key = candidate.pattern.strip()
|
|
111
|
+
if key in seen:
|
|
112
|
+
duplicates.append(candidate.pattern)
|
|
113
|
+
continue
|
|
114
|
+
seen.add(key)
|
|
115
|
+
deduped.append(candidate)
|
|
116
|
+
return deduped, duplicates
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _insert_at(text: str, idx: int, insertion: str) -> str:
|
|
120
|
+
"""Splice `insertion` into `text` at char offset `idx`, restoring a
|
|
121
|
+
missing line terminator right at the splice point (matching
|
|
122
|
+
`gherkin_feature_merge.merge_scenarios`'s identical guard) so neither
|
|
123
|
+
side's content is ever rewritten — only the separator whose absence
|
|
124
|
+
would otherwise fuse two lines together. No-op when `insertion` is empty."""
|
|
125
|
+
if not insertion:
|
|
126
|
+
return text
|
|
127
|
+
prefix = text[:idx]
|
|
128
|
+
suffix = text[idx:]
|
|
129
|
+
if prefix and not prefix.endswith("\n"):
|
|
130
|
+
prefix += "\n"
|
|
131
|
+
if not insertion.endswith("\n"):
|
|
132
|
+
insertion += "\n"
|
|
133
|
+
return prefix + insertion + suffix
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _existing_bindings_use_blank_line_separator(existing_text: str, bindings: list) -> bool:
|
|
137
|
+
"""Infer whether this file's existing step bindings are separated by a
|
|
138
|
+
blank line, from the joins between consecutive existing bindings —
|
|
139
|
+
excluding the boundary after the very last binding, which sits at the
|
|
140
|
+
file's end and may have nothing after it to separate from for reasons
|
|
141
|
+
unrelated to the file's own convention. A binding's `.end` (from
|
|
142
|
+
`extend_to_line_end`) stops at its own closing line, so the gap between
|
|
143
|
+
one binding's end and the next binding's start is exactly whatever sits
|
|
144
|
+
between them — empty when the file has no blank line there, the blank
|
|
145
|
+
line's own line terminator when it does, or just the next binding's
|
|
146
|
+
leading indentation when the language wraps bindings in an indented
|
|
147
|
+
block (Java, C#, a class-wrapped JS/TS style) and there is no blank
|
|
148
|
+
line. That last case is whitespace-only but has no newline in it —
|
|
149
|
+
`gap.strip() == ""` alone can't tell it apart from a genuine blank
|
|
150
|
+
line, so a join is only counted as separated when the gap is BOTH
|
|
151
|
+
whitespace-only AND actually contains a newline (a blank line always
|
|
152
|
+
has one; bare indentation never does). Defaults to `True` when there
|
|
153
|
+
are fewer than two bindings to compare, matching the
|
|
154
|
+
blank-line-between-methods style most existing step-definition files
|
|
155
|
+
already use."""
|
|
156
|
+
comparable = bindings[:-1]
|
|
157
|
+
if not comparable:
|
|
158
|
+
return True
|
|
159
|
+
separated = sum(
|
|
160
|
+
1
|
|
161
|
+
for i, binding in enumerate(comparable)
|
|
162
|
+
if (gap := existing_text[binding.end : bindings[i + 1].start])
|
|
163
|
+
and gap.strip() == ""
|
|
164
|
+
and "\n" in gap
|
|
165
|
+
)
|
|
166
|
+
return separated * 2 >= len(comparable)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _splice_single_point(existing_text: str, bindings: list, new_candidates: list) -> str:
|
|
170
|
+
"""The default splice: append every new candidate's text as one block
|
|
171
|
+
right after the last existing binding (or at file end with no existing
|
|
172
|
+
bindings) — correct whenever a binding's `text` already contains
|
|
173
|
+
everything the language needs (JS/TS, Java, C#).
|
|
174
|
+
|
|
175
|
+
The last existing binding sits at the splice point with nothing after
|
|
176
|
+
it, so its own text alone can't say whether this file puts a blank
|
|
177
|
+
line between step definitions — infer that from the *other* existing
|
|
178
|
+
joins instead (`_existing_bindings_use_blank_line_separator`) and
|
|
179
|
+
reproduce it here, so a splice landing flush against the last existing
|
|
180
|
+
method's closing brace doesn't silently drop the blank line every
|
|
181
|
+
other method boundary in the file already has."""
|
|
182
|
+
insertion_point = bindings[-1].end if bindings else len(existing_text)
|
|
183
|
+
insertion = "".join(candidate.text for candidate in new_candidates)
|
|
184
|
+
if bindings and insertion and _existing_bindings_use_blank_line_separator(existing_text, bindings):
|
|
185
|
+
insertion = "\n" + insertion
|
|
186
|
+
return _insert_at(existing_text, insertion_point, insertion)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _splice_go_two_part(existing_text: str, bindings: list, new_candidates: list) -> str:
|
|
190
|
+
"""Go-only splice: a new step needs its function declaration inserted
|
|
191
|
+
at the top level (safe anywhere alongside the other existing step
|
|
192
|
+
functions — Go has no forward-declaration ordering requirement) and its
|
|
193
|
+
`sc.Step(...)` registration inserted separately, inside the existing
|
|
194
|
+
registration function (right after the last existing registration,
|
|
195
|
+
`bindings[-1].end` — unchanged from the single-point case). Applying
|
|
196
|
+
the two splices from the higher offset down means neither invalidates
|
|
197
|
+
the other's not-yet-applied position.
|
|
198
|
+
|
|
199
|
+
When `bindings` is empty — an existing, non-empty `.go` file whose
|
|
200
|
+
`InitializeScenario` has no `sc.Step(...)` calls yet (issue #1421 bug 1)
|
|
201
|
+
— there is no existing binding to anchor against. Anchor the call just
|
|
202
|
+
before `InitializeScenario`'s own closing brace (so it lands inside a
|
|
203
|
+
function body, not as an invalid top-level statement) and the
|
|
204
|
+
declaration at that function's own top-level start. Falls back to
|
|
205
|
+
appending both at file end (declaration first) only if
|
|
206
|
+
`InitializeScenario` itself can't be found or bounded — a shape this
|
|
207
|
+
module's own tests never produce, but still handled rather than raising."""
|
|
208
|
+
decl_text = "".join(c.decl_text or "" for c in new_candidates)
|
|
209
|
+
call_text = "".join(c.text for c in new_candidates)
|
|
210
|
+
|
|
211
|
+
if bindings:
|
|
212
|
+
decl_starts = [b.decl_start for b in bindings if b.decl_start is not None]
|
|
213
|
+
call_anchor = bindings[-1].end
|
|
214
|
+
decl_anchor = min(decl_starts) if decl_starts else call_anchor
|
|
215
|
+
else:
|
|
216
|
+
registration_body = _go_extractor.find_scenario_initializer_body(existing_text)
|
|
217
|
+
if registration_body is not None and registration_body.error is None:
|
|
218
|
+
call_anchor = registration_body.end - 1 # just before the closing '}'
|
|
219
|
+
decl_anchor = registration_body.decl_start
|
|
220
|
+
else:
|
|
221
|
+
call_anchor = decl_anchor = len(existing_text)
|
|
222
|
+
|
|
223
|
+
if call_anchor >= decl_anchor:
|
|
224
|
+
text = _insert_at(existing_text, call_anchor, call_text)
|
|
225
|
+
text = _insert_at(text, decl_anchor, decl_text)
|
|
226
|
+
else:
|
|
227
|
+
text = _insert_at(existing_text, decl_anchor, decl_text)
|
|
228
|
+
text = _insert_at(text, call_anchor, call_text)
|
|
229
|
+
return text
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def merge_steps(existing_text: str, ext: str, candidate_steps: list) -> MergeResult:
|
|
233
|
+
"""Append-only merge of `candidate_steps` into `existing_text`.
|
|
234
|
+
|
|
235
|
+
Relays `parse_existing_steps`'s structural-error sentinel unchanged when
|
|
236
|
+
the existing file can't be bounded — this function never re-derives or
|
|
237
|
+
guesses the cause. When `existing_text` is empty, the candidates' own
|
|
238
|
+
text is the entire file (no skeleton is synthesized — that is the
|
|
239
|
+
caller's concern, mirroring `merge_scenarios`'s identical empty-file
|
|
240
|
+
branch; for Go specifically this means a caller composing a genuinely
|
|
241
|
+
new file must supply a complete registration-function wrapper in one
|
|
242
|
+
candidate's `text`/`decl_text` — this function only concatenates, it
|
|
243
|
+
never synthesizes one)."""
|
|
244
|
+
candidate_steps, self_duplicate_patterns = _dedupe_candidates(candidate_steps)
|
|
245
|
+
|
|
246
|
+
if not existing_text:
|
|
247
|
+
decl_body = "".join(candidate.decl_text or "" for candidate in candidate_steps)
|
|
248
|
+
call_body = "".join(candidate.text for candidate in candidate_steps)
|
|
249
|
+
return MergeResult(
|
|
250
|
+
text=decl_body + call_body,
|
|
251
|
+
added_patterns=[candidate.pattern for candidate in candidate_steps],
|
|
252
|
+
skipped_duplicate_patterns=self_duplicate_patterns,
|
|
253
|
+
error=None,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
result = parse_existing_steps(existing_text, ext)
|
|
257
|
+
if result.error is not None:
|
|
258
|
+
return MergeResult(
|
|
259
|
+
text=existing_text,
|
|
260
|
+
added_patterns=[],
|
|
261
|
+
skipped_duplicate_patterns=[],
|
|
262
|
+
error=result.error,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
existing_patterns = {binding.pattern.strip() for binding in result.bindings}
|
|
266
|
+
new_candidates = [c for c in candidate_steps if c.pattern.strip() not in existing_patterns]
|
|
267
|
+
skipped = self_duplicate_patterns + [
|
|
268
|
+
c.pattern for c in candidate_steps if c.pattern.strip() in existing_patterns
|
|
269
|
+
]
|
|
270
|
+
|
|
271
|
+
if not new_candidates:
|
|
272
|
+
return MergeResult(
|
|
273
|
+
text=existing_text, added_patterns=[], skipped_duplicate_patterns=skipped, error=None
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
is_go = ext.lower() == ".go"
|
|
277
|
+
if is_go:
|
|
278
|
+
merged_text = _splice_go_two_part(existing_text, result.bindings, new_candidates)
|
|
279
|
+
else:
|
|
280
|
+
merged_text = _splice_single_point(existing_text, result.bindings, new_candidates)
|
|
281
|
+
|
|
282
|
+
return MergeResult(
|
|
283
|
+
text=merged_text,
|
|
284
|
+
added_patterns=[c.pattern for c in new_candidates],
|
|
285
|
+
skipped_duplicate_patterns=skipped,
|
|
286
|
+
error=None,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def parse_candidate_steps(text: str, ext: str) -> tuple:
|
|
291
|
+
"""Parse a `--candidates` scratch file's step-definition text (the same
|
|
292
|
+
syntax as an existing file's bindings — a candidates file is just
|
|
293
|
+
syntactically-valid step-definition fragments, no separate schema)
|
|
294
|
+
into `(candidates, error)`. Mirrors
|
|
295
|
+
`gherkin_feature_merge.parse_candidate_units`'s reuse of the same parser
|
|
296
|
+
used for existing content."""
|
|
297
|
+
result = parse_existing_steps(text, ext)
|
|
298
|
+
if result.error is not None:
|
|
299
|
+
return [], result.error
|
|
300
|
+
candidates = [
|
|
301
|
+
StepCandidate(pattern=b.pattern, text=b.text, decl_text=b.decl_text) for b in result.bindings
|
|
302
|
+
]
|
|
303
|
+
return candidates, None
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _write_error(message: str) -> None:
|
|
307
|
+
sys.stderr.write(message + "\n")
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _reject_path_traversal(raw: str) -> str | None:
|
|
311
|
+
"""Return an error message if `raw` contains a `..` path component, else
|
|
312
|
+
`None`. `--existing` is composed by `gherkin-derive/SKILL.md` Step 4 from
|
|
313
|
+
a surface name derived from the target repository's own content, not
|
|
314
|
+
always typed by a human — mirrors
|
|
315
|
+
`gherkin_feature_merge._reject_path_traversal` exactly."""
|
|
316
|
+
if ".." in Path(raw).parts:
|
|
317
|
+
return f"--existing {raw!r} must not contain a '..' path component"
|
|
318
|
+
return None
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _merge_payload(written: bool, added=(), skipped=(), error=None) -> dict:
|
|
322
|
+
"""The one JSON shape every `merge` response uses, named once so a future
|
|
323
|
+
field addition touches this single place rather than every call site
|
|
324
|
+
rebuilding the dict by hand — mirrors `gherkin_feature_merge._merge_payload`."""
|
|
325
|
+
return {
|
|
326
|
+
"written": written,
|
|
327
|
+
"added_patterns": list(added),
|
|
328
|
+
"skipped_duplicate_patterns": list(skipped),
|
|
329
|
+
"error": error,
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _write_atomic(path: Path, text: str) -> None:
|
|
334
|
+
"""Write `text` to `path` via a same-directory temp file + os.replace, so
|
|
335
|
+
a crash or kill mid-write can never leave a truncated/corrupted
|
|
336
|
+
step-definition file — identical pattern to
|
|
337
|
+
`gherkin_feature_merge._write_atomic`."""
|
|
338
|
+
fd, tmp_name = tempfile.mkstemp(dir=str(path.parent), prefix=f".{path.name}.", suffix=".tmp")
|
|
339
|
+
try:
|
|
340
|
+
with os.fdopen(fd, "w", encoding="utf-8") as tmp_file:
|
|
341
|
+
tmp_file.write(text)
|
|
342
|
+
os.replace(tmp_name, path)
|
|
343
|
+
except BaseException:
|
|
344
|
+
Path(tmp_name).unlink(missing_ok=True)
|
|
345
|
+
raise
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _cmd_merge(args: argparse.Namespace) -> int:
|
|
349
|
+
# Known limitation (concurrency-review, issue #1421 consistency with
|
|
350
|
+
# gherkin_feature_merge.py): read-then-write here is still a TOCTOU race
|
|
351
|
+
# if two `merge` invocations ever target the same --existing path
|
|
352
|
+
# concurrently — whichever writes last silently wins (the atomic write
|
|
353
|
+
# below only rules out a truncated file, not a lost update between two
|
|
354
|
+
# racing invocations). Not fixed: gherkin-derive's own design invokes
|
|
355
|
+
# this once per surface, sequentially, never in parallel against the
|
|
356
|
+
# same file (see gherkin-derive/SKILL.md Step 4), so there is no known
|
|
357
|
+
# live trigger; a cross-platform lock (fcntl vs. msvcrt) would close
|
|
358
|
+
# this remaining gap but is a design call for a human to make, not a
|
|
359
|
+
# mechanical fix — deliberately left to a human decision rather than
|
|
360
|
+
# guessed at here.
|
|
361
|
+
path_error = _reject_path_traversal(args.existing)
|
|
362
|
+
if path_error is not None:
|
|
363
|
+
if args.json:
|
|
364
|
+
print(json.dumps(_merge_payload(written=False, error=ERROR_UNSAFE_PATH)))
|
|
365
|
+
else:
|
|
366
|
+
_write_error(f"gherkin_stub_merge: {path_error} — no steps merged")
|
|
367
|
+
return 2
|
|
368
|
+
|
|
369
|
+
existing_path = Path(args.existing)
|
|
370
|
+
existing_text = existing_path.read_text(encoding="utf-8") if existing_path.is_file() else ""
|
|
371
|
+
|
|
372
|
+
try:
|
|
373
|
+
candidates_text = Path(args.candidates).read_text(encoding="utf-8")
|
|
374
|
+
except OSError as exc:
|
|
375
|
+
# Missing/unreadable --candidates (not found, a directory, denied
|
|
376
|
+
# permission, bad encoding, ...) used to escape as a raw traceback —
|
|
377
|
+
# issue #1421 bug 6.
|
|
378
|
+
if args.json:
|
|
379
|
+
print(json.dumps(_merge_payload(written=False, error=ERROR_UNREADABLE_CANDIDATES)))
|
|
380
|
+
else:
|
|
381
|
+
_write_error(
|
|
382
|
+
f"gherkin_stub_merge: --candidates {_safe_for_terminal(args.candidates)} "
|
|
383
|
+
f"could not be read ({exc}) — no steps merged"
|
|
384
|
+
)
|
|
385
|
+
return 2
|
|
386
|
+
|
|
387
|
+
try:
|
|
388
|
+
candidate_steps, candidates_error = parse_candidate_steps(candidates_text, args.ext)
|
|
389
|
+
except ValueError:
|
|
390
|
+
# An --ext with no known step-definition language (argparse has no
|
|
391
|
+
# `choices=` for it) used to escape parse_existing_steps's
|
|
392
|
+
# ValueError as a raw traceback — issue #1421 bug 6.
|
|
393
|
+
if args.json:
|
|
394
|
+
print(json.dumps(_merge_payload(written=False, error=ERROR_UNSUPPORTED_EXTENSION)))
|
|
395
|
+
else:
|
|
396
|
+
_write_error(
|
|
397
|
+
f"gherkin_stub_merge: --ext {args.ext!r} is not a supported "
|
|
398
|
+
"step-definition extension — no steps merged"
|
|
399
|
+
)
|
|
400
|
+
return 2
|
|
401
|
+
|
|
402
|
+
if candidates_error is not None:
|
|
403
|
+
if args.json:
|
|
404
|
+
print(json.dumps(_merge_payload(written=False, error=ERROR_MALFORMED_CANDIDATES)))
|
|
405
|
+
else:
|
|
406
|
+
_write_error(
|
|
407
|
+
f"gherkin_stub_merge: candidates file {_safe_for_terminal(args.candidates)} "
|
|
408
|
+
f"is malformed (error={candidates_error}) — no steps merged, existing file "
|
|
409
|
+
f"left untouched"
|
|
410
|
+
)
|
|
411
|
+
return 2
|
|
412
|
+
|
|
413
|
+
result = merge_steps(existing_text, args.ext, candidate_steps)
|
|
414
|
+
|
|
415
|
+
if result.error is not None:
|
|
416
|
+
if args.json:
|
|
417
|
+
print(json.dumps(_merge_payload(written=False, error=result.error)))
|
|
418
|
+
else:
|
|
419
|
+
_write_error(
|
|
420
|
+
f"gherkin_stub_merge: {_safe_for_terminal(args.existing)} structure could not "
|
|
421
|
+
f"be parsed (error={result.error}) — no steps merged, existing file left "
|
|
422
|
+
f"untouched"
|
|
423
|
+
)
|
|
424
|
+
return 2
|
|
425
|
+
|
|
426
|
+
if args.dry_run:
|
|
427
|
+
if args.json:
|
|
428
|
+
print(
|
|
429
|
+
json.dumps(
|
|
430
|
+
_merge_payload(
|
|
431
|
+
written=False,
|
|
432
|
+
added=result.added_patterns,
|
|
433
|
+
skipped=result.skipped_duplicate_patterns,
|
|
434
|
+
)
|
|
435
|
+
)
|
|
436
|
+
)
|
|
437
|
+
else:
|
|
438
|
+
sys.stdout.write(result.text)
|
|
439
|
+
return 0
|
|
440
|
+
|
|
441
|
+
existing_path.parent.mkdir(parents=True, exist_ok=True)
|
|
442
|
+
_write_atomic(existing_path, result.text)
|
|
443
|
+
|
|
444
|
+
if args.json:
|
|
445
|
+
print(
|
|
446
|
+
json.dumps(
|
|
447
|
+
_merge_payload(
|
|
448
|
+
written=True,
|
|
449
|
+
added=result.added_patterns,
|
|
450
|
+
skipped=result.skipped_duplicate_patterns,
|
|
451
|
+
)
|
|
452
|
+
)
|
|
453
|
+
)
|
|
454
|
+
else:
|
|
455
|
+
print(
|
|
456
|
+
f"OK: merged {len(result.added_patterns)} new step(s) into "
|
|
457
|
+
f"{_safe_for_terminal(args.existing)}"
|
|
458
|
+
)
|
|
459
|
+
return 0
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
def main(argv: list | None = None) -> int:
|
|
463
|
+
parser = argparse.ArgumentParser(prog="gherkin_stub_merge.py")
|
|
464
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
465
|
+
|
|
466
|
+
merge_parser = sub.add_parser("merge")
|
|
467
|
+
merge_parser.add_argument("--existing", required=True)
|
|
468
|
+
merge_parser.add_argument("--candidates", required=True)
|
|
469
|
+
merge_parser.add_argument("--ext", required=True)
|
|
470
|
+
merge_parser.add_argument("--dry-run", action="store_true")
|
|
471
|
+
merge_parser.add_argument("--json", action="store_true")
|
|
472
|
+
merge_parser.set_defaults(func=_cmd_merge)
|
|
473
|
+
|
|
474
|
+
args = parser.parse_args(argv)
|
|
475
|
+
return args.func(args)
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
if __name__ == "__main__": # pragma: no cover
|
|
479
|
+
sys.exit(main())
|