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,464 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""hooks/review_verdict_recorder.py — SubagentStop per-lens verdict recorder
|
|
3
|
+
(#2166, Step 2.3; plan: plans/2164-verdict-ledger-writer.md, Decisions 3/4/4a).
|
|
4
|
+
|
|
5
|
+
## Contract (docs/python-hook-contract.md)
|
|
6
|
+
|
|
7
|
+
Input : SubagentStop JSON on stdin (`transcript_path`, `session_id`, `cwd`)
|
|
8
|
+
Output: zero or more `.claude/metrics/review-verdicts.jsonl` rows via
|
|
9
|
+
`hooks/lib/review_verdicts.emit_review_verdict()` — one per in-scope
|
|
10
|
+
file the dispatch prompt's Step 2.1 scope marker declared, each
|
|
11
|
+
carrying `outcome: "pass"` or `"findings"`. Once `subagent_type` is
|
|
12
|
+
confirmed a registered review lens, a degenerate exit (missing/
|
|
13
|
+
reformatted scope marker, unparseable/malformed final result) also
|
|
14
|
+
writes one `.claude/metrics/boundary-events.jsonl` `"record"`-decision
|
|
15
|
+
row via `hooks/lib/boundary_events.emit_boundary_event()`, naming the
|
|
16
|
+
reason (`missing-scope-marker` | `unparseable-result`) (Fix #3, #2166
|
|
17
|
+
correctness review).
|
|
18
|
+
Posture: fail-open throughout. Any error, or any signal this hook can't
|
|
19
|
+
resolve confidently (missing/unreadable/non-JSON transcript, an
|
|
20
|
+
unresolvable `subagent_type`, an unregistered or registered-but-
|
|
21
|
+
non-review `subagent_type`, a missing/reformatted scope marker, an
|
|
22
|
+
unparseable/malformed final JSON result) -> zero rows written, exit
|
|
23
|
+
0. A per-file read failure (a deleted/unreadable in-scope file)
|
|
24
|
+
skips only that file — the rest still get their rows.
|
|
25
|
+
|
|
26
|
+
## Spike finding: `attributionAgent` reliability, checked against real
|
|
27
|
+
## transcripts before writing the rest of this hook (per this step's own
|
|
28
|
+
## instruction — not recalled/assumed)
|
|
29
|
+
|
|
30
|
+
`hooks/lib/cost_meter.py`'s "Attribution dimensions" docstring claims the
|
|
31
|
+
native top-level `attributionAgent` field is "present on every usage-bearing
|
|
32
|
+
sidechain record in real transcripts". Checked here directly against every
|
|
33
|
+
real subagent transcript from this session
|
|
34
|
+
(`~/.claude/projects/-home-user-agentic-dev-team/<session-id>/subagents/agent-*.jsonl`,
|
|
35
|
+
124 files, 10,795 total rows, 4,279 usage-bearing assistant rows):
|
|
36
|
+
|
|
37
|
+
* 124/124 files carried an `attributionAgent` value on 100% (4,279/4,279)
|
|
38
|
+
of their usage-bearing (assistant) records — no exceptions.
|
|
39
|
+
* Exactly one distinct value per file, always — never absent-then-present
|
|
40
|
+
partway through, never two different values in one file. The field
|
|
41
|
+
identifies the whole dispatch, not just one turn.
|
|
42
|
+
* Values are plugin-qualified for this plugin's own agents (e.g.
|
|
43
|
+
`dev-team:structure-review`, `dev-team:correctness-review`,
|
|
44
|
+
`dev-team:software-engineer`) and bare for harness-builtin agent types
|
|
45
|
+
(`general-purpose`, `claude-code-guide`) — `strip_plugin_prefix`
|
|
46
|
+
(`hooks/lib/review_agent_registry.py`) already normalizes exactly this,
|
|
47
|
+
reused below rather than reimplemented.
|
|
48
|
+
* The field is NOT stamped on every record in a subagent transcript — only
|
|
49
|
+
the usage-bearing (assistant) ones. The transcript's first record (the
|
|
50
|
+
dispatch-prompt `user` turn this hook also needs, for the Decision 3
|
|
51
|
+
scope marker) never carries it, confirming as a side effect that "the
|
|
52
|
+
dispatch prompt is the subagent's initial user message" holds in
|
|
53
|
+
practice, not just in the plan's own claim.
|
|
54
|
+
|
|
55
|
+
**Conclusion: the primary signal is fully reliable in this corpus — no scope
|
|
56
|
+
change to this step.** The documented Task/Agent-dispatch-join fallback
|
|
57
|
+
(main-thread `tool_use.input.subagent_type` + `toolUseResult.agentId`,
|
|
58
|
+
matched against the subagent transcript's own `agentId`, with the parent
|
|
59
|
+
transcript path derived from `transcript_path`'s own directory structure) is
|
|
60
|
+
still implemented below, per the plan's explicit instruction — but the spike
|
|
61
|
+
found no real transcript that ever needed it.
|
|
62
|
+
|
|
63
|
+
Stdlib-only (hashlib/json/pathlib/sys). See ADR 0014, ADR 0015.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
from __future__ import annotations
|
|
67
|
+
|
|
68
|
+
import json
|
|
69
|
+
import sys
|
|
70
|
+
from pathlib import Path
|
|
71
|
+
|
|
72
|
+
_HOOK_DIR = Path(__file__).resolve().parent
|
|
73
|
+
_LIB_DIR = _HOOK_DIR / "lib"
|
|
74
|
+
if str(_LIB_DIR) not in sys.path:
|
|
75
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
76
|
+
|
|
77
|
+
# hooks/ -> scripts/lib/session_log/ is a documented reverse-dependency
|
|
78
|
+
# exception (see hooks/lib/cost_meter.py's identical import for the full
|
|
79
|
+
# rationale): session_log/ ships INSIDE this same plugin package,
|
|
80
|
+
# always present wherever this hook runs, and session_log itself imports
|
|
81
|
+
# nothing from hooks/lib/ (no cycle). Mirrors cost_meter.py's own
|
|
82
|
+
# sys.path.insert + bare-package-import MECHANISM, not its directionality.
|
|
83
|
+
_SCRIPTS_LIB_DIR = _HOOK_DIR.parent / "scripts" / "lib"
|
|
84
|
+
if str(_SCRIPTS_LIB_DIR) not in sys.path:
|
|
85
|
+
sys.path.insert(0, str(_SCRIPTS_LIB_DIR))
|
|
86
|
+
|
|
87
|
+
from boundary_events import emit_boundary_event # type: ignore[import-not-found]
|
|
88
|
+
from review_agent_registry import ( # type: ignore[import-not-found]
|
|
89
|
+
is_registered_review_lens,
|
|
90
|
+
strip_plugin_prefix,
|
|
91
|
+
)
|
|
92
|
+
from review_verdicts import ( # type: ignore[import-not-found]
|
|
93
|
+
SCOPE_MARKER_PREFIX,
|
|
94
|
+
canonical_path,
|
|
95
|
+
emit_review_verdict,
|
|
96
|
+
)
|
|
97
|
+
from review_verdicts import (
|
|
98
|
+
hash_file as _hash_file,
|
|
99
|
+
)
|
|
100
|
+
from session_log import records as _records # type: ignore[import-not-found]
|
|
101
|
+
from stdin_json import read_stdin_json, resolve_cwd # type: ignore[import-not-found]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _read_transcript_records(path: Path) -> list[dict] | None:
|
|
105
|
+
"""Every JSON-object row from `path`, or `None` when the transcript
|
|
106
|
+
itself can't be used at all — missing, unreadable, or containing zero
|
|
107
|
+
valid JSON lines. The three "malformed/unreadable transcript" Gherkin
|
|
108
|
+
scenarios all collapse onto this one fail-open signal; a caller treats
|
|
109
|
+
`None` and an empty-but-readable transcript identically (fail open,
|
|
110
|
+
write nothing).
|
|
111
|
+
|
|
112
|
+
Delegates to `session_log.records.iter_file_records` (imported above as
|
|
113
|
+
`_records`, Fix #9 / #2166 correctness review) rather than
|
|
114
|
+
`read_text()`-ing the whole transcript into memory: this hook has no
|
|
115
|
+
need to distinguish "the trailing line is malformed JSON" as its own
|
|
116
|
+
outcome the way `subagent_completion_guard.py`'s private `_tail_lines`/
|
|
117
|
+
`_last_row` reader does (see that module's own docstring for why IT
|
|
118
|
+
keeps a private reader) — `_read_transcript_records` only ever needs
|
|
119
|
+
"did this transcript yield at least one usable JSON object", which the
|
|
120
|
+
shared streaming iterator answers just as well, at a fraction of the
|
|
121
|
+
peak memory on a multi-MB transcript."""
|
|
122
|
+
records: list[dict] = []
|
|
123
|
+
saw_json = False
|
|
124
|
+
for row in _records.iter_file_records(path):
|
|
125
|
+
saw_json = True
|
|
126
|
+
if isinstance(row, dict):
|
|
127
|
+
records.append(row)
|
|
128
|
+
return records if saw_json else None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _attribution_subagent_type(records: list[dict]) -> str | None:
|
|
132
|
+
"""Primary signal (see module docstring spike finding): the first
|
|
133
|
+
non-empty native attribution value found on any record in the subagent's
|
|
134
|
+
own transcript."""
|
|
135
|
+
for rec in records:
|
|
136
|
+
agent = _records.attribution_agent_of(rec)
|
|
137
|
+
if agent:
|
|
138
|
+
return agent
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _own_agent_id(records: list[dict]) -> str | None:
|
|
143
|
+
for rec in records:
|
|
144
|
+
agent_id = rec.get("agentId")
|
|
145
|
+
if isinstance(agent_id, str) and agent_id:
|
|
146
|
+
return agent_id
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _parent_transcript_path(subagent_transcript: Path) -> Path | None:
|
|
151
|
+
"""`<dir>/<session-id>/subagents/agent-<agentId>.jsonl` implies
|
|
152
|
+
`<dir>/<session-id>.jsonl` (this step's own documented derivation).
|
|
153
|
+
`None` when `subagent_transcript` doesn't match that layout."""
|
|
154
|
+
subagents_dir = subagent_transcript.parent
|
|
155
|
+
if subagents_dir.name != "subagents":
|
|
156
|
+
return None
|
|
157
|
+
session_dir = subagents_dir.parent
|
|
158
|
+
return session_dir.parent / f"{session_dir.name}.jsonl"
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _fallback_subagent_type(subagent_transcript: Path, records: list[dict]) -> str | None:
|
|
162
|
+
"""The documented Task/Agent dispatch join, used only when the primary
|
|
163
|
+
`attributionAgent` signal is absent from every record (see module
|
|
164
|
+
docstring: the spike found no real transcript that needed this path)."""
|
|
165
|
+
agent_id = _own_agent_id(records)
|
|
166
|
+
if not agent_id:
|
|
167
|
+
return None
|
|
168
|
+
parent_path = _parent_transcript_path(subagent_transcript)
|
|
169
|
+
if parent_path is None:
|
|
170
|
+
return None
|
|
171
|
+
parent_records = _read_transcript_records(parent_path)
|
|
172
|
+
if not parent_records:
|
|
173
|
+
return None
|
|
174
|
+
dispatch_types: dict[str, str] = {}
|
|
175
|
+
agent_types: dict[str, str] = {}
|
|
176
|
+
for rec in parent_records:
|
|
177
|
+
_records.join_dispatch_agent_ids(rec, dispatch_types, agent_types)
|
|
178
|
+
return agent_types.get(agent_id)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _resolve_subagent_type(subagent_transcript: Path, records: list[dict]) -> str | None:
|
|
182
|
+
raw = _attribution_subagent_type(records) or _fallback_subagent_type(
|
|
183
|
+
subagent_transcript, records
|
|
184
|
+
)
|
|
185
|
+
return strip_plugin_prefix(raw) if raw else None
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _message_text(message: object) -> str | None:
|
|
189
|
+
"""Assistant/user message `content` as plain text, whether it's a bare
|
|
190
|
+
string or a Messages-API content-block list (only `text` blocks
|
|
191
|
+
contribute; a block list with no text block returns `None`)."""
|
|
192
|
+
if not isinstance(message, dict):
|
|
193
|
+
return None
|
|
194
|
+
content = message.get("content")
|
|
195
|
+
if isinstance(content, str):
|
|
196
|
+
return content
|
|
197
|
+
if isinstance(content, list):
|
|
198
|
+
parts = [
|
|
199
|
+
block.get("text", "")
|
|
200
|
+
for block in content
|
|
201
|
+
if isinstance(block, dict) and block.get("type") == "text"
|
|
202
|
+
]
|
|
203
|
+
return "\n".join(parts) if parts else None
|
|
204
|
+
return None
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _first_turn_text(records: list[dict]) -> str | None:
|
|
208
|
+
if not records:
|
|
209
|
+
return None
|
|
210
|
+
return _message_text(records[0].get("message"))
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _handback_message_text(records: list[dict]) -> str | None:
|
|
214
|
+
"""PRIMARY result-extraction path (Fix #1, #2166 correctness review —
|
|
215
|
+
CRITICAL: this hook wrote zero rows in production before this fix).
|
|
216
|
+
|
|
217
|
+
Verified directly against a real transcript in this session's own
|
|
218
|
+
corpus before writing this (not assumed):
|
|
219
|
+
`~/.claude/projects/-home-user-agentic-dev-team/<session-id>/subagents/
|
|
220
|
+
agent-a006af1f32a025449.jsonl`, line 17 — a completed subagent's real
|
|
221
|
+
final JSON result lives inside its OWN `SubagentHandback` tool_use
|
|
222
|
+
block's `input.message` field (prose plus a fenced ```json block), never
|
|
223
|
+
as the transcript's literal last row. The literal last row is a short
|
|
224
|
+
wrap-up assistant turn ("Report delivered...") that comes AFTER the
|
|
225
|
+
handback's own `tool_result` ack — exactly the shape
|
|
226
|
+
`subagent_completion_guard.py`'s module docstring documents and confirms
|
|
227
|
+
across 70 real transcripts ("Finding 3 — SubagentHandback is a real,
|
|
228
|
+
distinguishable tool_use block"). Scans backward so the LAST handback
|
|
229
|
+
call wins if a transcript ever carries more than one."""
|
|
230
|
+
for rec in reversed(records):
|
|
231
|
+
message = rec.get("message")
|
|
232
|
+
if not isinstance(message, dict):
|
|
233
|
+
continue
|
|
234
|
+
content = message.get("content")
|
|
235
|
+
if not isinstance(content, list):
|
|
236
|
+
continue
|
|
237
|
+
for block in content:
|
|
238
|
+
if (
|
|
239
|
+
isinstance(block, dict)
|
|
240
|
+
and block.get("type") == "tool_use"
|
|
241
|
+
and block.get("name") == "SubagentHandback"
|
|
242
|
+
):
|
|
243
|
+
handback_input = block.get("input")
|
|
244
|
+
if isinstance(handback_input, dict):
|
|
245
|
+
text = handback_input.get("message")
|
|
246
|
+
if isinstance(text, str) and text:
|
|
247
|
+
return text
|
|
248
|
+
return None
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _fallback_last_parseable_turn_text(records: list[dict]) -> str | None:
|
|
252
|
+
"""FALLBACK ONLY (Fix #1): used when no `SubagentHandback` call is found
|
|
253
|
+
anywhere in the transcript. This session's own corpus never needed this
|
|
254
|
+
path (see `_handback_message_text` above) — kept per the plan's explicit
|
|
255
|
+
instruction for a transcript shape that never showed up in the sample.
|
|
256
|
+
The last turn (scanning backward) whose text itself recovers as a JSON
|
|
257
|
+
object via `_extract_json_object`, rather than blindly trusting the
|
|
258
|
+
transcript's literal last row the way the pre-fix code did."""
|
|
259
|
+
for rec in reversed(records):
|
|
260
|
+
text = _message_text(rec.get("message"))
|
|
261
|
+
if text and _extract_json_object(text) is not None:
|
|
262
|
+
return text
|
|
263
|
+
return None
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _final_result_text(records: list[dict]) -> str | None:
|
|
267
|
+
"""The text handed to `_extract_json_object` for the agent's final JSON
|
|
268
|
+
result: `_handback_message_text` first, `_fallback_last_parseable_turn_text`
|
|
269
|
+
only when no handback call is present at all (Fix #1)."""
|
|
270
|
+
return _handback_message_text(records) or _fallback_last_parseable_turn_text(records)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _parse_scope_marker(text: str) -> list[str] | None:
|
|
274
|
+
"""The in-scope file list from the Step 2.1 `SCOPE_MARKER_PREFIX` line,
|
|
275
|
+
or `None` when no line starts with it — a missing/reformatted marker,
|
|
276
|
+
which the caller treats as fail-open (zero rows)."""
|
|
277
|
+
for line in text.splitlines():
|
|
278
|
+
if line.startswith(SCOPE_MARKER_PREFIX):
|
|
279
|
+
remainder = line[len(SCOPE_MARKER_PREFIX) :]
|
|
280
|
+
return [f.strip() for f in remainder.split(",") if f.strip()]
|
|
281
|
+
return None
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _extract_json_object(text: str) -> dict | None:
|
|
285
|
+
"""A small, tolerant JSON-object extractor for an agent's final-turn
|
|
286
|
+
text: a clean parse first, then the first `{` to the last `}` span
|
|
287
|
+
(recovers a fenced ```json block or a prose preamble/trailing
|
|
288
|
+
sentence). Returns `None` for anything that isn't recoverable as a JSON
|
|
289
|
+
object — the caller treats that as a malformed final result and fails
|
|
290
|
+
open (zero rows), never guesses a verdict from a result it couldn't
|
|
291
|
+
parse."""
|
|
292
|
+
stripped = text.strip()
|
|
293
|
+
if not stripped:
|
|
294
|
+
return None
|
|
295
|
+
try:
|
|
296
|
+
parsed = json.loads(stripped)
|
|
297
|
+
except json.JSONDecodeError:
|
|
298
|
+
parsed = None
|
|
299
|
+
if isinstance(parsed, dict):
|
|
300
|
+
return parsed
|
|
301
|
+
start = stripped.find("{")
|
|
302
|
+
end = stripped.rfind("}")
|
|
303
|
+
if start == -1 or end == -1 or end <= start:
|
|
304
|
+
return None
|
|
305
|
+
try:
|
|
306
|
+
parsed = json.loads(stripped[start : end + 1])
|
|
307
|
+
except json.JSONDecodeError:
|
|
308
|
+
return None
|
|
309
|
+
return parsed if isinstance(parsed, dict) else None
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _issues_list(result: dict | None) -> list | None:
|
|
313
|
+
"""`None` means "can't trust any verdict from this result" (missing or
|
|
314
|
+
schema-drifted `issues`) — the caller fails open. A genuine empty list
|
|
315
|
+
is a usable clean result (every in-scope file gets `pass`)."""
|
|
316
|
+
if result is None:
|
|
317
|
+
return None
|
|
318
|
+
issues = result.get("issues")
|
|
319
|
+
return issues if isinstance(issues, list) else None
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _resolve_under_cwd(file_path: str, cwd) -> Path | None:
|
|
323
|
+
"""Resolve `file_path` (a scope-marker entry or an `issues[].file`
|
|
324
|
+
entry) against `cwd` to an absolute, symlink-resolved `Path` contained
|
|
325
|
+
within `cwd` — `None` when it can't be resolved or escapes `cwd` (a
|
|
326
|
+
`../../../../etc/passwd`-style traversal, Fix #5 security review).
|
|
327
|
+
|
|
328
|
+
Thin wrapper over the shared `review_verdicts.canonical_path` (#2167):
|
|
329
|
+
that function IS this one's containment-and-normalization logic, kept
|
|
330
|
+
in `hooks/lib/` so `scripts/verdict_scope.py`'s reader canonicalizes the
|
|
331
|
+
SAME way this writer does — real review-agent transcripts in this
|
|
332
|
+
session's own corpus report the SAME file in different path forms
|
|
333
|
+
(relative vs. absolute) across different agents (Fix #2, correctness
|
|
334
|
+
review), so a caller with its own second copy of this logic would drift
|
|
335
|
+
from the writer's own canonical form and silently never match a genuine
|
|
336
|
+
row."""
|
|
337
|
+
canonical = canonical_path(file_path, cwd)
|
|
338
|
+
if canonical is None:
|
|
339
|
+
return None
|
|
340
|
+
return Path(cwd).resolve() / canonical
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def _findings_files(issues: list, cwd) -> set[Path]:
|
|
344
|
+
files: set[Path] = set()
|
|
345
|
+
for issue in issues:
|
|
346
|
+
if not isinstance(issue, dict):
|
|
347
|
+
continue
|
|
348
|
+
file_path = issue.get("file")
|
|
349
|
+
if not isinstance(file_path, str) or not file_path:
|
|
350
|
+
continue
|
|
351
|
+
resolved = _resolve_under_cwd(file_path, cwd)
|
|
352
|
+
if resolved is not None:
|
|
353
|
+
files.add(resolved)
|
|
354
|
+
return files
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def process(payload: dict) -> None:
|
|
358
|
+
"""Fail-open SubagentStop processing (see module docstring Contract).
|
|
359
|
+
|
|
360
|
+
Writes zero or more rows via `emit_review_verdict`; never raises —
|
|
361
|
+
every input this function can't resolve confidently degrades to "write
|
|
362
|
+
nothing" rather than a guess (Decision 4a: this hook trusts the dispatch
|
|
363
|
+
prompt's declared scope, it does not independently re-verify it).
|
|
364
|
+
|
|
365
|
+
Fix #3 (correctness review): the early returns below the point where
|
|
366
|
+
`subagent_type` is confirmed to be a REGISTERED REVIEW LENS are
|
|
367
|
+
observationally degenerate (zero rows, zero stderr, exit 0) the same way
|
|
368
|
+
a legitimate no-op is — but unlike a legitimate no-op, they mean a
|
|
369
|
+
dispatch that SHOULD have produced rows didn't. Those two exits
|
|
370
|
+
(missing/reformatted scope marker, unparseable/malformed final result)
|
|
371
|
+
each record one `boundary_events` `"record"`-decision row naming the
|
|
372
|
+
reason, mirroring `subagent_completion_guard.py`'s own posture of
|
|
373
|
+
surfacing a non-clean, explainable classification instead of staying
|
|
374
|
+
silently indistinguishable from the happy path. The earlier,
|
|
375
|
+
PRE-resolution early returns (missing transcript, unreadable transcript,
|
|
376
|
+
unresolvable `subagent_type`, an entirely unregistered or a
|
|
377
|
+
registered-but-non-review `subagent_type`) stay silent — those are
|
|
378
|
+
legitimate no-ops: this dispatch was never confirmed to be a review
|
|
379
|
+
lens that should have produced rows at all."""
|
|
380
|
+
transcript_path = payload.get("transcript_path")
|
|
381
|
+
if not isinstance(transcript_path, str) or not transcript_path:
|
|
382
|
+
return
|
|
383
|
+
transcript = Path(transcript_path)
|
|
384
|
+
records = _read_transcript_records(transcript)
|
|
385
|
+
if not records:
|
|
386
|
+
return
|
|
387
|
+
|
|
388
|
+
subagent_type = _resolve_subagent_type(transcript, records)
|
|
389
|
+
if not subagent_type:
|
|
390
|
+
return
|
|
391
|
+
|
|
392
|
+
if not is_registered_review_lens(subagent_type):
|
|
393
|
+
return
|
|
394
|
+
|
|
395
|
+
# Past this point `subagent_type` is a confirmed, registered review
|
|
396
|
+
# lens -- this dispatch SHOULD produce rows (Fix #3).
|
|
397
|
+
cwd = resolve_cwd(payload)
|
|
398
|
+
session_id = payload.get("session_id")
|
|
399
|
+
|
|
400
|
+
first_text = _first_turn_text(records)
|
|
401
|
+
in_scope = _parse_scope_marker(first_text) if first_text else None
|
|
402
|
+
if not in_scope:
|
|
403
|
+
emit_boundary_event(
|
|
404
|
+
cwd,
|
|
405
|
+
"review_verdict_recorder",
|
|
406
|
+
"SubagentStop",
|
|
407
|
+
"record",
|
|
408
|
+
"missing-scope-marker",
|
|
409
|
+
session_id=session_id,
|
|
410
|
+
)
|
|
411
|
+
return
|
|
412
|
+
|
|
413
|
+
final_text = _final_result_text(records)
|
|
414
|
+
result = _extract_json_object(final_text) if final_text else None
|
|
415
|
+
issues = _issues_list(result)
|
|
416
|
+
if issues is None:
|
|
417
|
+
emit_boundary_event(
|
|
418
|
+
cwd,
|
|
419
|
+
"review_verdict_recorder",
|
|
420
|
+
"SubagentStop",
|
|
421
|
+
"record",
|
|
422
|
+
"unparseable-result",
|
|
423
|
+
session_id=session_id,
|
|
424
|
+
)
|
|
425
|
+
return
|
|
426
|
+
findings_files = _findings_files(issues, cwd)
|
|
427
|
+
# #2167 correctness review: per-file membership in `findings_files`
|
|
428
|
+
# alone recorded `pass` for every in-scope file whenever this lens's
|
|
429
|
+
# issues carried no `file` field, a `file` outside/unmapped to scope, or
|
|
430
|
+
# simply didn't happen to name one of THIS dispatch's files — even for a
|
|
431
|
+
# `status: "fail"`/`"warn"` result. Once #2167 acts on a `pass` row to
|
|
432
|
+
# skip a future dispatch, that silently erased the round's own verdict.
|
|
433
|
+
# A lens result that isn't clean marks every in-scope file `"findings"`,
|
|
434
|
+
# never just the ones an issue happens to name.
|
|
435
|
+
status = result.get("status") if isinstance(result, dict) else None
|
|
436
|
+
lens_result_is_clean = status in ("pass", "skip")
|
|
437
|
+
|
|
438
|
+
cwd_resolved = Path(cwd).resolve()
|
|
439
|
+
for file_path in in_scope:
|
|
440
|
+
canonical = canonical_path(file_path, cwd)
|
|
441
|
+
if canonical is None:
|
|
442
|
+
continue # unresolvable, or outside cwd containment (Fix #5)
|
|
443
|
+
resolved = cwd_resolved / canonical
|
|
444
|
+
file_hash = _hash_file(resolved)
|
|
445
|
+
if file_hash is None:
|
|
446
|
+
continue # deleted/unreadable/non-regular/oversized -- skip this one only
|
|
447
|
+
outcome = "pass" if lens_result_is_clean and resolved not in findings_files else "findings"
|
|
448
|
+
emit_review_verdict(
|
|
449
|
+
cwd, subagent_type, canonical, file_hash, outcome, session_id=session_id
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def main() -> int:
|
|
454
|
+
"""Fail-open SubagentStop entry point — see module docstring Contract."""
|
|
455
|
+
try:
|
|
456
|
+
payload = read_stdin_json() or {}
|
|
457
|
+
process(payload)
|
|
458
|
+
except Exception: # noqa: BLE001, S110 — fail-open by design, see module docstring
|
|
459
|
+
pass
|
|
460
|
+
return 0
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
if __name__ == "__main__":
|
|
464
|
+
sys.exit(main())
|