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,118 @@
1
+ """Model-pricing loader, rate lookup, and cost computation (issue #2045,
2
+ epic #2040).
3
+
4
+ Shared by `hooks/lib/cost_meter.py` (the Stop-hook cost meter) and
5
+ `session_report.py --profile maintainer` (originally a separate monorepo-only
6
+ session digest extractor, retired in #2048; #2045 unified the two). Before
7
+ this module existed each carried its
8
+ own near-identical copy of `_load_pricing`/`_rate`/`_cost`, and the two had
9
+ quietly drifted: cost_meter's loader raised on a missing/unreadable
10
+ pricing file where the extractor's degraded to an empty table, and
11
+ cost_meter's `_cost` required its caller to guard `if rate else 0.0` (it
12
+ indexed `rate["input"]` directly) where the extractor's guarded internally
13
+ and read `rate.get(...)`. Unified here on the more defensive shape throughout: an
14
+ absent/corrupt/`None` pricing path yields `{}` rather than raising, and
15
+ `cost()` itself returns `0.0` for an unpriced model rather than requiring
16
+ every caller to remember the ternary — consistent with this file's own
17
+ fail-open philosophy (see `cost_meter.py`'s `cmd_record`/`cmd_phase_mark`,
18
+ which return 0 on a missing transcript rather than raising: a hook must
19
+ never break a turn).
20
+
21
+ Placement — NOT `plugins/dev-team/scripts/lib/session_log/`, despite that
22
+ package's `__init__.py` briefly forward-declaring a `pricing` module for
23
+ this issue (corrected in the same commit that adds this file). Reason:
24
+ `hooks/lib/cost_meter.py` is a real Stop hook, registered in `settings.json`
25
+ and run on every session in every installed project.
26
+ `hooks/lib/review_agent_registry.py` and `hooks/lib/review_dispatch_ledger.py`
27
+ already established the rule this module follows — "a hook must be
28
+ import-safe without any `scripts/` module on its path; the dependency
29
+ direction is scripts/ -> hooks/lib/, never the reverse" (#1461) — so a
30
+ module a hook needs lives in `hooks/lib/`, and the `scripts/` side reaches
31
+ into it, exactly mirroring how `scripts/check_review_agent_mcp_tools.py`
32
+ already imports `review_agent_registry` from `hooks/lib/`. Putting pricing
33
+ here instead of `session_log/` keeps that boundary intact rather than
34
+ inverting it for this one module.
35
+
36
+ Downstream-cost decision (#2045): `session_report.py --profile downstream`
37
+ (originally a separate shipped script, retired in #2048; the shipped
38
+ report a downstream user hands to the plugin
39
+ maintainer) does NOT gain a cost figure as part of this issue, and does not
40
+ import this module. ADR 0036 already decided this narrower question — "The extractors'
41
+ divergent layers stay forked: discovery/CLI surface, **pricing and cost**,
42
+ rollup, escalation, and the report shapes... cost/pricing/rollup/escalation
43
+ exist only in the monorepo one. Divergence is not drift." — for exactly the
44
+ reason issue #2045 itself names as the argument against: a pricing table
45
+ shipped inside the plugin is unverifiable by the downstream user and goes
46
+ stale between releases, so it's presented in `cost_meter.py`'s own reports
47
+ (which run in the environment that produced the spend) rather than baked
48
+ into a portable summary file.
49
+
50
+ Stdlib only. See ADR 0014 / ADR 0015.
51
+ """
52
+
53
+ from __future__ import annotations
54
+
55
+ import json
56
+ from pathlib import Path
57
+
58
+ DEFAULT_CACHE_WRITE_MULTIPLIER = 1.25
59
+ DEFAULT_CACHE_READ_MULTIPLIER = 0.1
60
+
61
+
62
+ def _usage_field(usage: dict, field: str) -> int | float:
63
+ """`.get(field, 0) or 0` — the one canonical usage-field reader (matches
64
+ `scripts/lib/session_log/records.usage_field`'s null-handling contract;
65
+ duplicated here rather than imported, in service of the hooks/lib ->
66
+ scripts/ dependency direction described in the module docstring above —
67
+ this module must not reach INTO `scripts/lib/session_log/` any more than
68
+ `cost_meter.py` may)."""
69
+ return usage.get(field, 0) or 0
70
+
71
+
72
+ def load_pricing(path: Path | None) -> dict:
73
+ """Load a model-pricing.json table. Defensive: an absent path, a `None`
74
+ path, or malformed JSON all degrade to `{}` (every model then prices at
75
+ $0.00 and is flagged `unpriced`) rather than raising."""
76
+ if not path or not Path(path).is_file():
77
+ return {}
78
+ try:
79
+ return json.loads(Path(path).read_text())
80
+ except (OSError, json.JSONDecodeError):
81
+ return {}
82
+
83
+
84
+ def rate(pricing: dict, model: str) -> dict | None:
85
+ """Resolve one model id to its `{"input": .., "output": ..}` rate,
86
+ following a pricing table's `aliases` indirection when the model id has
87
+ no direct entry."""
88
+ models = pricing.get("models", {})
89
+ if model in models:
90
+ return models[model]
91
+ alias = pricing.get("aliases", {}).get(model)
92
+ if alias and alias in models:
93
+ return models[alias]
94
+ return None
95
+
96
+
97
+ def cost(usage: dict, rate_entry: dict | None, pricing: dict) -> float:
98
+ """Dollar cost of one usage block at `rate_entry`. `0.0` when no rate is
99
+ known for the model — an unpriced model contributes $0, never raises."""
100
+ if not rate_entry:
101
+ return 0.0
102
+ input_tokens = _usage_field(usage, "input_tokens")
103
+ output_tokens = _usage_field(usage, "output_tokens")
104
+ cache_write_tokens = _usage_field(usage, "cache_creation_input_tokens")
105
+ cache_read_tokens = _usage_field(usage, "cache_read_input_tokens")
106
+ in_rate = rate_entry.get("input", 0)
107
+ return (
108
+ input_tokens / 1e6 * in_rate
109
+ + output_tokens / 1e6 * rate_entry.get("output", 0)
110
+ + cache_write_tokens
111
+ / 1e6
112
+ * in_rate
113
+ * pricing.get("cache_write_multiplier", DEFAULT_CACHE_WRITE_MULTIPLIER)
114
+ + cache_read_tokens
115
+ / 1e6
116
+ * in_rate
117
+ * pricing.get("cache_read_multiplier", DEFAULT_CACHE_READ_MULTIPLIER)
118
+ )
@@ -0,0 +1,371 @@
1
+ #!/usr/bin/env python3
2
+ """Render a Markdown report to a styled PDF.
3
+
4
+ Backs the ``/report-pdf`` command and the ``--pdf`` flag on report-producing
5
+ skills. Stdlib only, (ADR 0014 / 0015). Detects a PDF engine via.
6
+ runtime probes and converts Markdown -> PDF, **never raising for a missing
7
+ engine** — callers get a structured :class:`RenderResult` and the underlying
8
+ Markdown report is left untouched.
9
+
10
+ Two pipelines sit behind one abstraction:
11
+
12
+ - **pandoc-mediated** — Markdown -> self-contained HTML (with the bundled
13
+ ``report-print.css``) via pandoc, then HTML -> PDF via headless
14
+ Chrome/Chromium, weasyprint, or wkhtmltopdf.
15
+ - **direct** — ``md-to-pdf`` consumes Markdown directly (no pandoc).
16
+
17
+ Fallback order: Chrome/Chromium -> weasyprint -> wkhtmltopdf -> md-to-pdf. The
18
+ first three require pandoc; md-to-pdf does not.
19
+
20
+ State is read off a single :class:`RenderResult`:
21
+
22
+ - success -> ``rendered=True``, ``engine``/``out_path`` set, reason fields None
23
+ - skip -> ``rendered=False``, ``reason``+``install_hint`` set, ``error`` None
24
+ - failure -> ``rendered=False``, ``error`` set, ``reason``/``install_hint`` None
25
+
26
+ CLI contract (``report_pdf.py <md> [--out <path>]``):
27
+
28
+ stdout : a ``Rendering …`` progress line, then one result line
29
+ exit 0 : rendered, or skipped (no engine) — the report is always safe
30
+ exit 1 : source file not found, or an engine was present but failed
31
+ exit 2 : usage error (no path given)
32
+ """
33
+ from __future__ import annotations
34
+
35
+ import argparse
36
+ import os
37
+ import platform
38
+ import shutil
39
+ import subprocess
40
+ import sys
41
+ import tempfile
42
+ from collections.abc import Callable
43
+ from dataclasses import dataclass
44
+ from pathlib import Path
45
+
46
+ # Detection order. ``kind`` is the pipeline: "pandoc" engines consume HTML that
47
+ # pandoc produces; "direct" engines consume Markdown themselves.
48
+ _PANDOC = "pandoc"
49
+ _DIRECT = "direct"
50
+
51
+ # Upper bound (seconds) on any single engine/pandoc invocation. A wedged
52
+ # headless Chrome must surface as an engine failure, never an indefinite hang.
53
+ _TIMEOUT_SECONDS = 120
54
+
55
+ # PATH names probed for a Chrome/Chromium binary, in preference order.
56
+ _CHROME_NAMES = (
57
+ "google-chrome",
58
+ "google-chrome-stable",
59
+ "chromium",
60
+ "chromium-browser",
61
+ "chrome",
62
+ )
63
+
64
+
65
+ @dataclass
66
+ class Engine:
67
+ """A resolved PDF engine: its ``name``, pipeline ``kind``, and (for Chrome)
68
+ the concrete ``binary`` path a PATH/app-path probe found."""
69
+
70
+ name: str
71
+ kind: str
72
+ binary: str | None = None
73
+
74
+
75
+ @dataclass
76
+ class RenderResult:
77
+ """Outcome of a render attempt — the single contract both surfaces key off.
78
+
79
+ See the module docstring for the field discriminant across
80
+ success / skip / failure.
81
+ """
82
+
83
+ rendered: bool
84
+ engine: str | None = None
85
+ out_path: str | None = None
86
+ reason: str | None = None
87
+ install_hint: str | None = None
88
+ error: str | None = None
89
+
90
+
91
+ def _chrome_binary() -> str | None:
92
+ """Locate a Chrome/Chromium binary via runtime probes only.
93
+
94
+ PATH names first (cross-OS), then OS-specific application paths chosen by
95
+ ``platform.system()`` so the probe stays a runtime decision (mockable in
96
+ tests) rather than a hard-coded constant.
97
+ """
98
+ for name in _CHROME_NAMES:
99
+ found = shutil.which(name)
100
+ if found:
101
+ return found
102
+ system = platform.system()
103
+ candidates: list[str] = []
104
+ if system == "Darwin":
105
+ candidates = [
106
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
107
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
108
+ ]
109
+ elif system == "Windows":
110
+ for env in ("PROGRAMFILES", "PROGRAMFILES(X86)", "LOCALAPPDATA"):
111
+ base = os.environ.get(env)
112
+ if base:
113
+ candidates.append(
114
+ os.path.join(base, "Google", "Chrome", "Application", "chrome.exe")
115
+ )
116
+ for candidate in candidates:
117
+ if os.path.isfile(candidate) and os.access(candidate, os.X_OK):
118
+ return candidate
119
+ return None
120
+
121
+
122
+ def detect_engine() -> Engine | None:
123
+ """Return the first available engine in fallback order, or ``None``.
124
+
125
+ Chrome/weasyprint/wkhtmltopdf are only offered when pandoc is present (they
126
+ consume pandoc's HTML). md-to-pdf is offered whether or not pandoc exists —
127
+ it must never be gated behind pandoc.
128
+ """
129
+ if shutil.which("pandoc"):
130
+ chrome = _chrome_binary()
131
+ if chrome:
132
+ return Engine("chrome", _PANDOC, binary=chrome)
133
+ if shutil.which("weasyprint"):
134
+ return Engine("weasyprint", _PANDOC)
135
+ if shutil.which("wkhtmltopdf"):
136
+ return Engine("wkhtmltopdf", _PANDOC)
137
+ if shutil.which("md-to-pdf"):
138
+ return Engine("md-to-pdf", _DIRECT)
139
+ return None
140
+
141
+
142
+ def install_hint() -> str:
143
+ """A single, OS-appropriate install suggestion — one actionable path, not a
144
+ menu of every engine (the report is already saved; the PDF is the extra)."""
145
+ system = platform.system()
146
+ if system == "Darwin":
147
+ cmd = "brew install pandoc && brew install --cask google-chrome"
148
+ elif system == "Windows":
149
+ cmd = "install pandoc + Google Chrome, or `npm i -g md-to-pdf`"
150
+ else:
151
+ cmd = "apt-get install pandoc chromium (or `pip install weasyprint`)"
152
+ return (
153
+ f"No PDF engine found. Install one, e.g.: {cmd}. "
154
+ "Markdown report saved; PDF skipped."
155
+ )
156
+
157
+
158
+ def default_css_path() -> Path:
159
+ """The bundled print stylesheet shipped with the plugin."""
160
+ return Path(__file__).resolve().parents[2] / "knowledge" / "report-print.css"
161
+
162
+
163
+ def _pandoc_html_cmd(src: Path, html: Path) -> list[str]:
164
+ # --sandbox blocks pandoc from fetching any external resource during
165
+ # conversion, so a report embedding an attacker-influenced remote URL
166
+ # (report content can quote code from a reviewed repo) cannot drive an
167
+ # outbound request at build time (SSRF). The stylesheet is injected in
168
+ # Python afterwards (_inject_css) — sandbox would otherwise block reading
169
+ # even an explicitly-passed --css file.
170
+ return [
171
+ "pandoc",
172
+ str(src),
173
+ "-f",
174
+ "gfm",
175
+ "-t",
176
+ "html5",
177
+ "--standalone",
178
+ "--sandbox",
179
+ "--metadata",
180
+ f"title={src.stem}",
181
+ "-o",
182
+ str(html),
183
+ ]
184
+
185
+
186
+ def _inject_css(html: Path, css: Path | None) -> None:
187
+ """Inline the bundled stylesheet into the pandoc HTML head.
188
+
189
+ Done in Python (not via pandoc ``--css``) because ``--sandbox`` blocks
190
+ pandoc from reading the CSS file. No-op when no stylesheet is available.
191
+ """
192
+ if not (css and css.is_file()):
193
+ return
194
+ try:
195
+ css_text = css.read_text(encoding="utf-8")
196
+ except (OSError, UnicodeDecodeError):
197
+ # An unreadable/malformed stylesheet degrades to unstyled output —
198
+ # never raises, matching the module's graceful-degradation contract.
199
+ return
200
+ style = f"<style>\n{css_text}\n</style>"
201
+ doc = html.read_text(encoding="utf-8")
202
+ if "</head>" in doc:
203
+ doc = doc.replace("</head>", style + "\n</head>", 1)
204
+ else:
205
+ doc = style + "\n" + doc
206
+ html.write_text(doc, encoding="utf-8")
207
+
208
+
209
+ def _engine_pdf_cmd(engine: Engine, html: Path, out: Path) -> list[str]:
210
+ # Absolute output paths so a value beginning with '-' can never be parsed
211
+ # as an option by a positional-arg engine (weasyprint/wkhtmltopdf).
212
+ out_abs = str(out.resolve())
213
+ if engine.name == "chrome":
214
+ return [
215
+ engine.binary or "google-chrome",
216
+ "--headless=new",
217
+ "--disable-gpu",
218
+ # No JavaScript: a Markdown-derived report never needs it, and it
219
+ # closes the headless-Chrome JS-execution vector on report content.
220
+ "--disable-javascript",
221
+ "--no-pdf-header-footer",
222
+ "--run-all-compositor-stages-before-draw",
223
+ "--virtual-time-budget=10000",
224
+ f"--print-to-pdf={out_abs}",
225
+ html.resolve().as_uri(),
226
+ ]
227
+ if engine.name == "weasyprint":
228
+ return ["weasyprint", str(html.resolve()), out_abs]
229
+ if engine.name == "wkhtmltopdf":
230
+ return ["wkhtmltopdf", str(html.resolve()), out_abs]
231
+ raise ValueError(f"not a pandoc-mediated engine: {engine.name}")
232
+
233
+
234
+ def _mdtopdf_cmd(src: Path, css: Path | None) -> list[str]:
235
+ cmd = ["md-to-pdf", str(src)]
236
+ if css and css.is_file():
237
+ cmd += ["--stylesheet", str(css)]
238
+ return cmd
239
+
240
+
241
+ def _run(runner: Callable, cmd: list[str]) -> subprocess.CompletedProcess:
242
+ return runner(cmd, capture_output=True, text=True, timeout=_TIMEOUT_SECONDS)
243
+
244
+
245
+ def _fail(engine_name: str, msg: str) -> RenderResult:
246
+ return RenderResult(rendered=False, engine=engine_name, error=msg)
247
+
248
+
249
+ def _step_error(label: str, proc: subprocess.CompletedProcess) -> str:
250
+ return f"{label} failed: {(proc.stderr or '').strip()}"
251
+
252
+
253
+ def _render_pandoc(
254
+ engine: Engine, src: Path, out: Path, css: Path | None, runner: Callable
255
+ ) -> str | None:
256
+ """pandoc-mediated pipeline (Markdown → HTML+CSS → PDF). Returns an error
257
+ string on failure, or None on success. Always unlinks the temp HTML."""
258
+ with tempfile.NamedTemporaryFile(suffix=".html", delete=False) as handle:
259
+ html = Path(handle.name)
260
+ try:
261
+ step1 = _run(runner, _pandoc_html_cmd(src, html))
262
+ if step1.returncode != 0:
263
+ return _step_error("pandoc", step1)
264
+ _inject_css(html, css)
265
+ step2 = _run(runner, _engine_pdf_cmd(engine, html, out))
266
+ if step2.returncode != 0:
267
+ return _step_error(engine.name, step2)
268
+ return None
269
+ finally:
270
+ html.unlink(missing_ok=True)
271
+
272
+
273
+ def _render_direct(
274
+ engine: Engine, src: Path, out: Path, css: Path | None, runner: Callable
275
+ ) -> str | None:
276
+ """Direct md-to-pdf pipeline (no pandoc). Returns an error string on
277
+ failure, or None on success."""
278
+ produced = src.with_suffix(".pdf")
279
+ step = _run(runner, _mdtopdf_cmd(src, css))
280
+ if step.returncode != 0:
281
+ return _step_error(engine.name, step)
282
+ if produced.resolve() != out.resolve() and produced.is_file():
283
+ shutil.move(str(produced), str(out))
284
+ return None
285
+
286
+
287
+ def render(
288
+ md_path: str,
289
+ out_path: str | None = None,
290
+ *,
291
+ engine: Engine | None = None,
292
+ css_path: str | None = None,
293
+ runner: Callable | None = None,
294
+ ) -> RenderResult:
295
+ """Render ``md_path`` to a PDF, returning a :class:`RenderResult`.
296
+
297
+ ``runner`` is injectable so tests never shell out to a real engine; it
298
+ defaults to the module's current ``subprocess.run`` (resolved at call time,
299
+ so a monkeypatch of it is honored).
300
+ """
301
+ if runner is None:
302
+ runner = subprocess.run
303
+ src = Path(md_path)
304
+ if not src.is_file():
305
+ return RenderResult(rendered=False, error=f"file not found: {md_path}")
306
+
307
+ if engine is None:
308
+ engine = detect_engine()
309
+ if engine is None:
310
+ return RenderResult(
311
+ rendered=False, reason="no PDF engine available", install_hint=install_hint()
312
+ )
313
+
314
+ out = Path(out_path) if out_path else src.with_suffix(".pdf")
315
+ try:
316
+ out.parent.mkdir(parents=True, exist_ok=True)
317
+ except OSError as exc:
318
+ return RenderResult(rendered=False, engine=engine.name, error=str(exc))
319
+
320
+ css = Path(css_path) if css_path else default_css_path()
321
+
322
+ try:
323
+ pipeline = _render_pandoc if engine.kind == _PANDOC else _render_direct
324
+ err = pipeline(engine, src, out, css, runner)
325
+ if err is not None:
326
+ return _fail(engine.name, err)
327
+ except subprocess.TimeoutExpired:
328
+ return _fail(engine.name, f"{engine.name} timed out after {_TIMEOUT_SECONDS}s")
329
+ except OSError as exc:
330
+ return _fail(engine.name, str(exc))
331
+
332
+ if not out.is_file():
333
+ return _fail(engine.name, f"{engine.name} reported success but no PDF was produced")
334
+ return RenderResult(rendered=True, engine=engine.name, out_path=str(out))
335
+
336
+
337
+ def _build_parser() -> argparse.ArgumentParser:
338
+ parser = argparse.ArgumentParser(
339
+ prog="report_pdf.py",
340
+ description="Render a Markdown report to a styled PDF.",
341
+ )
342
+ parser.add_argument("path", help="path to the Markdown report (.md)")
343
+ parser.add_argument(
344
+ "--out", dest="out", default=None, help="output PDF path (default: next to source)"
345
+ )
346
+ return parser
347
+
348
+
349
+ def main(argv: list[str] | None = None) -> int:
350
+ parser = _build_parser()
351
+ args = parser.parse_args(argv)
352
+
353
+ src = Path(args.path)
354
+ engine = detect_engine() if src.is_file() else None
355
+ if engine is not None:
356
+ print(f"Rendering PDF via {engine.name}…")
357
+ result = render(args.path, args.out, engine=engine)
358
+
359
+ if result.rendered:
360
+ print(f"PDF written: {result.out_path} (engine: {result.engine})")
361
+ return 0
362
+ if result.error is not None:
363
+ print(f"PDF not rendered: {result.error}", file=sys.stderr)
364
+ return 1
365
+ # skip (no engine) — non-fatal, the report is safe
366
+ print(result.install_hint or result.reason or "PDF skipped.")
367
+ return 0
368
+
369
+
370
+ if __name__ == "__main__":
371
+ raise SystemExit(main())
@@ -0,0 +1,142 @@
1
+ """hooks/lib/review_agent_registry.py — shared *-review agent glob discovery (#1461).
2
+
3
+ Both `scripts/check_review_agent_mcp_tools.py` (MCP tool-grant auditing) and
4
+ `hooks/agent_dispatch_ledger.py` (the dispatch-ledger PreToolUse hook, #1461)
5
+ need the same closed set of registered review-agent names: every
6
+ `agents/*-review.md` file's stem. This module is the single extraction point
7
+ so a hook never reaches into `scripts/` — the correct dependency direction is
8
+ `scripts/` -> `hooks/lib/`, never the reverse (a hook must be import-safe
9
+ without any `scripts/` module on its path).
10
+
11
+ Stdlib only. See ADR 0014 / ADR 0015.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from pathlib import Path
17
+
18
+ # This plugin's own marketplace-qualified prefix. A real Agent-tool dispatch
19
+ # of one of this plugin's registered review agents, once installed, is named
20
+ # "dev-team:<agent-name>" (e.g. "dev-team:doc-review") — the closed set below
21
+ # is built from bare `agents/*-review.md` file stems, so an unstripped
22
+ # qualified name never matches it (#1461 follow-up: this silently dropped
23
+ # every dispatch's ledger record for the plugin's normal, installed
24
+ # invocation form). A prefix for a DIFFERENT plugin is left untouched — it
25
+ # is never one of this registry's own agents.
26
+ _PLUGIN_PREFIX = "dev-team:"
27
+
28
+
29
+ def strip_plugin_prefix(subagent_type: str) -> str:
30
+ """Normalize a dispatch's `subagent_type` to the bare agent name this
31
+ registry's closed set uses, stripping only this plugin's own
32
+ `dev-team:` qualifier."""
33
+ if subagent_type.startswith(_PLUGIN_PREFIX):
34
+ return subagent_type[len(_PLUGIN_PREFIX) :]
35
+ return subagent_type
36
+
37
+
38
+ def find_review_agent_files(agents_dir: Path) -> list[Path]:
39
+ """Return the read-only review agent files (agents/*-review.md), sorted.
40
+
41
+ Glob-discovery logic extracted verbatim from
42
+ `scripts/check_review_agent_mcp_tools.py::find_review_agents` (#1461) —
43
+ behavior-identical, so existing callers/tests of that function regress
44
+ against this implementation unchanged.
45
+ """
46
+ return sorted(Path(agents_dir).glob("*-review.md"))
47
+
48
+
49
+ def registered_review_agent_names(agents_dir: Path) -> frozenset[str]:
50
+ """Return the closed set of registered review-agent names (file stems).
51
+
52
+ This is the authoritative closed vocabulary `hooks/agent_dispatch_ledger.py`
53
+ checks an Agent-tool dispatch's `subagent_type` against before recording a
54
+ ledger event — a name outside this set is never a real review agent, and
55
+ is never written to the ledger, not even as a rejected/flagged entry.
56
+ """
57
+ return frozenset(path.stem for path in find_review_agent_files(agents_dir))
58
+
59
+
60
+ def default_agents_dir() -> Path:
61
+ """The plugin's own `agents/` directory (#1904 item 3) — the single
62
+ source of truth every review-agent registry consumer resolves against,
63
+ never the caller's own project `cwd`.
64
+
65
+ Always `.resolve()`d: several call sites that once built this path by
66
+ hand (`scripts/check_agent_tool_mapping.py`,
67
+ `scripts/check_review_agent_mcp_tools.py`,
68
+ `skills/code-review/scripts/repo_invariants.py`,
69
+ `scripts/check_agent_scope.py`) previously did so without `.resolve()` —
70
+ a latent behavioral difference under a symlinked checkout — now fixed by
71
+ construction, since each delegates here instead of re-deriving its own
72
+ copy. Not yet exhaustive: `scripts/verify_tier.py` still derives its own
73
+ `_AGENTS_DIR` independently (its `_PLUGIN_ROOT` is already resolved via
74
+ `Path(__file__).resolve()`, so it does not carry the same symlink bug,
75
+ but it remains a duplicate resolution path this module has not yet
76
+ absorbed).
77
+ """
78
+ # hooks/lib/review_agent_registry.py -> hooks/lib -> hooks -> plugin root
79
+ # -> agents
80
+ return Path(__file__).resolve().parents[2] / "agents"
81
+
82
+
83
+ def is_registered_review_lens(subagent_type: str) -> bool:
84
+ """True when `subagent_type` (raw, or plugin-qualified like
85
+ `dev-team:security-review`) names a registered `agents/*-review.md`
86
+ review lens.
87
+
88
+ Encapsulates the repeated three-step check — `strip_plugin_prefix` ->
89
+ read the registered review-agent set via `default_agents_dir()` ->
90
+ membership test — previously hand-rolled independently in
91
+ `hooks/agent_dispatch_ledger.py`, `hooks/lib/boundary_events.py`, and
92
+ `hooks/review_verdict_recorder.py` (backstop review finding, #2166 +
93
+ #2171 — this repo's own `hooks/lib/review_dispatch_ledger.py` module
94
+ docstring already applied the identical consolidation lesson to a
95
+ sibling predicate).
96
+
97
+ An unreadable registry (`read_registered_review_agent_names()` returns
98
+ `None`) collapses to `False`, matching every prior call site's own
99
+ "don't record"/"skip" posture exactly: a lost registry read only
100
+ narrows what counts as a registered review lens, never widens it.
101
+ """
102
+ if not subagent_type:
103
+ return False
104
+ name = strip_plugin_prefix(subagent_type)
105
+ registered = read_registered_review_agent_names(default_agents_dir())
106
+ return bool(registered) and name in registered
107
+
108
+
109
+ def read_registered_review_agent_names(agents_dir: Path) -> frozenset[str] | None:
110
+ """Checked variant of `registered_review_agent_names()` that owns the
111
+ read-failure-vs-empty distinction (#1904 item 1) instead of forcing every
112
+ consumer to reinvent it.
113
+
114
+ Returns `None` on a read failure (a missing or unreadable `agents_dir`);
115
+ a genuine `frozenset()` on a successful read that legitimately finds zero
116
+ `*-review.md` files. The two states require OPPOSITE treatment depending
117
+ on which side of a corroboration check consumes them: for POSITIVE
118
+ evidence (e.g. "which agents dispatched"), a caller may safely collapse
119
+ `None` to an empty set — narrowing corroboration can only ever narrow,
120
+ never widen, what counts as a passing gate. For NEGATIVE evidence (e.g.
121
+ "which agents have an unsuperseded dispatch failure"), collapsing `None`
122
+ to empty would WIDEN the result instead — every genuine negative-evidence
123
+ entry would be filtered out by an empty "registered" set, producing an
124
+ all-clear indistinguishable from "provably none". See
125
+ `hooks/lib/review_gate_corroboration.py`'s own docstring for the full
126
+ account of this asymmetry.
127
+
128
+ Two failure modes are checked EXPLICITLY here, not left to an exception:
129
+ `registered_review_agent_names()` globs `agents_dir.glob("*-review.md")`,
130
+ and `Path.glob()` does not raise for either — it silently yields nothing
131
+ for a missing directory and swallows a permission error. Without the
132
+ explicit `is_dir()` check, a missing/unreadable `agents_dir` would
133
+ produce an empty `frozenset()`, not `None`, defeating the very
134
+ distinction this function's contract promises.
135
+ """
136
+ path = Path(agents_dir)
137
+ if not path.is_dir():
138
+ return None
139
+ try:
140
+ return registered_review_agent_names(path)
141
+ except Exception: # noqa: BLE001 - caller decides how to fail closed for its own evidence direction
142
+ return None