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,546 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""coverage_discovery_js.py — discover and classify every package in a
|
|
3
|
+
JS/TS workspace for multi-project coverage discovery (issue #1759, Slice 3).
|
|
4
|
+
|
|
5
|
+
Resolves the declared workspace globs — from a root `package.json`'s
|
|
6
|
+
`workspaces` field (npm/yarn), `pnpm-workspace.yaml`'s `packages` list, or
|
|
7
|
+
`lerna.json`'s `packages` list, in that precedence order (first present
|
|
8
|
+
config wins; no cross-stack merge) — purely against the filesystem
|
|
9
|
+
(`pathlib`/`glob`, stdlib only). No package-manager CLI is invoked.
|
|
10
|
+
|
|
11
|
+
Each resolved package directory (a glob match that is a directory containing
|
|
12
|
+
its own `package.json`) is classified via `coverage_config.TestClassification`:
|
|
13
|
+
`TEST` when it has both a `test` script and a coverage-capable test-runner
|
|
14
|
+
devDependency (`jest`, `vitest`, or `mocha`/`ava` paired with `nyc`/`c8`),
|
|
15
|
+
`NOT_TEST` otherwise. Unlike .NET's discovery (Slice 2), there is no
|
|
16
|
+
`AMBIGUOUS` case for this stack — JS/TS has no analogue to MSBuild's
|
|
17
|
+
conditioned-property-inheritance ambiguity.
|
|
18
|
+
|
|
19
|
+
**Identity contract.** A package's "path" is its directory, resolved by
|
|
20
|
+
matching a workspace glob against the filesystem, expressed relative to
|
|
21
|
+
`repo_root` in POSIX form (matching the .NET discovery module's
|
|
22
|
+
repo-relative-path convention) — the exact, unmodified string every caller
|
|
23
|
+
compares against `included`/`excluded` entries, per `coverage_config`'s
|
|
24
|
+
identity contract (no normalization beyond this one POSIX-relative
|
|
25
|
+
rendering, which is applied once at resolution time, not per comparison).
|
|
26
|
+
|
|
27
|
+
**Security hardening.** Every glob-resolved package directory is verified to
|
|
28
|
+
stay within the resolved repository root before it is read or classified — a
|
|
29
|
+
workspace glob containing `..` can never cause this module to read or
|
|
30
|
+
classify a directory outside the repository. Brace expansion (below) happens
|
|
31
|
+
*before* that containment check, so an escaping path hidden inside a single
|
|
32
|
+
brace alternative (`{apps,../outside}/*`) is refused exactly like a bare
|
|
33
|
+
`../outside/*`.
|
|
34
|
+
|
|
35
|
+
**Brace expansion (issue #1827).** npm, yarn and pnpm all accept shell-style
|
|
36
|
+
brace alternations in workspace globs (`apps/{web,api}`), but `pathlib` does
|
|
37
|
+
not expand them — it looks for a literal directory named `{web,api}` and
|
|
38
|
+
finds nothing. Each declared glob is therefore expanded into its
|
|
39
|
+
alternatives here before being resolved. Multiple groups expand as a
|
|
40
|
+
cartesian product and nested groups expand recursively, matching the package
|
|
41
|
+
managers. An unbalanced brace is a `discovery_error`, never a silent
|
|
42
|
+
fallthrough to zero matches.
|
|
43
|
+
|
|
44
|
+
**Explicit `**` validation (issue #1832).** `**` placement is validated by
|
|
45
|
+
inspecting each path component rather than by catching `ValueError` from
|
|
46
|
+
`Path.glob`. CPython 3.13+ accepts a non-component `**` and treats it as
|
|
47
|
+
`*`, so the exception this module previously relied on is no longer raised
|
|
48
|
+
there — which turned a `discovery_error` into a silent empty result.
|
|
49
|
+
|
|
50
|
+
**Minimal pnpm-workspace.yaml parser.** This module never imports PyYAML
|
|
51
|
+
(stdlib-only, ADR 0014/0015) and does not implement general YAML. It
|
|
52
|
+
recognizes exactly one documented subset of `packages:` — a top-level,
|
|
53
|
+
unindented `packages:` key followed by one or more indented `- 'glob'`
|
|
54
|
+
list-item lines. Any other shape (a flow-style array, a block scalar, an
|
|
55
|
+
anchor, a scalar value, or no top-level `packages:` key at all) is reported
|
|
56
|
+
as `coverage_config.discovery_error(...)` naming the unsupported shape —
|
|
57
|
+
never silently treated as `DISCOVERY_NOT_APPLICABLE` or an empty package
|
|
58
|
+
list, which would reintroduce this issue's exact silent-exclusion failure
|
|
59
|
+
mode one layer down in the parser.
|
|
60
|
+
|
|
61
|
+
Stdlib-only (ADR 0014/0015).
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
from __future__ import annotations
|
|
65
|
+
|
|
66
|
+
import json
|
|
67
|
+
import re
|
|
68
|
+
import sys
|
|
69
|
+
from pathlib import Path
|
|
70
|
+
|
|
71
|
+
_HERE = Path(__file__).resolve().parent
|
|
72
|
+
sys.path.insert(0, str(_HERE))
|
|
73
|
+
|
|
74
|
+
import coverage_config
|
|
75
|
+
from coverage_config import TestClassification
|
|
76
|
+
|
|
77
|
+
# Coverage-capable test-runner devDependencies. jest/vitest are
|
|
78
|
+
# self-contained; mocha/ava need a paired coverage tool.
|
|
79
|
+
_SELF_CONTAINED_RUNNERS = ("jest", "vitest")
|
|
80
|
+
_BARE_RUNNERS = ("mocha", "ava")
|
|
81
|
+
_COVERAGE_TOOLS = ("nyc", "c8")
|
|
82
|
+
|
|
83
|
+
_PNPM_PACKAGES_KEY_RE = re.compile(r"^packages:\s*(.*)$")
|
|
84
|
+
_YAML_LIST_ITEM_RE = re.compile(r"^\s+-\s*(.+)$")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def discover_js_packages(repo_root):
|
|
88
|
+
"""Discover and classify every package in `repo_root`'s JS/TS workspace.
|
|
89
|
+
|
|
90
|
+
Returns a list of `{"path": <repo-relative POSIX package directory>,
|
|
91
|
+
"classification": TestClassification}` entries on success,
|
|
92
|
+
`coverage_config.DISCOVERY_NOT_APPLICABLE` when no workspace config
|
|
93
|
+
(`package.json#workspaces`, `pnpm-workspace.yaml`, or `lerna.json`) is
|
|
94
|
+
present, or `coverage_config.discovery_error(...)` for a parsing or
|
|
95
|
+
path-containment failure.
|
|
96
|
+
"""
|
|
97
|
+
root = Path(repo_root).resolve()
|
|
98
|
+
|
|
99
|
+
globs = _package_json_workspace_globs(root)
|
|
100
|
+
if isinstance(globs, dict):
|
|
101
|
+
return globs # a discovery_error propagated up
|
|
102
|
+
if globs is None:
|
|
103
|
+
pnpm_path = root / "pnpm-workspace.yaml"
|
|
104
|
+
lerna_path = root / "lerna.json"
|
|
105
|
+
if pnpm_path.is_file():
|
|
106
|
+
parsed = _parse_pnpm_workspace_yaml(pnpm_path)
|
|
107
|
+
elif lerna_path.is_file():
|
|
108
|
+
parsed = _parse_lerna_json(lerna_path)
|
|
109
|
+
else:
|
|
110
|
+
return coverage_config.DISCOVERY_NOT_APPLICABLE
|
|
111
|
+
if isinstance(parsed, dict):
|
|
112
|
+
return parsed # a discovery_error propagated up
|
|
113
|
+
globs = parsed
|
|
114
|
+
|
|
115
|
+
rel_paths = _resolve_globs_to_rel_paths(root, globs)
|
|
116
|
+
if isinstance(rel_paths, dict):
|
|
117
|
+
return rel_paths # a discovery_error propagated up
|
|
118
|
+
|
|
119
|
+
packages = []
|
|
120
|
+
for rel_path in rel_paths:
|
|
121
|
+
classification = _classify_package(root / rel_path, root)
|
|
122
|
+
if isinstance(classification, dict):
|
|
123
|
+
return classification # a discovery_error propagated up
|
|
124
|
+
packages.append({"path": rel_path, "classification": classification})
|
|
125
|
+
return packages
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# ---------------------------------------------------------------------------
|
|
129
|
+
# Workspace-glob resolution — package.json / pnpm-workspace.yaml / lerna.json
|
|
130
|
+
# ---------------------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _package_json_workspace_globs(root: Path):
|
|
134
|
+
"""Return the `workspaces` globs declared in `root`'s `package.json`
|
|
135
|
+
(npm's plain array form, or yarn's `{"packages": [...]}` extended
|
|
136
|
+
form); `None` when `package.json` is absent or has no `workspaces` key
|
|
137
|
+
at all — callers fall through to `pnpm-workspace.yaml`/`lerna.json` on
|
|
138
|
+
`None`, matching this module's precedence order (no workspace is
|
|
139
|
+
declared here, so falling through is legitimate); or
|
|
140
|
+
`coverage_config.discovery_error(...)` when `package.json` exists but
|
|
141
|
+
fails to parse as JSON, isn't a JSON object, or declares `workspaces`
|
|
142
|
+
in a shape this module doesn't recognize — that case must never
|
|
143
|
+
silently fall through to a different workspace stack."""
|
|
144
|
+
path = root / "package.json"
|
|
145
|
+
if not path.is_file():
|
|
146
|
+
return None
|
|
147
|
+
try:
|
|
148
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
149
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
150
|
+
return coverage_config.discovery_error(
|
|
151
|
+
f"Could not parse {str(path)!r} as JSON: {exc}"
|
|
152
|
+
)
|
|
153
|
+
if not isinstance(data, dict):
|
|
154
|
+
return coverage_config.discovery_error(
|
|
155
|
+
f"{str(path)!r} does not contain a JSON object."
|
|
156
|
+
)
|
|
157
|
+
if "workspaces" not in data:
|
|
158
|
+
return None
|
|
159
|
+
workspaces = data["workspaces"]
|
|
160
|
+
if isinstance(workspaces, list):
|
|
161
|
+
return workspaces
|
|
162
|
+
if isinstance(workspaces, dict) and isinstance(workspaces.get("packages"), list):
|
|
163
|
+
return workspaces["packages"]
|
|
164
|
+
return coverage_config.discovery_error(
|
|
165
|
+
f"{str(path)!r} declares 'workspaces' in an unsupported shape "
|
|
166
|
+
"(expected an array of globs, or {\"packages\": [...]}); got "
|
|
167
|
+
f"{type(workspaces).__name__} instead."
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _parse_pnpm_workspace_yaml(path: Path):
|
|
172
|
+
"""Minimal, documented, block-style-only parser for `pnpm-workspace.yaml`'s
|
|
173
|
+
`packages:` key — see the module docstring for the exact supported
|
|
174
|
+
subset. Returns a list of glob strings, or
|
|
175
|
+
`coverage_config.discovery_error(...)` naming the unsupported or
|
|
176
|
+
unparseable shape."""
|
|
177
|
+
try:
|
|
178
|
+
text = path.read_text(encoding="utf-8")
|
|
179
|
+
except OSError as exc:
|
|
180
|
+
return coverage_config.discovery_error(f"Could not read '{path}': {exc}")
|
|
181
|
+
|
|
182
|
+
lines = text.splitlines()
|
|
183
|
+
key_line_idx = None
|
|
184
|
+
trailing = None
|
|
185
|
+
for i, raw_line in enumerate(lines):
|
|
186
|
+
if raw_line[:1].isspace():
|
|
187
|
+
continue # only a top-level (unindented) key is this document's own `packages:`
|
|
188
|
+
stripped = raw_line.split("#", 1)[0].rstrip()
|
|
189
|
+
match = _PNPM_PACKAGES_KEY_RE.match(stripped)
|
|
190
|
+
if match:
|
|
191
|
+
key_line_idx = i
|
|
192
|
+
trailing = match.group(1).strip()
|
|
193
|
+
break
|
|
194
|
+
|
|
195
|
+
if key_line_idx is None:
|
|
196
|
+
return coverage_config.discovery_error(
|
|
197
|
+
f"'{path}' has no top-level 'packages:' key that this minimal "
|
|
198
|
+
"parser recognizes (block-style list only, e.g. "
|
|
199
|
+
"\"packages:\\n - 'glob'\"); this shape is unsupported."
|
|
200
|
+
)
|
|
201
|
+
if trailing:
|
|
202
|
+
return coverage_config.discovery_error(
|
|
203
|
+
f"'{path}' declares 'packages:' with an unsupported shape "
|
|
204
|
+
f"({trailing!r}); only a block-style list (packages:\\n - "
|
|
205
|
+
"'glob') is supported."
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
globs = []
|
|
209
|
+
for raw_line in lines[key_line_idx + 1 :]:
|
|
210
|
+
stripped_line = raw_line.strip()
|
|
211
|
+
if not stripped_line:
|
|
212
|
+
continue
|
|
213
|
+
if stripped_line.startswith("#"):
|
|
214
|
+
continue # whole-line comment inside the block — not a dedent
|
|
215
|
+
item_match = _YAML_LIST_ITEM_RE.match(raw_line)
|
|
216
|
+
if item_match is None:
|
|
217
|
+
break # dedent, or the next top-level key, ends the list
|
|
218
|
+
value = item_match.group(1).split("#", 1)[0].strip()
|
|
219
|
+
if len(value) >= 2 and value[0] == value[-1] and value[0] in "'\"":
|
|
220
|
+
value = value[1:-1]
|
|
221
|
+
globs.append(value)
|
|
222
|
+
|
|
223
|
+
if not globs:
|
|
224
|
+
return coverage_config.discovery_error(
|
|
225
|
+
f"'{path}' declares a top-level 'packages:' key but no "
|
|
226
|
+
"recognized \"- 'glob'\" list items followed it; this minimal "
|
|
227
|
+
"parser only supports a block-style list (packages:\\n - "
|
|
228
|
+
"'glob')."
|
|
229
|
+
)
|
|
230
|
+
return globs
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _parse_lerna_json(path: Path):
|
|
234
|
+
"""Return `lerna.json`'s `packages` list, or
|
|
235
|
+
`coverage_config.discovery_error(...)` when the file fails to parse as
|
|
236
|
+
JSON. A valid `lerna.json` with no `packages` list (or a non-list value)
|
|
237
|
+
resolves to zero globs rather than an error — the file itself is a
|
|
238
|
+
recognized, present workspace config; it simply declares no packages."""
|
|
239
|
+
try:
|
|
240
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
241
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
242
|
+
return coverage_config.discovery_error(f"Could not parse '{path}' as JSON: {exc}")
|
|
243
|
+
if not isinstance(data, dict):
|
|
244
|
+
return coverage_config.discovery_error(f"'{path}' does not contain a JSON object.")
|
|
245
|
+
packages = data.get("packages")
|
|
246
|
+
return packages if isinstance(packages, list) else []
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class _UnbalancedBrace(Exception):
|
|
250
|
+
"""Raised internally by `_expand_braces` for a glob whose braces do not
|
|
251
|
+
pair up. Converted to a `coverage_config.discovery_error` by the caller —
|
|
252
|
+
never allowed to surface as an empty match set."""
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class _BraceExpansionTooLarge(Exception):
|
|
256
|
+
"""Raised internally by `_expand_braces` for a glob whose expansion would
|
|
257
|
+
exceed `_MAX_BRACE_EXPANSIONS` alternatives or `_MAX_BRACE_NESTING` levels
|
|
258
|
+
of nesting. Converted to a `coverage_config.discovery_error` by the
|
|
259
|
+
caller. Brace expansion is a cartesian product, so a modest-looking
|
|
260
|
+
pattern (20 two-way groups) yields 2**20 globs and as many filesystem
|
|
261
|
+
walks; deep nesting recurses per level and would otherwise surface as an
|
|
262
|
+
uncaught `RecursionError` traceback rather than a discovery error."""
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
# Generous enough that no legitimate npm/yarn/pnpm workspace declaration comes
|
|
266
|
+
# close, small enough that a pathological `package.json` cannot turn discovery
|
|
267
|
+
# into a filesystem-walk bomb.
|
|
268
|
+
_MAX_BRACE_EXPANSIONS = 256
|
|
269
|
+
_MAX_BRACE_NESTING = 16
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _brace_balance_problem(pattern: str) -> str | None:
|
|
273
|
+
"""Return a reason when `pattern`'s braces do not pair up, else `None`.
|
|
274
|
+
|
|
275
|
+
Validated across the WHOLE pattern in one pass, deliberately: an earlier
|
|
276
|
+
version of this module scanned only from the first `{` onward, so a stray
|
|
277
|
+
`}` to its left (`apps/}x{a,b}`) was copied verbatim into the literal
|
|
278
|
+
prefix and expanded to globs that match nothing — reintroducing the exact
|
|
279
|
+
silent-zero-packages outcome #1827 exists to prevent. Both reviewers of
|
|
280
|
+
that change caught it independently; hence a single global check rather
|
|
281
|
+
than a per-recursion one."""
|
|
282
|
+
depth = 0
|
|
283
|
+
max_depth = 0
|
|
284
|
+
for index, char in enumerate(pattern):
|
|
285
|
+
if char == "{":
|
|
286
|
+
depth += 1
|
|
287
|
+
max_depth = max(max_depth, depth)
|
|
288
|
+
elif char == "}":
|
|
289
|
+
depth -= 1
|
|
290
|
+
if depth < 0:
|
|
291
|
+
return (
|
|
292
|
+
f"closes a brace group at position {index} that was never "
|
|
293
|
+
"opened"
|
|
294
|
+
)
|
|
295
|
+
if depth > 0:
|
|
296
|
+
return f"leaves {depth} brace group(s) unclosed"
|
|
297
|
+
if max_depth > _MAX_BRACE_NESTING:
|
|
298
|
+
return (
|
|
299
|
+
f"nests brace groups {max_depth} deep, beyond the supported "
|
|
300
|
+
f"maximum of {_MAX_BRACE_NESTING}"
|
|
301
|
+
)
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _expand_braces(pattern: str) -> list:
|
|
306
|
+
"""Expand shell-style brace alternations in `pattern` into the list of
|
|
307
|
+
concrete globs npm/yarn/pnpm would resolve (issue #1827).
|
|
308
|
+
|
|
309
|
+
`apps/{web,api}` -> `['apps/web', 'apps/api']`. Multiple groups expand as
|
|
310
|
+
a cartesian product; nested groups expand recursively. A pattern with no
|
|
311
|
+
braces returns itself unchanged, so this is safe to apply to every glob.
|
|
312
|
+
|
|
313
|
+
Raises `_UnbalancedBrace` when the braces do not pair up anywhere in the
|
|
314
|
+
pattern — the package managers reject those too, and treating them as a
|
|
315
|
+
literal path would silently resolve to nothing. Raises
|
|
316
|
+
`_BraceExpansionTooLarge` when the expansion would exceed
|
|
317
|
+
`_MAX_BRACE_EXPANSIONS`."""
|
|
318
|
+
problem = _brace_balance_problem(pattern)
|
|
319
|
+
if problem is not None:
|
|
320
|
+
raise _UnbalancedBrace(problem)
|
|
321
|
+
return _expand_braces_balanced(pattern)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def _expand_braces_balanced(pattern: str) -> list:
|
|
325
|
+
"""Recursive worker for `_expand_braces`, assuming `pattern`'s braces are
|
|
326
|
+
already known to balance (every sub-pattern of a balanced pattern is
|
|
327
|
+
itself balanced, so the global check runs once at entry, not per level)."""
|
|
328
|
+
open_idx = pattern.find("{")
|
|
329
|
+
if open_idx == -1:
|
|
330
|
+
return [pattern]
|
|
331
|
+
|
|
332
|
+
depth = 0
|
|
333
|
+
close_idx = -1
|
|
334
|
+
alternatives = []
|
|
335
|
+
alt_start = open_idx + 1
|
|
336
|
+
for i in range(open_idx, len(pattern)):
|
|
337
|
+
char = pattern[i]
|
|
338
|
+
if char == "{":
|
|
339
|
+
depth += 1
|
|
340
|
+
elif char == "}":
|
|
341
|
+
depth -= 1
|
|
342
|
+
if depth == 0:
|
|
343
|
+
alternatives.append(pattern[alt_start:i])
|
|
344
|
+
close_idx = i
|
|
345
|
+
break
|
|
346
|
+
elif char == "," and depth == 1:
|
|
347
|
+
alternatives.append(pattern[alt_start:i])
|
|
348
|
+
alt_start = i + 1
|
|
349
|
+
prefix = pattern[:open_idx]
|
|
350
|
+
expanded_suffixes = _expand_braces_balanced(pattern[close_idx + 1 :])
|
|
351
|
+
expanded = []
|
|
352
|
+
for alternative in alternatives:
|
|
353
|
+
for expanded_alt in _expand_braces_balanced(alternative):
|
|
354
|
+
for suffix in expanded_suffixes:
|
|
355
|
+
expanded.append(prefix + expanded_alt + suffix)
|
|
356
|
+
if len(expanded) > _MAX_BRACE_EXPANSIONS:
|
|
357
|
+
raise _BraceExpansionTooLarge(
|
|
358
|
+
f"expands to more than {_MAX_BRACE_EXPANSIONS} "
|
|
359
|
+
"alternatives"
|
|
360
|
+
)
|
|
361
|
+
return expanded
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _double_star_placement_problem(pattern: str) -> str | None:
|
|
365
|
+
"""Return a human-readable reason when `pattern`'s `**` usage is one this
|
|
366
|
+
module refuses to resolve, else `None` (issue #1832).
|
|
367
|
+
|
|
368
|
+
Checked by inspecting path components rather than by catching `ValueError`
|
|
369
|
+
from `Path.glob`: CPython 3.13+ accepts a non-component `**` and silently
|
|
370
|
+
treats it as `*`, so the exception this module used to depend on is not
|
|
371
|
+
raised on every supported interpreter. A version-dependent guard here
|
|
372
|
+
meant a malformed glob became an empty result instead of an error."""
|
|
373
|
+
if pattern.count("**") > 1:
|
|
374
|
+
return (
|
|
375
|
+
"contains more than one '**' segment; no legitimate "
|
|
376
|
+
"npm/yarn/pnpm workspace glob needs more than one, and multiple "
|
|
377
|
+
"non-adjacent '**' segments can cause pathological "
|
|
378
|
+
"filesystem-walk cost"
|
|
379
|
+
)
|
|
380
|
+
for component in pattern.split("/"):
|
|
381
|
+
if "**" in component and component != "**":
|
|
382
|
+
return (
|
|
383
|
+
f"places '**' inside the path component {component!r}; '**' "
|
|
384
|
+
"must be an entire path component of its own"
|
|
385
|
+
)
|
|
386
|
+
return None
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def _resolve_globs_to_rel_paths(root: Path, globs: list):
|
|
390
|
+
"""Resolve each glob in `globs` against `root`'s filesystem, keeping
|
|
391
|
+
only matches that are directories containing their own `package.json`.
|
|
392
|
+
Returns a sorted list of repo-relative POSIX paths, or
|
|
393
|
+
`coverage_config.discovery_error(...)` naming: the first resolved match
|
|
394
|
+
found outside `root` (e.g. a glob containing `..`) — refusing to include
|
|
395
|
+
or silently drop it; a glob pattern this module refuses to resolve at
|
|
396
|
+
all (an absolute path, an unbalanced brace, a malformed `**` placement,
|
|
397
|
+
or more than one `**` segment); or a filesystem error encountered while
|
|
398
|
+
resolving it.
|
|
399
|
+
|
|
400
|
+
Brace alternations are expanded first (`_expand_braces`), so every check
|
|
401
|
+
below — including the containment guard — runs against each concrete
|
|
402
|
+
alternative rather than the unexpanded pattern."""
|
|
403
|
+
rel_paths = set()
|
|
404
|
+
for declared_pattern in globs:
|
|
405
|
+
if not isinstance(declared_pattern, str) or not declared_pattern:
|
|
406
|
+
continue
|
|
407
|
+
# The `**` budget is enforced on the DECLARED pattern, not only on each
|
|
408
|
+
# expanded alternative: brace multiplication would otherwise smuggle
|
|
409
|
+
# several `**` walks past a per-alternative check ({**/x,**/y,**/z} is
|
|
410
|
+
# three single-`**` alternatives), defeating the cost guard's purpose.
|
|
411
|
+
if declared_pattern.count("**") > 1:
|
|
412
|
+
return coverage_config.discovery_error(
|
|
413
|
+
f"Workspace glob {declared_pattern!r} contains more than one "
|
|
414
|
+
"'**' segment; no legitimate npm/yarn/pnpm workspace glob "
|
|
415
|
+
"needs more than one, and multiple non-adjacent '**' segments "
|
|
416
|
+
"can cause pathological filesystem-walk cost. Refusing to "
|
|
417
|
+
"resolve it."
|
|
418
|
+
)
|
|
419
|
+
try:
|
|
420
|
+
expanded_patterns = _expand_braces(declared_pattern)
|
|
421
|
+
except _UnbalancedBrace as exc:
|
|
422
|
+
return coverage_config.discovery_error(
|
|
423
|
+
f"Workspace glob {declared_pattern!r} {exc}; npm/yarn/pnpm "
|
|
424
|
+
"reject unbalanced braces too, and resolving the pattern as a "
|
|
425
|
+
"literal path would silently match nothing. Refusing to "
|
|
426
|
+
"resolve it."
|
|
427
|
+
)
|
|
428
|
+
except _BraceExpansionTooLarge as exc:
|
|
429
|
+
return coverage_config.discovery_error(
|
|
430
|
+
f"Workspace glob {declared_pattern!r} {exc}; each alternative "
|
|
431
|
+
"costs a separate filesystem walk. Refusing to resolve it."
|
|
432
|
+
)
|
|
433
|
+
for pattern in expanded_patterns:
|
|
434
|
+
# An empty or bare-`/` alternative ({packages/*,} — legal in
|
|
435
|
+
# npm/minimatch, where it simply contributes nothing) must not
|
|
436
|
+
# reach `Path.glob`, which rejects '' outright and treats a
|
|
437
|
+
# trailing separator version-dependently. Dropping it here keeps
|
|
438
|
+
# one empty alternative from failing the whole workspace.
|
|
439
|
+
pattern = pattern.rstrip("/")
|
|
440
|
+
if not pattern:
|
|
441
|
+
continue
|
|
442
|
+
result = _resolve_one_glob(root, pattern, declared_pattern, rel_paths)
|
|
443
|
+
if result is not None:
|
|
444
|
+
return result
|
|
445
|
+
return sorted(rel_paths)
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def _resolve_one_glob(root: Path, pattern: str, declared_pattern: str, rel_paths: set):
|
|
449
|
+
"""Resolve a single brace-expanded `pattern`, adding every qualifying
|
|
450
|
+
match to `rel_paths`. Returns `None` on success, or a
|
|
451
|
+
`coverage_config.discovery_error(...)` to propagate. `declared_pattern` is
|
|
452
|
+
the original glob as written in the manifest — named in every error
|
|
453
|
+
alongside the expanded form so a brace-expanded failure is traceable back
|
|
454
|
+
to what the operator actually declared."""
|
|
455
|
+
|
|
456
|
+
def described(reason: str) -> str:
|
|
457
|
+
if pattern == declared_pattern:
|
|
458
|
+
return f"Workspace glob {pattern!r} {reason}."
|
|
459
|
+
return (
|
|
460
|
+
f"Workspace glob {pattern!r} (expanded from "
|
|
461
|
+
f"{declared_pattern!r}) {reason}."
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
placement_problem = _double_star_placement_problem(pattern)
|
|
465
|
+
if placement_problem is not None:
|
|
466
|
+
return coverage_config.discovery_error(
|
|
467
|
+
described(f"{placement_problem}. Refusing to resolve it")
|
|
468
|
+
)
|
|
469
|
+
try:
|
|
470
|
+
matches = list(root.glob(pattern))
|
|
471
|
+
except (ValueError, NotImplementedError, OSError) as exc:
|
|
472
|
+
return coverage_config.discovery_error(
|
|
473
|
+
described(f"could not be resolved: {exc}")
|
|
474
|
+
)
|
|
475
|
+
for match in matches:
|
|
476
|
+
resolved = match.resolve()
|
|
477
|
+
if not coverage_config.is_within(resolved, root):
|
|
478
|
+
return coverage_config.discovery_error(
|
|
479
|
+
described(
|
|
480
|
+
f"resolved to {str(resolved)!r}, which is outside the "
|
|
481
|
+
f"repository root ({str(root)!r}); refusing to include it"
|
|
482
|
+
)
|
|
483
|
+
)
|
|
484
|
+
if not resolved.is_dir():
|
|
485
|
+
continue
|
|
486
|
+
if not (resolved / "package.json").is_file():
|
|
487
|
+
continue
|
|
488
|
+
rel_paths.add(resolved.relative_to(root).as_posix())
|
|
489
|
+
return None
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
# ---------------------------------------------------------------------------
|
|
493
|
+
# Package classification
|
|
494
|
+
# ---------------------------------------------------------------------------
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def _classify_package(pkg_dir: Path, root: Path):
|
|
498
|
+
"""`TEST` when `pkg_dir`'s `package.json` declares both a `test` script
|
|
499
|
+
and a coverage-capable test-runner devDependency (`jest`, `vitest`, or
|
|
500
|
+
`mocha`/`ava` paired with `nyc`/`c8`); `NOT_TEST` otherwise. No
|
|
501
|
+
`AMBIGUOUS` case for this stack.
|
|
502
|
+
|
|
503
|
+
Returns `coverage_config.discovery_error(...)` instead — never
|
|
504
|
+
`NOT_TEST` — when `pkg_dir`'s `package.json` exists but is unreadable or
|
|
505
|
+
fails to parse as a JSON object, or when the manifest file itself
|
|
506
|
+
(resolved, to catch a symlink) escapes `root`. `_resolve_globs_to_rel_paths`
|
|
507
|
+
already guarantees `pkg_dir`'s `package.json` exists as a plain
|
|
508
|
+
containment check on the directory; this re-resolves the manifest FILE
|
|
509
|
+
itself because a symlinked `package.json` inside an already-contained
|
|
510
|
+
directory could still point outside the repository."""
|
|
511
|
+
manifest_path = pkg_dir / "package.json"
|
|
512
|
+
try:
|
|
513
|
+
resolved_manifest = manifest_path.resolve()
|
|
514
|
+
except OSError as exc:
|
|
515
|
+
return coverage_config.discovery_error(
|
|
516
|
+
f"Could not resolve manifest {str(manifest_path)!r}: {exc}"
|
|
517
|
+
)
|
|
518
|
+
if not coverage_config.is_within(resolved_manifest, root):
|
|
519
|
+
return coverage_config.discovery_error(
|
|
520
|
+
f"Package manifest {str(manifest_path)!r} resolves to "
|
|
521
|
+
f"{str(resolved_manifest)!r}, which is outside the repository "
|
|
522
|
+
f"root ({str(root)!r}); refusing to read it."
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
try:
|
|
526
|
+
pkg = json.loads(resolved_manifest.read_text(encoding="utf-8"))
|
|
527
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
528
|
+
return coverage_config.discovery_error(
|
|
529
|
+
f"Could not parse {str(manifest_path)!r} as JSON: {exc}"
|
|
530
|
+
)
|
|
531
|
+
if not isinstance(pkg, dict):
|
|
532
|
+
return coverage_config.discovery_error(
|
|
533
|
+
f"{str(manifest_path)!r} does not contain a JSON object."
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
scripts = pkg.get("scripts")
|
|
537
|
+
has_test_script = isinstance(scripts, dict) and bool(scripts.get("test"))
|
|
538
|
+
|
|
539
|
+
dev_deps = pkg.get("devDependencies")
|
|
540
|
+
dev_deps = dev_deps if isinstance(dev_deps, dict) else {}
|
|
541
|
+
has_runner = any(runner in dev_deps for runner in _SELF_CONTAINED_RUNNERS) or (
|
|
542
|
+
any(runner in dev_deps for runner in _BARE_RUNNERS)
|
|
543
|
+
and any(tool in dev_deps for tool in _COVERAGE_TOOLS)
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
return TestClassification.TEST if (has_test_script and has_runner) else TestClassification.NOT_TEST
|