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,683 @@
1
+ """Tests for the Codex weekly-usage probe CLI.
2
+
3
+ Fixtures note the binary version they were captured against:
4
+ codex-cli 0.144.3 (account/rateLimits/read via ``codex app-server``).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import importlib.util
10
+ import json
11
+ import subprocess
12
+ import sys
13
+ import threading
14
+ import time
15
+ from pathlib import Path
16
+ from types import ModuleType
17
+
18
+ import pytest
19
+
20
+ SCRIPTS_DIRECTORY = Path(__file__).resolve().parent
21
+ if str(SCRIPTS_DIRECTORY) not in sys.path:
22
+ sys.path.insert(0, str(SCRIPTS_DIRECTORY))
23
+
24
+ from codex_review_scripts_constants.codex_usage_probe_constants import (
25
+ EXIT_CODE_CRASH,
26
+ EXIT_CODE_SUCCESS,
27
+ PERCENT_FULL,
28
+ READER_THREAD_JOIN_TIMEOUT_SECONDS,
29
+ SOURCE_APP_SERVER_RATE_LIMITS,
30
+ SOURCE_NO_USAGE_SURFACE,
31
+ SOURCE_TEXT_STATUS,
32
+ USAGE_REPORT_KEY_PERCENT_LEFT,
33
+ USAGE_REPORT_KEY_SOURCE,
34
+ USAGE_REPORT_KEY_WINDOW_RESET,
35
+ WEEKLY_USAGE_GATE_THRESHOLD_PERCENT,
36
+ WEEKLY_WINDOW_DURATION_MINUTES,
37
+ )
38
+
39
+ PROBE_PATH = SCRIPTS_DIRECTORY / "codex_usage_probe.py"
40
+
41
+ REAL_APP_SERVER_RATE_LIMITS_REPLY_CODEX_0_144_3 = json.dumps(
42
+ {
43
+ "id": 2,
44
+ "result": {
45
+ "rateLimits": {
46
+ "limitId": "codex",
47
+ "limitName": None,
48
+ "primary": {
49
+ "usedPercent": 95,
50
+ "windowDurationMins": WEEKLY_WINDOW_DURATION_MINUTES,
51
+ "resetsAt": 1784504948,
52
+ },
53
+ "secondary": None,
54
+ "credits": {
55
+ "hasCredits": False,
56
+ "unlimited": False,
57
+ "balance": None,
58
+ },
59
+ "individualLimit": None,
60
+ "planType": "team",
61
+ "rateLimitReachedType": None,
62
+ }
63
+ },
64
+ }
65
+ )
66
+
67
+ SESSION_WINDOW_DURATION_MINUTES = 300
68
+
69
+ DUAL_WINDOW_APP_SERVER_RATE_LIMITS_REPLY = json.dumps(
70
+ {
71
+ "id": 2,
72
+ "result": {
73
+ "rateLimits": {
74
+ "limitId": "codex",
75
+ "primary": {
76
+ "usedPercent": 40,
77
+ "windowDurationMins": SESSION_WINDOW_DURATION_MINUTES,
78
+ "resetsAt": 1783958400,
79
+ },
80
+ "secondary": {
81
+ "usedPercent": 20,
82
+ "windowDurationMins": WEEKLY_WINDOW_DURATION_MINUTES,
83
+ "resetsAt": 1784504948,
84
+ },
85
+ }
86
+ },
87
+ }
88
+ )
89
+
90
+ PRIMARY_ONLY_SESSION_WINDOW_REPLY = json.dumps(
91
+ {
92
+ "id": 2,
93
+ "result": {
94
+ "rateLimits": {
95
+ "limitId": "codex",
96
+ "primary": {
97
+ "usedPercent": 10,
98
+ "windowDurationMins": SESSION_WINDOW_DURATION_MINUTES,
99
+ "resetsAt": 1783958400,
100
+ },
101
+ "secondary": None,
102
+ }
103
+ },
104
+ }
105
+ )
106
+
107
+ EXPECTED_TEXT_STATUS_WINDOW_RESET = "2026-07-19T23:49:08+00:00"
108
+ EXPECTED_FIVE_HOUR_WINDOW_RESET = "2026-07-01T00:00:00+00:00"
109
+
110
+ NO_USAGE_SURFACE_LOGIN_STATUS_OUTPUT = "Logged in using ChatGPT\n"
111
+
112
+ TEXT_STATUS_WITH_FIVE_HOUR_AND_WEEKLY_RESETS = (
113
+ "Status\n"
114
+ f"5-hour limit: 60% left (resets {EXPECTED_FIVE_HOUR_WINDOW_RESET})\n"
115
+ f"Weekly limit: 42% left (resets {EXPECTED_TEXT_STATUS_WINDOW_RESET})\n"
116
+ )
117
+
118
+ PROCESS_TREE_WAIT_SECONDS = 5
119
+ READER_JOIN_TEARDOWN_WAIT_SECONDS = 0.2
120
+
121
+ NO_RATE_LIMITS_APP_SERVER_REPLY = json.dumps(
122
+ {
123
+ "id": 2,
124
+ "result": {"rateLimits": {}},
125
+ }
126
+ )
127
+
128
+ JSON_RPC_ERROR_APP_SERVER_REPLY = json.dumps(
129
+ {
130
+ "id": 2,
131
+ "error": {
132
+ "code": -32601,
133
+ "message": "Method not found",
134
+ },
135
+ }
136
+ )
137
+
138
+ TEXT_STATUS_WITH_WEEKLY_LEFT = (
139
+ "Status\n"
140
+ "5-hour limit: 60% left\n"
141
+ "Weekly limit: 42% left (resets 2026-07-19T23:49:08+00:00)\n"
142
+ )
143
+
144
+ TEXT_STATUS_WITH_RESETS_AT_PHRASING = (
145
+ "Status\n"
146
+ "Weekly limit: 42% left, resets at 2026-07-19T23:49:08+00:00\n"
147
+ )
148
+
149
+ TIMEOUT_SECONDS = 30
150
+ TIMEOUT_COMMAND = "codex"
151
+
152
+
153
+
154
+ def load_probe_module() -> ModuleType:
155
+ spec = importlib.util.spec_from_file_location("codex_usage_probe", PROBE_PATH)
156
+ assert spec is not None
157
+ assert spec.loader is not None
158
+ probe_module = importlib.util.module_from_spec(spec)
159
+ sys.modules[spec.name] = probe_module
160
+ spec.loader.exec_module(probe_module)
161
+ return probe_module
162
+
163
+
164
+ def _app_server_lines_from_rate_limits_payload(payload_line: str) -> list[str]:
165
+ return [
166
+ json.dumps(
167
+ {
168
+ "id": 1,
169
+ "result": {
170
+ "userAgent": "codex-usage-probe/0.144.3",
171
+ "platformOs": "windows",
172
+ },
173
+ }
174
+ ),
175
+ payload_line,
176
+ ]
177
+
178
+
179
+ def _assert_main_yields_null_skip_report(
180
+ probe: ModuleType,
181
+ capsys: pytest.CaptureFixture[str],
182
+ ) -> None:
183
+ exit_code = probe.main()
184
+ assert exit_code == EXIT_CODE_SUCCESS
185
+ captured = capsys.readouterr()
186
+ payload = json.loads(captured.out)
187
+ assert payload[USAGE_REPORT_KEY_PERCENT_LEFT] is None
188
+ assert payload[USAGE_REPORT_KEY_SOURCE] == SOURCE_NO_USAGE_SURFACE
189
+ assert USAGE_REPORT_KEY_WINDOW_RESET in payload
190
+
191
+
192
+ def _assert_main_yields_cli_failure_not_usage_skip(
193
+ probe: ModuleType,
194
+ capsys: pytest.CaptureFixture[str],
195
+ ) -> None:
196
+ exit_code = probe.main()
197
+ assert exit_code == EXIT_CODE_CRASH
198
+ captured = capsys.readouterr()
199
+ payload = json.loads(captured.out)
200
+ assert payload[USAGE_REPORT_KEY_PERCENT_LEFT] is None
201
+ assert payload[USAGE_REPORT_KEY_SOURCE] == SOURCE_NO_USAGE_SURFACE
202
+ assert USAGE_REPORT_KEY_WINDOW_RESET in payload
203
+
204
+
205
+ class TestParseRateLimitsMessage:
206
+ def should_compute_percent_left_from_weekly_primary_window(
207
+ self,
208
+ ) -> None:
209
+ probe = load_probe_module()
210
+ usage_report = probe.parse_rate_limits_message(
211
+ REAL_APP_SERVER_RATE_LIMITS_REPLY_CODEX_0_144_3
212
+ )
213
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] == 5
214
+ assert usage_report[USAGE_REPORT_KEY_WINDOW_RESET] is not None
215
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_APP_SERVER_RATE_LIMITS
216
+
217
+ def should_prefer_secondary_weekly_window_over_primary_session(
218
+ self,
219
+ ) -> None:
220
+ probe = load_probe_module()
221
+ usage_report = probe.parse_rate_limits_message(
222
+ DUAL_WINDOW_APP_SERVER_RATE_LIMITS_REPLY
223
+ )
224
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] == 80
225
+ assert usage_report[USAGE_REPORT_KEY_WINDOW_RESET] is not None
226
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_APP_SERVER_RATE_LIMITS
227
+
228
+ def should_return_null_when_only_non_weekly_session_window(self) -> None:
229
+ probe = load_probe_module()
230
+ usage_report = probe.parse_rate_limits_message(
231
+ PRIMARY_ONLY_SESSION_WINDOW_REPLY
232
+ )
233
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] is None
234
+ assert usage_report[USAGE_REPORT_KEY_WINDOW_RESET] is None
235
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_NO_USAGE_SURFACE
236
+
237
+ def should_return_null_percent_when_rate_limits_empty(self) -> None:
238
+ probe = load_probe_module()
239
+ usage_report = probe.parse_rate_limits_message(
240
+ NO_RATE_LIMITS_APP_SERVER_REPLY
241
+ )
242
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] is None
243
+ assert usage_report[USAGE_REPORT_KEY_WINDOW_RESET] is None
244
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_NO_USAGE_SURFACE
245
+
246
+ def should_return_null_percent_when_json_rpc_error_payload(self) -> None:
247
+ probe = load_probe_module()
248
+ usage_report = probe.parse_rate_limits_message(JSON_RPC_ERROR_APP_SERVER_REPLY)
249
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] is None
250
+ assert usage_report[USAGE_REPORT_KEY_WINDOW_RESET] is None
251
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_NO_USAGE_SURFACE
252
+
253
+
254
+ class TestParseTextStatus:
255
+ def should_parse_weekly_percent_left_from_status_text(self) -> None:
256
+ probe = load_probe_module()
257
+ usage_report = probe.parse_text_usage_status(TEXT_STATUS_WITH_WEEKLY_LEFT)
258
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] == 42.0
259
+ assert (
260
+ usage_report[USAGE_REPORT_KEY_WINDOW_RESET]
261
+ == EXPECTED_TEXT_STATUS_WINDOW_RESET
262
+ )
263
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_TEXT_STATUS
264
+
265
+ def should_parse_window_reset_from_resets_at_phrasing(self) -> None:
266
+ probe = load_probe_module()
267
+ usage_report = probe.parse_text_usage_status(
268
+ TEXT_STATUS_WITH_RESETS_AT_PHRASING
269
+ )
270
+ assert (
271
+ usage_report[USAGE_REPORT_KEY_WINDOW_RESET]
272
+ == EXPECTED_TEXT_STATUS_WINDOW_RESET
273
+ )
274
+
275
+ def should_prefer_weekly_reset_when_five_hour_reset_appears_first(self) -> None:
276
+ probe = load_probe_module()
277
+ usage_report = probe.parse_text_usage_status(
278
+ TEXT_STATUS_WITH_FIVE_HOUR_AND_WEEKLY_RESETS
279
+ )
280
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] == 42.0
281
+ assert (
282
+ usage_report[USAGE_REPORT_KEY_WINDOW_RESET]
283
+ == EXPECTED_TEXT_STATUS_WINDOW_RESET
284
+ )
285
+ assert usage_report[USAGE_REPORT_KEY_WINDOW_RESET] != (
286
+ EXPECTED_FIVE_HOUR_WINDOW_RESET
287
+ )
288
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_TEXT_STATUS
289
+
290
+ def should_yield_null_for_login_status_without_usage(self) -> None:
291
+ probe = load_probe_module()
292
+ usage_report = probe.parse_text_usage_status(
293
+ NO_USAGE_SURFACE_LOGIN_STATUS_OUTPUT
294
+ )
295
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] is None
296
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_NO_USAGE_SURFACE
297
+
298
+
299
+ class TestProcessTreeTeardown:
300
+ def should_end_a_running_app_server_and_reap_it(self) -> None:
301
+ """A real sleeping child is gone once teardown returns, on any platform."""
302
+ probe = load_probe_module()
303
+ sleeping_process = subprocess.Popen(
304
+ [sys.executable, "-c", "import time; time.sleep(30)"],
305
+ stdout=subprocess.DEVNULL,
306
+ stderr=subprocess.DEVNULL,
307
+ start_new_session=probe.should_start_new_session(),
308
+ )
309
+ try:
310
+ probe._terminate_process_tree(sleeping_process)
311
+ assert sleeping_process.poll() is not None
312
+ finally:
313
+ if sleeping_process.poll() is None:
314
+ sleeping_process.kill()
315
+ sleeping_process.wait(timeout=PROCESS_TREE_WAIT_SECONDS)
316
+
317
+ def should_hand_the_whole_tree_to_the_shared_kill(
318
+ self,
319
+ monkeypatch: pytest.MonkeyPatch,
320
+ ) -> None:
321
+ """Teardown routes the server process through the shared tree kill.
322
+
323
+ ::
324
+
325
+ shared tree kill ok: the cmd.exe shim's app-server child dies too
326
+ Popen.kill() flag: the app-server grandchild holds stdout open
327
+ """
328
+ probe = load_probe_module()
329
+ all_killed_processes: list[object] = []
330
+ finished_process = subprocess.Popen(
331
+ [sys.executable, "-c", ""],
332
+ stdout=subprocess.DEVNULL,
333
+ stderr=subprocess.DEVNULL,
334
+ )
335
+ finished_process.wait(timeout=PROCESS_TREE_WAIT_SECONDS)
336
+ monkeypatch.setattr(
337
+ probe,
338
+ "terminate_process_tree",
339
+ lambda target_process: all_killed_processes.append(target_process),
340
+ )
341
+
342
+ probe._terminate_process_tree(finished_process)
343
+
344
+ assert all_killed_processes == [finished_process]
345
+
346
+ def should_return_when_a_killed_child_never_reaps(
347
+ self,
348
+ monkeypatch: pytest.MonkeyPatch,
349
+ ) -> None:
350
+ """A child that outlives its grace window ends teardown, never hangs it."""
351
+ probe = load_probe_module()
352
+
353
+ class _UnreapableProcess:
354
+ def wait(self, timeout: float | None = None) -> int:
355
+ raise subprocess.TimeoutExpired(cmd="codex", timeout=timeout or 0)
356
+
357
+ monkeypatch.setattr(probe, "terminate_process_tree", lambda _process: None)
358
+
359
+ probe._terminate_process_tree(_UnreapableProcess())
360
+
361
+
362
+ class TestReaderThreadLifecycle:
363
+ def should_join_stdout_reader_after_process_tree_teardown(self) -> None:
364
+ probe = load_probe_module()
365
+ is_exchange_over = threading.Event()
366
+ all_server_lines: list[str] = []
367
+
368
+ def collect_until_event(
369
+ _server_stdout: object,
370
+ collected_lines: list[str],
371
+ exchange_over: threading.Event,
372
+ ) -> None:
373
+ collected_lines.append("reader-started")
374
+ time.sleep(READER_JOIN_TEARDOWN_WAIT_SECONDS)
375
+ collected_lines.append("reader-finished")
376
+ exchange_over.set()
377
+
378
+ reader_thread = threading.Thread(
379
+ target=collect_until_event,
380
+ args=(None, all_server_lines, is_exchange_over),
381
+ daemon=True,
382
+ )
383
+ reader_thread.start()
384
+ finished_process = subprocess.Popen(
385
+ [sys.executable, "-c", "pass"],
386
+ stdout=subprocess.DEVNULL,
387
+ stderr=subprocess.DEVNULL,
388
+ )
389
+ finished_process.wait(timeout=PROCESS_TREE_WAIT_SECONDS)
390
+ probe._teardown_app_server_exchange(
391
+ server_process=finished_process,
392
+ reader_thread=reader_thread,
393
+ )
394
+ assert reader_thread.is_alive() is False
395
+ assert all_server_lines == ["reader-started", "reader-finished"]
396
+ assert READER_THREAD_JOIN_TIMEOUT_SECONDS >= 1
397
+
398
+
399
+ class TestDefaultExchangeWiring:
400
+ def should_wire_subprocess_exchange_from_main(
401
+ self,
402
+ monkeypatch: pytest.MonkeyPatch,
403
+ capsys: pytest.CaptureFixture[str],
404
+ ) -> None:
405
+ probe = load_probe_module()
406
+ all_server_lines = _app_server_lines_from_rate_limits_payload(
407
+ REAL_APP_SERVER_RATE_LIMITS_REPLY_CODEX_0_144_3
408
+ )
409
+ all_call_counts = {"exchange": 0}
410
+
411
+ def fake_exchange(all_request_messages: list[dict[str, object]]) -> list[str]:
412
+ all_call_counts["exchange"] += 1
413
+ assert len(all_request_messages) >= 2
414
+ return all_server_lines
415
+
416
+ monkeypatch.setattr(
417
+ probe,
418
+ "_exchange_app_server_messages_via_subprocess",
419
+ fake_exchange,
420
+ )
421
+ exit_code = probe.main()
422
+ captured = capsys.readouterr()
423
+ usage_report = json.loads(captured.out)
424
+ assert exit_code == EXIT_CODE_SUCCESS
425
+ assert all_call_counts["exchange"] == 1
426
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] == 5
427
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_APP_SERVER_RATE_LIMITS
428
+
429
+
430
+ class TestProbeWeeklyUsage:
431
+ def should_probe_through_swappable_app_server_exchange(self) -> None:
432
+ probe = load_probe_module()
433
+ all_server_lines = _app_server_lines_from_rate_limits_payload(
434
+ REAL_APP_SERVER_RATE_LIMITS_REPLY_CODEX_0_144_3
435
+ )
436
+
437
+ def fake_exchange(all_request_messages: list[dict[str, object]]) -> list[str]:
438
+ assert len(all_request_messages) >= 2
439
+ return all_server_lines
440
+
441
+ usage_report = probe.probe_weekly_usage(
442
+ exchange_app_server_messages=fake_exchange
443
+ )
444
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] == 5
445
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_APP_SERVER_RATE_LIMITS
446
+
447
+ def should_yield_null_when_exchange_returns_no_usage_payload(self) -> None:
448
+ probe = load_probe_module()
449
+
450
+ def empty_exchange(
451
+ all_request_messages: list[dict[str, object]],
452
+ ) -> list[str]:
453
+ del all_request_messages
454
+ return [
455
+ json.dumps({"id": 1, "result": {}}),
456
+ NO_RATE_LIMITS_APP_SERVER_REPLY,
457
+ ]
458
+
459
+ usage_report = probe.probe_weekly_usage(
460
+ exchange_app_server_messages=empty_exchange
461
+ )
462
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] is None
463
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_NO_USAGE_SURFACE
464
+
465
+ def should_yield_null_when_exchange_returns_json_rpc_error(self) -> None:
466
+ probe = load_probe_module()
467
+
468
+ def error_exchange(
469
+ all_request_messages: list[dict[str, object]],
470
+ ) -> list[str]:
471
+ del all_request_messages
472
+ return _app_server_lines_from_rate_limits_payload(
473
+ JSON_RPC_ERROR_APP_SERVER_REPLY
474
+ )
475
+
476
+ usage_report = probe.probe_weekly_usage(
477
+ exchange_app_server_messages=error_exchange
478
+ )
479
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] is None
480
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_NO_USAGE_SURFACE
481
+
482
+
483
+ class TestProbeWeeklyUsageViaSubprocess:
484
+ def should_report_usage_from_the_real_subprocess_exchange(
485
+ self,
486
+ monkeypatch: pytest.MonkeyPatch,
487
+ ) -> None:
488
+ probe = load_probe_module()
489
+ all_server_lines = _app_server_lines_from_rate_limits_payload(
490
+ REAL_APP_SERVER_RATE_LIMITS_REPLY_CODEX_0_144_3
491
+ )
492
+
493
+ def fake_subprocess_exchange(
494
+ all_request_messages: list[dict[str, object]],
495
+ ) -> list[str]:
496
+ assert len(all_request_messages) >= 2
497
+ return all_server_lines
498
+
499
+ monkeypatch.setattr(
500
+ probe,
501
+ "_exchange_app_server_messages_via_subprocess",
502
+ fake_subprocess_exchange,
503
+ )
504
+
505
+ usage_report = probe.probe_weekly_usage_via_subprocess()
506
+
507
+ assert usage_report[USAGE_REPORT_KEY_PERCENT_LEFT] == 5
508
+ assert usage_report[USAGE_REPORT_KEY_SOURCE] == SOURCE_APP_SERVER_RATE_LIMITS
509
+
510
+
511
+ class TestGateThresholdHelper:
512
+ def should_export_threshold_constant_of_ten(self) -> None:
513
+ assert WEEKLY_USAGE_GATE_THRESHOLD_PERCENT == 10
514
+
515
+ def should_skip_review_when_percent_is_null(self) -> None:
516
+ probe = load_probe_module()
517
+ assert probe.is_codex_review_required(None) is False
518
+
519
+ def should_skip_review_when_percent_at_or_below_threshold(self) -> None:
520
+ probe = load_probe_module()
521
+ assert (
522
+ probe.is_codex_review_required(float(WEEKLY_USAGE_GATE_THRESHOLD_PERCENT))
523
+ is False
524
+ )
525
+ assert probe.is_codex_review_required(5.0) is False
526
+
527
+ def should_require_review_when_percent_above_threshold(self) -> None:
528
+ probe = load_probe_module()
529
+ assert probe.is_codex_review_required(10.1) is True
530
+ assert probe.is_codex_review_required(float(PERCENT_FULL)) is True
531
+
532
+
533
+ class TestMainExitCodes:
534
+ def should_exit_zero_with_json_even_when_usage_is_null(
535
+ self,
536
+ capsys: pytest.CaptureFixture[str],
537
+ monkeypatch: pytest.MonkeyPatch,
538
+ ) -> None:
539
+ probe = load_probe_module()
540
+
541
+ def empty_exchange(
542
+ all_request_messages: list[dict[str, object]],
543
+ ) -> list[str]:
544
+ del all_request_messages
545
+ return [NO_RATE_LIMITS_APP_SERVER_REPLY]
546
+
547
+ monkeypatch.setattr(
548
+ probe,
549
+ "_exchange_app_server_messages_via_subprocess",
550
+ empty_exchange,
551
+ )
552
+ _assert_main_yields_null_skip_report(probe, capsys)
553
+
554
+ def should_exit_nonzero_when_binary_missing(
555
+ self,
556
+ capsys: pytest.CaptureFixture[str],
557
+ monkeypatch: pytest.MonkeyPatch,
558
+ ) -> None:
559
+ probe = load_probe_module()
560
+
561
+ def missing_binary_exchange(
562
+ all_request_messages: list[dict[str, object]],
563
+ ) -> list[str]:
564
+ del all_request_messages
565
+ raise FileNotFoundError("codex binary not found on PATH")
566
+
567
+ monkeypatch.setattr(
568
+ probe,
569
+ "_exchange_app_server_messages_via_subprocess",
570
+ missing_binary_exchange,
571
+ )
572
+ _assert_main_yields_cli_failure_not_usage_skip(probe, capsys)
573
+
574
+ def should_exit_nonzero_when_subprocess_times_out(
575
+ self,
576
+ capsys: pytest.CaptureFixture[str],
577
+ monkeypatch: pytest.MonkeyPatch,
578
+ ) -> None:
579
+ probe = load_probe_module()
580
+
581
+ def timeout_exchange(
582
+ all_request_messages: list[dict[str, object]],
583
+ ) -> list[str]:
584
+ del all_request_messages
585
+ raise subprocess.TimeoutExpired(
586
+ cmd=TIMEOUT_COMMAND,
587
+ timeout=TIMEOUT_SECONDS,
588
+ )
589
+
590
+ monkeypatch.setattr(
591
+ probe,
592
+ "_exchange_app_server_messages_via_subprocess",
593
+ timeout_exchange,
594
+ )
595
+ _assert_main_yields_cli_failure_not_usage_skip(probe, capsys)
596
+
597
+ def should_exit_nonzero_when_os_error(
598
+ self,
599
+ capsys: pytest.CaptureFixture[str],
600
+ monkeypatch: pytest.MonkeyPatch,
601
+ ) -> None:
602
+ probe = load_probe_module()
603
+
604
+ def os_error_exchange(
605
+ all_request_messages: list[dict[str, object]],
606
+ ) -> list[str]:
607
+ del all_request_messages
608
+ raise OSError("permission denied launching codex")
609
+
610
+ monkeypatch.setattr(
611
+ probe,
612
+ "_exchange_app_server_messages_via_subprocess",
613
+ os_error_exchange,
614
+ )
615
+ _assert_main_yields_cli_failure_not_usage_skip(probe, capsys)
616
+
617
+ def should_exit_nonzero_when_subprocess_error(
618
+ self,
619
+ capsys: pytest.CaptureFixture[str],
620
+ monkeypatch: pytest.MonkeyPatch,
621
+ ) -> None:
622
+ probe = load_probe_module()
623
+
624
+ def subprocess_error_exchange(
625
+ all_request_messages: list[dict[str, object]],
626
+ ) -> list[str]:
627
+ del all_request_messages
628
+ raise subprocess.SubprocessError("codex app-server failed")
629
+
630
+ monkeypatch.setattr(
631
+ probe,
632
+ "_exchange_app_server_messages_via_subprocess",
633
+ subprocess_error_exchange,
634
+ )
635
+ _assert_main_yields_cli_failure_not_usage_skip(probe, capsys)
636
+
637
+ def should_exit_zero_with_null_report_when_json_rpc_error_payload(
638
+ self,
639
+ capsys: pytest.CaptureFixture[str],
640
+ monkeypatch: pytest.MonkeyPatch,
641
+ ) -> None:
642
+ probe = load_probe_module()
643
+
644
+ def error_payload_exchange(
645
+ all_request_messages: list[dict[str, object]],
646
+ ) -> list[str]:
647
+ del all_request_messages
648
+ return _app_server_lines_from_rate_limits_payload(
649
+ JSON_RPC_ERROR_APP_SERVER_REPLY
650
+ )
651
+
652
+ monkeypatch.setattr(
653
+ probe,
654
+ "_exchange_app_server_messages_via_subprocess",
655
+ error_payload_exchange,
656
+ )
657
+ _assert_main_yields_null_skip_report(probe, capsys)
658
+
659
+ def should_exit_nonzero_when_unicode_decode_error(
660
+ self,
661
+ capsys: pytest.CaptureFixture[str],
662
+ monkeypatch: pytest.MonkeyPatch,
663
+ ) -> None:
664
+ probe = load_probe_module()
665
+
666
+ def unicode_decode_error_exchange(
667
+ all_request_messages: list[dict[str, object]],
668
+ ) -> list[str]:
669
+ del all_request_messages
670
+ raise UnicodeDecodeError(
671
+ "utf-8",
672
+ b"\xff",
673
+ 0,
674
+ 1,
675
+ "invalid start byte",
676
+ )
677
+
678
+ monkeypatch.setattr(
679
+ probe,
680
+ "_exchange_app_server_messages_via_subprocess",
681
+ unicode_decode_error_exchange,
682
+ )
683
+ _assert_main_yields_cli_failure_not_usage_skip(probe, capsys)