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.
Files changed (780) hide show
  1. package/LICENSE +21 -0
  2. package/PORTING.md +134 -0
  3. package/README.md +207 -0
  4. package/UPSTREAM.json +64 -0
  5. package/agents/Explore.md +15 -0
  6. package/agents/a11y-review.md +118 -0
  7. package/agents/adr-author.md +70 -0
  8. package/agents/ai-provenance-review.md +120 -0
  9. package/agents/angular-reactivity-review.md +95 -0
  10. package/agents/arch-review.md +135 -0
  11. package/agents/architect.md +78 -0
  12. package/agents/autoship-batch-proposer.md +69 -0
  13. package/agents/claude-setup-review.md +136 -0
  14. package/agents/codebase-recon.md +184 -0
  15. package/agents/component-architecture-review.md +119 -0
  16. package/agents/concurrency-review.md +109 -0
  17. package/agents/correctness-review.md +290 -0
  18. package/agents/data-flow-tracer.md +120 -0
  19. package/agents/doc-review.md +165 -0
  20. package/agents/domain-review.md +136 -0
  21. package/agents/general-purpose.md +10 -0
  22. package/agents/gherkin-quality-critic.md +113 -0
  23. package/agents/js-fp-review.md +114 -0
  24. package/agents/mutation-kill.md +684 -0
  25. package/agents/naming-review.md +142 -0
  26. package/agents/orchestrator.md +339 -0
  27. package/agents/performance-review.md +105 -0
  28. package/agents/plan-review-acceptance.md +115 -0
  29. package/agents/plan-review-design.md +90 -0
  30. package/agents/plan-review-parallelization.md +84 -0
  31. package/agents/plan-review-strategic.md +96 -0
  32. package/agents/plan-review-ux.md +110 -0
  33. package/agents/platform-engineer.md +64 -0
  34. package/agents/product-manager.md +68 -0
  35. package/agents/progress-guardian.md +79 -0
  36. package/agents/qa-engineer.md +289 -0
  37. package/agents/quality-reviewer.md +132 -0
  38. package/agents/react-reactivity-review.md +102 -0
  39. package/agents/refactor-opportunity-review.md +128 -0
  40. package/agents/security-engineer.md +60 -0
  41. package/agents/security-review.md +218 -0
  42. package/agents/session-analysis.md +95 -0
  43. package/agents/software-engineer.md +105 -0
  44. package/agents/spec-compliance-review.md +100 -0
  45. package/agents/spec-reviewer.md +114 -0
  46. package/agents/structure-review.md +146 -0
  47. package/agents/tech-writer.md +84 -0
  48. package/agents/test-review.md +246 -0
  49. package/agents/test-smell-review.md +188 -0
  50. package/agents/token-efficiency-review.md +139 -0
  51. package/agents/ui-ux-designer.md +54 -0
  52. package/agents/vue-reactivity-review.md +95 -0
  53. package/bin/__pycache__/claudecpython-314.pyc +0 -0
  54. package/bin/claude +258 -0
  55. package/docs/upstream/.pages +1 -0
  56. package/docs/upstream/CHANGELOG.md +2586 -0
  57. package/docs/upstream/README.md +155 -0
  58. package/docs/upstream/agent-architecture.md +214 -0
  59. package/docs/upstream/agent_info.md +187 -0
  60. package/docs/upstream/artifact-migration.md +124 -0
  61. package/docs/upstream/code-intelligence-nudge.md +149 -0
  62. package/docs/upstream/code-review-process.md +294 -0
  63. package/docs/upstream/concurrent-use.md +73 -0
  64. package/docs/upstream/context-management.md +111 -0
  65. package/docs/upstream/developer-notes.md +280 -0
  66. package/docs/upstream/diagrams/architecture-overview.svg +101 -0
  67. package/docs/upstream/diagrams/review-dispatch.svg +139 -0
  68. package/docs/upstream/diagrams/team-agents.svg +128 -0
  69. package/docs/upstream/diagrams/test-improve-flow.svg +166 -0
  70. package/docs/upstream/diagrams/workflow-linear.svg +66 -0
  71. package/docs/upstream/diagrams/workflow-three-phase.svg +200 -0
  72. package/docs/upstream/eval-maintenance.md +95 -0
  73. package/docs/upstream/eval-running-guide.md +147 -0
  74. package/docs/upstream/eval-system.md +291 -0
  75. package/docs/upstream/session-review-oss-complements.md +75 -0
  76. package/docs/upstream/session-review.md +212 -0
  77. package/docs/upstream/skills.md +188 -0
  78. package/docs/upstream/team-structure.md +21 -0
  79. package/docs/upstream/telemetry-ci-access.md +129 -0
  80. package/docs/upstream/telemetry-repo-security.md +120 -0
  81. package/docs/upstream/test-evaluation.md +277 -0
  82. package/docs/upstream/test-improve.md +154 -0
  83. package/docs/upstream/triage-workflow.md +282 -0
  84. package/docs/upstream/workflows.md +289 -0
  85. package/extensions/dev-team/index.ts +539 -0
  86. package/extensions/dev-team/lib/agents.ts +272 -0
  87. package/extensions/dev-team/lib/ai-credits.ts +92 -0
  88. package/extensions/dev-team/lib/autocompact.ts +81 -0
  89. package/extensions/dev-team/lib/child-run.ts +102 -0
  90. package/extensions/dev-team/lib/config.ts +236 -0
  91. package/extensions/dev-team/lib/gh-command.ts +103 -0
  92. package/extensions/dev-team/lib/github-style.ts +307 -0
  93. package/extensions/dev-team/lib/hooks.ts +350 -0
  94. package/extensions/dev-team/lib/metrics.ts +115 -0
  95. package/extensions/dev-team/lib/safe-read.ts +49 -0
  96. package/extensions/dev-team/lib/session-files.ts +57 -0
  97. package/extensions/dev-team/lib/session-spend.ts +123 -0
  98. package/extensions/dev-team/lib/shell-scan.ts +205 -0
  99. package/extensions/dev-team/lib/skills.ts +213 -0
  100. package/extensions/dev-team/lib/subagent-render.ts +245 -0
  101. package/extensions/dev-team/lib/subagent-types.ts +164 -0
  102. package/extensions/dev-team/lib/subagent.ts +596 -0
  103. package/extensions/dev-team/lib/terminal-text.ts +54 -0
  104. package/extensions/dev-team/lib/tools-misc.ts +152 -0
  105. package/extensions/dev-team/lib/transcript.ts +110 -0
  106. package/extensions/dev-team/lib/trust.ts +52 -0
  107. package/extensions/dev-team/lib/usage-breakdown.ts +176 -0
  108. package/extensions/dev-team/lib/usage-chart.ts +153 -0
  109. package/extensions/dev-team/lib/usage-command.ts +107 -0
  110. package/extensions/dev-team/lib/usage-history.ts +203 -0
  111. package/extensions/dev-team/lib/usage-render.ts +225 -0
  112. package/extensions/dev-team/lib/usage-split-bar.ts +127 -0
  113. package/extensions/dev-team/lib/usage-state.ts +116 -0
  114. package/extensions/dev-team/lib/usage-text.ts +159 -0
  115. package/extensions/dev-team/lib/usage-view.ts +109 -0
  116. package/hooks/__pycache__/refactor_test_freeze_guard.cpython-314.pyc +0 -0
  117. package/hooks/agent_dispatch_ledger.py +190 -0
  118. package/hooks/autocompact_setup_nudge.py +99 -0
  119. package/hooks/bash_retry_guard.py +228 -0
  120. package/hooks/boundary_events_write_guard.py +352 -0
  121. package/hooks/code_intelligence_nudge.py +293 -0
  122. package/hooks/code_intelligence_turn_mark.py +317 -0
  123. package/hooks/codegraph_bootstrap.py +139 -0
  124. package/hooks/contract_version_guard.py +362 -0
  125. package/hooks/cost_meter.py +106 -0
  126. package/hooks/destructive-commands.json +62 -0
  127. package/hooks/destructive_guard.py +477 -0
  128. package/hooks/eval_compliance_check.py +440 -0
  129. package/hooks/guards.json +17 -0
  130. package/hooks/hooks.json +323 -0
  131. package/hooks/internal_double_gate.py +296 -0
  132. package/hooks/js_fp_review.py +212 -0
  133. package/hooks/knowledge_index.py +119 -0
  134. package/hooks/lib/__pycache__/artifact_paths.cpython-314.pyc +0 -0
  135. package/hooks/lib/__pycache__/atomic_state.cpython-314.pyc +0 -0
  136. package/hooks/lib/__pycache__/autocompact_config.cpython-314.pyc +0 -0
  137. package/hooks/lib/__pycache__/boundary_events.cpython-314.pyc +0 -0
  138. package/hooks/lib/__pycache__/doc_classification.cpython-314.pyc +0 -0
  139. package/hooks/lib/__pycache__/gh_pr_create_detect.cpython-314.pyc +0 -0
  140. package/hooks/lib/__pycache__/git_safe_diff.cpython-314.pyc +0 -0
  141. package/hooks/lib/__pycache__/instrument_log.cpython-314.pyc +0 -0
  142. package/hooks/lib/__pycache__/metrics_query.cpython-314.pyc +0 -0
  143. package/hooks/lib/__pycache__/plugin_version.cpython-314.pyc +0 -0
  144. package/hooks/lib/__pycache__/pre_commit_doc_classifier.cpython-314.pyc +0 -0
  145. package/hooks/lib/__pycache__/review_agent_registry.cpython-314.pyc +0 -0
  146. package/hooks/lib/__pycache__/review_gate_corroboration.cpython-314.pyc +0 -0
  147. package/hooks/lib/__pycache__/review_gate_hash.cpython-314.pyc +0 -0
  148. package/hooks/lib/__pycache__/review_verdicts.cpython-314.pyc +0 -0
  149. package/hooks/lib/__pycache__/stdin_json.cpython-314.pyc +0 -0
  150. package/hooks/lib/__pycache__/stryker_invocation.cpython-314.pyc +0 -0
  151. package/hooks/lib/__pycache__/telemetry_consent.cpython-314.pyc +0 -0
  152. package/hooks/lib/__pycache__/test_file_classify.cpython-314.pyc +0 -0
  153. package/hooks/lib/__pycache__/token_efficiency_limits.cpython-314.pyc +0 -0
  154. package/hooks/lib/__pycache__/verify_guard_state.cpython-314.pyc +0 -0
  155. package/hooks/lib/__pycache__/xunit_v3_operator_gate.cpython-314.pyc +0 -0
  156. package/hooks/lib/agent_skill_hints.py +74 -0
  157. package/hooks/lib/artifact_paths.py +263 -0
  158. package/hooks/lib/atomic_state.py +557 -0
  159. package/hooks/lib/autocompact_config.py +103 -0
  160. package/hooks/lib/autoship_log.py +106 -0
  161. package/hooks/lib/banned_scripts_policy.py +51 -0
  162. package/hooks/lib/boundary_events.py +436 -0
  163. package/hooks/lib/build_knowledge_index.py +504 -0
  164. package/hooks/lib/build_skills_index.py +361 -0
  165. package/hooks/lib/build_state.py +116 -0
  166. package/hooks/lib/classify_ship_outcome.py +126 -0
  167. package/hooks/lib/config_changelog_schema.py +115 -0
  168. package/hooks/lib/cost_meter.py +955 -0
  169. package/hooks/lib/doc_classification.py +116 -0
  170. package/hooks/lib/gh_pr_create_detect.py +136 -0
  171. package/hooks/lib/git_safe_diff.py +123 -0
  172. package/hooks/lib/instrument_log.py +66 -0
  173. package/hooks/lib/iteration_journal_gate.py +197 -0
  174. package/hooks/lib/knowledge_index_paths.py +88 -0
  175. package/hooks/lib/mcp_json_repowise.py +177 -0
  176. package/hooks/lib/metrics_query.py +202 -0
  177. package/hooks/lib/minimal_yaml.py +434 -0
  178. package/hooks/lib/plugin_version.py +142 -0
  179. package/hooks/lib/pre_commit_detect.py +537 -0
  180. package/hooks/lib/pre_commit_doc_classifier.py +126 -0
  181. package/hooks/lib/pricing.py +118 -0
  182. package/hooks/lib/report_pdf.py +371 -0
  183. package/hooks/lib/review_agent_registry.py +142 -0
  184. package/hooks/lib/review_dispatch_ledger.py +101 -0
  185. package/hooks/lib/review_gate_corroboration.py +521 -0
  186. package/hooks/lib/review_gate_hash.py +252 -0
  187. package/hooks/lib/review_gate_normalized_hash.py +1115 -0
  188. package/hooks/lib/review_verdicts.py +301 -0
  189. package/hooks/lib/run_report.py +160 -0
  190. package/hooks/lib/skill_categories.yaml +125 -0
  191. package/hooks/lib/stdin_json.py +57 -0
  192. package/hooks/lib/stryker_invocation.py +102 -0
  193. package/hooks/lib/telemetry_consent.py +41 -0
  194. package/hooks/lib/telemetry_report.py +108 -0
  195. package/hooks/lib/test_file_classify.py +160 -0
  196. package/hooks/lib/token_efficiency_limits.py +51 -0
  197. package/hooks/lib/turn_identity.py +77 -0
  198. package/hooks/lib/verify_guard_state.py +110 -0
  199. package/hooks/lib/workflow_state.py +206 -0
  200. package/hooks/lib/xunit_v3_operator_gate.py +596 -0
  201. package/hooks/mcp_json_repowise_nudge.py +74 -0
  202. package/hooks/mutation_adapters/__init__.py +7 -0
  203. package/hooks/mutation_adapters/__pycache__/__init__.cpython-314.pyc +0 -0
  204. package/hooks/mutation_adapters/__pycache__/lib.cpython-314.pyc +0 -0
  205. package/hooks/mutation_adapters/__pycache__/mutmut.cpython-314.pyc +0 -0
  206. package/hooks/mutation_adapters/__pycache__/pitest.cpython-314.pyc +0 -0
  207. package/hooks/mutation_adapters/__pycache__/stryker.cpython-314.pyc +0 -0
  208. package/hooks/mutation_adapters/__pycache__/stryker_net.cpython-314.pyc +0 -0
  209. package/hooks/mutation_adapters/lib.py +478 -0
  210. package/hooks/mutation_adapters/mutmut.py +188 -0
  211. package/hooks/mutation_adapters/pitest.py +266 -0
  212. package/hooks/mutation_adapters/stryker.py +157 -0
  213. package/hooks/mutation_adapters/stryker_net.py +264 -0
  214. package/hooks/mutation_gate.py +193 -0
  215. package/hooks/mutation_testing_smoke_gate.py +371 -0
  216. package/hooks/pending_review_notify.py +121 -0
  217. package/hooks/phase_marker.py +138 -0
  218. package/hooks/post_compact_state_reinject.py +180 -0
  219. package/hooks/post_format.py +115 -0
  220. package/hooks/pre_commit_knowledge_index.py +128 -0
  221. package/hooks/pre_commit_review.py +66 -0
  222. package/hooks/pre_pr_review.py +694 -0
  223. package/hooks/pre_tool_guard.py +405 -0
  224. package/hooks/py.sh +73 -0
  225. package/hooks/refactor-bash-write-patterns.json +29 -0
  226. package/hooks/refactor_test_bash_guard.py +253 -0
  227. package/hooks/refactor_test_freeze_guard.py +139 -0
  228. package/hooks/refactor_test_revert_guard.py +186 -0
  229. package/hooks/repo_review_nudge.py +287 -0
  230. package/hooks/review_verdict_recorder.py +464 -0
  231. package/hooks/scan_bash_command_for_banned_scripts.py +428 -0
  232. package/hooks/scan_worktree_for_banned_scripts.py +238 -0
  233. package/hooks/session_learning_trigger.py +248 -0
  234. package/hooks/skills_index.py +126 -0
  235. package/hooks/stryker_xunit_shim_guard.py +571 -0
  236. package/hooks/subagent_completion_guard.py +309 -0
  237. package/hooks/subagent_skill_context.py +139 -0
  238. package/hooks/task_completion_metrics.py +216 -0
  239. package/hooks/tdd_guard.py +229 -0
  240. package/hooks/telemetry.py +341 -0
  241. package/hooks/token_efficiency_review.py +194 -0
  242. package/hooks/verify_guard.py +183 -0
  243. package/hooks/verify_guard_edit_marker.py +73 -0
  244. package/hooks/version_check.py +173 -0
  245. package/knowledge/accepted-risks-schema.md +98 -0
  246. package/knowledge/adr-decision-criteria.md +64 -0
  247. package/knowledge/adversarial-review-protocol.md +139 -0
  248. package/knowledge/agent-registry.md +228 -0
  249. package/knowledge/agent-review-methodology.md +80 -0
  250. package/knowledge/ai-friendly-repo-guidelines.md +67 -0
  251. package/knowledge/architecture-assessment.md +96 -0
  252. package/knowledge/artifact-lifecycle.md +57 -0
  253. package/knowledge/cd-maturity-model.md +82 -0
  254. package/knowledge/cd-test-architecture.md +190 -0
  255. package/knowledge/ci-cd-file-scope.md +24 -0
  256. package/knowledge/codegraph-vs-graphify.md +192 -0
  257. package/knowledge/component-test-patterns.md +139 -0
  258. package/knowledge/database-change-management.md +80 -0
  259. package/knowledge/database-test-patterns.md +79 -0
  260. package/knowledge/decision-defaults.md +88 -0
  261. package/knowledge/dependency-breaking-techniques.md +116 -0
  262. package/knowledge/deployment-pipeline.md +86 -0
  263. package/knowledge/design-smells.md +122 -0
  264. package/knowledge/directory-enumeration.md +38 -0
  265. package/knowledge/domain-modeling.md +123 -0
  266. package/knowledge/evidence-bundle.md +90 -0
  267. package/knowledge/exploratory-testing-field-guide.md +122 -0
  268. package/knowledge/failure-routing.md +28 -0
  269. package/knowledge/fixture-construction.md +56 -0
  270. package/knowledge/frontend-component-architecture.md +139 -0
  271. package/knowledge/gherkin-quality-review-dispatch.md +135 -0
  272. package/knowledge/index.json +6766 -0
  273. package/knowledge/internal-collaborator-doubling.md +101 -0
  274. package/knowledge/legacy-test-strategy.md +71 -0
  275. package/knowledge/long-run-waiting.md +66 -0
  276. package/knowledge/microservice-testing.md +71 -0
  277. package/knowledge/model-pricing.json +23 -0
  278. package/knowledge/mutation-score-formulas.md +60 -0
  279. package/knowledge/object-calisthenics.md +147 -0
  280. package/knowledge/oracle-provenance.md +94 -0
  281. package/knowledge/orchestrator-script-implementation.md +185 -0
  282. package/knowledge/owasp-detection.md +148 -0
  283. package/knowledge/plan-review-rubric.md +56 -0
  284. package/knowledge/proxy-connectivity.md +62 -0
  285. package/knowledge/reactive-effect-patterns.md +73 -0
  286. package/knowledge/recon-inventory-excludes.txt +32 -0
  287. package/knowledge/references/bdd-value-guide.md +61 -0
  288. package/knowledge/references/csharp-http-client-testing.md +264 -0
  289. package/knowledge/release-strategies.md +74 -0
  290. package/knowledge/report-output-location.md +117 -0
  291. package/knowledge/report-pdf-integration.md +63 -0
  292. package/knowledge/report-print.css +129 -0
  293. package/knowledge/report-template.md +114 -0
  294. package/knowledge/report-to-pdf.md +69 -0
  295. package/knowledge/request-processing-flow.md +63 -0
  296. package/knowledge/result-verification.md +52 -0
  297. package/knowledge/review-agent-output-contract.md +121 -0
  298. package/knowledge/review-lens-classification.md +113 -0
  299. package/knowledge/review-rubric.md +62 -0
  300. package/knowledge/review-template.md +104 -0
  301. package/knowledge/rule-fixtures/A02.insecure-random-js/negative.js +1 -0
  302. package/knowledge/rule-fixtures/A02.insecure-random-js/positive.js +1 -0
  303. package/knowledge/rule-fixtures/A02.weak-hashing-md5/negative.py +1 -0
  304. package/knowledge/rule-fixtures/A02.weak-hashing-md5/positive.py +1 -0
  305. package/knowledge/rule-fixtures/A03.command-injection/negative.js +1 -0
  306. package/knowledge/rule-fixtures/A03.command-injection/positive.js +1 -0
  307. package/knowledge/rule-fixtures/A03.sql-injection/negative.js +1 -0
  308. package/knowledge/rule-fixtures/A03.sql-injection/positive.js +1 -0
  309. package/knowledge/rule-fixtures/A03.xss-innerhtml/negative.js +1 -0
  310. package/knowledge/rule-fixtures/A03.xss-innerhtml/positive.js +1 -0
  311. package/knowledge/rule-fixtures/A05.cors-wildcard/negative.js +1 -0
  312. package/knowledge/rule-fixtures/A05.cors-wildcard/positive.js +1 -0
  313. package/knowledge/rule-fixtures/A05.default-credentials/negative.js +1 -0
  314. package/knowledge/rule-fixtures/A05.default-credentials/positive.js +1 -0
  315. package/knowledge/rule-fixtures/A07.jwt-alg-none/negative.js +1 -0
  316. package/knowledge/rule-fixtures/A07.jwt-alg-none/positive.js +1 -0
  317. package/knowledge/rule-fixtures/A08.binary-formatter/negative.cs +1 -0
  318. package/knowledge/rule-fixtures/A08.binary-formatter/positive.cs +1 -0
  319. package/knowledge/rule-fixtures/A08.js-eval/negative.js +1 -0
  320. package/knowledge/rule-fixtures/A08.js-eval/positive.js +1 -0
  321. package/knowledge/rule-fixtures/A08.object-input-stream/negative.java +1 -0
  322. package/knowledge/rule-fixtures/A08.object-input-stream/positive.java +1 -0
  323. package/knowledge/schemas/disposition-register-v1.json +65 -0
  324. package/knowledge/schemas/recon-envelope-v1.json +198 -0
  325. package/knowledge/schemas/unified-finding-v1.json +72 -0
  326. package/knowledge/security-primitives-contract.md +301 -0
  327. package/knowledge/security-review-rule-map.yaml +107 -0
  328. package/knowledge/skills-registry.md +72 -0
  329. package/knowledge/task-size-classifier.md +103 -0
  330. package/knowledge/telemetry-schema.md +881 -0
  331. package/knowledge/test-automation-maturity.md +56 -0
  332. package/knowledge/test-automation-principles.md +71 -0
  333. package/knowledge/test-cadence-tradeoffs.md +68 -0
  334. package/knowledge/test-doubles.md +105 -0
  335. package/knowledge/test-file-indicators.md +22 -0
  336. package/knowledge/test-layer-gates.md +35 -0
  337. package/knowledge/test-matrix-examples/django-batch.md +24 -0
  338. package/knowledge/test-matrix-examples/dotnet-grpc-fronting-api.md +90 -0
  339. package/knowledge/test-matrix-examples/dotnet-http-consumer.md +131 -0
  340. package/knowledge/test-matrix-examples/react-node-spa.md +24 -0
  341. package/knowledge/test-matrix-examples/spring-boot-service.md +25 -0
  342. package/knowledge/test-matrix-examples/ssr-htmx.md +24 -0
  343. package/knowledge/test-organization.md +70 -0
  344. package/knowledge/test-pyramid.md +84 -0
  345. package/knowledge/test-refactoring.md +67 -0
  346. package/knowledge/test-review-division-of-labor.md +85 -0
  347. package/knowledge/test-smells.md +80 -0
  348. package/knowledge/test-stack-profiles/bdd-frameworks.md +235 -0
  349. package/knowledge/test-stack-profiles/django.md +13 -0
  350. package/knowledge/test-stack-profiles/dotnet.md +18 -0
  351. package/knowledge/test-stack-profiles/go.md +16 -0
  352. package/knowledge/test-stack-profiles/node.md +16 -0
  353. package/knowledge/test-stack-profiles/react.md +12 -0
  354. package/knowledge/test-stack-profiles/spring-boot.md +16 -0
  355. package/knowledge/test-stack-profiles/ssr-htmx.md +14 -0
  356. package/knowledge/test-stack-profiles/vue.md +12 -0
  357. package/knowledge/test-strategy.md +70 -0
  358. package/knowledge/testability-patterns.md +240 -0
  359. package/knowledge/testing-quadrants.md +44 -0
  360. package/knowledge/testing-techniques/approval.md +15 -0
  361. package/knowledge/testing-techniques/chaos.md +17 -0
  362. package/knowledge/testing-techniques/fuzz.md +15 -0
  363. package/knowledge/testing-techniques/property-based.md +15 -0
  364. package/knowledge/testing-techniques/schema-validation.md +15 -0
  365. package/knowledge/testing-techniques/screenshot.md +15 -0
  366. package/knowledge/three-phase-workflow.md +198 -0
  367. package/knowledge/value-patterns.md +55 -0
  368. package/knowledge/verification-mode.md +116 -0
  369. package/knowledge/virtual-service-libraries.md +75 -0
  370. package/knowledge/wave-consolidation-guidance.md +21 -0
  371. package/overrides/agents/Explore.md +15 -0
  372. package/overrides/agents/general-purpose.md +10 -0
  373. package/overrides/notes/autoship.md +6 -0
  374. package/overrides/notes/issues-from-assessment.md +3 -0
  375. package/overrides/notes/issues-from-plan.md +3 -0
  376. package/overrides/notes/mutation-night-watch.md +3 -0
  377. package/overrides/notes/mutation-testing.md +3 -0
  378. package/overrides/notes/pr.md +7 -0
  379. package/overrides/notes/project-init.md +6 -0
  380. package/overrides/notes/setup.md +13 -0
  381. package/overrides/notes/specs.md +3 -0
  382. package/overrides/skills/headless-run/SKILL.md +45 -0
  383. package/overrides/skills/upgrade/SKILL.md +30 -0
  384. package/overrides/skills/version/SKILL.md +25 -0
  385. package/package.json +36 -0
  386. package/scripts/authoring_digest.py +93 -0
  387. package/scripts/autoship_discover.py +121 -0
  388. package/scripts/autoship_group.py +409 -0
  389. package/scripts/autoship_proposals.py +494 -0
  390. package/scripts/autoship_queue.py +291 -0
  391. package/scripts/autoship_reclaim.py +495 -0
  392. package/scripts/build_jobs.py +108 -0
  393. package/scripts/build_rollback_point.py +240 -0
  394. package/scripts/build_slice_scope.py +157 -0
  395. package/scripts/build_wave.py +109 -0
  396. package/scripts/build_wave_reconcile.py +252 -0
  397. package/scripts/build_worktree_baseref.py +113 -0
  398. package/scripts/check_agent_scope.py +117 -0
  399. package/scripts/check_agent_tool_mapping.py +213 -0
  400. package/scripts/check_review_agent_mcp_tools.py +317 -0
  401. package/scripts/check_security_assessment_mcp_tools.py +165 -0
  402. package/scripts/checkpoint_abort.py +502 -0
  403. package/scripts/claude_setup_review.py +438 -0
  404. package/scripts/codebase_recon.py +556 -0
  405. package/scripts/coverage_config.py +623 -0
  406. package/scripts/coverage_delta_steering.py +330 -0
  407. package/scripts/coverage_discovery_dotnet.py +315 -0
  408. package/scripts/coverage_discovery_java.py +742 -0
  409. package/scripts/coverage_discovery_js.py +546 -0
  410. package/scripts/coverage_gap_ranking.py +556 -0
  411. package/scripts/coverage_readiness.py +455 -0
  412. package/scripts/coverage_report_parse.py +521 -0
  413. package/scripts/detect_bdd_convention.py +252 -0
  414. package/scripts/eval_ablation.py +376 -0
  415. package/scripts/gherkin_analysis_coverage_gate.py +306 -0
  416. package/scripts/gherkin_cross_feature_duplicate_titles_gate.py +173 -0
  417. package/scripts/gherkin_effectiveness_rollup.py +238 -0
  418. package/scripts/gherkin_failure_path_gate.py +206 -0
  419. package/scripts/gherkin_feature_merge.py +720 -0
  420. package/scripts/gherkin_stub_gate.py +163 -0
  421. package/scripts/gherkin_stub_merge.py +479 -0
  422. package/scripts/git_origin_host.py +88 -0
  423. package/scripts/install-java-static-analysis.py +110 -0
  424. package/scripts/issue_deps.py +74 -0
  425. package/scripts/lib/_bdd_markers.py +28 -0
  426. package/scripts/lib/_gherkin_text.py +93 -0
  427. package/scripts/lib/_vendored_tree.py +70 -0
  428. package/scripts/lib/autoship_state.py +397 -0
  429. package/scripts/lib/claude_md_guard.py +226 -0
  430. package/scripts/lib/deterministic_recon.py +446 -0
  431. package/scripts/lib/mcp_tool_grants.py +211 -0
  432. package/scripts/lib/plan_parse.py +386 -0
  433. package/scripts/lib/review_result.py +84 -0
  434. package/scripts/lib/review_roster.py +86 -0
  435. package/scripts/lib/session_log/__init__.py +34 -0
  436. package/scripts/lib/session_log/__pycache__/__init__.cpython-314.pyc +0 -0
  437. package/scripts/lib/session_log/__pycache__/records.cpython-314.pyc +0 -0
  438. package/scripts/lib/session_log/classify.py +231 -0
  439. package/scripts/lib/session_log/corrections.py +194 -0
  440. package/scripts/lib/session_log/discovery.py +108 -0
  441. package/scripts/lib/session_log/records.py +218 -0
  442. package/scripts/lib/session_log/redact.py +76 -0
  443. package/scripts/lib/session_log/signals.py +373 -0
  444. package/scripts/lib/session_report_downstream.py +614 -0
  445. package/scripts/lib/session_report_maintainer.py +1273 -0
  446. package/scripts/lib/session_report_shared.py +262 -0
  447. package/scripts/lib/settings_hook_guard.py +157 -0
  448. package/scripts/lib/slug.py +33 -0
  449. package/scripts/lib/stub_extractors/__init__.py +82 -0
  450. package/scripts/lib/stub_extractors/_common.py +328 -0
  451. package/scripts/lib/stub_extractors/csharp.py +19 -0
  452. package/scripts/lib/stub_extractors/go.py +173 -0
  453. package/scripts/lib/stub_extractors/java.py +18 -0
  454. package/scripts/lib/stub_extractors/jsts.py +126 -0
  455. package/scripts/mutation_stack_sections.py +149 -0
  456. package/scripts/mutation_yield_steering.py +345 -0
  457. package/scripts/orchestrator.py +895 -0
  458. package/scripts/plan_gherkin_export.py +227 -0
  459. package/scripts/plan_waves.py +208 -0
  460. package/scripts/pr_close_keyword_lint.py +108 -0
  461. package/scripts/progress_guardian.py +888 -0
  462. package/scripts/recon_inventory.py +273 -0
  463. package/scripts/review_findings_log.py +93 -0
  464. package/scripts/run_invariants.py +124 -0
  465. package/scripts/select_lenses.py +640 -0
  466. package/scripts/session_report.py +486 -0
  467. package/scripts/set_autocompact_env.py +221 -0
  468. package/scripts/ship_resume_guard.py +135 -0
  469. package/scripts/ship_review_gate.py +63 -0
  470. package/scripts/specs_convention_marker.py +103 -0
  471. package/scripts/test_improve_resume.py +277 -0
  472. package/scripts/test_review_mechanics.py +958 -0
  473. package/scripts/token_efficiency_review.py +322 -0
  474. package/scripts/verdict_scope.py +285 -0
  475. package/scripts/verify_gherkin_quality_critic_isolation.py +296 -0
  476. package/scripts/verify_tier.py +157 -0
  477. package/skills/adr-tools/SKILL.md +118 -0
  478. package/skills/agent-readiness/SKILL.md +105 -0
  479. package/skills/agent-readiness/ai_friendly_analyzers.py +326 -0
  480. package/skills/agent-readiness/scanner.py +441 -0
  481. package/skills/agent-readiness/scorecard.yaml +88 -0
  482. package/skills/api-design/SKILL.md +115 -0
  483. package/skills/apply-fixes/SKILL.md +171 -0
  484. package/skills/apply-test-doubles/SKILL.md +321 -0
  485. package/skills/artifact-lifecycle/SKILL.md +127 -0
  486. package/skills/autoship/SKILL.md +1124 -0
  487. package/skills/benchmark/SKILL.md +105 -0
  488. package/skills/branch-workflow/SKILL.md +89 -0
  489. package/skills/browse/SKILL.md +184 -0
  490. package/skills/browser-testing/SKILL.md +62 -0
  491. package/skills/browser-testing/references/playwright-patterns.md +216 -0
  492. package/skills/build/SKILL.md +422 -0
  493. package/skills/build/references/static-self-heal.md +245 -0
  494. package/skills/careful/SKILL.md +72 -0
  495. package/skills/cd-test-architecture/SKILL.md +371 -0
  496. package/skills/ci-debugging/SKILL.md +105 -0
  497. package/skills/co-evolution-audit/SKILL.md +269 -0
  498. package/skills/code-review/SKILL.md +1015 -0
  499. package/skills/code-review/examples/aggregated-sample.json +56 -0
  500. package/skills/code-review/examples/sample-report.md +41 -0
  501. package/skills/code-review/output-format.md +478 -0
  502. package/skills/code-review/scripts/activation.py +86 -0
  503. package/skills/code-review/scripts/change_impact.py +357 -0
  504. package/skills/code-review/scripts/change_shape.py +372 -0
  505. package/skills/code-review/scripts/change_size.py +212 -0
  506. package/skills/code-review/scripts/changed_file_list.py +141 -0
  507. package/skills/code-review/scripts/closing_pass.py +187 -0
  508. package/skills/code-review/scripts/consolidate.py +277 -0
  509. package/skills/code-review/scripts/contract_failure_report.py +185 -0
  510. package/skills/code-review/scripts/dispatch_reconcile.py +66 -0
  511. package/skills/code-review/scripts/dispatch_waves.py +164 -0
  512. package/skills/code-review/scripts/finding_signature.py +446 -0
  513. package/skills/code-review/scripts/ledger.py +283 -0
  514. package/skills/code-review/scripts/partition.py +169 -0
  515. package/skills/code-review/scripts/render_tiered_findings.py +274 -0
  516. package/skills/code-review/scripts/repo_invariants.py +1066 -0
  517. package/skills/code-review/scripts/review_context_pack.py +306 -0
  518. package/skills/code-review/scripts/review_round_log.py +345 -0
  519. package/skills/code-review/scripts/review_value_coverage.py +297 -0
  520. package/skills/code-review/scripts/validate_review_output.py +467 -0
  521. package/skills/code-review/sliced-mode.md +205 -0
  522. package/skills/competitive-analysis/SKILL.md +191 -0
  523. package/skills/context-loading-protocol/SKILL.md +157 -0
  524. package/skills/continue/SKILL.md +90 -0
  525. package/skills/cost-report/SKILL.md +178 -0
  526. package/skills/coverage-baseline/SKILL.md +335 -0
  527. package/skills/coverage-baseline/references/multi-project-discovery.md +202 -0
  528. package/skills/coverage-delta/SKILL.md +181 -0
  529. package/skills/coverage-delta/references/mutation-gate.md +70 -0
  530. package/skills/design-doc/SKILL.md +95 -0
  531. package/skills/design-interrogation/SKILL.md +89 -0
  532. package/skills/design-it-twice/SKILL.md +91 -0
  533. package/skills/docker-image-audit/SKILL.md +108 -0
  534. package/skills/docker-image-audit/references/install-guide.md +64 -0
  535. package/skills/docker-image-audit/references/report-template.md +73 -0
  536. package/skills/docker-image-create/SKILL.md +185 -0
  537. package/skills/domain-analysis/SKILL.md +183 -0
  538. package/skills/domain-driven-design/SKILL.md +194 -0
  539. package/skills/exploratory-testing/SKILL.md +108 -0
  540. package/skills/explore/SKILL.md +51 -0
  541. package/skills/farley-score/SKILL.md +165 -0
  542. package/skills/feature-file-validation/SKILL.md +78 -0
  543. package/skills/feature-file-validation/references/validation-rules.md +115 -0
  544. package/skills/feedback-learning/SKILL.md +414 -0
  545. package/skills/fix/SKILL.md +450 -0
  546. package/skills/freeze/SKILL.md +68 -0
  547. package/skills/frontend-architecture/SKILL.md +113 -0
  548. package/skills/gherkin-derive/SKILL.md +630 -0
  549. package/skills/gherkin-public/SKILL.md +266 -0
  550. package/skills/governance-compliance/SKILL.md +150 -0
  551. package/skills/guard/SKILL.md +75 -0
  552. package/skills/handoff/SKILL.md +139 -0
  553. package/skills/handoff/references/summary-templates.md +242 -0
  554. package/skills/harness-audit/SKILL.md +751 -0
  555. package/skills/harness-audit/scripts/lesson_validate.py +386 -0
  556. package/skills/harness-audit/scripts/redundancy_criterion.py +188 -0
  557. package/skills/headless-run/SKILL.md +45 -0
  558. package/skills/headless-run/scripts/isolated_dispatch.py +381 -0
  559. package/skills/help/SKILL.md +72 -0
  560. package/skills/hexagonal-architecture/SKILL.md +85 -0
  561. package/skills/human-oversight-protocol/SKILL.md +224 -0
  562. package/skills/issues-from-assessment/SKILL.md +223 -0
  563. package/skills/issues-from-plan/SKILL.md +133 -0
  564. package/skills/legacy-code/SKILL.md +132 -0
  565. package/skills/mermaid-diagramming/SKILL.md +120 -0
  566. package/skills/mutation-night-watch/SKILL.md +154 -0
  567. package/skills/mutation-night-watch/references/scheduling.md +135 -0
  568. package/skills/mutation-testing/SKILL.md +396 -0
  569. package/skills/mutation-testing/references/languages/csharp-stryker-net.md +676 -0
  570. package/skills/mutation-testing/references/languages/go-go-mutesting.md +95 -0
  571. package/skills/mutation-testing/references/languages/java-pitest.md +77 -0
  572. package/skills/mutation-testing/references/languages/javascript-stryker.md +188 -0
  573. package/skills/mutation-testing/references/languages/python-mutmut.md +97 -0
  574. package/skills/mutation-testing/references/time-estimation.md +34 -0
  575. package/skills/mutation-testing/references/tool-detection.md +15 -0
  576. package/skills/mutation-testing/references/workflow-callers.md +23 -0
  577. package/skills/mutation-testing/scripts/__pycache__/xunit_v3_feature_detector.cpython-314.pyc +0 -0
  578. package/skills/mutation-testing/scripts/csharp_stryker_net_slice_runner.py +635 -0
  579. package/skills/mutation-testing/scripts/csharp_stryker_net_status_loop.py +525 -0
  580. package/skills/mutation-testing/scripts/csharp_stryker_net_wrapper.py +681 -0
  581. package/skills/mutation-testing/scripts/mutation_baseline_reuse.py +292 -0
  582. package/skills/mutation-testing/scripts/mutation_exclude_policy.py +268 -0
  583. package/skills/mutation-testing/scripts/mutation_feasibility_gate.py +463 -0
  584. package/skills/mutation-testing/scripts/mutation_kill_headless.py +331 -0
  585. package/skills/mutation-testing/scripts/mutation_kill_insert.py +199 -0
  586. package/skills/mutation-testing/scripts/mutation_kill_insert_python.py +150 -0
  587. package/skills/mutation-testing/scripts/mutation_kill_loop.py +869 -0
  588. package/skills/mutation-testing/scripts/mutation_kill_loop_python.py +949 -0
  589. package/skills/mutation-testing/scripts/mutation_kill_retry.py +592 -0
  590. package/skills/mutation-testing/scripts/mutation_kill_shared.py +620 -0
  591. package/skills/mutation-testing/scripts/mutation_nightwatch.py +462 -0
  592. package/skills/mutation-testing/scripts/mutation_nightwatch_stacks.py +425 -0
  593. package/skills/mutation-testing/scripts/mutation_report.py +743 -0
  594. package/skills/mutation-testing/scripts/mutation_report_cli.py +175 -0
  595. package/skills/mutation-testing/scripts/mutation_safety_gate.py +69 -0
  596. package/skills/mutation-testing/scripts/stryker_shard_pipeline.py +847 -0
  597. package/skills/mutation-testing/scripts/stryker_shard_setup.py +440 -0
  598. package/skills/mutation-testing/scripts/stryker_timeout_retry.py +142 -0
  599. package/skills/mutation-testing/scripts/xunit_v3_feature_detector.py +341 -0
  600. package/skills/performance-benchmark/SKILL.md +174 -0
  601. package/skills/performance-benchmark/examples/report-format.md +43 -0
  602. package/skills/performance-benchmark/references/benchmark-script.md +169 -0
  603. package/skills/performance-metrics/SKILL.md +265 -0
  604. package/skills/plan/SKILL.md +199 -0
  605. package/skills/plan/references/gherkin-persistence.md +43 -0
  606. package/skills/plan/references/plan-template.md +182 -0
  607. package/skills/pr/SKILL.md +289 -0
  608. package/skills/pr/scripts/gate_retry_state.py +368 -0
  609. package/skills/project-init/README.md +141 -0
  610. package/skills/project-init/SKILL.md +1197 -0
  611. package/skills/project-init/evals/evals.json +200 -0
  612. package/skills/project-init/references/capability-tools.md +55 -0
  613. package/skills/project-init/references/configs.md +221 -0
  614. package/skills/property-based-testing/SKILL.md +121 -0
  615. package/skills/property-based-testing/fixtures/invariant_fixture.py +15 -0
  616. package/skills/property-based-testing/fixtures/js-roundtrip/README.md +42 -0
  617. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/LICENSE +21 -0
  618. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/README.md +263 -0
  619. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.d.ts +5165 -0
  620. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.js +12147 -0
  621. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/package.json +3 -0
  622. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/types57/fast-check.d.ts +5165 -0
  623. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.d.ts +5165 -0
  624. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.js +12011 -0
  625. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/rolldown-runtime-D7D4PA-g.js +13 -0
  626. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/types57/fast-check.d.ts +5165 -0
  627. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/package.json +94 -0
  628. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/LICENSE +21 -0
  629. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/README.md +168 -0
  630. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/RandomGenerator-DcXj09Ch.d.ts +14 -0
  631. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.d.ts +15 -0
  632. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.js +38 -0
  633. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.d.ts +15 -0
  634. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.js +18 -0
  635. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.d.ts +15 -0
  636. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.js +22 -0
  637. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.d.ts +15 -0
  638. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.js +134 -0
  639. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/RandomGenerator-DcXj09Ch.d.ts +14 -0
  640. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.d.ts +15 -0
  641. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.js +37 -0
  642. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.d.ts +15 -0
  643. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.js +17 -0
  644. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.d.ts +15 -0
  645. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.js +21 -0
  646. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.d.ts +15 -0
  647. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.js +133 -0
  648. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.d.ts +7 -0
  649. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.js +44 -0
  650. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.d.ts +7 -0
  651. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.js +90 -0
  652. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.d.ts +7 -0
  653. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.js +80 -0
  654. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.d.ts +7 -0
  655. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.js +78 -0
  656. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/package.json +3 -0
  657. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.d.ts +16 -0
  658. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.js +0 -0
  659. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.d.ts +2 -0
  660. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.js +0 -0
  661. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.d.ts +6 -0
  662. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.js +8 -0
  663. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.d.ts +12 -0
  664. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.js +9 -0
  665. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.d.ts +6 -0
  666. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.js +6 -0
  667. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.d.ts +7 -0
  668. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.js +46 -0
  669. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.d.ts +7 -0
  670. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.js +92 -0
  671. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.d.ts +7 -0
  672. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.js +82 -0
  673. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.d.ts +7 -0
  674. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.js +80 -0
  675. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.d.ts +16 -0
  676. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.js +0 -0
  677. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.d.ts +2 -0
  678. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.js +0 -0
  679. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.d.ts +6 -0
  680. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.js +9 -0
  681. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.d.ts +12 -0
  682. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.js +10 -0
  683. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.d.ts +6 -0
  684. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.js +7 -0
  685. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/package.json +133 -0
  686. package/skills/property-based-testing/fixtures/js-roundtrip/package-lock.json +1179 -0
  687. package/skills/property-based-testing/fixtures/js-roundtrip/package.json +14 -0
  688. package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.js +29 -0
  689. package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.properties.test.js +16 -0
  690. package/skills/property-based-testing/fixtures/no_property_fixture.py +10 -0
  691. package/skills/property-based-testing/fixtures/roundtrip_fixture.py +16 -0
  692. package/skills/property-based-testing/references/languages/javascript.md +54 -0
  693. package/skills/property-based-testing/scripts/detect_and_dispatch.py +80 -0
  694. package/skills/property-based-testing/scripts/hypothesis_scaffold.py +276 -0
  695. package/skills/proxy-resilience/SKILL.md +84 -0
  696. package/skills/quality-gate-pipeline/SKILL.md +184 -0
  697. package/skills/quality-targets-converge/SKILL.md +254 -0
  698. package/skills/repo-review/SKILL.md +159 -0
  699. package/skills/report-pdf/SKILL.md +66 -0
  700. package/skills/review/SKILL.md +47 -0
  701. package/skills/review-agent/SKILL.md +152 -0
  702. package/skills/review-summary/SKILL.md +73 -0
  703. package/skills/run-report/SKILL.md +70 -0
  704. package/skills/semantic-duplication-scan/SKILL.md +337 -0
  705. package/skills/semantic-scan/SKILL.md +53 -0
  706. package/skills/semgrep-analyze/SKILL.md +139 -0
  707. package/skills/setup/SKILL.md +1122 -0
  708. package/skills/ship/SKILL.md +240 -0
  709. package/skills/source-verification/SKILL.md +210 -0
  710. package/skills/source-verification/scripts/claim_extractor.py +155 -0
  711. package/skills/specs/.size-baseline.json +4 -0
  712. package/skills/specs/SKILL.md +243 -0
  713. package/skills/specs/references/completeness-checklist.md +83 -0
  714. package/skills/specs/references/extraction.md +58 -0
  715. package/skills/specs/references/glossary.md +59 -0
  716. package/skills/specs/references/persistence.md +115 -0
  717. package/skills/specs/references/predictability-check.md +77 -0
  718. package/skills/static-analysis-integration/SKILL.md +235 -0
  719. package/skills/static-analysis-integration/adapters/_envelope.py +26 -0
  720. package/skills/static-analysis-integration/adapters/jscpd-adapter.py +66 -0
  721. package/skills/static-analysis-integration/adapters/lizard-adapter.py +81 -0
  722. package/skills/static-analysis-integration/adapters/mypy-adapter.py +50 -0
  723. package/skills/static-analysis-integration/adapters/mypy-src-layout.py +93 -0
  724. package/skills/static-analysis-integration/adapters/security-review-adapter.py +212 -0
  725. package/skills/static-analysis-integration/maintenance.md +23 -0
  726. package/skills/static-analysis-integration/references/language-setup.md +228 -0
  727. package/skills/static-analysis-integration/references/sarif-parser.md +124 -0
  728. package/skills/static-analysis-integration/references/security-review-adapter.md +118 -0
  729. package/skills/static-analysis-integration/references/tool-configs.md +617 -0
  730. package/skills/static-analysis-integration/rulesets/pmd-quickstart.xml +24 -0
  731. package/skills/stryker-xunit-v2-shim/SKILL.md +274 -0
  732. package/skills/stryker-xunit-v2-shim/references/shim-howto.md +256 -0
  733. package/skills/stryker-xunit-v2-shim/scripts/generate_shim.py +143 -0
  734. package/skills/systematic-debugging/SKILL.md +130 -0
  735. package/skills/telemetry/SKILL.md +75 -0
  736. package/skills/test-audit-disable/SKILL.md +129 -0
  737. package/skills/test-design/SKILL.md +177 -0
  738. package/skills/test-design/scripts/__pycache__/internal_double_detector.cpython-314.pyc +0 -0
  739. package/skills/test-design/scripts/internal_double_detector.py +631 -0
  740. package/skills/test-design-advisor/SKILL.md +166 -0
  741. package/skills/test-driven-development/SKILL.md +169 -0
  742. package/skills/test-health/SKILL.md +262 -0
  743. package/skills/test-improve/SKILL.md +239 -0
  744. package/skills/test-improve/references/phase-0-approach-contract.md +228 -0
  745. package/skills/test-improve/references/phase-1-analyze.md +131 -0
  746. package/skills/test-improve/references/phase-2-baseline.md +121 -0
  747. package/skills/test-improve/references/phase-3-derive-gherkin.md +53 -0
  748. package/skills/test-improve/references/phase-4-plan-fixes.md +34 -0
  749. package/skills/test-improve/references/phase-5-improve.md +215 -0
  750. package/skills/test-improve/references/phase-6-refactor-decision.md +45 -0
  751. package/skills/test-improve/references/phase-7-refactor.md +44 -0
  752. package/skills/test-improve/references/phase-8-validate.md +66 -0
  753. package/skills/test-improve/references/phase-9-close-out-prompt.md +11 -0
  754. package/skills/test-improve/references/phase-9-report.md +62 -0
  755. package/skills/test-improve/references/review-loop.md +92 -0
  756. package/skills/test-improve/templates/executive-summary.md +123 -0
  757. package/skills/threat-modeling/SKILL.md +108 -0
  758. package/skills/triage/SKILL.md +211 -0
  759. package/skills/ubiquitous-language/SKILL.md +192 -0
  760. package/skills/ubiquitous-language/scripts/collect_domain_signals.py +300 -0
  761. package/skills/unfreeze/SKILL.md +37 -0
  762. package/skills/upgrade/SKILL.md +31 -0
  763. package/skills/upgrade/scripts/check_version_drift.py +113 -0
  764. package/skills/upgrade/scripts/enable_autoupdate.py +149 -0
  765. package/skills/version/SKILL.md +25 -0
  766. package/sync/__pycache__/sync_upstream.cpython-314.pyc +0 -0
  767. package/sync/sync_upstream.py +293 -0
  768. package/templates/ACCEPTED-RISKS.md.tmpl +46 -0
  769. package/templates/agents/agent-template.md +151 -0
  770. package/templates/agents/angular-testing.md +66 -0
  771. package/templates/agents/csharp-quality.md +63 -0
  772. package/templates/agents/esm-enforcer.md +52 -0
  773. package/templates/agents/front-end-testing.md +65 -0
  774. package/templates/agents/go-quality.md +65 -0
  775. package/templates/agents/python-quality.md +62 -0
  776. package/templates/agents/react-testing.md +61 -0
  777. package/templates/agents/ts-enforcer.md +60 -0
  778. package/templates/agents/twelve-factor-audit.md +49 -0
  779. package/tools/entropy-check.py +250 -0
  780. package/tools/model-hash-verify.py +213 -0
@@ -0,0 +1,635 @@
1
+ #!/usr/bin/env python3
2
+ """csharp_stryker_net_slice_runner.py — first-class slicing + configurable
3
+ slice-level parallelism for Stryker.NET (issue #561).
4
+
5
+ Layers on top of ``csharp_stryker_net_wrapper.py``: the wrapper's
6
+ ``hide_sln``/``restore_sln``/``build_project`` functions are reused directly,
7
+ but the hide/restore ceremony happens **once around the whole parallel
8
+ fleet** — not per slice — because only one Stryker instance can safely hide
9
+ the shared ``.sln`` at a time (see issue #561 §2.1).
10
+
11
+ Public API (importable, pure functions first):
12
+
13
+ load_slices_config(path) -> list[dict]
14
+ resolve_slice_selection(configured, requested) -> list[dict]
15
+ slice_output_dir(output_root, name) -> Path
16
+ slice_report_path(output_root, name) -> Path
17
+ is_terminal_report(path) -> bool
18
+ partition_terminal_slices(slices, output_root, force) -> (to_run, skipped)
19
+ resolve_total_workers(value, cpu_count) -> int
20
+ total_worker_ceiling_check(total_workers, cores, force) -> (bool, Optional[str])
21
+ resolve_worker_allocation(total_workers, slice_count, parallel_slices, per_slice_concurrency, force) -> (int, int)
22
+ build_slice_stryker_config(base_config, slice_def) -> dict
23
+ write_slice_config(output_root, name, stryker_config) -> Path
24
+ summarize_native_report(native_report) -> dict
25
+ aggregate_slice_summaries(summaries) -> dict
26
+ format_progress_line(order, states) -> str
27
+
28
+ Refs: #561, #667, #669.
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import argparse
34
+ import json
35
+ import os
36
+ import sys
37
+ from collections.abc import Sequence
38
+ from concurrent.futures import ThreadPoolExecutor
39
+ from pathlib import Path
40
+ from typing import Any
41
+
42
+ # Reuse the shipped wrapper's hide/restore/build/run primitives so the
43
+ # hide-once-around-the-fleet contract composes with the existing
44
+ # pre-build-before-hide and signal-safe-run guarantees instead of
45
+ # duplicating them.
46
+ import csharp_stryker_net_wrapper as wrapper
47
+
48
+ REQUIRED_SLICE_FIELDS = ("name", "mutate")
49
+ # Reserved for #667's within-slice refinements — accepted but not yet acted
50
+ # on by this runner. Listed here so a typo in a reserved field still fails
51
+ # validation instead of silently doing nothing.
52
+ RESERVED_SLICE_FIELDS = ("kind", "mutation-level", "exclude-converged")
53
+ KNOWN_SLICE_FIELDS = REQUIRED_SLICE_FIELDS + RESERVED_SLICE_FIELDS
54
+
55
+ # Stryker.NET config keys this skill's generic slice passthrough
56
+ # (build_slice_stryker_config) is known to be used with in practice. NOT an
57
+ # exhaustive copy of Stryker's own schema — duplicating that schema here is
58
+ # exactly what the passthrough's "single generic seam" design avoids (#2145),
59
+ # so this list only gates a WARNING, never a rejection: a legitimate Stryker
60
+ # key that isn't listed yet still passes through unchanged, just noisily.
61
+ # Extend as new keys are used in a slices config.
62
+ KNOWN_STRYKER_PASSTHROUGH_KEYS = frozenset(
63
+ {
64
+ "project",
65
+ "coverage-analysis",
66
+ "since",
67
+ "additional-timeout",
68
+ "reporters",
69
+ "concurrency",
70
+ "test-projects",
71
+ "ignore-mutations",
72
+ "thresholds",
73
+ "dashboard-api-key",
74
+ "disable-bail",
75
+ "solution",
76
+ "target-framework",
77
+ "language-version",
78
+ "ignore-methods",
79
+ "break-at",
80
+ "report-file-name",
81
+ "verbosity",
82
+ "log-to-file",
83
+ "open-report",
84
+ }
85
+ )
86
+
87
+
88
+ # =============================================================================
89
+ # Slice config loading + validation
90
+ # =============================================================================
91
+ def load_slices_config(path: Path) -> list[dict[str, Any]]:
92
+ """Load and validate the ``slices:`` block from a JSON config file.
93
+
94
+ Only ``name`` + ``mutate`` are required per slice (#561's "first cut").
95
+ ``kind`` / ``mutation-level`` / ``exclude-converged`` are accepted and
96
+ passed through (reserved for #667) but not otherwise interpreted here.
97
+ Raises ValueError with an actionable message on any structural problem.
98
+ """
99
+ try:
100
+ data = json.loads(Path(path).read_text())
101
+ except FileNotFoundError:
102
+ raise ValueError(f"slices config not found: {path}")
103
+ except json.JSONDecodeError as e:
104
+ raise ValueError(f"slices config is not valid JSON: {path} ({e})")
105
+
106
+ slices = data.get("slices")
107
+ if not isinstance(slices, list) or not slices:
108
+ raise ValueError(
109
+ f'slices config {path} must have a non-empty top-level "slices" array'
110
+ )
111
+
112
+ seen_names = set()
113
+ for i, s in enumerate(slices):
114
+ if not isinstance(s, dict):
115
+ raise TypeError(f"slices[{i}] must be an object")
116
+ missing = [f for f in REQUIRED_SLICE_FIELDS if f not in s]
117
+ if missing:
118
+ raise ValueError(
119
+ f"slices[{i}] is missing required field(s): {', '.join(missing)}"
120
+ )
121
+ if s["name"] in seen_names:
122
+ raise ValueError(f"duplicate slice name: {s['name']!r}")
123
+ seen_names.add(s["name"])
124
+ return slices
125
+
126
+
127
+ def resolve_slice_selection(
128
+ configured: Sequence[dict[str, Any]], requested: str
129
+ ) -> list[dict[str, Any]]:
130
+ """Return the configured slice(s) matching ``--slice <requested>``.
131
+
132
+ ``requested == "all"`` returns every configured slice, in config order.
133
+ A named slice must match a configured ``name`` exactly, else ValueError.
134
+ """
135
+ if requested == "all":
136
+ return list(configured)
137
+ for s in configured:
138
+ if s["name"] == requested:
139
+ return [s]
140
+ known = ", ".join(s["name"] for s in configured)
141
+ raise ValueError(f"no slice named {requested!r} in config (known: {known})")
142
+
143
+
144
+ # =============================================================================
145
+ # Per-slice output layout
146
+ # =============================================================================
147
+ def slice_output_dir(output_root: Path, name: str) -> Path:
148
+ return Path(output_root) / f"slice-{name}"
149
+
150
+
151
+ def slice_report_path(output_root: Path, name: str) -> Path:
152
+ return slice_output_dir(output_root, name) / "reports" / "mutation-report.json"
153
+
154
+
155
+ def is_terminal_report(path: Path) -> bool:
156
+ """A report is terminal when it exists, parses as JSON, and has a
157
+ non-empty top-level ``files`` map — Stryker.NET's own JSON-reporter
158
+ shape. A partial file from a crashed run either doesn't parse or has no
159
+ ``files`` entries, so it is never mistaken for a completed run.
160
+ """
161
+ p = Path(path)
162
+ if not p.exists():
163
+ return False
164
+ try:
165
+ data = json.loads(p.read_text())
166
+ except (json.JSONDecodeError, OSError, UnicodeDecodeError):
167
+ return False
168
+ if not isinstance(data, dict):
169
+ return False
170
+ files = data.get("files")
171
+ return isinstance(files, dict) and len(files) > 0
172
+
173
+
174
+ def partition_terminal_slices(
175
+ slices: Sequence[dict[str, Any]], output_root: Path, force: bool
176
+ ) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
177
+ """Split ``slices`` into (to_run, skipped). A slice is skipped when its
178
+ report is terminal AND ``--force`` was not passed — resume-by-default.
179
+ """
180
+ if force:
181
+ return list(slices), []
182
+ to_run: list[dict[str, Any]] = []
183
+ skipped: list[dict[str, Any]] = []
184
+ for s in slices:
185
+ report = slice_report_path(output_root, s["name"])
186
+ if is_terminal_report(report):
187
+ skipped.append(s)
188
+ else:
189
+ to_run.append(s)
190
+ return to_run, skipped
191
+
192
+
193
+ # =============================================================================
194
+ # Total-worker budget + slice/concurrency split
195
+ # =============================================================================
196
+ def resolve_total_workers(value: str | None, cpu_count: int | None) -> int:
197
+ """``None``/``"auto"`` -> ``max(2, cores / 2)``; otherwise the given int."""
198
+ if value is None or value == "auto":
199
+ cores = cpu_count or 2
200
+ return max(2, cores // 2)
201
+ return int(value)
202
+
203
+
204
+ def total_worker_ceiling_check(
205
+ total_workers: int, cores: int | None, force: bool
206
+ ) -> tuple[bool, str | None]:
207
+ """Return ``(allowed, message)``. Refuses (``allowed=False``, an error
208
+ message) a total-worker count over ``cores - 1`` unless ``--force`` is
209
+ set, in which case it is allowed with a warning message instead.
210
+ """
211
+ ceiling = max(1, (cores or 2) - 1)
212
+ if total_workers <= ceiling:
213
+ return True, None
214
+ if force:
215
+ return True, (
216
+ f"warning: --total-workers {total_workers} exceeds the cores-1 "
217
+ f"ceiling ({ceiling}, cores={cores or 2}); proceeding due to --force\n"
218
+ )
219
+ return False, (
220
+ f"error: --total-workers {total_workers} exceeds the cores-1 ceiling "
221
+ f"({ceiling}, cores={cores or 2}); pass --force to override\n"
222
+ )
223
+
224
+
225
+ def default_split(total_workers: int, slice_count: int) -> tuple[int, int]:
226
+ """Allocate slices first (up to the configured slice count), then divide
227
+ the remainder as per-slice concurrency — favours cross-slice parallelism
228
+ over deeper within-slice parallelism (#561 §2 default-split rule).
229
+ """
230
+ parallel_slices = max(1, min(total_workers, slice_count))
231
+ per_slice_concurrency = max(1, total_workers // parallel_slices)
232
+ return parallel_slices, per_slice_concurrency
233
+
234
+
235
+ def resolve_worker_allocation(
236
+ total_workers: int,
237
+ slice_count: int,
238
+ parallel_slices: int | None,
239
+ per_slice_concurrency: int | None,
240
+ force: bool,
241
+ ) -> tuple[int, int, str | None]:
242
+ """Return ``(parallel_slices, per_slice_concurrency, message)``.
243
+
244
+ When both axes are set explicitly, refuse (unless ``--force``) if their
245
+ product exceeds ``total_workers``. When only one axis is set, derive the
246
+ other from ``total_workers``. When neither is set, use the default split.
247
+ """
248
+ if parallel_slices is not None and per_slice_concurrency is not None:
249
+ product = parallel_slices * per_slice_concurrency
250
+ if product > total_workers:
251
+ msg_kind = "warning" if force else "error"
252
+ msg = (
253
+ f"{msg_kind}: --parallel-slices {parallel_slices} x "
254
+ f"--per-slice-concurrency {per_slice_concurrency} = {product} "
255
+ f"exceeds the total-worker ceiling ({total_workers})"
256
+ + (
257
+ "; proceeding due to --force\n"
258
+ if force
259
+ else "; pass --force to override\n"
260
+ )
261
+ )
262
+ return parallel_slices, per_slice_concurrency, msg
263
+ return parallel_slices, per_slice_concurrency, None
264
+ if parallel_slices is not None:
265
+ per_slice_concurrency = max(1, total_workers // parallel_slices)
266
+ return parallel_slices, per_slice_concurrency, None
267
+ if per_slice_concurrency is not None:
268
+ parallel_slices = max(1, total_workers // per_slice_concurrency)
269
+ return parallel_slices, per_slice_concurrency, None
270
+ parallel_slices, per_slice_concurrency = default_split(total_workers, slice_count)
271
+ return parallel_slices, per_slice_concurrency, None
272
+
273
+
274
+ # =============================================================================
275
+ # Per-slice Stryker config generation
276
+ # =============================================================================
277
+ def build_slice_stryker_config(
278
+ base_config: dict[str, Any], slice_def: dict[str, Any]
279
+ ) -> dict[str, Any]:
280
+ """Merge ``base_config`` with the slice's ``mutate`` glob. Defaults
281
+ ``coverage-analysis`` to ``"perTest"`` per #669's validated
282
+ recommendation, unless the base config already sets it (escape hatch,
283
+ e.g. xunit.v3/MTP projects that must keep it ``"off"``).
284
+
285
+ A slice may also carry additional Stryker-config-shaped keys beyond
286
+ ``mutate`` — most notably ``"project"``, naming the single source
287
+ ``.csproj`` under test (Stryker's own ``-p``/``--project``/config
288
+ ``"project"`` key). Without it, Stryker auto-discovers every source
289
+ project transitively referenced by the configured ``test-projects`` and
290
+ re-runs its build + initial-test-run + coverage-capture cycle for each
291
+ one on **every** slice invocation, regardless of that slice's ``mutate``
292
+ glob — multiplying fixed per-slice overhead by the number of source
293
+ projects in the solution. Any slice key other than the reserved/required
294
+ ones handled above is passed through verbatim, so this stays a single
295
+ generic seam rather than one hardcoded field for ``"project"`` alone.
296
+
297
+ This passthrough is deliberately unvalidated (#2145) — a slice-level
298
+ ``"coverage-analysis"`` key, for instance, silently overrides the
299
+ ``setdefault`` above, which is intentional (the same xunit.v3/MTP escape
300
+ hatch, applied per-slice instead of once for the whole base config) but
301
+ otherwise indistinguishable at this layer from a typo. As a middle
302
+ ground between "stay generic" and "catch typos", any passthrough key not
303
+ in :data:`KNOWN_STRYKER_PASSTHROUGH_KEYS` prints a warning (to stderr)
304
+ naming the slice and the key — informational only; the value is still
305
+ applied unchanged.
306
+ """
307
+ cfg = dict(base_config)
308
+ mutate = slice_def["mutate"]
309
+ cfg["mutate"] = mutate if isinstance(mutate, list) else [mutate]
310
+ cfg.setdefault("coverage-analysis", "perTest")
311
+ for key, value in slice_def.items():
312
+ if key in KNOWN_SLICE_FIELDS:
313
+ continue
314
+ if key not in KNOWN_STRYKER_PASSTHROUGH_KEYS:
315
+ print(
316
+ f"WARNING: slice {slice_def.get('name')!r} passes through "
317
+ f"unrecognized Stryker config key {key!r} — applied "
318
+ "unchanged; check for a typo if this wasn't intentional.",
319
+ file=sys.stderr,
320
+ )
321
+ cfg[key] = value
322
+ return cfg
323
+
324
+
325
+ def write_slice_config(
326
+ output_root: Path, name: str, stryker_config: dict[str, Any]
327
+ ) -> Path:
328
+ out_dir = slice_output_dir(output_root, name)
329
+ out_dir.mkdir(parents=True, exist_ok=True)
330
+ path = out_dir / "stryker-config.json"
331
+ path.write_text(json.dumps({"stryker-config": stryker_config}, indent=2))
332
+ return path
333
+
334
+
335
+ # =============================================================================
336
+ # Report summarizing + aggregate roll-up
337
+ # =============================================================================
338
+ def summarize_native_report(native: dict[str, Any]) -> dict[str, int]:
339
+ """Reduce a Stryker.NET native ``mutation-report.json`` (top-level
340
+ ``files`` map of file -> {"mutants": [...]}) to per-status counts.
341
+ """
342
+ counts: dict[str, int] = {}
343
+ for file_entry in native.get("files", {}).values():
344
+ for mutant in file_entry.get("mutants", []):
345
+ status = mutant.get("status", "Unknown")
346
+ counts[status] = counts.get(status, 0) + 1
347
+ return counts
348
+
349
+
350
+ def aggregate_slice_summaries(
351
+ summaries: dict[str, dict[str, int]],
352
+ ) -> dict[str, Any]:
353
+ """Roll up per-slice status counts into one aggregate document."""
354
+ totals: dict[str, int] = {}
355
+ per_slice: dict[str, dict[str, int]] = {}
356
+ for name, counts in summaries.items():
357
+ per_slice[name] = counts
358
+ for status, n in counts.items():
359
+ totals[status] = totals.get(status, 0) + n
360
+ killed = totals.get("Killed", 0)
361
+ survived = totals.get("Survived", 0)
362
+ no_coverage = totals.get("NoCoverage", 0)
363
+ denom = killed + survived + no_coverage
364
+ honest_score = (killed / denom * 100.0) if denom else 0.0
365
+ return {
366
+ "schema_version": 1,
367
+ "tool": "stryker-net",
368
+ "slices": per_slice,
369
+ "totals": totals,
370
+ "honest_score": honest_score,
371
+ }
372
+
373
+
374
+ def write_aggregate_report(output_root: Path, aggregate: dict[str, Any]) -> Path:
375
+ path = Path(output_root) / "aggregate-mutation-report.json"
376
+ path.write_text(json.dumps(aggregate, indent=2))
377
+ return path
378
+
379
+
380
+ # =============================================================================
381
+ # Rolled-up progress reporting
382
+ # =============================================================================
383
+ def format_progress_line(order: Sequence[str], states: dict[str, str]) -> str:
384
+ """Render a rolled-up progress line, e.g.:
385
+
386
+ ``slice 3/7 done, slice 4/7 running, slice 5/7 running, slice 6/7 queued``
387
+ """
388
+ total = len(order)
389
+ parts = []
390
+ for i, name in enumerate(order, start=1):
391
+ status = states.get(name, "queued")
392
+ parts.append(f"slice {i}/{total} {status}")
393
+ return ", ".join(parts)
394
+
395
+
396
+ # =============================================================================
397
+ # Single-slice run (fleet-level hide/restore already done by the caller)
398
+ # =============================================================================
399
+ def run_slice(
400
+ slice_def: dict[str, Any],
401
+ *,
402
+ base_config: dict[str, Any],
403
+ output_root: Path,
404
+ stryker_bin: str,
405
+ per_slice_concurrency: int,
406
+ ) -> int:
407
+ """Write the slice's config, invoke Stryker scoped to it, return the
408
+ Stryker exit code. Does NOT hide/restore ``.sln`` — the fleet caller
409
+ owns that ceremony once for the whole run.
410
+ """
411
+ name = slice_def["name"]
412
+ cfg = build_slice_stryker_config(base_config, slice_def)
413
+ config_path = write_slice_config(output_root, name, cfg)
414
+ out_dir = slice_output_dir(output_root, name)
415
+ logfile = out_dir / "wrapper.log"
416
+ stryker_args = [
417
+ "--config-file",
418
+ str(config_path),
419
+ "-c",
420
+ str(per_slice_concurrency),
421
+ "-O",
422
+ str(out_dir),
423
+ ]
424
+ return wrapper.run_stryker(
425
+ stryker_bin=stryker_bin, stryker_args=stryker_args, logfile=logfile
426
+ )
427
+
428
+
429
+ # =============================================================================
430
+ # Main
431
+ # =============================================================================
432
+ def parse_args(argv: Sequence[str]) -> argparse.Namespace:
433
+ p = argparse.ArgumentParser(
434
+ prog="csharp_stryker_net_slice_runner.py",
435
+ description=(
436
+ "First-class slicing + configurable slice-level parallelism for "
437
+ "Stryker.NET (#561)."
438
+ ),
439
+ )
440
+ p.add_argument(
441
+ "--slices-config",
442
+ default=os.environ.get("MUTATION_SLICES_CONFIG", "mutation-slices.json"),
443
+ help="Path to the slices config JSON (default: %(default)s)",
444
+ )
445
+ p.add_argument(
446
+ "--slice",
447
+ required=True,
448
+ help='Slice name, or "all" to run every configured slice.',
449
+ )
450
+ p.add_argument(
451
+ "--output-root",
452
+ default=os.environ.get("MUTATION_SLICE_OUTPUT_ROOT", "StrykerOutput"),
453
+ help="Root directory for per-slice output (default: %(default)s)",
454
+ )
455
+ p.add_argument(
456
+ "--sln", default=os.environ.get("SLN", "Foo.sln"), help="Solution file."
457
+ )
458
+ p.add_argument(
459
+ "--shim-project",
460
+ default=os.environ.get("SHIM_PROJECT", ""),
461
+ help="Optional shim test project to pre-build.",
462
+ )
463
+ p.add_argument(
464
+ "--stryker-bin",
465
+ default=os.environ.get("STRYKER_BIN", "dotnet"),
466
+ help="Stryker executable name, or 'dotnet' to invoke a local-tool-"
467
+ "manifest install via 'dotnet stryker' (default: %(default)s)",
468
+ )
469
+ p.add_argument(
470
+ "--base-config",
471
+ default=os.environ.get("MUTATION_BASE_CONFIG", ""),
472
+ help="Path to a base stryker-config.json's inner config to merge "
473
+ "into each slice's generated config. Empty = start from {}.",
474
+ )
475
+ p.add_argument(
476
+ "--total-workers",
477
+ default=os.environ.get("MUTATION_TOTAL_WORKERS", "auto"),
478
+ help='Integer, or "auto" = max(2, cores / 2) (default: auto).',
479
+ )
480
+ p.add_argument("--parallel-slices", type=int, default=None)
481
+ p.add_argument("--per-slice-concurrency", type=int, default=None)
482
+ p.add_argument(
483
+ "--force",
484
+ action="store_true",
485
+ help="Rerun terminal slices and override worker-ceiling refusals.",
486
+ )
487
+ return p.parse_args(list(argv))
488
+
489
+
490
+ def _load_base_config(path: str) -> dict[str, Any]:
491
+ if not path:
492
+ return {}
493
+ data = json.loads(Path(path).read_text())
494
+ return data.get("stryker-config", data)
495
+
496
+
497
+ def main(argv: Sequence[str] | None = None) -> int:
498
+ argv = list(sys.argv[1:] if argv is None else argv)
499
+ args = parse_args(argv)
500
+
501
+ try:
502
+ configured = load_slices_config(Path(args.slices_config))
503
+ selected = resolve_slice_selection(configured, args.slice)
504
+ except (ValueError, TypeError) as e:
505
+ sys.stderr.write(f"error: {e}\n")
506
+ return 2
507
+
508
+ output_root = Path(args.output_root)
509
+ to_run, skipped = partition_terminal_slices(selected, output_root, args.force)
510
+ for s in skipped:
511
+ print(f"SKIPPED {s['name']} — terminal report exists (use --force to rerun)")
512
+
513
+ if not to_run:
514
+ print("no slices to run (all terminal; pass --force to rerun)")
515
+ return 0
516
+
517
+ cores = os.cpu_count()
518
+ total_workers = resolve_total_workers(args.total_workers, cores)
519
+ allowed, msg = total_worker_ceiling_check(total_workers, cores, args.force)
520
+ if msg:
521
+ sys.stderr.write(msg)
522
+ if not allowed:
523
+ return 2
524
+
525
+ parallel_slices, per_slice_concurrency, split_msg = resolve_worker_allocation(
526
+ total_workers,
527
+ len(to_run),
528
+ args.parallel_slices,
529
+ args.per_slice_concurrency,
530
+ args.force,
531
+ )
532
+ if split_msg:
533
+ sys.stderr.write(split_msg)
534
+ if split_msg.startswith("error") and not args.force:
535
+ return 2
536
+
537
+ base_config = _load_base_config(args.base_config)
538
+
539
+ # ---- Fleet-level .sln hide/restore — ONCE, not per slice. ----
540
+ sln = Path(args.sln)
541
+ sln_hidden = Path(f"{args.sln}.stryker-hidden")
542
+ stale_err = wrapper.check_stale_hidden_sln(sln, sln_hidden)
543
+ if stale_err is not None:
544
+ sys.stderr.write(stale_err)
545
+ return wrapper.EXIT_STALE_HIDDEN_SLN
546
+
547
+ rc = wrapper.build_project(args.sln)
548
+ if rc != 0:
549
+ return rc
550
+ if args.shim_project:
551
+ rc = wrapper.build_project(args.shim_project)
552
+ if rc != 0:
553
+ return rc
554
+
555
+ wrapper.hide_sln(sln, sln_hidden)
556
+
557
+ order = [s["name"] for s in to_run]
558
+ states: dict[str, str] = {name: "queued" for name in order}
559
+ exit_codes: dict[str, int] = {}
560
+
561
+ # ---- Install signal handlers now that we're about to spawn a fleet of
562
+ # concurrent Stryker subprocesses (one per in-flight slice). This reuses
563
+ # the wrapper's own SIGINT/SIGTERM handler, which terminates every Popen
564
+ # tracked in wrapper._RUNNING_STRYKER_PROCS — a set shared across every
565
+ # ThreadPoolExecutor worker thread below, so Ctrl-C / SIGTERM kills ALL
566
+ # still-running slices, not just one (#732). Save/restore previous
567
+ # handlers exactly as wrapper.main() does, so library-style callers
568
+ # (e.g. pytest) don't inherit our handlers past this call.
569
+ previous_signal_handlers = wrapper._install_signal_handlers()
570
+ interrupted = False
571
+ try:
572
+ with ThreadPoolExecutor(max_workers=max(1, parallel_slices)) as pool:
573
+ futures = {}
574
+ for s in to_run:
575
+ states[s["name"]] = "running"
576
+ futures[
577
+ pool.submit(
578
+ run_slice,
579
+ s,
580
+ base_config=base_config,
581
+ output_root=output_root,
582
+ stryker_bin=args.stryker_bin,
583
+ per_slice_concurrency=per_slice_concurrency,
584
+ )
585
+ ] = s["name"]
586
+ print(format_progress_line(order, states))
587
+ for future, name in futures.items():
588
+ exit_codes[name] = future.result()
589
+ states[name] = "done" if exit_codes[name] == 0 else "failed"
590
+ print(format_progress_line(order, states))
591
+ except KeyboardInterrupt:
592
+ # SIGINT/SIGTERM propagated through the signal handlers, which have
593
+ # already terminate()'d every live Stryker subprocess across all
594
+ # slice worker threads. Fall through to fleet-level .sln restoration
595
+ # below rather than let this escape uncaught.
596
+ interrupted = True
597
+ sys.stderr.write("mutation slice run interrupted; restoring .sln\n")
598
+ finally:
599
+ restored = wrapper.restore_sln(sln, sln_hidden)
600
+ if not restored:
601
+ sys.stderr.write(
602
+ f"error: failed to restore {sln} from {sln_hidden} — the "
603
+ "solution file is left hidden/renamed, which will break the "
604
+ "next build (#1955)\n"
605
+ )
606
+ wrapper._restore_signal_handlers(previous_signal_handlers)
607
+
608
+ if interrupted:
609
+ return 130
610
+
611
+ # ---- Aggregate roll-up ----
612
+ summaries = {}
613
+ for s in to_run:
614
+ report = slice_report_path(output_root, s["name"])
615
+ if report.exists():
616
+ try:
617
+ summaries[s["name"]] = summarize_native_report(
618
+ json.loads(report.read_text())
619
+ )
620
+ except (json.JSONDecodeError, OSError):
621
+ pass
622
+ if summaries:
623
+ aggregate = aggregate_slice_summaries(summaries)
624
+ write_aggregate_report(output_root, aggregate)
625
+
626
+ fleet_rc = max(exit_codes.values(), default=0)
627
+ # Don't clobber a real per-slice failure — surface the restore failure
628
+ # only when every slice otherwise looked clean (#1955).
629
+ if not restored and fleet_rc == 0:
630
+ fleet_rc = wrapper.EXIT_RESTORE_SLN_FAILED
631
+ return fleet_rc
632
+
633
+
634
+ if __name__ == "__main__":
635
+ sys.exit(main())