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,309 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""subagent_completion_guard.py — SubagentStop transcript-tail classifier (#2188).
|
|
3
|
+
|
|
4
|
+
Step 2.1a's research findings (below, preserved verbatim as the source citation
|
|
5
|
+
for the classifier Step 2.1b implements after them) confirmed the real
|
|
6
|
+
transcript-level shape of a subagent's completion against 70 real subagent
|
|
7
|
+
transcripts from this session. Step 2.1b (this implementation) turns those
|
|
8
|
+
findings into `classify_stop()`.
|
|
9
|
+
|
|
10
|
+
## Contract (docs/python-hook-contract.md)
|
|
11
|
+
|
|
12
|
+
Input : SubagentStop JSON on stdin (`transcript_path`, `session_id`, `cwd`)
|
|
13
|
+
Output: one `boundary-events.jsonl` `"record"`-decision row (#1461's
|
|
14
|
+
non-verdict, observational sense -- this hook never blocks, warns,
|
|
15
|
+
bypasses, intervenes, or reverts anything; see
|
|
16
|
+
`knowledge/telemetry-schema.md`) via
|
|
17
|
+
`hooks/lib/boundary_events.emit_boundary_event` for the two
|
|
18
|
+
non-clean, explainable classifications (`empty-final-turn`,
|
|
19
|
+
`truncated-final-turn`); nothing emitted for `clean` or
|
|
20
|
+
`unreadable` (Step 2.2, see `_EMIT_CLASSIFICATIONS`).
|
|
21
|
+
Posture: record-only and fail-open. Any error -> exit 0 silently.
|
|
22
|
+
|
|
23
|
+
Stdlib-only (json/pathlib/sys). See ADR 0014, ADR 0015.
|
|
24
|
+
|
|
25
|
+
## What was confirmed, and how
|
|
26
|
+
|
|
27
|
+
Primary source: this session's own subagent dispatch transcripts on disk at
|
|
28
|
+
~/.claude/projects/<project-slug>/<session-id>/subagents/agent-<hash>.jsonl
|
|
29
|
+
(+ a sibling agent-<hash>.meta.json per dispatch). 70 completed subagent transcripts were
|
|
30
|
+
inspected directly (not recalled/guessed) — this is real, live harness output from
|
|
31
|
+
Claude Code 2.1.278, not documentation. No web-doc citation was needed or used since a
|
|
32
|
+
real transcript was reachable, per this step's own instructions.
|
|
33
|
+
|
|
34
|
+
Compared against `hooks/cost_meter.py` (reads `transcript_path` from the hook payload,
|
|
35
|
+
checks `.is_file()`, does not itself parse rows — delegates to
|
|
36
|
+
`hooks/lib/cost_meter.py record`) and `hooks/task_completion_metrics.py` (reads
|
|
37
|
+
`payload.get("stop_reason")` — informational only, never branches on it) for how
|
|
38
|
+
existing SubagentStop hooks already touch this payload, and against
|
|
39
|
+
the former context ceiling guard's `_tail_lines`/`_is_sidechain`/`_measure_occupancy`
|
|
40
|
+
(its former lines 270-424) for the tail-reading and sidechain-row pattern.
|
|
41
|
+
|
|
42
|
+
## Finding 1 — where a subagent's own transcript lives, and what "sidechain" means here
|
|
43
|
+
|
|
44
|
+
A subagent's transcript is a SEPARATE file from the orchestrator/main-thread session
|
|
45
|
+
file, not inlined into it: `<session>.jsonl` (main thread) has a sibling
|
|
46
|
+
`<session>/subagents/agent-<hash>.jsonl` per dispatched subagent (confirmed: the main
|
|
47
|
+
thread's own `<session>.jsonl` had zero `"isSidechain":true` rows across 7798 lines,
|
|
48
|
+
while every row inside a per-agent `subagents/agent-*.jsonl` file is
|
|
49
|
+
`"isSidechain":true`). This matches Step 2.1b's own plan text precisely: for a
|
|
50
|
+
SubagentStop payload, the "sidechain" rows the former context ceiling guard excluded when
|
|
51
|
+
scanning the MAIN thread are exactly the subagent's own transcript rows when read from
|
|
52
|
+
its own file — nothing needs excluding when reading a subagent's transcript directly.
|
|
53
|
+
|
|
54
|
+
## Finding 2 — message.stop_reason IS present, but is null far more often than not
|
|
55
|
+
|
|
56
|
+
`message.stop_reason` uses the same field name and the same Anthropic Messages API
|
|
57
|
+
values (`end_turn` | `max_tokens` | `stop_sequence` | `tool_use`) as main-thread rows —
|
|
58
|
+
confirmed directly (e.g. a mid-turn row with `stop_reason:"tool_use"` on a finalized
|
|
59
|
+
tool_use block). However, across the true LAST row of 70 completed subagent transcripts:
|
|
60
|
+
|
|
61
|
+
stop_reason == null -> 61/70 (87%)
|
|
62
|
+
stop_reason == "end_turn" -> 8/70 (11%)
|
|
63
|
+
stop_reason == "tool_use" -> 1/70 (this session's own still-in-progress transcript
|
|
64
|
+
at the time of sampling, not a stopped turn)
|
|
65
|
+
stop_reason == "max_tokens" or "stop_sequence" -> 0/70 (no real example seen either
|
|
66
|
+
way; both remain unverified against a real
|
|
67
|
+
transcript — Anthropic's documented contract is
|
|
68
|
+
the only source for those two values)
|
|
69
|
+
|
|
70
|
+
All 61 `null` cases were genuinely clean, complete hand-backs (e.g. "Report delivered.",
|
|
71
|
+
"Report delivered to caller.", "Handed back: skip — no `.feature` files..."), not
|
|
72
|
+
truncated or errored ones — content was well-formed, non-empty text every time. A
|
|
73
|
+
classifier that treats "clean" as `stop_reason in ("end_turn", "tool_use")` on the final
|
|
74
|
+
row alone will misclassify the large majority of real clean completions. Step 2.1b's
|
|
75
|
+
classifier needs "non-empty content AND stop_reason != 'max_tokens'" as the clean
|
|
76
|
+
signal, not a stop_reason allow-list — `null` must be treated as equivalent to clean,
|
|
77
|
+
not as an unhandled case. (This finding was outside Step 2.1a's edit mandate, which was
|
|
78
|
+
scoped to the malformed-hand-back scenario only, so the plan's Gherkin "Clean
|
|
79
|
+
completion" `Given` clause text was left unedited — flagged here and in the plan's
|
|
80
|
+
Risks & Open Questions section for Step 2.1b to account for.)
|
|
81
|
+
|
|
82
|
+
## Finding 3 — SubagentHandback is a real, distinguishable tool_use block
|
|
83
|
+
|
|
84
|
+
`SubagentHandback` (the tool a dispatched subagent calls to report back to its caller,
|
|
85
|
+
per this session's own system-prompt tool description) shows up as a genuine
|
|
86
|
+
`{"type":"tool_use","name":"SubagentHandback","input":{"message": "..."}}` block — 69
|
|
87
|
+
real occurrences found across the 70 transcripts. It is a real, greppable signal beyond
|
|
88
|
+
bare stop_reason+content.
|
|
89
|
+
|
|
90
|
+
It is essentially NEVER the transcript's true final row, though: every real example
|
|
91
|
+
followed the same shape — `tool_use` (SubagentHandback, stop_reason "tool_use") ->
|
|
92
|
+
`tool_result` (ack) -> one more short assistant text turn (stop_reason usually null, see
|
|
93
|
+
Finding 2) such as "Report delivered." That final wrap-up turn, not the SubagentHandback
|
|
94
|
+
call itself, is the transcript's real last row on a clean path.
|
|
95
|
+
|
|
96
|
+
## Finding 4 — "malformed hand-back" has no reliable, unique transcript-level signal
|
|
97
|
+
|
|
98
|
+
Zero of the 69 real `SubagentHandback` calls were malformed (none missing/empty the
|
|
99
|
+
required `message` field), and zero `tool_result` rows tied to a `SubagentHandback`
|
|
100
|
+
`tool_use_id` were flagged `is_error`. Structurally: the tool schema requires `message`
|
|
101
|
+
as a string parameter, so a call missing it would almost certainly be rejected at the
|
|
102
|
+
tool-call-validation layer before ever being persisted as a "call with a missing
|
|
103
|
+
field" — producing a generic `is_error` tool_result indistinguishable in shape from any
|
|
104
|
+
other tool's error (a bad `Read` path, a failed `Bash` command, etc.), not a
|
|
105
|
+
hand-back-specific signature. Combined with Finding 3 (the call is essentially never the
|
|
106
|
+
final row anyway, so "final turn contains a hand-back-shaped call" doesn't match the
|
|
107
|
+
real shape), there is no way to build the plan's original "Malformed hand-back" scenario
|
|
108
|
+
against real evidence rather than a guess.
|
|
109
|
+
|
|
110
|
+
**Decision (per this step's own instruction): the "Malformed hand-back" Gherkin
|
|
111
|
+
scenario and its corresponding Acceptance Criteria bullet are DROPPED, not rescoped.**
|
|
112
|
+
Recorded against issue #2188 (epic #2172) — its Gherkin block, Acceptance Criteria
|
|
113
|
+
bullet, and Risks & Open Questions entry were revised to match, in the same commit-set
|
|
114
|
+
as this file's header.
|
|
115
|
+
|
|
116
|
+
## Classification precedence (#2188 Step 2.1b — stated explicitly here so two
|
|
117
|
+
## implementers can't disagree)
|
|
118
|
+
|
|
119
|
+
1. Unreadable/missing transcript, or a readable transcript whose last row is
|
|
120
|
+
missing an expected `message`/`content` field entirely (structurally
|
|
121
|
+
malformed, not just "empty") -> fail-open, `"unreadable"`, no event.
|
|
122
|
+
2. `message.stop_reason == "max_tokens"` -> `"truncated-final-turn"`. Checked
|
|
123
|
+
BEFORE the empty-content check: a token-limit cutoff can itself produce
|
|
124
|
+
empty/near-empty content (Finding 2 notes no real `max_tokens` example was
|
|
125
|
+
seen, but the Messages API contract still governs it), and `stop_reason` is
|
|
126
|
+
the more specific, intentional signal, so it wins the overlap case.
|
|
127
|
+
3. Empty/whitespace-only final assistant content, with `stop_reason` anything
|
|
128
|
+
other than `"max_tokens"` (including the common `null` case, per Finding 2)
|
|
129
|
+
-> `"empty-final-turn"`.
|
|
130
|
+
4. Otherwise (including `stop_reason: null` with non-empty content, and
|
|
131
|
+
`stop_reason: "end_turn"`/`"tool_use"` with non-empty content) -> `"clean"`.
|
|
132
|
+
|
|
133
|
+
No "malformed hand-back" branch: Finding 4 above found no reliable,
|
|
134
|
+
uniquely-identifying transcript-level signal for it, and the plan's Gherkin
|
|
135
|
+
scenario for it was dropped rather than built against a guess.
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
from __future__ import annotations
|
|
139
|
+
|
|
140
|
+
import json
|
|
141
|
+
import sys
|
|
142
|
+
from pathlib import Path
|
|
143
|
+
from typing import Literal
|
|
144
|
+
|
|
145
|
+
_HOOK_DIR = Path(__file__).resolve().parent
|
|
146
|
+
_LIB_DIR = _HOOK_DIR / "lib"
|
|
147
|
+
if str(_LIB_DIR) not in sys.path:
|
|
148
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
149
|
+
|
|
150
|
+
from boundary_events import emit_boundary_event # type: ignore[import-not-found]
|
|
151
|
+
from instrument_log import append_row # type: ignore[import-not-found]
|
|
152
|
+
from stdin_json import read_stdin_json # type: ignore[import-not-found]
|
|
153
|
+
|
|
154
|
+
StopClassification = Literal[
|
|
155
|
+
"clean", "empty-final-turn", "truncated-final-turn", "unreadable"
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
# Classifications that warrant a boundary event (#2188 Step 2.2). "clean" and
|
|
159
|
+
# "unreadable" are both no-ops: "clean" is the expected happy path (nothing to
|
|
160
|
+
# record), and "unreadable" has no reliable transcript-level signal to name a
|
|
161
|
+
# rule for (see Finding 4 above) -- emitting a matched_rule for a case this
|
|
162
|
+
# hook itself can't explain would be a fabricated-confidence event, so it
|
|
163
|
+
# stays silent like every other fail-open path in this hook.
|
|
164
|
+
_EMIT_CLASSIFICATIONS: frozenset[StopClassification] = frozenset(
|
|
165
|
+
{"empty-final-turn", "truncated-final-turn"}
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _tail_lines(path: Path, n: int = 50) -> list[str]:
|
|
170
|
+
"""Read the last `n` lines of `path`. Fail-safe: [] on any IO error.
|
|
171
|
+
|
|
172
|
+
Deliberately a small, private, inline reader for this hook rather than
|
|
173
|
+
`scripts/lib/session_log/records.py`'s `iter_file_records` (the
|
|
174
|
+
sanctioned shared transcript-row reader that `review_verdict_recorder.py`
|
|
175
|
+
and `hooks/lib/cost_meter.py` already use over the documented
|
|
176
|
+
hooks/ -> scripts/lib/session_log/ edge — see the import note in
|
|
177
|
+
`hooks/lib/cost_meter.py`). Not reused here because the semantics genuinely differ: `iter_file_records` streams
|
|
178
|
+
forward and silently skips an undecodable line, continuing to the next
|
|
179
|
+
one, while this hook needs "the transcript's true LAST line is malformed
|
|
180
|
+
JSON" to classify as its own distinct outcome (`"unreadable"`, see
|
|
181
|
+
`_last_row` below) rather than silently falling back to an earlier valid
|
|
182
|
+
row. A skip-and-continue streaming reader cannot express that
|
|
183
|
+
distinction, so this hook keeps its own minimal last-row reader (#2188
|
|
184
|
+
Step 2.1b).
|
|
185
|
+
"""
|
|
186
|
+
try:
|
|
187
|
+
with path.open("r", encoding="utf-8", errors="replace") as fh:
|
|
188
|
+
lines = fh.readlines()
|
|
189
|
+
except OSError:
|
|
190
|
+
return []
|
|
191
|
+
return lines[-n:] if len(lines) > n else lines
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _last_row(transcript_path: str) -> dict | None:
|
|
195
|
+
"""Return the transcript's true last JSON row as a dict, or None.
|
|
196
|
+
|
|
197
|
+
None covers every fail-open case this hook treats identically: a missing
|
|
198
|
+
file, an unreadable file, an empty file, or a last non-blank line that
|
|
199
|
+
isn't valid JSON / isn't a JSON object. Per Finding 1, a subagent's own
|
|
200
|
+
transcript file needs no sidechain filtering — every row in it already
|
|
201
|
+
belongs to this subagent.
|
|
202
|
+
"""
|
|
203
|
+
lines = _tail_lines(Path(transcript_path))
|
|
204
|
+
for raw in reversed(lines):
|
|
205
|
+
raw = raw.strip()
|
|
206
|
+
if not raw:
|
|
207
|
+
continue
|
|
208
|
+
try:
|
|
209
|
+
row = json.loads(raw)
|
|
210
|
+
except (json.JSONDecodeError, ValueError):
|
|
211
|
+
return None
|
|
212
|
+
return row if isinstance(row, dict) else None
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _is_empty_content(content: object) -> bool:
|
|
217
|
+
"""True when an assistant message's `content` carries no real text.
|
|
218
|
+
|
|
219
|
+
A plain string is checked directly. A content-block list (the normal
|
|
220
|
+
Messages API shape) is empty when every block is a `text` block and their
|
|
221
|
+
concatenated text is blank; a list containing any non-text block (e.g. a
|
|
222
|
+
`tool_use` block) is never considered empty here.
|
|
223
|
+
"""
|
|
224
|
+
if content is None:
|
|
225
|
+
return True
|
|
226
|
+
if isinstance(content, str):
|
|
227
|
+
return not content.strip()
|
|
228
|
+
if isinstance(content, list):
|
|
229
|
+
if not content:
|
|
230
|
+
return True
|
|
231
|
+
text_parts: list[str] = []
|
|
232
|
+
for block in content:
|
|
233
|
+
if isinstance(block, dict) and block.get("type") == "text":
|
|
234
|
+
text_parts.append(block.get("text") or "")
|
|
235
|
+
else:
|
|
236
|
+
return False
|
|
237
|
+
return not "".join(text_parts).strip()
|
|
238
|
+
return True
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def classify_stop(transcript_path: str) -> StopClassification:
|
|
242
|
+
"""Classify a subagent's SubagentStop transcript tail.
|
|
243
|
+
|
|
244
|
+
See the module-level "Classification precedence" section above for the
|
|
245
|
+
full rule order and citations. Pure function: no I/O beyond reading
|
|
246
|
+
`transcript_path`, no side effects — `main()` wires the result to
|
|
247
|
+
`hooks/lib/boundary_events.emit_boundary_event` (Step 2.2).
|
|
248
|
+
"""
|
|
249
|
+
row = _last_row(transcript_path)
|
|
250
|
+
if row is None:
|
|
251
|
+
return "unreadable"
|
|
252
|
+
|
|
253
|
+
message = row.get("message")
|
|
254
|
+
if not isinstance(message, dict) or "content" not in message:
|
|
255
|
+
return "unreadable"
|
|
256
|
+
|
|
257
|
+
if message.get("stop_reason") == "max_tokens":
|
|
258
|
+
return "truncated-final-turn"
|
|
259
|
+
|
|
260
|
+
if _is_empty_content(message.get("content")):
|
|
261
|
+
return "empty-final-turn"
|
|
262
|
+
|
|
263
|
+
return "clean"
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def main() -> int:
|
|
267
|
+
"""Fail-open SubagentStop entry point.
|
|
268
|
+
|
|
269
|
+
Reads the hook payload, classifies the transcript tail, and emits a
|
|
270
|
+
`boundary-events.jsonl` `"record"`-decision row for the two non-clean,
|
|
271
|
+
explainable outcomes (`empty-final-turn`, `truncated-final-turn`) via
|
|
272
|
+
`hooks/lib/boundary_events.emit_boundary_event` — see
|
|
273
|
+
`_EMIT_CLASSIFICATIONS` above for why `clean`/`unreadable` stay silent.
|
|
274
|
+
`emit_boundary_event` is already fail-open internally (module docstring,
|
|
275
|
+
`boundary_events.py`); this function's own try/except is the same
|
|
276
|
+
outer safety net every other hook in this plugin wraps its entire
|
|
277
|
+
`main()` in (e.g. `destructive_guard.py`), so a failure anywhere in
|
|
278
|
+
this hook — payload parsing, classification, or emission — degrades to a
|
|
279
|
+
silent no-op, never a crash or a non-zero exit.
|
|
280
|
+
"""
|
|
281
|
+
try:
|
|
282
|
+
payload = read_stdin_json() or {}
|
|
283
|
+
transcript_path = payload.get("transcript_path")
|
|
284
|
+
if isinstance(transcript_path, str) and transcript_path:
|
|
285
|
+
classification = classify_stop(transcript_path)
|
|
286
|
+
# Every classification, incl. clean/unreadable: the denominator
|
|
287
|
+
# the divergence rate needs (#2201). Observational only.
|
|
288
|
+
append_row(
|
|
289
|
+
"subagent-stops",
|
|
290
|
+
{"classification": classification},
|
|
291
|
+
cwd=payload.get("cwd"),
|
|
292
|
+
session_id=payload.get("session_id"),
|
|
293
|
+
)
|
|
294
|
+
if classification in _EMIT_CLASSIFICATIONS:
|
|
295
|
+
emit_boundary_event(
|
|
296
|
+
payload.get("cwd"),
|
|
297
|
+
"subagent_completion_guard",
|
|
298
|
+
"SubagentStop",
|
|
299
|
+
"record",
|
|
300
|
+
classification,
|
|
301
|
+
payload.get("session_id"),
|
|
302
|
+
)
|
|
303
|
+
except Exception: # noqa: BLE001, S110 — fail-open by design, see module docstring
|
|
304
|
+
pass
|
|
305
|
+
return 0
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
if __name__ == "__main__":
|
|
309
|
+
sys.exit(main())
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""subagent_skill_context.py — PreToolUse hook injecting skill-loading
|
|
3
|
+
context into an Agent/Task dispatch (#2187, Slice 1 Step 1.2).
|
|
4
|
+
|
|
5
|
+
Registered in the existing `PreToolUse` `"Agent|Task"` matcher (alongside
|
|
6
|
+
`agent_dispatch_ledger.py`). Reads
|
|
7
|
+
`tool_input.subagent_type`, resolves its declared skills via
|
|
8
|
+
`hooks/lib/agent_skill_hints.py::skills_for_agent_type` (frontmatter
|
|
9
|
+
`skills:` is the single source of truth — ADR 0028), and when that list is
|
|
10
|
+
non-empty, emits `hookSpecificOutput.updatedInput` naming those skills as an
|
|
11
|
+
`additionalContext` note appended to the dispatch's `tool_input` — the
|
|
12
|
+
original `tool_input` keys are preserved unchanged, never replaced.
|
|
13
|
+
|
|
14
|
+
No collision with the other hooks on this matcher: none emits
|
|
15
|
+
`hookSpecificOutput`/`updatedInput` today, so this hook is the sole supplier of `updatedInput`
|
|
16
|
+
for `Agent|Task` PreToolUse.
|
|
17
|
+
|
|
18
|
+
Fail-open throughout, matching every other hook in this plugin:
|
|
19
|
+
- `tool_name` not in {"Agent", "Task"} -> exit 0, no stdout.
|
|
20
|
+
- `tool_input.subagent_type` missing or not a non-empty string -> exit 0,
|
|
21
|
+
no stdout, no `updatedInput`.
|
|
22
|
+
- unrecognized agent type / no declared skills -> exit 0, no stdout.
|
|
23
|
+
- malformed/missing stdin -> exit 0 (mirrors `read_stdin_json`'s own
|
|
24
|
+
fail-open contract exactly).
|
|
25
|
+
|
|
26
|
+
Contract (docs/python-hook-contract.md):
|
|
27
|
+
Input : PreToolUse JSON on stdin
|
|
28
|
+
Output: JSON on stdout carrying `hookSpecificOutput.updatedInput` when a
|
|
29
|
+
skill hint applies; otherwise no stdout. Always exits 0.
|
|
30
|
+
|
|
31
|
+
Stdlib only. See ADR 0014 / ADR 0015.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
import json
|
|
37
|
+
import sys
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
|
|
40
|
+
_HOOKS_DIR = Path(__file__).resolve().parent
|
|
41
|
+
_LIB_DIR = _HOOKS_DIR / "lib"
|
|
42
|
+
if str(_LIB_DIR) not in sys.path:
|
|
43
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
44
|
+
|
|
45
|
+
from agent_skill_hints import skills_for_agent_type # type: ignore[import-not-found]
|
|
46
|
+
from instrument_log import append_row # type: ignore[import-not-found]
|
|
47
|
+
from review_agent_registry import strip_plugin_prefix # type: ignore[import-not-found]
|
|
48
|
+
from stdin_json import read_stdin_json # type: ignore[import-not-found]
|
|
49
|
+
|
|
50
|
+
# hooks/subagent_skill_context.py -> hooks -> plugin root -> agents
|
|
51
|
+
_DEFAULT_AGENTS_DIR = _HOOKS_DIR.parent / "agents"
|
|
52
|
+
|
|
53
|
+
_DISPATCH_TOOLS = frozenset({"Agent", "Task"})
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _build_note(skills: list[str]) -> str:
|
|
57
|
+
return (
|
|
58
|
+
"Relevant skills for this dispatch (per the agent's own frontmatter "
|
|
59
|
+
f"`skills:` list): {', '.join(skills)}."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def resolve_updated_input(
|
|
64
|
+
payload: dict, agents_dir: Path | None = None
|
|
65
|
+
) -> dict | None:
|
|
66
|
+
"""Compute the `updatedInput` dict for a PreToolUse payload, or `None`
|
|
67
|
+
when no hint applies. Split from `main()` for testability.
|
|
68
|
+
|
|
69
|
+
`agents_dir` defaults to the module-level `_DEFAULT_AGENTS_DIR`, read at
|
|
70
|
+
call time (not bound as a mutable default) so tests can
|
|
71
|
+
`monkeypatch.setattr(hook, "_DEFAULT_AGENTS_DIR", tmp_path)` and have it
|
|
72
|
+
take effect.
|
|
73
|
+
"""
|
|
74
|
+
if agents_dir is None:
|
|
75
|
+
agents_dir = _DEFAULT_AGENTS_DIR
|
|
76
|
+
|
|
77
|
+
tool_name = payload.get("tool_name")
|
|
78
|
+
if tool_name not in _DISPATCH_TOOLS:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
tool_input = payload.get("tool_input")
|
|
82
|
+
if not isinstance(tool_input, dict):
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
subagent_type = tool_input.get("subagent_type")
|
|
86
|
+
if not isinstance(subagent_type, str) or not subagent_type:
|
|
87
|
+
return None
|
|
88
|
+
subagent_type = strip_plugin_prefix(subagent_type)
|
|
89
|
+
|
|
90
|
+
skills = skills_for_agent_type(subagent_type, agents_dir)
|
|
91
|
+
if not skills:
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
return {**tool_input, "additionalContext": _build_note(skills)}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def main() -> int:
|
|
98
|
+
try:
|
|
99
|
+
payload = read_stdin_json()
|
|
100
|
+
if payload is None:
|
|
101
|
+
# Empty or malformed stdin -> silent pass, same as every other hook.
|
|
102
|
+
return 0
|
|
103
|
+
|
|
104
|
+
updated_input = resolve_updated_input(payload)
|
|
105
|
+
if updated_input is None:
|
|
106
|
+
return 0
|
|
107
|
+
|
|
108
|
+
# Observational only (#2201): lets uptake be computed against the
|
|
109
|
+
# subagent transcripts' Skill tool calls.
|
|
110
|
+
append_row(
|
|
111
|
+
"skill-injection",
|
|
112
|
+
{
|
|
113
|
+
"agent_type": payload["tool_input"]["subagent_type"],
|
|
114
|
+
"skills": skills_for_agent_type(
|
|
115
|
+
strip_plugin_prefix(payload["tool_input"]["subagent_type"]),
|
|
116
|
+
_DEFAULT_AGENTS_DIR,
|
|
117
|
+
),
|
|
118
|
+
"added_chars": len(updated_input["additionalContext"]),
|
|
119
|
+
},
|
|
120
|
+
cwd=payload.get("cwd"),
|
|
121
|
+
session_id=payload.get("session_id"),
|
|
122
|
+
)
|
|
123
|
+
print(
|
|
124
|
+
json.dumps(
|
|
125
|
+
{
|
|
126
|
+
"hookSpecificOutput": {
|
|
127
|
+
"hookEventName": "PreToolUse",
|
|
128
|
+
"updatedInput": updated_input,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
except Exception: # noqa: BLE001, S110 — fail-open by design, see module docstring
|
|
134
|
+
pass
|
|
135
|
+
return 0
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__": # pragma: no cover
|
|
139
|
+
sys.exit(main())
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""task_completion_metrics.py — Stop/SubagentStop hook for JSONL audit logging.
|
|
3
|
+
|
|
4
|
+
Fires on task/session completion signals (Stop + SubagentStop) and writes
|
|
5
|
+
standard metrics fields to their respective JSONL files, mechanically,
|
|
6
|
+
regardless of which skill or agent was active.
|
|
7
|
+
|
|
8
|
+
Skills no longer need "remember to log X" prose in their Output sections.
|
|
9
|
+
They only need to have populated the shared scratch file
|
|
10
|
+
`.claude/session-metrics.json` with any task-local values they want recorded.
|
|
11
|
+
The hook consumes that file and clears it after writing.
|
|
12
|
+
|
|
13
|
+
## Scratch file format (.claude/session-metrics.json)
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"task_id": "optional-human-slug",
|
|
18
|
+
"task_type": "implementation",
|
|
19
|
+
"task_description": "Short description of the task",
|
|
20
|
+
"agents_used": ["software-engineer"],
|
|
21
|
+
"skills_used": ["quality-gate-pipeline"],
|
|
22
|
+
"hallucination_detected": false,
|
|
23
|
+
"rework_cycles": 0,
|
|
24
|
+
"defects_found": 0,
|
|
25
|
+
"config_change": {
|
|
26
|
+
"parameter": "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE",
|
|
27
|
+
"old_value": "40",
|
|
28
|
+
"new_value": "50",
|
|
29
|
+
"reason": "Increased for larger context models"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
All fields are optional. If the scratch file is absent or empty, the hook
|
|
35
|
+
writes **nothing** and exits — a Stop/SubagentStop with no task-local payload
|
|
36
|
+
carries no signal worth recording, and a bare heartbeat only produces
|
|
37
|
+
`task_type:"unknown"` noise that dilutes `/harness-audit` Step 3 (see #1258;
|
|
38
|
+
a single 2026-07-20 audit run emitted 172 empty heartbeats vs 10 real rows).
|
|
39
|
+
|
|
40
|
+
## Output files
|
|
41
|
+
|
|
42
|
+
- `.claude/metrics/{date}-task-log.jsonl` — task completion entry
|
|
43
|
+
- `.claude/metrics/config-changelog.jsonl` — config change entry (if `config_change` present)
|
|
44
|
+
|
|
45
|
+
## Contract (docs/python-hook-contract.md)
|
|
46
|
+
|
|
47
|
+
Input : Stop / SubagentStop JSON on stdin
|
|
48
|
+
Output: appends to metrics JSONL files; no stdout. Exit 0.
|
|
49
|
+
Posture: record-only and fail-open. Any error -> exit 0 silently.
|
|
50
|
+
Opt-out: DEV_TEAM_TASK_METRICS=off disables entirely.
|
|
51
|
+
|
|
52
|
+
Stdlib-only (datetime/json/os/pathlib/sys/uuid).
|
|
53
|
+
See ADR 0014, ADR 0015.
|
|
54
|
+
|
|
55
|
+
Refs: #1044 (this hook), #1042 (parent epic).
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
from __future__ import annotations
|
|
59
|
+
|
|
60
|
+
import datetime
|
|
61
|
+
import json
|
|
62
|
+
import os
|
|
63
|
+
import sys
|
|
64
|
+
import uuid
|
|
65
|
+
from pathlib import Path
|
|
66
|
+
|
|
67
|
+
_HOOK_DIR = Path(__file__).resolve().parent
|
|
68
|
+
_PLUGIN_DIR = _HOOK_DIR.parent
|
|
69
|
+
_LIB_DIR = _HOOK_DIR / "lib"
|
|
70
|
+
if str(_LIB_DIR) not in sys.path:
|
|
71
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
72
|
+
|
|
73
|
+
import artifact_paths
|
|
74
|
+
import telemetry_consent
|
|
75
|
+
from atomic_state import append_line_locked
|
|
76
|
+
from stdin_json import read_stdin_json # type: ignore[import-not-found]
|
|
77
|
+
|
|
78
|
+
# Scratch file location: resolved relative to the project root (cwd when hook
|
|
79
|
+
# fires) so it is session-local, not baked into the plugin install tree.
|
|
80
|
+
_SCRATCH_RELATIVE = Path(".claude") / "session-metrics.json"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _env_off(var: str) -> bool:
|
|
84
|
+
return os.environ.get(var, "").strip().lower() == "off"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _load_scratch(cwd: Path) -> dict:
|
|
88
|
+
scratch = cwd / _SCRATCH_RELATIVE
|
|
89
|
+
try:
|
|
90
|
+
if not scratch.exists():
|
|
91
|
+
return {}
|
|
92
|
+
text = scratch.read_text(encoding="utf-8").strip()
|
|
93
|
+
if not text:
|
|
94
|
+
return {}
|
|
95
|
+
parsed = json.loads(text)
|
|
96
|
+
return parsed if isinstance(parsed, dict) else {}
|
|
97
|
+
except (json.JSONDecodeError, UnicodeDecodeError, OSError):
|
|
98
|
+
return {}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _clear_scratch(cwd: Path) -> None:
|
|
102
|
+
scratch = cwd / _SCRATCH_RELATIVE
|
|
103
|
+
try:
|
|
104
|
+
if scratch.exists():
|
|
105
|
+
scratch.unlink()
|
|
106
|
+
except OSError: # best-effort cleanup; a stale scratch file is harmless
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _ensure_metrics_dir(cwd: Path) -> Path:
|
|
111
|
+
metrics = artifact_paths.metrics_dir(cwd)
|
|
112
|
+
metrics.mkdir(parents=True, exist_ok=True)
|
|
113
|
+
return metrics
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _now_iso() -> str:
|
|
117
|
+
return datetime.datetime.now(tz=datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _today() -> str:
|
|
121
|
+
return datetime.datetime.now(tz=datetime.timezone.utc).strftime("%Y-%m-%d")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _append_jsonl(path: Path, entry: dict) -> None:
|
|
125
|
+
"""Append one JSON line to a JSONL file, creating it if needed.
|
|
126
|
+
|
|
127
|
+
Serialized against concurrent writers via `atomic_state.append_line_locked`
|
|
128
|
+
(#1896) — fail-open, matching this hook's outer `main()` try/except.
|
|
129
|
+
"""
|
|
130
|
+
line = json.dumps(entry, separators=(",", ":"), sort_keys=False)
|
|
131
|
+
append_line_locked(path, line + "\n")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _write_task_completion(cwd: Path, scratch: dict, payload: dict) -> None:
|
|
135
|
+
"""Write a task completion entry to .claude/metrics/{date}-task-log.jsonl."""
|
|
136
|
+
ts = _now_iso()
|
|
137
|
+
entry: dict = {
|
|
138
|
+
"timestamp": ts,
|
|
139
|
+
"task_id": scratch.get("task_id") or str(uuid.uuid4()),
|
|
140
|
+
"task_type": scratch.get("task_type", "unknown"),
|
|
141
|
+
"task_description": scratch.get("task_description", ""),
|
|
142
|
+
"agents_used": scratch.get("agents_used") or [],
|
|
143
|
+
"skills_used": scratch.get("skills_used") or [],
|
|
144
|
+
"hallucination_detected": bool(scratch.get("hallucination_detected", False)),
|
|
145
|
+
"rework_cycles": int(scratch.get("rework_cycles", 0)),
|
|
146
|
+
"defects_found": int(scratch.get("defects_found", 0)),
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Include stop-reason from harness if available (informational).
|
|
150
|
+
stop_reason = payload.get("stop_reason") or payload.get("stopReason")
|
|
151
|
+
if stop_reason:
|
|
152
|
+
entry["stop_reason"] = stop_reason
|
|
153
|
+
|
|
154
|
+
log_path = artifact_paths.resolve_file(
|
|
155
|
+
"metrics", f"{_today()}-task-log.jsonl", cwd
|
|
156
|
+
)
|
|
157
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
158
|
+
_append_jsonl(log_path, entry)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _write_config_changelog(cwd: Path, scratch: dict) -> None:
|
|
162
|
+
"""Write a config-changelog entry if scratch contains config_change."""
|
|
163
|
+
change = scratch.get("config_change")
|
|
164
|
+
if not change or not isinstance(change, dict):
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
ts = _now_iso()
|
|
168
|
+
entry: dict = {
|
|
169
|
+
"timestamp": ts,
|
|
170
|
+
"parameter": change.get("parameter", ""),
|
|
171
|
+
"old_value": change.get("old_value", ""),
|
|
172
|
+
"new_value": change.get("new_value", ""),
|
|
173
|
+
"reason": change.get("reason", ""),
|
|
174
|
+
}
|
|
175
|
+
log_path = artifact_paths.resolve_file("metrics", "config-changelog.jsonl", cwd)
|
|
176
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
177
|
+
_append_jsonl(log_path, entry)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def main() -> int:
|
|
181
|
+
if _env_off("DEV_TEAM_TASK_METRICS"):
|
|
182
|
+
return 0
|
|
183
|
+
if not telemetry_consent.is_enabled():
|
|
184
|
+
return 0
|
|
185
|
+
|
|
186
|
+
payload = read_stdin_json() or {}
|
|
187
|
+
|
|
188
|
+
# Resolve project root from the hook payload's cwd, falling back to
|
|
189
|
+
# process cwd (which the harness sets to the project root).
|
|
190
|
+
raw_cwd = payload.get("cwd") or os.environ.get("CLAUDE_PROJECT_DIR") or ""
|
|
191
|
+
cwd = Path(raw_cwd).resolve() if raw_cwd else Path.cwd()
|
|
192
|
+
|
|
193
|
+
scratch = _load_scratch(cwd)
|
|
194
|
+
|
|
195
|
+
# Suppress empty heartbeats (#1258). A Stop/SubagentStop with no scratch
|
|
196
|
+
# payload has nothing task-local to record — writing an entry would only
|
|
197
|
+
# emit a hollow task_type:"unknown" row that dilutes downstream analysis
|
|
198
|
+
# (harness-audit Step 3). The stop payload alone (stop_reason, cost) is not
|
|
199
|
+
# enough to justify a row; a skill that wants a row populates the scratch.
|
|
200
|
+
if not scratch:
|
|
201
|
+
return 0
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
_ensure_metrics_dir(cwd)
|
|
205
|
+
_write_task_completion(cwd, scratch, payload)
|
|
206
|
+
_write_config_changelog(cwd, scratch)
|
|
207
|
+
_clear_scratch(cwd)
|
|
208
|
+
except Exception: # noqa: BLE001, S110
|
|
209
|
+
# Fail-open: never block the session on a metrics write failure.
|
|
210
|
+
pass
|
|
211
|
+
|
|
212
|
+
return 0
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
if __name__ == "__main__":
|
|
216
|
+
sys.exit(main())
|