claude-dev-env 2.16.0 → 2.17.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 (535) hide show
  1. package/.agents/agents/AGENTS.md +6 -0
  2. package/.agents/skills/AGENTS.md +34 -35
  3. package/.agents/skills/_shared/pr-loop/AGENTS.md +22 -15
  4. package/.agents/skills/_shared/pr-loop/portable-driver.md +6 -7
  5. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +2 -2
  6. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +1 -1
  7. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +25 -16
  8. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +1 -5
  9. package/.agents/skills/autoconverge/reference/convergence-gates.md +31 -0
  10. package/.agents/skills/autoconverge/reference/convergence.md +8 -10
  11. package/.agents/skills/autoconverge/reference/gotchas.md +1 -1
  12. package/.agents/skills/autoconverge/reference/stop-conditions.md +1 -1
  13. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +1 -1
  14. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +1 -1
  15. package/.agents/skills/autoconverge/workflow/converge.mjs +3 -3
  16. package/.agents/skills/cert-classification-rule/SKILL.md +224 -0
  17. package/.agents/skills/cert-classification-rule/scripts/resort_cert_folders.py +158 -0
  18. package/.agents/skills/eli5/SKILL.md +128 -0
  19. package/.agents/skills/eli5/reference/task-seeds.md +11 -0
  20. package/.agents/skills/fresh-branch/scripts/test_create_fresh_branch.py +2 -3
  21. package/.agents/skills/name-by-capability-audit/SKILL.md +67 -0
  22. package/.agents/skills/name-by-capability-audit/reference/fetch-commands.md +29 -0
  23. package/.agents/skills/name-by-capability-audit/reference/offense-examples.md +32 -0
  24. package/.agents/skills/name-by-capability-audit/reference/report-template.md +29 -0
  25. package/.agents/skills/name-by-capability-audit/reference/rule-checklist.md +38 -0
  26. package/.agents/skills/name-by-capability-audit/reference/task-seeds.md +9 -0
  27. package/.agents/skills/pr-cleanup/SKILL.md +99 -0
  28. package/.agents/skills/prototype/reference/honest-limitations.md +1 -1
  29. package/.agents/skills/prototype/reference/promotion-tasks.md +1 -1
  30. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +2 -2
  31. package/.agents/skills/prototype/workflows/promotion.md +2 -2
  32. package/.agents/skills/review-router/SKILL.md +51 -0
  33. package/.agents/skills/review-router/reference/route-policy.json +7 -0
  34. package/.agents/skills/review-router/reference/task-seeds.md +1 -0
  35. package/.agents/skills/review-router/scripts/conftest.py +4 -0
  36. package/.agents/skills/review-router/scripts/review_router.py +50 -0
  37. package/.agents/skills/review-router/scripts/review_router_cli.py +211 -0
  38. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +1 -0
  39. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  40. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +13 -0
  41. package/.agents/skills/review-router/scripts/test_review_router.py +23 -0
  42. package/.agents/skills/review-router/scripts/test_review_router_cli.py +47 -0
  43. package/.agents/skills/review-tier/SKILL.md +56 -0
  44. package/.agents/skills/review-tier/reference/task-seeds.md +1 -0
  45. package/.agents/skills/review-tier/reference/tier-policy.json +9 -0
  46. package/.agents/skills/review-tier/scripts/conftest.py +4 -0
  47. package/.agents/skills/review-tier/scripts/review_tier.py +332 -0
  48. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +1 -0
  49. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  50. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +29 -0
  51. package/.agents/skills/review-tier/scripts/test_generation.py +171 -0
  52. package/.agents/skills/review-tier/scripts/test_review_tier.py +33 -0
  53. package/.agents/skills/session-log/SKILL.md +1 -1
  54. package/.agents/skills/shared-extraction-audit/SKILL.md +160 -0
  55. package/.agents/skills/shared-extraction-audit/reference/examples.md +46 -0
  56. package/.agents/skills/shared-extraction-audit/reference/offense-taxonomy.md +100 -0
  57. package/.agents/skills/source-command-logifix/SKILL.md +29 -0
  58. package/.agents/skills/source-command-sr-loop/SKILL.md +58 -0
  59. package/.agents/skills-archived/AGENTS.md +45 -0
  60. package/.agents/{skills → skills-archived}/anthropic-plan/AGENTS.md +1 -1
  61. package/.agents/{skills → skills-archived}/bugteam/scripts/reflow_skill_md.py +3 -3
  62. package/.agents/{skills → skills-archived}/codex-review/test_skill_scaffold.py +1 -1
  63. package/.agents/{skills → skills-archived}/copilot-finding-triage/SKILL.md +1 -1
  64. package/.agents/{skills → skills-archived}/pr-converge/SKILL.md +6 -6
  65. package/.agents/{skills → skills-archived}/pr-converge/pr_converge_skill_constants/AGENTS.md +1 -1
  66. package/.agents/{skills → skills-archived}/pr-converge/pr_converge_skill_constants/constants.py +1 -1
  67. package/.agents/{skills → skills-archived}/pr-converge/reference/multi-pr-orchestration.md +1 -1
  68. package/.agents/{skills → skills-archived}/pr-converge/reference/per-tick.md +3 -3
  69. package/.agents/{skills → skills-archived}/pr-converge/scripts/reflow_skill_md.py +2 -2
  70. package/.agents/{skills → skills-archived}/pr-converge/test_portable_pacer_gate.py +6 -2
  71. package/.agents/{skills → skills-archived}/pr-converge/workflows/schedule-wakeup-loop.md +1 -1
  72. package/.agents/{skills → skills-archived}/split-pr/reference/proposal-format.md +1 -1
  73. package/AGENTS.md +34 -58
  74. package/_shared/AGENTS.md +2 -0
  75. package/_shared/advisor/reference/sol-rung.md +2 -2
  76. package/_shared/advisor/reference/third-party-bind.md +1 -1
  77. package/_shared/pr-loop/audit-reply-template.md +4 -0
  78. package/_shared/pr-loop/fix-protocol.md +7 -6
  79. package/_shared/pr-loop/gh-payloads.md +8 -6
  80. package/_shared/pr-loop/precatch-rubric.md +6 -5
  81. package/_shared/pr-loop/scripts/AGENTS.md +15 -0
  82. package/_shared/pr-loop/scripts/_pr_converge_path_setup.py +38 -0
  83. package/_shared/pr-loop/scripts/check_bugbot_ci.py +279 -0
  84. package/_shared/pr-loop/scripts/check_convergence.py +923 -0
  85. package/_shared/pr-loop/scripts/check_convergence_availability.py +275 -0
  86. package/_shared/pr-loop/scripts/check_convergence_gates.py +279 -0
  87. package/_shared/pr-loop/scripts/check_convergence_thread_gates.py +219 -0
  88. package/_shared/pr-loop/scripts/check_pending_reviews.py +154 -0
  89. package/_shared/pr-loop/scripts/codex_down_classifier.py +98 -0
  90. package/_shared/pr-loop/scripts/codex_review_scripts_constants/.claude/CLAUDE.md +1 -0
  91. package/_shared/pr-loop/scripts/codex_review_scripts_constants/AGENTS.md +18 -0
  92. package/_shared/pr-loop/scripts/codex_review_scripts_constants/__init__.py +1 -0
  93. package/_shared/pr-loop/scripts/codex_review_scripts_constants/classifier_constants.py +35 -0
  94. package/_shared/pr-loop/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py +82 -0
  95. package/_shared/pr-loop/scripts/codex_review_scripts_constants/findings_constants.py +18 -0
  96. package/_shared/pr-loop/scripts/codex_review_scripts_constants/run_constants.py +53 -0
  97. package/_shared/pr-loop/scripts/codex_usage_probe.py +570 -0
  98. package/_shared/pr-loop/scripts/conftest.py +43 -0
  99. package/_shared/pr-loop/scripts/fetch_copilot_reviews.py +134 -0
  100. package/_shared/pr-loop/scripts/fixtures/auth_failure_synthetic.txt +1 -0
  101. package/_shared/pr-loop/scripts/fixtures/config_load_failure_v0.125.0.txt +1 -0
  102. package/_shared/pr-loop/scripts/fixtures/freeform_findings_v0.144.3.txt +6 -0
  103. package/_shared/pr-loop/scripts/fixtures/model_rejection_v0.125.0.jsonl +5 -0
  104. package/_shared/pr-loop/scripts/fixtures/structured_findings.txt +13 -0
  105. package/_shared/pr-loop/scripts/fixtures/success_stream_v0.144.3.jsonl +6 -0
  106. package/_shared/pr-loop/scripts/fixtures/unknown_failure_synthetic.txt +1 -0
  107. package/_shared/pr-loop/scripts/fixtures/usage_limit_synthetic.txt +1 -0
  108. package/_shared/pr-loop/scripts/parse_codex_findings.py +207 -0
  109. package/_shared/pr-loop/scripts/post_fix_reply.py +168 -0
  110. package/_shared/pr-loop/scripts/pr_converge_scripts_constants/.claude/CLAUDE.md +1 -0
  111. package/_shared/pr-loop/scripts/pr_converge_scripts_constants/AGENTS.md +18 -0
  112. package/_shared/pr-loop/scripts/pr_converge_scripts_constants/__init__.py +0 -0
  113. package/_shared/pr-loop/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +70 -0
  114. package/_shared/pr-loop/scripts/pr_converge_scripts_constants/pr_converge_constants.py +118 -0
  115. package/_shared/pr-loop/scripts/pr_converge_scripts_constants/reflow_skill_md_constants.py +13 -0
  116. package/_shared/pr-loop/scripts/pr_converge_skill_constants/.claude/CLAUDE.md +1 -0
  117. package/_shared/pr-loop/scripts/pr_converge_skill_constants/AGENTS.md +26 -0
  118. package/_shared/pr-loop/scripts/pr_converge_skill_constants/__init__.py +0 -0
  119. package/_shared/pr-loop/scripts/pr_converge_skill_constants/constants.py +69 -0
  120. package/_shared/pr-loop/scripts/run_codex_review.py +609 -0
  121. package/_shared/pr-loop/scripts/test__pr_converge_path_setup.py +30 -0
  122. package/_shared/pr-loop/scripts/test_check_bugbot_ci.py +312 -0
  123. package/_shared/pr-loop/scripts/test_check_convergence.py +438 -0
  124. package/_shared/pr-loop/scripts/test_check_convergence_availability.py +391 -0
  125. package/_shared/pr-loop/scripts/test_check_convergence_codex.py +517 -0
  126. package/_shared/pr-loop/scripts/test_check_convergence_contract.py +400 -0
  127. package/_shared/pr-loop/scripts/test_check_convergence_fixture.py +179 -0
  128. package/_shared/pr-loop/scripts/test_check_convergence_gates.py +84 -0
  129. package/_shared/pr-loop/scripts/test_check_convergence_thread_gates.py +99 -0
  130. package/_shared/pr-loop/scripts/test_codex_down_classifier.py +143 -0
  131. package/_shared/pr-loop/scripts/test_codex_usage_probe.py +683 -0
  132. package/_shared/pr-loop/scripts/test_parse_codex_findings.py +130 -0
  133. package/_shared/pr-loop/scripts/test_run_codex_review.py +969 -0
  134. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +1 -1
  135. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +1 -1
  136. package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +1 -1
  137. package/_shared/pr-loop/state-schema.md +20 -28
  138. package/_shared/process-tree/AGENTS.md +3 -3
  139. package/bin/ever-shipped-skills.mjs +29 -1
  140. package/bin/install-constants.mjs +15 -6
  141. package/bin/install.agents-home.test.mjs +13 -0
  142. package/bin/install.cursor-rules.test.mjs +3 -3
  143. package/bin/install.mjs +80 -20
  144. package/bin/install.profile-root.test.mjs +1 -1
  145. package/bin/install.prune.test.mjs +23 -204
  146. package/bin/install.test.mjs +8 -5
  147. package/bin/resolve-install-root.mjs +21 -0
  148. package/bin/resolve-package-managed-directory.mjs +4 -4
  149. package/commands/AGENTS.md +2 -0
  150. package/commands/sr-loop.md +3 -0
  151. package/docs/references/prose-style-enforcement.md +3 -7
  152. package/hooks/AGENTS.md +0 -3
  153. package/hooks/blocking/AGENTS.md +0 -2
  154. package/hooks/blocking/ask_user_question_shape_blocker.py +83 -0
  155. package/hooks/blocking/pre_tool_use_dispatcher.py +2 -19
  156. package/hooks/blocking/state_description_blocker.py +1 -1
  157. package/hooks/blocking/test_ask_user_question_shape.py +69 -0
  158. package/hooks/blocking/test_pre_tool_use_dispatcher.py +17 -58
  159. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +9 -104
  160. package/hooks/blocking/test_state_description_blocker.py +1 -0
  161. package/hooks/blocking/test_stop_dispatcher.py +1 -26
  162. package/hooks/hooks.json +1 -1
  163. package/hooks/hooks_constants/AGENTS.md +0 -3
  164. package/hooks/hooks_constants/ask_user_question_shape.py +1 -1
  165. package/hooks/hooks_constants/ask_user_question_shape_constants.py +73 -0
  166. package/hooks/hooks_constants/bot_mention_comment_blocker_constants.py +1 -2
  167. package/hooks/hooks_constants/code_rules_path_utils_constants.py +0 -1
  168. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +0 -7
  169. package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -1
  170. package/hooks/hooks_constants/test_ask_user_question_shape.py +1 -1
  171. package/hooks/hooks_constants/test_prose_metrics_parity.py +29 -107
  172. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -1
  173. package/hooks/hooks_constants/working_style_prompt_constants.py +9 -10
  174. package/hooks/session/AGENTS.md +4 -1
  175. package/hooks/session/test_working_style_prompt.py +8 -4
  176. package/hooks/session/working_style_prompt.py +4 -2
  177. package/package.json +1 -4
  178. package/rules/AGENTS.md +2 -5
  179. package/rules/asd-ste100-language.md +39 -0
  180. package/rules/ask-user-question-required.md +1 -1
  181. package/rules/long-horizon-autonomy.md +1 -1
  182. package/scripts/AGENTS.md +1 -0
  183. package/scripts/Show-Asset.ps1 +106 -0
  184. package/scripts/test_validate_instruction_pairs.py +30 -3
  185. package/scripts/tests/test_engine.py +4 -4
  186. package/scripts/tests/test_rules.py +5 -5
  187. package/system-prompts/AGENTS.md +8 -0
  188. package/system-prompts/software-engineer.xml +8 -3
  189. package/.agents/skills/grokify/evals/README.md +0 -72
  190. package/.agents/skills/grokify/evals/parse-payload.test.mjs +0 -171
  191. package/.agents/skills/grokify/evals/run-capability-evals.mjs +0 -545
  192. package/_shared/pr-loop/scripts/README.md +0 -21
  193. package/docs/imagegen.md +0 -22
  194. package/hooks/blocking/eli11_reply_enforcer.py +0 -436
  195. package/hooks/blocking/plain_language_blocker.py +0 -758
  196. package/hooks/blocking/test_eli11_reply_enforcer.py +0 -390
  197. package/hooks/blocking/test_plain_language_blocker.py +0 -683
  198. package/hooks/blocking/test_plain_language_blocker_allowlist.py +0 -228
  199. package/hooks/diagnostic/AGENTS.md +0 -75
  200. package/hooks/diagnostic/CLAUDE.md +0 -1
  201. package/hooks/diagnostic/hook_log_extractor.py +0 -875
  202. package/hooks/diagnostic/hook_log_init.py +0 -202
  203. package/hooks/diagnostic/hook_log_stop_wrapper.py +0 -26
  204. package/hooks/diagnostic/migrations/2026-04-25-drop-themes-hook-events.sql +0 -3
  205. package/hooks/diagnostic/migrations/AGENTS.md +0 -16
  206. package/hooks/diagnostic/migrations/CLAUDE.md +0 -1
  207. package/hooks/diagnostic/migrations/README.md +0 -76
  208. package/hooks/diagnostic/queries/AGENTS.md +0 -19
  209. package/hooks/diagnostic/queries/CLAUDE.md +0 -1
  210. package/hooks/diagnostic/queries/block_details_for_hook.sql +0 -26
  211. package/hooks/diagnostic/queries/blocks_by_category.sql +0 -10
  212. package/hooks/diagnostic/queries/blocks_by_tool.sql +0 -9
  213. package/hooks/diagnostic/queries/blocks_last_7_days.sql +0 -11
  214. package/hooks/diagnostic/queries/top_blockers_last_24_hours.sql +0 -12
  215. package/hooks/diagnostic/queries/top_blockers_overall.sql +0 -12
  216. package/hooks/diagnostic/requirements-hook-logs-dev.txt +0 -2
  217. package/hooks/diagnostic/requirements-hook-logs.txt +0 -1
  218. package/hooks/diagnostic/schema.sql +0 -51
  219. package/hooks/diagnostic/test_hook_log_extractor.py +0 -1518
  220. package/hooks/diagnostic/test_hook_log_init.py +0 -227
  221. package/hooks/diagnostic/test_hook_log_stop_wrapper.py +0 -17
  222. package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +0 -94
  223. package/hooks/hooks_constants/hook_log_extractor_constants.py +0 -233
  224. package/hooks/hooks_constants/plain_language_blocker_constants.py +0 -366
  225. package/hooks/hooks_constants/test_hook_log_extractor_constants.py +0 -123
  226. package/rules/doc-prose-cuts.md +0 -58
  227. package/rules/eli11-replies.md +0 -36
  228. package/rules/opus5-communication-contract.md +0 -45
  229. package/rules/plain-language.md +0 -9
  230. /package/.agents/{skills → skills-archived}/anthropic-plan/.claude/CLAUDE.md +0 -0
  231. /package/.agents/{skills → skills-archived}/anthropic-plan/SKILL.md +0 -0
  232. /package/.agents/{skills → skills-archived}/anthropic-plan/scripts/.claude/CLAUDE.md +0 -0
  233. /package/.agents/{skills → skills-archived}/anthropic-plan/scripts/AGENTS.md +0 -0
  234. /package/.agents/{skills → skills-archived}/anthropic-plan/scripts/anthropic_plan_scripts_constants/.claude/CLAUDE.md +0 -0
  235. /package/.agents/{skills → skills-archived}/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +0 -0
  236. /package/.agents/{skills → skills-archived}/anthropic-plan/scripts/anthropic_plan_scripts_constants/__init__.py +0 -0
  237. /package/.agents/{skills → skills-archived}/anthropic-plan/scripts/anthropic_plan_scripts_constants/validate_packet_constants.py +0 -0
  238. /package/.agents/{skills → skills-archived}/anthropic-plan/scripts/test_validate_packet.py +0 -0
  239. /package/.agents/{skills → skills-archived}/anthropic-plan/scripts/validate_packet.py +0 -0
  240. /package/.agents/{skills → skills-archived}/anthropic-plan/templates/.claude/CLAUDE.md +0 -0
  241. /package/.agents/{skills → skills-archived}/anthropic-plan/templates/AGENTS.md +0 -0
  242. /package/.agents/{skills → skills-archived}/anthropic-plan/templates/README.md +0 -0
  243. /package/.agents/{skills → skills-archived}/anthropic-plan/templates/build-prompt.md +0 -0
  244. /package/.agents/{skills → skills-archived}/anthropic-plan/templates/reuse-audit.md +0 -0
  245. /package/.agents/{skills → skills-archived}/anthropic-plan/templates/source-map.md +0 -0
  246. /package/.agents/{skills → skills-archived}/anthropic-plan/templates/visual-plan.template.html +0 -0
  247. /package/.agents/{skills → skills-archived}/anthropic-plan/test_skill_contract.py +0 -0
  248. /package/.agents/{skills → skills-archived}/anthropic-plan/workflow/.claude/CLAUDE.md +0 -0
  249. /package/.agents/{skills → skills-archived}/anthropic-plan/workflow/AGENTS.md +0 -0
  250. /package/.agents/{skills → skills-archived}/anthropic-plan/workflow/plan-packet.contract.test.mjs +0 -0
  251. /package/.agents/{skills → skills-archived}/anthropic-plan/workflow/plan-packet.mjs +0 -0
  252. /package/.agents/{skills → skills-archived}/auditing-claude-config/.claude/CLAUDE.md +0 -0
  253. /package/.agents/{skills → skills-archived}/auditing-claude-config/AGENTS.md +0 -0
  254. /package/.agents/{skills → skills-archived}/auditing-claude-config/SKILL.md +0 -0
  255. /package/.agents/{skills → skills-archived}/auditing-claude-config/reference/probe-hook.md +0 -0
  256. /package/.agents/{skills → skills-archived}/beat-sheet/SKILL.md +0 -0
  257. /package/.agents/{skills → skills-archived}/beat-sheet/reference/visual-beats.md +0 -0
  258. /package/.agents/{skills → skills-archived}/bugteam/.claude/CLAUDE.md +0 -0
  259. /package/.agents/{skills → skills-archived}/bugteam/AGENTS.md +0 -0
  260. /package/.agents/{skills → skills-archived}/bugteam/CONSTRAINTS.md +0 -0
  261. /package/.agents/{skills → skills-archived}/bugteam/EXAMPLES.md +0 -0
  262. /package/.agents/{skills → skills-archived}/bugteam/PROMPTS.md +0 -0
  263. /package/.agents/{skills → skills-archived}/bugteam/SKILL.md +0 -0
  264. /package/.agents/{skills → skills-archived}/bugteam/reference/.claude/CLAUDE.md +0 -0
  265. /package/.agents/{skills → skills-archived}/bugteam/reference/AGENTS.md +0 -0
  266. /package/.agents/{skills → skills-archived}/bugteam/reference/README.md +0 -0
  267. /package/.agents/{skills → skills-archived}/bugteam/reference/audit-and-teammates.md +0 -0
  268. /package/.agents/{skills → skills-archived}/bugteam/reference/copilot-gap-analysis.md +0 -0
  269. /package/.agents/{skills → skills-archived}/bugteam/reference/design-rationale.md +0 -0
  270. /package/.agents/{skills → skills-archived}/bugteam/reference/github-pr-reviews.md +0 -0
  271. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/.claude/CLAUDE.md +0 -0
  272. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/AGENTS.md +0 -0
  273. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/audit-assign-ids.md +0 -0
  274. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/audit-capture-excerpts.md +0 -0
  275. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/audit-walk-categories.md +0 -0
  276. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/audit-write-xml.md +0 -0
  277. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-append-summary.md +0 -0
  278. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-apply-fixes.md +0 -0
  279. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-git-add-commit.md +0 -0
  280. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-git-push.md +0 -0
  281. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-post-reply.md +0 -0
  282. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-publish-summary.md +0 -0
  283. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-py-compile.md +0 -0
  284. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-read-files.md +0 -0
  285. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-resolve-thread.md +0 -0
  286. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-test-suite.md +0 -0
  287. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-violation-count.md +0 -0
  288. /package/.agents/{skills → skills-archived}/bugteam/reference/obstacles/fix-write-xml.md +0 -0
  289. /package/.agents/{skills → skills-archived}/bugteam/reference/team-setup.md +0 -0
  290. /package/.agents/{skills → skills-archived}/bugteam/scripts/.claude/CLAUDE.md +0 -0
  291. /package/.agents/{skills → skills-archived}/bugteam/scripts/AGENTS.md +0 -0
  292. /package/.agents/{skills → skills-archived}/bugteam/scripts/README.md +0 -0
  293. /package/.agents/{skills → skills-archived}/bugteam/scripts/bugteam_code_rules_gate.py +0 -0
  294. /package/.agents/{skills → skills-archived}/bugteam/scripts/bugteam_fix_hookspath.py +0 -0
  295. /package/.agents/{skills → skills-archived}/bugteam/scripts/bugteam_preflight.py +0 -0
  296. /package/.agents/{skills → skills-archived}/bugteam/scripts/bugteam_scripts_constants/.claude/CLAUDE.md +0 -0
  297. /package/.agents/{skills → skills-archived}/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +0 -0
  298. /package/.agents/{skills → skills-archived}/bugteam/scripts/bugteam_scripts_constants/__init__.py +0 -0
  299. /package/.agents/{skills → skills-archived}/bugteam/scripts/bugteam_scripts_constants/probe_code_rules_enforcer_check_constants.py +0 -0
  300. /package/.agents/{skills → skills-archived}/bugteam/scripts/bugteam_scripts_constants/reflow_skill_md_constants.py +0 -0
  301. /package/.agents/{skills → skills-archived}/bugteam/scripts/bugteam_scripts_constants/windows_safe_rmtree_constants.py +0 -0
  302. /package/.agents/{skills → skills-archived}/bugteam/scripts/probe_code_rules_enforcer_check.py +0 -0
  303. /package/.agents/{skills → skills-archived}/bugteam/scripts/test_bugteam_code_rules_gate.py +0 -0
  304. /package/.agents/{skills → skills-archived}/bugteam/scripts/test_bugteam_fix_hookspath.py +0 -0
  305. /package/.agents/{skills → skills-archived}/bugteam/scripts/test_bugteam_preflight.py +0 -0
  306. /package/.agents/{skills → skills-archived}/bugteam/scripts/test_probe_code_rules_enforcer_check.py +0 -0
  307. /package/.agents/{skills → skills-archived}/bugteam/scripts/test_windows_safe_rmtree.py +0 -0
  308. /package/.agents/{skills → skills-archived}/bugteam/scripts/windows_safe_rmtree.py +0 -0
  309. /package/.agents/{skills → skills-archived}/bugteam/sources.md +0 -0
  310. /package/.agents/{skills → skills-archived}/bugteam/test_skill_additions.py +0 -0
  311. /package/.agents/{skills → skills-archived}/closeout/SKILL.md +0 -0
  312. /package/.agents/{skills → skills-archived}/closeout/reference/handoff-prompt-template.md +0 -0
  313. /package/.agents/{skills → skills-archived}/closeout/reference/pii-redaction-checklist.md +0 -0
  314. /package/.agents/{skills → skills-archived}/codex-review/.claude/CLAUDE.md +0 -0
  315. /package/.agents/{skills → skills-archived}/codex-review/AGENTS.md +0 -0
  316. /package/.agents/{skills → skills-archived}/codex-review/SKILL.md +0 -0
  317. /package/.agents/{skills → skills-archived}/codex-review/reference/.claude/CLAUDE.md +0 -0
  318. /package/.agents/{skills → skills-archived}/codex-review/reference/AGENTS.md +0 -0
  319. /package/.agents/{skills → skills-archived}/codex-review/reference/cli-contract.md +0 -0
  320. /package/.agents/{skills → skills-archived}/codex-review/reference/loop-integration.md +0 -0
  321. /package/.agents/{skills → skills-archived}/codex-review/scripts/codex_down_classifier.py +0 -0
  322. /package/.agents/{skills → skills-archived}/codex-review/scripts/codex_review_scripts_constants/.claude/CLAUDE.md +0 -0
  323. /package/.agents/{skills → skills-archived}/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +0 -0
  324. /package/.agents/{skills → skills-archived}/codex-review/scripts/codex_review_scripts_constants/__init__.py +0 -0
  325. /package/.agents/{skills → skills-archived}/codex-review/scripts/codex_review_scripts_constants/classifier_constants.py +0 -0
  326. /package/.agents/{skills → skills-archived}/codex-review/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py +0 -0
  327. /package/.agents/{skills → skills-archived}/codex-review/scripts/codex_review_scripts_constants/findings_constants.py +0 -0
  328. /package/.agents/{skills → skills-archived}/codex-review/scripts/codex_review_scripts_constants/run_constants.py +0 -0
  329. /package/.agents/{skills → skills-archived}/codex-review/scripts/codex_usage_probe.py +0 -0
  330. /package/.agents/{skills → skills-archived}/codex-review/scripts/fixtures/auth_failure_synthetic.txt +0 -0
  331. /package/.agents/{skills → skills-archived}/codex-review/scripts/fixtures/config_load_failure_v0.125.0.txt +0 -0
  332. /package/.agents/{skills → skills-archived}/codex-review/scripts/fixtures/freeform_findings_v0.144.3.txt +0 -0
  333. /package/.agents/{skills → skills-archived}/codex-review/scripts/fixtures/model_rejection_v0.125.0.jsonl +0 -0
  334. /package/.agents/{skills → skills-archived}/codex-review/scripts/fixtures/structured_findings.txt +0 -0
  335. /package/.agents/{skills → skills-archived}/codex-review/scripts/fixtures/success_stream_v0.144.3.jsonl +0 -0
  336. /package/.agents/{skills → skills-archived}/codex-review/scripts/fixtures/unknown_failure_synthetic.txt +0 -0
  337. /package/.agents/{skills → skills-archived}/codex-review/scripts/fixtures/usage_limit_synthetic.txt +0 -0
  338. /package/.agents/{skills → skills-archived}/codex-review/scripts/parse_codex_findings.py +0 -0
  339. /package/.agents/{skills → skills-archived}/codex-review/scripts/run_codex_review.py +0 -0
  340. /package/.agents/{skills → skills-archived}/codex-review/scripts/test_codex_down_classifier.py +0 -0
  341. /package/.agents/{skills → skills-archived}/codex-review/scripts/test_codex_usage_probe.py +0 -0
  342. /package/.agents/{skills → skills-archived}/codex-review/scripts/test_parse_codex_findings.py +0 -0
  343. /package/.agents/{skills → skills-archived}/codex-review/scripts/test_run_codex_review.py +0 -0
  344. /package/.agents/{skills → skills-archived}/comments/SKILL.md +0 -0
  345. /package/.agents/{skills → skills-archived}/condensing-instructions/SKILL.md +0 -0
  346. /package/.agents/{skills → skills-archived}/copilot-finding-triage/reference/tier-rubric.md +0 -0
  347. /package/.agents/{skills → skills-archived}/copilot-finding-triage/scripts/conftest.py +0 -0
  348. /package/.agents/{skills → skills-archived}/copilot-finding-triage/scripts/copilot_finding_triage_constants/__init__.py +0 -0
  349. /package/.agents/{skills → skills-archived}/copilot-finding-triage/scripts/copilot_finding_triage_constants/config/__init__.py +0 -0
  350. /package/.agents/{skills → skills-archived}/copilot-finding-triage/scripts/copilot_finding_triage_constants/config/notify_ntfy_constants.py +0 -0
  351. /package/.agents/{skills → skills-archived}/copilot-finding-triage/scripts/notify_ntfy.py +0 -0
  352. /package/.agents/{skills → skills-archived}/copilot-finding-triage/scripts/test_notify_ntfy.py +0 -0
  353. /package/.agents/{skills → skills-archived}/copilot-finding-triage/templates/notification.md +0 -0
  354. /package/.agents/{skills → skills-archived}/copilot-review/.claude/CLAUDE.md +0 -0
  355. /package/.agents/{skills → skills-archived}/copilot-review/AGENTS.md +0 -0
  356. /package/.agents/{skills → skills-archived}/copilot-review/SKILL.md +0 -0
  357. /package/.agents/{skills → skills-archived}/copilot-review/templates/subagent-prompt.md +0 -0
  358. /package/.agents/{skills → skills-archived}/descriptions/SKILL.md +0 -0
  359. /package/.agents/{skills → skills-archived}/emergencies/SKILL.md +0 -0
  360. /package/.agents/{skills → skills-archived}/grokify/SKILL.md +0 -0
  361. /package/.agents/{skills → skills-archived}/grokify/capability-claims.test.mjs +0 -0
  362. /package/.agents/{skills → skills-archived}/grokify/templates/handoff-template.md +0 -0
  363. /package/.agents/{skills → skills-archived}/plan-to-pr/SKILL.md +0 -0
  364. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/final-validation-tasks.md +0 -0
  365. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/model-routing.md +0 -0
  366. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/packet-contract.md +0 -0
  367. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/packet-schema.json +0 -0
  368. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/process-inventory.md +0 -0
  369. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/review-loop.md +0 -0
  370. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/run-record.schema.json +0 -0
  371. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/self-audit-tasks.md +0 -0
  372. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/task-seeds.md +0 -0
  373. /package/.agents/{skills → skills-archived}/plan-to-pr/reference/task-ticket.md +0 -0
  374. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/config/__init__.py +0 -0
  375. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/config/constants.py +0 -0
  376. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/create_packet.py +0 -0
  377. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/load_skill_constants.py +0 -0
  378. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/test_create_packet.py +0 -0
  379. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/test_validate_packet.py +0 -0
  380. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/test_validate_protocol.py +0 -0
  381. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/test_validate_run.py +0 -0
  382. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/validate_packet.py +0 -0
  383. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/validate_protocol.py +0 -0
  384. /package/.agents/{skills → skills-archived}/plan-to-pr/scripts/validate_run.py +0 -0
  385. /package/.agents/{skills → skills-archived}/plan-to-pr/test_skill_contract.py +0 -0
  386. /package/.agents/{skills → skills-archived}/plan-to-pr/test_task_ticket_contract.py +0 -0
  387. /package/.agents/{skills → skills-archived}/pr-converge/.claude/CLAUDE.md +0 -0
  388. /package/.agents/{skills → skills-archived}/pr-converge/AGENTS.md +0 -0
  389. /package/.agents/{skills → skills-archived}/pr-converge/pr_converge_skill_constants/.claude/CLAUDE.md +0 -0
  390. /package/.agents/{skills → skills-archived}/pr-converge/pr_converge_skill_constants/__init__.py +0 -0
  391. /package/.agents/{skills → skills-archived}/pr-converge/reference/.claude/CLAUDE.md +0 -0
  392. /package/.agents/{skills → skills-archived}/pr-converge/reference/AGENTS.md +0 -0
  393. /package/.agents/{skills → skills-archived}/pr-converge/reference/convergence-gates.md +0 -0
  394. /package/.agents/{skills → skills-archived}/pr-converge/reference/examples.md +0 -0
  395. /package/.agents/{skills → skills-archived}/pr-converge/reference/fix-protocol.md +0 -0
  396. /package/.agents/{skills → skills-archived}/pr-converge/reference/ground-rules.md +0 -0
  397. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/.claude/CLAUDE.md +0 -0
  398. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/AGENTS.md +0 -0
  399. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-post-replies.md +0 -0
  400. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-publish-summary.md +0 -0
  401. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-push.md +0 -0
  402. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-read-filelines.md +0 -0
  403. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-reset-state.md +0 -0
  404. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-resolve-threads.md +0 -0
  405. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-spawn-clean-coder.md +0 -0
  406. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-stage-commit.md +0 -0
  407. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-trigger-bugbot.md +0 -0
  408. /package/.agents/{skills → skills-archived}/pr-converge/reference/obstacles/fix-write-test.md +0 -0
  409. /package/.agents/{skills → skills-archived}/pr-converge/reference/progress-checklist.md +0 -0
  410. /package/.agents/{skills → skills-archived}/pr-converge/reference/state-schema.md +0 -0
  411. /package/.agents/{skills → skills-archived}/pr-converge/reference/stop-conditions.md +0 -0
  412. /package/.agents/{skills → skills-archived}/pr-converge/scripts/.claude/CLAUDE.md +0 -0
  413. /package/.agents/{skills → skills-archived}/pr-converge/scripts/AGENTS.md +0 -0
  414. /package/.agents/{skills → skills-archived}/pr-converge/scripts/README.md +0 -0
  415. /package/.agents/{skills → skills-archived}/pr-converge/scripts/_pr_converge_path_setup.py +0 -0
  416. /package/.agents/{skills → skills-archived}/pr-converge/scripts/caller-window-pid.ps1 +0 -0
  417. /package/.agents/{skills → skills-archived}/pr-converge/scripts/check_bugbot_ci.py +0 -0
  418. /package/.agents/{skills → skills-archived}/pr-converge/scripts/check_convergence.py +0 -0
  419. /package/.agents/{skills → skills-archived}/pr-converge/scripts/check_convergence_availability.py +0 -0
  420. /package/.agents/{skills → skills-archived}/pr-converge/scripts/check_convergence_gates.py +0 -0
  421. /package/.agents/{skills → skills-archived}/pr-converge/scripts/check_convergence_thread_gates.py +0 -0
  422. /package/.agents/{skills → skills-archived}/pr-converge/scripts/check_pending_reviews.py +0 -0
  423. /package/.agents/{skills → skills-archived}/pr-converge/scripts/conftest.py +0 -0
  424. /package/.agents/{skills → skills-archived}/pr-converge/scripts/cursor-agents-continue-caller.cmd +0 -0
  425. /package/.agents/{skills → skills-archived}/pr-converge/scripts/cursor-agents-continue-stop-others.ps1 +0 -0
  426. /package/.agents/{skills → skills-archived}/pr-converge/scripts/cursor-agents-continue.ahk +0 -0
  427. /package/.agents/{skills → skills-archived}/pr-converge/scripts/cursor-agents-continue.cmd +0 -0
  428. /package/.agents/{skills → skills-archived}/pr-converge/scripts/fetch_copilot_reviews.py +0 -0
  429. /package/.agents/{skills → skills-archived}/pr-converge/scripts/post_fix_reply.py +0 -0
  430. /package/.agents/{skills → skills-archived}/pr-converge/scripts/pr_converge_scripts_constants/.claude/CLAUDE.md +0 -0
  431. /package/.agents/{skills → skills-archived}/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +0 -0
  432. /package/.agents/{skills → skills-archived}/pr-converge/scripts/pr_converge_scripts_constants/__init__.py +0 -0
  433. /package/.agents/{skills → skills-archived}/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +0 -0
  434. /package/.agents/{skills → skills-archived}/pr-converge/scripts/pr_converge_scripts_constants/pr_converge_constants.py +0 -0
  435. /package/.agents/{skills → skills-archived}/pr-converge/scripts/pr_converge_scripts_constants/reflow_skill_md_constants.py +0 -0
  436. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test__pr_converge_path_setup.py +0 -0
  437. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_check_bugbot_ci.py +0 -0
  438. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_check_convergence.py +0 -0
  439. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_check_convergence_availability.py +0 -0
  440. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_check_convergence_codex.py +0 -0
  441. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_check_convergence_contract.py +0 -0
  442. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_check_convergence_fixture.py +0 -0
  443. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_check_convergence_gates.py +0 -0
  444. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_check_convergence_thread_gates.py +0 -0
  445. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_cursor_agents_continue.py +0 -0
  446. /package/.agents/{skills → skills-archived}/pr-converge/scripts/test_reflow_skill_md.py +0 -0
  447. /package/.agents/{skills → skills-archived}/pr-converge/test_step5_host_branch.py +0 -0
  448. /package/.agents/{skills → skills-archived}/pr-converge/workflows/.claude/CLAUDE.md +0 -0
  449. /package/.agents/{skills → skills-archived}/pr-converge/workflows/AGENTS.md +0 -0
  450. /package/.agents/{skills → skills-archived}/pr-fix-protocol/SKILL.md +0 -0
  451. /package/.agents/{skills → skills-archived}/pr-loop-cloud-transport/SKILL.md +0 -0
  452. /package/.agents/{skills → skills-archived}/pr-loop-cloud-transport/reference/identity-and-hooks.md +0 -0
  453. /package/.agents/{skills → skills-archived}/pr-loop-cloud-transport/reference/substitution-matrix.md +0 -0
  454. /package/.agents/{skills → skills-archived}/pr-loop-lifecycle/SKILL.md +0 -0
  455. /package/.agents/{skills → skills-archived}/pr-loop-lifecycle/reference/teardown-publish-permissions.md +0 -0
  456. /package/.agents/{skills → skills-archived}/recall/.claude/CLAUDE.md +0 -0
  457. /package/.agents/{skills → skills-archived}/recall/AGENTS.md +0 -0
  458. /package/.agents/{skills → skills-archived}/recall/SKILL.md +0 -0
  459. /package/.agents/{skills → skills-archived}/release-notes-html/SKILL.md +0 -0
  460. /package/.agents/{skills → skills-archived}/remember/.claude/CLAUDE.md +0 -0
  461. /package/.agents/{skills → skills-archived}/remember/AGENTS.md +0 -0
  462. /package/.agents/{skills → skills-archived}/remember/SKILL.md +0 -0
  463. /package/.agents/{skills → skills-archived}/reviewer-gates/SKILL.md +0 -0
  464. /package/.agents/{skills → skills-archived}/reviews/SKILL.md +0 -0
  465. /package/.agents/{skills → skills-archived}/show/SKILL.md +0 -0
  466. /package/.agents/{skills → skills-archived}/show/references/accessibility.md +0 -0
  467. /package/.agents/{skills → skills-archived}/show/references/art.md +0 -0
  468. /package/.agents/{skills → skills-archived}/show/references/charts.md +0 -0
  469. /package/.agents/{skills → skills-archived}/show/references/core-design.md +0 -0
  470. /package/.agents/{skills → skills-archived}/show/references/erds.md +0 -0
  471. /package/.agents/{skills → skills-archived}/show/references/flowcharts.md +0 -0
  472. /package/.agents/{skills → skills-archived}/show/references/host-and-html.md +0 -0
  473. /package/.agents/{skills → skills-archived}/show/references/illustrative-diagrams.md +0 -0
  474. /package/.agents/{skills → skills-archived}/show/references/interaction.md +0 -0
  475. /package/.agents/{skills → skills-archived}/show/references/mockups.md +0 -0
  476. /package/.agents/{skills → skills-archived}/show/references/quality-gates.md +0 -0
  477. /package/.agents/{skills → skills-archived}/show/references/structural-diagrams.md +0 -0
  478. /package/.agents/{skills → skills-archived}/show/references/subject-inventory.md +0 -0
  479. /package/.agents/{skills → skills-archived}/show/references/svg-contract.md +0 -0
  480. /package/.agents/{skills → skills-archived}/show/routing.yaml +0 -0
  481. /package/.agents/{skills → skills-archived}/show/samples/pr1262-v2.svg +0 -0
  482. /package/.agents/{skills → skills-archived}/show/scripts/README.md +0 -0
  483. /package/.agents/{skills → skills-archived}/show/scripts/validate-artifact.py +0 -0
  484. /package/.agents/{skills → skills-archived}/show/scripts/validate-package.py +0 -0
  485. /package/.agents/{skills → skills-archived}/show/templates/html-widget.html +0 -0
  486. /package/.agents/{skills → skills-archived}/show/templates/svg-base.svg +0 -0
  487. /package/.agents/{skills → skills-archived}/show/tests/fixtures/css-var.svg +0 -0
  488. /package/.agents/{skills → skills-archived}/show/tests/fixtures/dead-ref.svg +0 -0
  489. /package/.agents/{skills → skills-archived}/show/tests/fixtures/filled-glyph.svg +0 -0
  490. /package/.agents/{skills → skills-archived}/show/tests/fixtures/inherited-fill.svg +0 -0
  491. /package/.agents/{skills → skills-archived}/show/tests/fixtures/invalid.svg +0 -0
  492. /package/.agents/{skills → skills-archived}/show/tests/fixtures/large-canvas.svg +0 -0
  493. /package/.agents/{skills → skills-archived}/show/tests/fixtures/unfilled-connector.svg +0 -0
  494. /package/.agents/{skills → skills-archived}/show/tests/fixtures/valid.html +0 -0
  495. /package/.agents/{skills → skills-archived}/show/tests/test_validate-artifact.py +0 -0
  496. /package/.agents/{skills → skills-archived}/show/tests/test_validators.py +0 -0
  497. /package/.agents/{skills → skills-archived}/show/workflows/create-visual.md +0 -0
  498. /package/.agents/{skills → skills-archived}/show/workflows/review-visual.md +0 -0
  499. /package/.agents/{skills → skills-archived}/split-pr/SKILL.md +0 -0
  500. /package/.agents/{skills → skills-archived}/split-pr/reference/path-layers.md +0 -0
  501. /package/.agents/{skills → skills-archived}/split-pr/reference/split-further-loop.md +0 -0
  502. /package/.agents/{skills → skills-archived}/split-pr/reference/splitting-principles.md +0 -0
  503. /package/.agents/{skills → skills-archived}/split-pr/scripts/analyze_pr.py +0 -0
  504. /package/.agents/{skills → skills-archived}/split-pr/scripts/categorize_files.py +0 -0
  505. /package/.agents/{skills → skills-archived}/split-pr/scripts/config/__init__.py +0 -0
  506. /package/.agents/{skills → skills-archived}/split-pr/scripts/config/dependency_constants.py +0 -0
  507. /package/.agents/{skills → skills-archived}/split-pr/scripts/config/git_operations_constants.py +0 -0
  508. /package/.agents/{skills → skills-archived}/split-pr/scripts/config/packing_constants.py +0 -0
  509. /package/.agents/{skills → skills-archived}/split-pr/scripts/config/plan_constants.py +0 -0
  510. /package/.agents/{skills → skills-archived}/split-pr/scripts/config/split_pr_constants.py +0 -0
  511. /package/.agents/{skills → skills-archived}/split-pr/scripts/execute_split_slices.py +0 -0
  512. /package/.agents/{skills → skills-archived}/split-pr/scripts/pack_files_into_slices.py +0 -0
  513. /package/.agents/{skills → skills-archived}/split-pr/scripts/split_pr_dependency_graph.py +0 -0
  514. /package/.agents/{skills → skills-archived}/split-pr/scripts/split_pr_git_operations.py +0 -0
  515. /package/.agents/{skills → skills-archived}/split-pr/scripts/split_pr_layer_order.py +0 -0
  516. /package/.agents/{skills → skills-archived}/split-pr/scripts/split_pr_paginate.py +0 -0
  517. /package/.agents/{skills → skills-archived}/split-pr/scripts/split_pr_process_runner.py +0 -0
  518. /package/.agents/{skills → skills-archived}/split-pr/scripts/split_pr_script_types.py +0 -0
  519. /package/.agents/{skills → skills-archived}/split-pr/scripts/split_pr_title.py +0 -0
  520. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_analyze_pr.py +0 -0
  521. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_categorize_files.py +0 -0
  522. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_categorize_files_packing.py +0 -0
  523. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_execute_split_slices.py +0 -0
  524. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_split_pr_dependency_graph.py +0 -0
  525. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_split_pr_git_operations.py +0 -0
  526. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_split_pr_layer_order.py +0 -0
  527. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_split_pr_paginate.py +0 -0
  528. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_split_pr_script_types.py +0 -0
  529. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_split_pr_title.py +0 -0
  530. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_verify_dependency_graph.py +0 -0
  531. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_verify_plan.py +0 -0
  532. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_verify_plan_contract.py +0 -0
  533. /package/.agents/{skills → skills-archived}/split-pr/scripts/test_verify_plan_path_normalization.py +0 -0
  534. /package/.agents/{skills → skills-archived}/split-pr/scripts/verify_dependency_graph.py +0 -0
  535. /package/.agents/{skills → skills-archived}/split-pr/scripts/verify_plan.py +0 -0
@@ -0,0 +1,275 @@
1
+ """Resolve whether a reviewer gate is waived, and why, for the convergence check.
2
+
3
+ ::
4
+
5
+ flag / resolved settings disable the reviewer -> waived, note "copilot_down"
6
+ copilot out of quota -> waived, "copilot unavailable: <reason>"
7
+ bugbot settings-disabled (opt-out / no opt-in) -> waived, "bugbot_down"
8
+ copilot quota available -> not waived (live gates run)
9
+ copilot probe error / indeterminate -> not waived; probe_error_reason set;
10
+ live gates still run (no hard-fail)
11
+
12
+ When ``~/.claude/settings.json`` is readable it is the sole source for both
13
+ ``CLAUDE_REVIEWS_DISABLED`` and ``CLAUDE_REVIEWS_ENABLED``. The process env is
14
+ the fallback only when that file is missing, unreadable, or not a JSON object.
15
+
16
+ Bugbot has no quota or outage API. Confirmed-down for Bugbot means the resolved
17
+ settings disable it (opt-out or missing opt-in). A runtime Bugbot outage is
18
+ detected later as a poll timeout, not at this gate.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import functools
24
+ import json
25
+ import logging
26
+ import os
27
+ import subprocess
28
+ from typing import NamedTuple
29
+
30
+ import _pr_converge_path_setup # noqa: F401
31
+ from copilot_quota import evaluate_copilot_quota
32
+ from pr_converge_scripts_constants.convergence_gate_constants import (
33
+ BUGBOT_DOWN_BYPASS_NOTE,
34
+ COPILOT_DOWN_BYPASS_NOTE,
35
+ REVIEWER_UNAVAILABLE_NOTE_TEMPLATE,
36
+ SETTINGS_DISK_FALLBACK_LOG_TEMPLATE,
37
+ )
38
+ from pr_loop_shared_constants.claude_permissions_constants import (
39
+ get_claude_user_settings_path,
40
+ )
41
+ from pr_loop_shared_constants.copilot_quota_constants import (
42
+ COPILOT_QUOTA_DEFAULT_ENV_FILE_PATH,
43
+ EXIT_CODE_OUT_OF_QUOTA,
44
+ EXIT_CODE_QUOTA_AVAILABLE,
45
+ )
46
+ from pr_loop_shared_constants.reviews_disabled_constants import (
47
+ CLAUDE_REVIEWS_DISABLED_BUGBOT_TOKEN,
48
+ CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN,
49
+ CLAUDE_REVIEWS_DISABLED_CODEX_TOKEN,
50
+ CLAUDE_REVIEWS_DISABLED_COPILOT_TOKEN,
51
+ CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME,
52
+ CLAUDE_REVIEWS_DISABLED_TOKEN_SEPARATOR,
53
+ CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME,
54
+ )
55
+
56
+ _logger = logging.getLogger(__name__)
57
+
58
+
59
+ class ReviewerWaiver(NamedTuple):
60
+ """Whether a reviewer gate is waived, and the note printed on the bypassed line."""
61
+
62
+ is_waived: bool
63
+ bypass_note: str
64
+ probe_error_reason: str = ""
65
+
66
+
67
+ class _ReviewsSettings(NamedTuple):
68
+ """Resolved disabled and enabled reviewer tokens for one settings source."""
69
+
70
+ disabled_tokens: frozenset[str]
71
+ enabled_tokens: frozenset[str]
72
+
73
+
74
+ def _tokens_from_text(reviews_token_text: str) -> frozenset[str]:
75
+ """Split a comma-separated reviews token list into lowercase tokens."""
76
+ return frozenset(
77
+ each_token.strip().lower()
78
+ for each_token in reviews_token_text.split(CLAUDE_REVIEWS_DISABLED_TOKEN_SEPARATOR)
79
+ if each_token.strip()
80
+ )
81
+
82
+
83
+ def _tokens_from_env(environment_variable_name: str) -> frozenset[str]:
84
+ """Return the tokens listed in a process environment variable."""
85
+ return _tokens_from_text(os.environ.get(environment_variable_name, ""))
86
+
87
+
88
+ def _tokens_from_env_block(
89
+ all_env_entries: dict[str, object], environment_variable_name: str
90
+ ) -> frozenset[str]:
91
+ """Return the tokens listed under one key of a settings.json env block."""
92
+ reviews_token_text = all_env_entries.get(environment_variable_name, "")
93
+ if not isinstance(reviews_token_text, str):
94
+ return frozenset()
95
+ return _tokens_from_text(reviews_token_text)
96
+
97
+
98
+ def _try_read_disk_env_block() -> dict[str, object] | None:
99
+ """Return the settings.json env block, or None when disk is not authoritative."""
100
+ settings_path = get_claude_user_settings_path()
101
+ if not settings_path.is_file():
102
+ return None
103
+ try:
104
+ settings_payload = json.loads(settings_path.read_text(encoding="utf-8"))
105
+ except (OSError, ValueError):
106
+ return None
107
+ if not isinstance(settings_payload, dict):
108
+ return None
109
+ all_env_entries = settings_payload.get("env", {})
110
+ if not isinstance(all_env_entries, dict):
111
+ return {}
112
+ return all_env_entries
113
+
114
+
115
+ @functools.lru_cache(maxsize=1)
116
+ def _log_disk_settings_fallback_once() -> None:
117
+ """Log once per process that settings.json fell back to the process env."""
118
+ _logger.warning(
119
+ SETTINGS_DISK_FALLBACK_LOG_TEMPLATE,
120
+ CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME,
121
+ CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME,
122
+ )
123
+
124
+
125
+ @functools.lru_cache(maxsize=1)
126
+ def _resolve_reviews_settings() -> _ReviewsSettings:
127
+ """Return disabled and enabled tokens from disk, or env when disk is unreadable.
128
+
129
+ Cached for the process. Four reviewer gates ask for these tokens in one
130
+ run, and settings cannot change under a running check, so the disk read
131
+ and JSON parse happen once. A test that rebinds the settings path calls
132
+ ``_resolve_reviews_settings.cache_clear()`` first.
133
+ """
134
+ all_disk_env_entries = _try_read_disk_env_block()
135
+ if all_disk_env_entries is not None:
136
+ return _ReviewsSettings(
137
+ disabled_tokens=_tokens_from_env_block(
138
+ all_disk_env_entries, CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME
139
+ ),
140
+ enabled_tokens=_tokens_from_env_block(
141
+ all_disk_env_entries, CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME
142
+ ),
143
+ )
144
+ _log_disk_settings_fallback_once()
145
+ return _ReviewsSettings(
146
+ disabled_tokens=_tokens_from_env(CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME),
147
+ enabled_tokens=_tokens_from_env(CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME),
148
+ )
149
+
150
+
151
+ def _is_copilot_disabled_via_resolved_settings() -> bool:
152
+ """Return True when the resolved settings disable the copilot reviewer."""
153
+ return (
154
+ CLAUDE_REVIEWS_DISABLED_COPILOT_TOKEN
155
+ in _resolve_reviews_settings().disabled_tokens
156
+ )
157
+
158
+
159
+ def _is_off_by_default_reviewer_disabled(reviewer_token: str) -> bool:
160
+ """Return True when the resolved settings leave an opt-in reviewer off.
161
+
162
+ ::
163
+
164
+ enabled names the token, disabled empty -> False (gate runs)
165
+ neither list names the token -> True (off by default)
166
+ both lists name the token -> True (opt-out wins)
167
+
168
+ Args:
169
+ reviewer_token: The lowercase reviewer token to look up in both lists.
170
+
171
+ Returns:
172
+ True when the reviewer stays off for this run.
173
+ """
174
+ reviews_settings = _resolve_reviews_settings()
175
+ is_opted_out = reviewer_token in reviews_settings.disabled_tokens
176
+ is_opted_in = reviewer_token in reviews_settings.enabled_tokens
177
+ return is_opted_out or not is_opted_in
178
+
179
+
180
+ def _is_bugbot_disabled_via_resolved_settings() -> bool:
181
+ """Return True when the resolved settings disable the bugbot reviewer.
182
+
183
+ Bugbot is off by default. It is disabled when the disabled list names it, or
184
+ when the enabled list does not name it.
185
+ """
186
+ return _is_off_by_default_reviewer_disabled(CLAUDE_REVIEWS_DISABLED_BUGBOT_TOKEN)
187
+
188
+
189
+ def _is_bugteam_disabled_via_resolved_settings() -> bool:
190
+ """Return True when the resolved settings disable the bug-audit family.
191
+
192
+ Bugteam is off by default. It is disabled when the disabled list names it,
193
+ or when the enabled list does not name it.
194
+ """
195
+ return _is_off_by_default_reviewer_disabled(CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN)
196
+
197
+
198
+ def _is_codex_disabled_via_resolved_settings() -> bool:
199
+ """Return True when the resolved settings disable the Codex reviewer.
200
+
201
+ Codex is off by default. It is disabled when the disabled list names it, or
202
+ when the enabled list does not name it.
203
+ """
204
+ return _is_off_by_default_reviewer_disabled(CLAUDE_REVIEWS_DISABLED_CODEX_TOKEN)
205
+
206
+
207
+ def _unavailable_note(reviewer_token: str, message: str) -> str:
208
+ """Format the bypass note for a confirmed-down reviewer."""
209
+ return REVIEWER_UNAVAILABLE_NOTE_TEMPLATE.format(
210
+ token=reviewer_token, message=message
211
+ )
212
+
213
+
214
+ @functools.lru_cache(maxsize=None)
215
+ def _probe_copilot_quota() -> ReviewerWaiver:
216
+ """Probe Copilot quota once per run; waive only on confirmed out-of-quota.
217
+
218
+ ::
219
+
220
+ exit == out-of-quota (1) -> waived, "copilot unavailable: <msg>"
221
+ exit == available (0) -> not waived (live gates run)
222
+ exit == API down / no account / other non-zero
223
+ -> not waived; probe_error_reason set (live gates run)
224
+ probe raises -> not waived; probe_error_reason set (live gates run)
225
+ """
226
+ try:
227
+ quota_decision = evaluate_copilot_quota(
228
+ cli_account=None,
229
+ env_file_path=COPILOT_QUOTA_DEFAULT_ENV_FILE_PATH,
230
+ )
231
+ except (OSError, ValueError, RuntimeError, subprocess.SubprocessError) as probe_error:
232
+ _logger.warning(
233
+ "reviewer-availability: probe error for %s: %s",
234
+ CLAUDE_REVIEWS_DISABLED_COPILOT_TOKEN,
235
+ probe_error,
236
+ )
237
+ return ReviewerWaiver(False, "", str(probe_error))
238
+ if quota_decision.exit_code == EXIT_CODE_OUT_OF_QUOTA:
239
+ return ReviewerWaiver(
240
+ True,
241
+ _unavailable_note(
242
+ CLAUDE_REVIEWS_DISABLED_COPILOT_TOKEN, quota_decision.message
243
+ ),
244
+ "",
245
+ )
246
+ if quota_decision.exit_code == EXIT_CODE_QUOTA_AVAILABLE:
247
+ return ReviewerWaiver(False, "", "")
248
+ return ReviewerWaiver(False, "", quota_decision.message)
249
+
250
+
251
+ def _waiver_from_cli_flag(is_down_flag: bool, bypass_note: str) -> ReviewerWaiver:
252
+ """Build a waiver from an explicit CLI flag alone (fixture offline path)."""
253
+ if is_down_flag:
254
+ return ReviewerWaiver(True, bypass_note, "")
255
+ return ReviewerWaiver(False, "", "")
256
+
257
+
258
+ def _resolve_copilot_waiver(is_copilot_down_flag: bool) -> ReviewerWaiver:
259
+ """Resolve the Copilot waiver from flag, resolved settings, then the quota probe."""
260
+ if is_copilot_down_flag or _is_copilot_disabled_via_resolved_settings():
261
+ return ReviewerWaiver(True, COPILOT_DOWN_BYPASS_NOTE, "")
262
+ return _probe_copilot_quota()
263
+
264
+
265
+ def _resolve_bugbot_waiver(is_bugbot_down_flag: bool) -> ReviewerWaiver:
266
+ """Resolve the Bugbot waiver from flag, then resolved settings.
267
+
268
+ Bugbot has no quota or outage API. Once the resolved settings (disk when
269
+ readable, else env) confirm the opt-in, the gate is enforced. Re-probing
270
+ via ``evaluate_reviewer_availability`` would re-read the process env and
271
+ undo a mid-session disk enable of Bugbot.
272
+ """
273
+ if is_bugbot_down_flag or _is_bugbot_disabled_via_resolved_settings():
274
+ return ReviewerWaiver(True, BUGBOT_DOWN_BYPASS_NOTE, "")
275
+ return ReviewerWaiver(False, "", "")
@@ -0,0 +1,279 @@
1
+ """Review and Bugbot IO leaves for the convergence gate checks.
2
+
3
+ Each function issues one ``gh`` REST call and returns a ``(passed, detail)``
4
+ pair the convergence checker turns into a PASS/FAIL line, or a raw
5
+ ``(returncode, stdout)`` pair for the low-level callers. The checker re-imports
6
+ these names, so a test patches them on the checker module.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import re
13
+ import subprocess
14
+ import sys
15
+
16
+ import _pr_converge_path_setup # noqa: F401
17
+ from pr_converge_skill_constants.constants import (
18
+ ALL_BUGBOT_CHECK_RUN_COMPLETE_CONCLUSIONS,
19
+ BUGBOT_CHECK_RUN_NAME_SUBSTRING,
20
+ BUGBOT_DIRTY_BODY_REGEX,
21
+ CHECK_RUNS_PER_PAGE,
22
+ CURSOR_LOGIN_FILTER_SUBSTRING,
23
+ EXIT_CODE_GH_ERROR,
24
+ GH_CHECK_RUNS_PATH_TEMPLATE,
25
+ GH_PR_OBJECT_PATH_TEMPLATE,
26
+ GH_REVIEWS_PATH_TEMPLATE,
27
+ REVIEWS_PER_PAGE,
28
+ )
29
+ from pr_converge_scripts_constants.convergence_gate_constants import (
30
+ MERGEABLE_STATE_CLEAN,
31
+ REVIEW_SUBMITTED_AT_KEY,
32
+ SHORT_SHA_LENGTH,
33
+ )
34
+
35
+ JsonObject = dict[str, object]
36
+ ReviewStateGroup = tuple[str, ...]
37
+
38
+
39
+ def _run_gh_command(all_arguments: list[str]) -> tuple[int, str]:
40
+ completed_process = subprocess.run(
41
+ all_arguments,
42
+ capture_output=True,
43
+ text=True,
44
+ encoding="utf-8",
45
+ errors="replace",
46
+ check=False,
47
+ )
48
+ return completed_process.returncode, completed_process.stdout
49
+
50
+
51
+ def _gh_api(endpoint_path: str) -> tuple[int, str]:
52
+ return _run_gh_command(["gh", "api", endpoint_path])
53
+
54
+
55
+ def _gh_api_paginated(endpoint_path: str) -> tuple[int, str]:
56
+ return _run_gh_command(["gh", "api", endpoint_path, "--paginate", "--slurp"])
57
+
58
+
59
+ def _short_sha(commit_id: str) -> str:
60
+ return commit_id[:SHORT_SHA_LENGTH]
61
+
62
+
63
+ def _get_pr_head_sha(*, owner: str, repo: str, number: int) -> str:
64
+ """Return the PR HEAD SHA, exiting with the gh-error code when the call fails."""
65
+ endpoint = GH_PR_OBJECT_PATH_TEMPLATE.format(owner=owner, repo=repo, number=number)
66
+ returncode, stdout = _gh_api(endpoint)
67
+ if returncode != 0:
68
+ sys.stderr.write(f"gh api error fetching PR object: {stdout}\n")
69
+ raise SystemExit(EXIT_CODE_GH_ERROR)
70
+ try:
71
+ pr_object = json.loads(stdout)
72
+ except json.JSONDecodeError as decode_error:
73
+ sys.stderr.write(f"gh api PR object not valid JSON: {stdout}\n")
74
+ raise SystemExit(EXIT_CODE_GH_ERROR) from decode_error
75
+ head_object = pr_object.get("head") if isinstance(pr_object, dict) else None
76
+ head_sha: object = head_object.get("sha") if isinstance(head_object, dict) else None
77
+ if not isinstance(head_sha, str):
78
+ raise SystemExit(EXIT_CODE_GH_ERROR)
79
+ return head_sha
80
+
81
+
82
+ def _evaluate_mergeable_from_pr_object(pr_object: JsonObject) -> tuple[bool, str]:
83
+ """Return whether a PR object dict is cleanly mergeable.
84
+
85
+ Pure evaluator: no network IO. Live and fixture paths share this contract.
86
+
87
+ Args:
88
+ pr_object: Pull request JSON object with mergeable and mergeable_state fields.
89
+
90
+ Returns:
91
+ (True, clean) when mergeable is true and state is clean; otherwise (False, state).
92
+ """
93
+ mergeable: object = pr_object.get("mergeable")
94
+ mergeable_state: object = pr_object.get("mergeable_state", "unknown")
95
+ state_text = str(mergeable_state)
96
+ if mergeable is True and state_text == MERGEABLE_STATE_CLEAN:
97
+ return True, MERGEABLE_STATE_CLEAN
98
+ return False, state_text
99
+
100
+
101
+ def _get_mergeable(*, owner: str, repo: str, number: int) -> tuple[bool, str]:
102
+ """Return whether the PR is cleanly mergeable, with the mergeable-state detail."""
103
+ endpoint = GH_PR_OBJECT_PATH_TEMPLATE.format(owner=owner, repo=repo, number=number)
104
+ returncode, stdout = _gh_api(endpoint)
105
+ if returncode != 0:
106
+ return False, f"gh api error: {stdout}"
107
+ try:
108
+ pr_object = json.loads(stdout)
109
+ except json.JSONDecodeError:
110
+ return False, "gh api PR object not valid JSON"
111
+ if not isinstance(pr_object, dict):
112
+ return False, "unknown"
113
+ return _evaluate_mergeable_from_pr_object(pr_object)
114
+
115
+
116
+ def _bugbot_check_runs(
117
+ *, owner: str, repo: str, sha: str
118
+ ) -> tuple[int, list[JsonObject]]:
119
+ """Fetch the check runs for a SHA and return the returncode and run dicts."""
120
+ endpoint = GH_CHECK_RUNS_PATH_TEMPLATE.format(owner=owner, repo=repo, sha=sha)
121
+ returncode, stdout = _gh_api(f"{endpoint}?per_page={CHECK_RUNS_PER_PAGE}")
122
+ if returncode != 0:
123
+ return returncode, []
124
+ try:
125
+ payload = json.loads(stdout)
126
+ except json.JSONDecodeError:
127
+ return returncode, []
128
+ raw_runs = payload.get("check_runs") if isinstance(payload, dict) else None
129
+ if not isinstance(raw_runs, list):
130
+ return returncode, []
131
+ return returncode, [each_run for each_run in raw_runs if isinstance(each_run, dict)]
132
+
133
+
134
+ def _bugbot_run_conclusion_detail(check_run: JsonObject) -> tuple[bool, str]:
135
+ """Return the pass flag and detail for one bugbot check run."""
136
+ conclusion = check_run.get("conclusion", "")
137
+ if conclusion in ALL_BUGBOT_CHECK_RUN_COMPLETE_CONCLUSIONS:
138
+ check_id = check_run.get("id", "?")
139
+ detail_url = check_run.get("html_url", "")
140
+ details_suffix = f" ({detail_url})" if detail_url else ""
141
+ return True, f"check run {check_id}, conclusion: {conclusion}{details_suffix}"
142
+ return (
143
+ False,
144
+ f"check run conclusion is '{conclusion}', expected {ALL_BUGBOT_CHECK_RUN_COMPLETE_CONCLUSIONS}",
145
+ )
146
+
147
+
148
+ def _check_bugbot(*, owner: str, repo: str, sha: str) -> tuple[bool, str]:
149
+ """Return whether the Cursor Bugbot check run on a SHA completed successfully."""
150
+ returncode, check_runs = _bugbot_check_runs(owner=owner, repo=repo, sha=sha)
151
+ if returncode != 0:
152
+ return False, "gh api error fetching check runs"
153
+ for each_check_run in check_runs:
154
+ each_name = each_check_run.get("name", "")
155
+ if not isinstance(each_name, str):
156
+ continue
157
+ if BUGBOT_CHECK_RUN_NAME_SUBSTRING.lower() not in each_name.lower():
158
+ continue
159
+ return _bugbot_run_conclusion_detail(each_check_run)
160
+ return False, "no bugbot check run found"
161
+
162
+
163
+ def _sort_reviews_newest_first(all_reviews: list[JsonObject]) -> list[JsonObject]:
164
+ """Return the reviews ordered newest-first by submission time.
165
+
166
+ The live gh path and the offline fixture path both feed the same
167
+ newest-first evaluators, so both order their reviews through here.
168
+
169
+ Args:
170
+ all_reviews: Review objects in any order.
171
+
172
+ Returns:
173
+ A new list ordered newest-first; a review with no submitted_at sorts last.
174
+ """
175
+ return sorted(
176
+ all_reviews,
177
+ key=lambda each_review: str(each_review.get(REVIEW_SUBMITTED_AT_KEY, "")),
178
+ reverse=True,
179
+ )
180
+
181
+
182
+ def _flatten_paginated_reviews(stdout: str) -> list[JsonObject] | None:
183
+ """Flatten a slurped, paginated reviews payload into a newest-first list."""
184
+ try:
185
+ reviews_payload = json.loads(stdout)
186
+ except json.JSONDecodeError:
187
+ return None
188
+ if not isinstance(reviews_payload, list):
189
+ return None
190
+ all_flat: list[JsonObject] = [
191
+ each_entry
192
+ for each_page in reviews_payload
193
+ if isinstance(each_page, list)
194
+ for each_entry in each_page
195
+ if isinstance(each_entry, dict)
196
+ ]
197
+ return _sort_reviews_newest_first(all_flat)
198
+
199
+
200
+ def _review_matches_login(review: JsonObject, login_substring: str) -> bool:
201
+ user_object = review.get("user")
202
+ if not isinstance(user_object, dict):
203
+ return False
204
+ login = user_object.get("login", "")
205
+ return isinstance(login, str) and login_substring in login.lower()
206
+
207
+
208
+ def _review_commit_starts_with(review: JsonObject, head_sha: str) -> bool:
209
+ commit_id = review.get("commit_id", "")
210
+ return isinstance(commit_id, str) and commit_id.startswith(head_sha)
211
+
212
+
213
+ def _check_bugbot_not_dirty(
214
+ *, owner: str, repo: str, number: int, head_sha: str
215
+ ) -> tuple[bool, str]:
216
+ """Return whether the newest Cursor Bugbot review on HEAD reports no findings."""
217
+ endpoint = GH_REVIEWS_PATH_TEMPLATE.format(owner=owner, repo=repo, number=number)
218
+ returncode, stdout = _gh_api_paginated(f"{endpoint}?per_page={REVIEWS_PER_PAGE}")
219
+ if returncode != 0:
220
+ return True, "bugbot reviews unavailable (non-fatal)"
221
+ all_flat = _flatten_paginated_reviews(stdout)
222
+ if all_flat is None:
223
+ return True, "bugbot reviews not valid JSON (non-fatal)"
224
+ dirty_pattern = re.compile(BUGBOT_DIRTY_BODY_REGEX, re.IGNORECASE)
225
+ for each_review in all_flat:
226
+ if not _review_matches_login(each_review, CURSOR_LOGIN_FILTER_SUBSTRING):
227
+ continue
228
+ if not _review_commit_starts_with(each_review, head_sha):
229
+ continue
230
+ body = each_review.get("body", "")
231
+ if isinstance(body, str) and dirty_pattern.search(body):
232
+ return False, "bugbot review body reports findings"
233
+ return True, "clean"
234
+ return True, "no bugbot review at HEAD"
235
+
236
+
237
+ def _bot_review_state_detail(
238
+ review: JsonObject,
239
+ clean_states: ReviewStateGroup,
240
+ dirty_states: ReviewStateGroup,
241
+ ) -> tuple[bool, str]:
242
+ """Return the pass flag and detail for one bot review's state."""
243
+ review_state = review.get("state", "")
244
+ commit_id = review.get("commit_id", "")
245
+ short_commit = _short_sha(commit_id) if isinstance(commit_id, str) else "?"
246
+ if review_state in clean_states:
247
+ review_id = review.get("id", "?")
248
+ return True, f"review {review_id}, state: {review_state}, commit {short_commit}"
249
+ if review_state in dirty_states:
250
+ return False, f"review state is '{review_state}' (dirty), commit {short_commit}"
251
+ return False, f"review state is '{review_state}', commit {short_commit}"
252
+
253
+
254
+ def _check_bot_review(
255
+ *,
256
+ owner: str,
257
+ repo: str,
258
+ number: int,
259
+ head_sha: str,
260
+ login_substring: str,
261
+ clean_states: ReviewStateGroup,
262
+ dirty_states: ReviewStateGroup,
263
+ label: str,
264
+ ) -> tuple[bool, str]:
265
+ """Return whether the newest matching bot review on HEAD is in a clean state."""
266
+ endpoint = GH_REVIEWS_PATH_TEMPLATE.format(owner=owner, repo=repo, number=number)
267
+ returncode, stdout = _gh_api_paginated(f"{endpoint}?per_page={REVIEWS_PER_PAGE}")
268
+ if returncode != 0:
269
+ return False, f"gh api error: {stdout}"
270
+ all_flat = _flatten_paginated_reviews(stdout)
271
+ if all_flat is None:
272
+ return False, f"no {label} review found"
273
+ for each_review in all_flat:
274
+ if not _review_matches_login(each_review, login_substring):
275
+ continue
276
+ if not _review_commit_starts_with(each_review, head_sha):
277
+ continue
278
+ return _bot_review_state_detail(each_review, clean_states, dirty_states)
279
+ return False, f"no {label} review found on {_short_sha(head_sha)}"