claude-dev-env 4.3.0 → 7.1.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 (480) hide show
  1. package/.agents/agents/pr-description-writer.md +2 -2
  2. package/.agents/agents/test_agent_frontmatter.py +2 -2
  3. package/.agents/agents/test_pr_description_writer_style.py +1 -3
  4. package/.agents/skills/e-code-review/SKILL.md +12 -12
  5. package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
  6. package/.agents/skills/e-code-review/reference/fix.md +15 -17
  7. package/.agents/skills/e-code-review/reference/loop.md +35 -39
  8. package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
  9. package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
  10. package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
  11. package/.agents/skills/issue-tracker/SKILL.md +5 -4
  12. package/.agents/skills/pull-request/SKILL.md +11 -13
  13. package/.agents/skills/pull-request/reference/publication-tasks.md +3 -3
  14. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +9 -1
  15. package/.agents/skills/pull-request/scripts/pull_request.py +35 -44
  16. package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +9 -0
  17. package/.agents/skills/pull-request/scripts/test_pull_request.py +35 -3
  18. package/.agents/skills/session-continuity/README.md +189 -0
  19. package/.agents/skills/session-continuity/SKILL.md +114 -0
  20. package/.agents/skills/session-continuity/continuity.mjs +375 -0
  21. package/.agents/skills/session-continuity/continuity.test.mjs +303 -0
  22. package/.agents/skills/skill-builder/SKILL.md +3 -196
  23. package/.agents/skills/syncing-submodules/scripts/test_sync_parent_pointer.py +0 -7
  24. package/.agents/skills/windows-scheduled-task/SKILL.md +153 -0
  25. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
  26. package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
  27. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
  28. package/bin/cde.mjs +36 -8
  29. package/bin/cde.test.mjs +48 -0
  30. package/bin/ever-shipped-skills.mjs +2 -20
  31. package/bin/ever-shipped-skills.test.mjs +8 -0
  32. package/bin/expand_home_directory_tokens.mjs +4 -5
  33. package/bin/expand_home_directory_tokens.test.mjs +128 -0
  34. package/bin/git_hooks_installer.mjs +22 -3
  35. package/bin/git_hooks_installer.test.mjs +159 -5
  36. package/bin/install-session-continuity.mjs +78 -0
  37. package/bin/install-session-continuity.test.mjs +42 -0
  38. package/bin/install.agents-home.test.mjs +15 -13
  39. package/bin/install.codex-rules.test.mjs +5 -2
  40. package/bin/install.cursor-rules.test.mjs +5 -2
  41. package/bin/install.mjs +506 -63
  42. package/bin/install.policy-lint.test.mjs +130 -0
  43. package/bin/install.profiles.test.mjs +10 -0
  44. package/bin/install.prune.test.mjs +286 -37
  45. package/bin/install.pstack-plugin.test.mjs +114 -0
  46. package/bin/install.test.mjs +537 -120
  47. package/bin/install.transaction.test.mjs +3 -3
  48. package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
  49. package/docs/CODE_RULES.md +1 -1
  50. package/hooks/advisory/pr_done_reminder.py +342 -0
  51. package/hooks/advisory/test_pr_done_reminder.py +249 -0
  52. package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
  53. package/hooks/blocking/code_rules_banned_identifiers.py +3 -0
  54. package/hooks/blocking/code_rules_paired_test.py +22 -15
  55. package/hooks/blocking/precommit_code_rules_gate.py +5 -8
  56. package/hooks/blocking/test_bash_dispatcher_interpreter_starts.py +7 -52
  57. package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
  58. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -69
  59. package/hooks/blocking/test_code_rules_banned_identifiers.py +64 -0
  60. package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
  61. package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
  62. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
  63. package/hooks/blocking/test_pre_tool_use_dispatcher.py +43 -342
  64. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
  65. package/hooks/blocking/test_shared_stdin_adoption.py +1 -47
  66. package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
  67. package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +116 -0
  68. package/hooks/git-hooks/post_commit.py +33 -0
  69. package/hooks/git-hooks/pre_commit.py +18 -49
  70. package/hooks/git-hooks/pre_push.py +45 -541
  71. package/hooks/git-hooks/test_installed_policy_lint.py +208 -0
  72. package/hooks/git-hooks/test_native_hook_support.py +129 -0
  73. package/hooks/git-hooks/test_native_policy_commit.py +120 -0
  74. package/hooks/git-hooks/test_post_commit.py +43 -0
  75. package/hooks/git-hooks/test_pre_commit.py +38 -148
  76. package/hooks/git-hooks/test_pre_push.py +48 -1631
  77. package/hooks/git-hooks/test_verification_notice.py +60 -0
  78. package/hooks/git-hooks/test_verification_start.py +173 -0
  79. package/hooks/git-hooks/verification_notice.py +192 -0
  80. package/hooks/git-hooks/verification_notice_context.py +253 -0
  81. package/hooks/git-hooks/verification_notice_state.py +237 -0
  82. package/hooks/git-hooks/verification_start.py +100 -0
  83. package/hooks/hooks.json +1 -120
  84. package/hooks/hooks_constants/banned_identifiers_constants.py +4 -0
  85. package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
  86. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +1 -15
  87. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -4
  88. package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
  89. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -93
  90. package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -4
  91. package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
  92. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +3 -66
  93. package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
  94. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +46 -201
  95. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +3 -25
  96. package/hooks/validation/test_post_tool_use_dispatcher.py +35 -298
  97. package/hooks/validators/run_all_validators.py +5 -1
  98. package/hooks/validators/security_checks.py +57 -2
  99. package/hooks/validators/test_hook_timing_harness.py +2 -5
  100. package/hooks/validators/test_run_all_validators_mutation_tool_parity.py +3 -11
  101. package/hooks/validators/test_run_all_validators_policy_lint.py +36 -0
  102. package/hooks/validators/test_security_checks.py +57 -0
  103. package/package.json +2 -2
  104. package/rules/confirm-implementation-forks.md +2 -0
  105. package/rules/durable-post-artifacts.md +2 -1
  106. package/rules/git-workflow.md +18 -6
  107. package/rules/pstack-host-mapping.md +48 -0
  108. package/rules/vault-context.md +3 -5
  109. package/rules/verify-runtime-state.md +7 -0
  110. package/scripts/audit-hooks-cli.mjs +5 -0
  111. package/scripts/audit-hooks.mjs +72 -16
  112. package/scripts/automatic_advisory/__init__.py +1 -0
  113. package/scripts/automatic_advisory/checkout.py +51 -0
  114. package/scripts/automatic_advisory/cli.py +334 -0
  115. package/scripts/automatic_advisory/config/__init__.py +1 -0
  116. package/scripts/automatic_advisory/config/constants.py +93 -0
  117. package/scripts/automatic_advisory/config/timing.py +4 -0
  118. package/scripts/automatic_advisory/configuration.py +197 -0
  119. package/scripts/automatic_advisory/execution.py +350 -0
  120. package/scripts/automatic_advisory/git.py +69 -0
  121. package/scripts/automatic_advisory/model.py +107 -0
  122. package/scripts/automatic_advisory/process_host.py +32 -0
  123. package/scripts/automatic_advisory/publisher.py +84 -0
  124. package/scripts/automatic_advisory/runner.py +399 -0
  125. package/scripts/automatic_advisory/state.py +116 -0
  126. package/scripts/automatic_advisory/window_flags.py +41 -0
  127. package/scripts/automatic_advisory/windows_job.py +122 -0
  128. package/scripts/check.ps1 +0 -1
  129. package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
  130. package/scripts/ci/installer-lifecycle.test.mjs +26 -0
  131. package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
  132. package/scripts/codex_compat_materializer.py +99 -13
  133. package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
  134. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +35 -43
  135. package/{.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py → scripts/durable_post_lint_config/config/constants.py} +10 -10
  136. package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +14 -1
  137. package/scripts/local_report_cli.py +184 -0
  138. package/scripts/local_report_core.py +247 -0
  139. package/scripts/local_report_publisher.py +12 -0
  140. package/scripts/local_report_validation.py +357 -0
  141. package/scripts/local_verification/__init__.py +23 -0
  142. package/scripts/local_verification/check_runner.py +364 -0
  143. package/scripts/local_verification/check_support.py +99 -0
  144. package/scripts/local_verification/cli.py +158 -0
  145. package/scripts/local_verification/command_runner.py +84 -0
  146. package/scripts/local_verification/config/__init__.py +1 -0
  147. package/scripts/local_verification/config/constants.py +89 -0
  148. package/scripts/local_verification/config/timing.py +1 -0
  149. package/scripts/local_verification/git_state.py +146 -0
  150. package/scripts/local_verification/manifest.py +224 -0
  151. package/scripts/local_verification/model.py +174 -0
  152. package/scripts/local_verification/runner.py +234 -0
  153. package/scripts/policy_lint/adapter_detectors.py +13 -6
  154. package/scripts/policy_lint/adapter_pairing.py +58 -3
  155. package/scripts/policy_lint/adapters.py +7 -4
  156. package/scripts/policy_lint/config/approved_test_pairs.py +323 -0
  157. package/scripts/policy_lint/config/constants.py +5 -0
  158. package/scripts/policy_lint/engine.py +48 -4
  159. package/scripts/policy_lint/model.py +1 -0
  160. package/scripts/policy_lint/registry.py +1 -1
  161. package/scripts/policy_lint/selection.py +2 -1
  162. package/scripts/policy_lint/selection_git.py +2 -0
  163. package/scripts/pr_verification/__init__.py +1 -0
  164. package/scripts/pr_verification/branch_refs.py +114 -0
  165. package/scripts/pr_verification/config/__init__.py +1 -0
  166. package/scripts/pr_verification/config/constants.py +84 -0
  167. package/scripts/pr_verification/config/timing.py +5 -0
  168. package/scripts/pr_verification/github.py +137 -0
  169. package/scripts/pr_verification/github_api.py +376 -0
  170. package/scripts/pr_verification/github_labels.py +88 -0
  171. package/scripts/pr_verification/github_parsing.py +182 -0
  172. package/scripts/pr_verification/github_transport.py +91 -0
  173. package/scripts/pr_verification/lock.py +122 -0
  174. package/scripts/pr_verification/model.py +43 -0
  175. package/scripts/pr_verification/requirements.txt +1 -0
  176. package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
  177. package/scripts/shared_tree_paths.py +32 -3
  178. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/test_durable_post_lint.py +97 -0
  179. package/scripts/test_shared_tree_paths.py +33 -0
  180. package/scripts/tests/test-audit-hooks-cli.mjs +150 -0
  181. package/scripts/tests/test-audit-hooks.mjs +94 -2
  182. package/scripts/tests/test_automatic_advisory.py +376 -0
  183. package/scripts/tests/test_automatic_advisory_job_cleanup.py +71 -0
  184. package/scripts/tests/test_automatic_advisory_polling.py +216 -0
  185. package/scripts/tests/test_automatic_advisory_recovery.py +320 -0
  186. package/scripts/tests/test_automatic_advisory_repairs.py +400 -0
  187. package/scripts/tests/test_automatic_advisory_settings.py +48 -0
  188. package/scripts/tests/test_automatic_advisory_window_flags.py +163 -0
  189. package/scripts/tests/test_closed_pr_label.py +157 -0
  190. package/scripts/tests/test_codex_compat_materializer.py +189 -6
  191. package/scripts/tests/test_github_labels.py +101 -0
  192. package/scripts/tests/test_github_transport.py +125 -0
  193. package/scripts/tests/test_local_report_publisher.py +396 -0
  194. package/scripts/tests/test_local_report_publisher_cli.py +85 -0
  195. package/scripts/tests/test_local_verification.py +348 -0
  196. package/scripts/tests/test_local_verification_cli.py +98 -0
  197. package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
  198. package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
  199. package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
  200. package/scripts/tests/test_policy_lint_rules_pairing.py +163 -0
  201. package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
  202. package/scripts/tests/test_policy_lint_selection.py +25 -2
  203. package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
  204. package/scripts/tests/test_pr_verification_github.py +392 -0
  205. package/scripts/tests/test_pr_verification_lock.py +168 -0
  206. package/scripts/tests/test_rules.py +3 -7
  207. package/scripts/tests/test_verification_notice.py +347 -0
  208. package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
  209. package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
  210. package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
  211. package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
  212. package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
  213. package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
  214. package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
  215. package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
  216. package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
  217. package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
  218. package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
  219. package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
  220. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
  221. package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
  222. package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
  223. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
  224. package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
  225. package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
  226. package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
  227. package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
  228. package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
  229. package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
  230. package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
  231. package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
  232. package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
  233. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
  234. package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
  235. package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
  236. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
  237. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
  238. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
  239. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
  240. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
  241. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
  242. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
  243. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
  244. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
  245. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
  246. package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
  247. package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
  248. package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
  249. package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
  250. package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
  251. package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
  252. package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
  253. package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
  254. package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
  255. package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
  256. package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
  257. package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
  258. package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
  259. package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
  260. package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
  261. package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
  262. package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
  263. package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
  264. package/.agents/skills/autoconverge/AGENTS.md +0 -1
  265. package/.agents/skills/autoconverge/SKILL.md +0 -431
  266. package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
  267. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
  268. package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
  269. package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
  270. package/.agents/skills/autoconverge/reference/convergence.md +0 -219
  271. package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
  272. package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
  273. package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
  274. package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
  275. package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
  276. package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
  277. package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
  278. package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
  279. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
  280. package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
  281. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
  282. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
  283. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
  284. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
  285. package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
  286. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
  287. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
  288. package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
  289. package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
  290. package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
  291. package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
  292. package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
  293. package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
  294. package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
  295. package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
  296. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
  297. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
  298. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
  299. package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
  300. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
  301. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
  302. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
  303. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
  304. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
  305. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
  306. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
  307. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
  308. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
  309. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
  310. package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
  311. package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
  312. package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
  313. package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
  314. package/.agents/skills/hitl/SKILL.md +0 -45
  315. package/.agents/skills/pr-cleanup/SKILL.md +0 -140
  316. package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
  317. package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
  318. package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
  319. package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
  320. package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
  321. package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
  322. package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
  323. package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
  324. package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
  325. package/.agents/skills/pr-refinement/SKILL.md +0 -31
  326. package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
  327. package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
  328. package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
  329. package/.agents/skills/pr-small-cl/SKILL.md +0 -52
  330. package/.agents/skills/pr-title-description/SKILL.md +0 -96
  331. package/.agents/skills/prototype/SKILL.md +0 -85
  332. package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
  333. package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
  334. package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
  335. package/.agents/skills/prototype/scripts/conftest.py +0 -15
  336. package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
  337. package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
  338. package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
  339. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  340. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
  341. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
  342. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
  343. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
  344. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
  345. package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
  346. package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
  347. package/.agents/skills/prototype/workflows/promotion.md +0 -25
  348. package/.agents/skills/prototype/workflows/sandbox.md +0 -35
  349. package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
  350. package/.agents/skills/rebase/AGENTS.md +0 -1
  351. package/.agents/skills/rebase/SKILL.md +0 -178
  352. package/.agents/skills/review-router/SKILL.md +0 -51
  353. package/.agents/skills/review-router/reference/route-policy.json +0 -7
  354. package/.agents/skills/review-router/reference/task-seeds.md +0 -1
  355. package/.agents/skills/review-router/scripts/conftest.py +0 -4
  356. package/.agents/skills/review-router/scripts/review_router.py +0 -50
  357. package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
  358. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
  359. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  360. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
  361. package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
  362. package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
  363. package/.agents/skills/review-tier/SKILL.md +0 -56
  364. package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
  365. package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
  366. package/.agents/skills/review-tier/scripts/conftest.py +0 -4
  367. package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
  368. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
  369. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  370. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
  371. package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
  372. package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
  373. package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
  374. package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
  375. package/.agents/skills/session-log/AGENTS.md +0 -1
  376. package/.agents/skills/session-log/SKILL.md +0 -170
  377. package/.agents/skills/session-log/templates/frontmatter.md +0 -40
  378. package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
  379. package/.agents/skills/session-tidy/AGENTS.md +0 -1
  380. package/.agents/skills/session-tidy/SKILL.md +0 -191
  381. package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
  382. package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
  383. package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
  384. package/.agents/skills/skill-builder/references/description-field.md +0 -111
  385. package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
  386. package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
  387. package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
  388. package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
  389. package/.agents/skills/skill-builder/references/skill-types.md +0 -232
  390. package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
  391. package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
  392. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
  393. package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
  394. package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
  395. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
  396. package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
  397. package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
  398. package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
  399. package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
  400. package/.agents/skills/update/.claude/CLAUDE.md +0 -1
  401. package/.agents/skills/update/AGENTS.md +0 -1
  402. package/.agents/skills/update/SKILL.md +0 -190
  403. package/_shared/pr-loop/AGENTS.md +0 -1
  404. package/_shared/pr-loop/audit-contract.md +0 -183
  405. package/_shared/pr-loop/audit-reply-template.md +0 -151
  406. package/_shared/pr-loop/code-rules-gate.md +0 -65
  407. package/_shared/pr-loop/fix-protocol.md +0 -60
  408. package/_shared/pr-loop/gh-payloads.md +0 -75
  409. package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
  410. package/_shared/pr-loop/precatch-rubric.md +0 -66
  411. package/_shared/pr-loop/preflight-proposal.md +0 -56
  412. package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
  413. package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
  414. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
  415. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
  416. package/_shared/pr-loop/state-schema.md +0 -45
  417. package/_shared/pr-loop/worker-spawn.md +0 -189
  418. package/hooks/blocking/ask_user_question_shape_blocker.py +0 -83
  419. package/hooks/blocking/bot_mention_comment_blocker.py +0 -76
  420. package/hooks/blocking/claude_md_orphan_file_blocker.py +0 -129
  421. package/hooks/blocking/cursor_cli_python_misfire_blocker.py +0 -108
  422. package/hooks/blocking/destructive_command_blocker.py +0 -2073
  423. package/hooks/blocking/fable_spawn_gate.py +0 -187
  424. package/hooks/blocking/luna_fast_mode_gate.py +0 -160
  425. package/hooks/blocking/nas_ssh_binary_enforcer.py +0 -163
  426. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +0 -260
  427. package/hooks/blocking/package_inventory_stale_blocker.py +0 -107
  428. package/hooks/blocking/pii_prevention_blocker.py +0 -365
  429. package/hooks/blocking/piped_pytest_blocker.py +0 -1223
  430. package/hooks/blocking/question_to_user_enforcer.py +0 -130
  431. package/hooks/blocking/send_user_file_open_locally_blocker.py +0 -71
  432. package/hooks/blocking/sensitive_file_protector.py +0 -167
  433. package/hooks/blocking/session_edit_stage_gate.py +0 -684
  434. package/hooks/blocking/session_handoff_blocker.py +0 -182
  435. package/hooks/blocking/shell_substitution_blocker.py +0 -350
  436. package/hooks/blocking/test_ask_user_question_shape.py +0 -69
  437. package/hooks/blocking/test_bot_mention_comment_blocker.py +0 -131
  438. package/hooks/blocking/test_claude_md_orphan_file_blocker.py +0 -1277
  439. package/hooks/blocking/test_cursor_cli_python_misfire_blocker.py +0 -208
  440. package/hooks/blocking/test_destructive_command_blocker.py +0 -2024
  441. package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +0 -105
  442. package/hooks/blocking/test_destructive_command_blocker_no_verify.py +0 -122
  443. package/hooks/blocking/test_destructive_command_blocker_patterns.py +0 -133
  444. package/hooks/blocking/test_fable_spawn_gate.py +0 -381
  445. package/hooks/blocking/test_inventory_deadlock_resolution.py +0 -154
  446. package/hooks/blocking/test_luna_fast_mode_gate.py +0 -211
  447. package/hooks/blocking/test_nas_ssh_binary_enforcer.py +0 -225
  448. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +0 -231
  449. package/hooks/blocking/test_package_inventory_stale_blocker.py +0 -382
  450. package/hooks/blocking/test_pii_prevention_blocker.py +0 -1222
  451. package/hooks/blocking/test_pii_prevention_windows_git_path.py +0 -41
  452. package/hooks/blocking/test_pii_write_surface_ephemeral.py +0 -221
  453. package/hooks/blocking/test_piped_pytest_blocker.py +0 -587
  454. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +0 -233
  455. package/hooks/blocking/test_question_to_user_enforcer.py +0 -169
  456. package/hooks/blocking/test_send_user_file_open_locally_blocker.py +0 -118
  457. package/hooks/blocking/test_sensitive_file_protector.py +0 -365
  458. package/hooks/blocking/test_session_edit_stage_gate.py +0 -537
  459. package/hooks/blocking/test_session_edit_stage_gate_staging.py +0 -64
  460. package/hooks/blocking/test_session_edit_stage_gate_support.py +0 -204
  461. package/hooks/blocking/test_session_edit_stage_gate_tracker.py +0 -116
  462. package/hooks/blocking/test_session_handoff_blocker.py +0 -318
  463. package/hooks/blocking/test_shell_substitution_blocker.py +0 -298
  464. package/hooks/blocking/test_unscoped_search_blocker.py +0 -102
  465. package/hooks/blocking/test_write_existing_file_blocker.py +0 -122
  466. package/hooks/blocking/tests/test_pii_prevention_blocker.py +0 -259
  467. package/hooks/blocking/unscoped_search_blocker.py +0 -391
  468. package/hooks/blocking/write_existing_file_blocker.py +0 -124
  469. package/hooks/hooks_constants/bot_mention_comment_blocker_constants.py +0 -19
  470. package/hooks/hooks_constants/cursor_cli_python_misfire_blocker_constants.py +0 -79
  471. package/hooks/hooks_constants/fable_spawn_gate_constants.py +0 -61
  472. package/hooks/hooks_constants/luna_fast_mode_gate_constants.py +0 -45
  473. package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +0 -20
  474. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +0 -57
  475. package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +0 -17
  476. package/hooks/hooks_constants/sensitive_file_protector_constants.py +0 -40
  477. package/hooks/hooks_constants/session_handoff_blocker_constants.py +0 -10
  478. package/hooks/hooks_constants/shell_substitution_blocker_constants.py +0 -80
  479. /package/.agents/skills/{_shared/pr-loop → session-continuity}/AGENTS.md +0 -0
  480. /package/{_shared/pr-loop → .agents/skills/session-continuity}/CLAUDE.md +0 -0
@@ -0,0 +1,399 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from pathlib import Path
5
+ from typing import Protocol
6
+
7
+ from pr_verification.config.constants import LOCAL_CHECKS_PASSED_LABEL
8
+ from pr_verification.lock import SupervisorLock
9
+ from pr_verification.model import PullRequestCandidate, RepositorySettings
10
+
11
+ from .checkout import read_local_checkout as _read_local_checkout
12
+ from .config.constants import (
13
+ GIT_BASE_REF_TEMPLATE,
14
+ STATE_REASON_BASE_FETCH_FAILED,
15
+ STATE_REASON_CHECKOUT_MISMATCH,
16
+ STATE_REASON_CHILD_INCOMPLETE,
17
+ STATE_REASON_DIRTY_CHECKOUT,
18
+ STATE_REASON_GITHUB_UNAVAILABLE,
19
+ STATE_REASON_PUBLISH_FAILED,
20
+ STATE_REASON_PULL_REQUEST_CLOSED,
21
+ STATE_REASON_UNCHANGED,
22
+ STATE_STATUS_CLOSED,
23
+ STATE_STATUS_ERROR,
24
+ STATE_STATUS_OFFLINE,
25
+ STATE_STATUS_PASSED,
26
+ STATE_STATUS_WAITING,
27
+ )
28
+ from .execution import _child_produced_report, run_verification_child
29
+ from .git import _fetch_base
30
+ from .model import (
31
+ AdvisoryRegistration,
32
+ AdvisorySettings,
33
+ AdvisoryState,
34
+ ChildOutcome,
35
+ candidate_identity_matches_state,
36
+ )
37
+ from .publisher import Publication, _cache_status_for_publication, _publish_report
38
+ from .state import _utc_timestamp
39
+ from .state import read_state as _read_state
40
+ from .state import write_state as _write_state
41
+
42
+
43
+ class AdvisoryGitHub(Protocol):
44
+ def list_open_candidates(
45
+ self,
46
+ repository: RepositorySettings,
47
+ *,
48
+ should_require_merge_commit: bool = True,
49
+ ) -> tuple[PullRequestCandidate, ...]: ...
50
+
51
+ def remove_label(
52
+ self, repository: RepositorySettings, pull_request_number: int, label: str
53
+ ) -> None: ...
54
+
55
+
56
+ AdvisoryPublisher = Callable[
57
+ [object, RepositorySettings, int, Path, Path, Path], Publication
58
+ ]
59
+ ChildRunner = Callable[[AdvisoryRegistration, str, float], ChildOutcome]
60
+ AdvisoryGitHubFactory = Callable[[RepositorySettings], AdvisoryGitHub]
61
+ Clock = Callable[[], str]
62
+
63
+
64
+ class AutomaticAdvisoryRunner:
65
+ def __init__(
66
+ self,
67
+ settings: AdvisorySettings,
68
+ github: AdvisoryGitHub | None,
69
+ *,
70
+ child_runner: ChildRunner | None = None,
71
+ publisher: AdvisoryPublisher | None = None,
72
+ github_factory: AdvisoryGitHubFactory | None = None,
73
+ clock: Clock | None = None,
74
+ ) -> None:
75
+ self.settings = settings
76
+ self.github = github
77
+ self.child_runner = child_runner or run_verification_child
78
+ self.publisher = publisher or _publish_report
79
+ if github_factory is not None:
80
+ self.github_factory = github_factory
81
+ elif github is not None:
82
+ self.github_factory = lambda _repository: github
83
+ else:
84
+ self.github_factory = _github_is_unavailable
85
+ self.clock = clock or _utc_timestamp
86
+
87
+ def run_once(self, should_rerun: bool = False) -> tuple[AdvisoryState, ...]:
88
+ """Run each registration once and return its persisted state.
89
+
90
+ Args:
91
+ should_rerun: True to force a fresh run for every registration.
92
+
93
+ Returns:
94
+ The persisted state of each registration, in settings order.
95
+ """
96
+ return tuple(
97
+ self.run_registration(each_registration, should_rerun)
98
+ for each_registration in self.settings.registrations
99
+ )
100
+
101
+ def run_registration(
102
+ self,
103
+ registration: AdvisoryRegistration,
104
+ should_rerun: bool,
105
+ ) -> AdvisoryState:
106
+ with SupervisorLock(registration.repository_lock_root):
107
+ return self._run_registration_locked(registration, should_rerun)
108
+
109
+ def _run_registration_locked(
110
+ self,
111
+ registration: AdvisoryRegistration,
112
+ should_rerun: bool,
113
+ ) -> AdvisoryState:
114
+ github_or_state = self._get_github(registration)
115
+ if isinstance(github_or_state, AdvisoryState):
116
+ return github_or_state
117
+ github = github_or_state
118
+ candidate_or_state = self._discover_candidate(registration, github)
119
+ if isinstance(candidate_or_state, AdvisoryState):
120
+ return candidate_or_state
121
+ maybe_previous_state = _read_state(registration.state_path)
122
+ maybe_invalidation_state = self._invalidate_changed_identity(
123
+ registration, candidate_or_state, maybe_previous_state, github
124
+ )
125
+ if maybe_invalidation_state is not None:
126
+ return maybe_invalidation_state
127
+ maybe_blocked_state = self._prepare_candidate(registration, candidate_or_state)
128
+ if maybe_blocked_state is not None:
129
+ return maybe_blocked_state
130
+ return self._run_ready_candidate(
131
+ registration,
132
+ candidate_or_state,
133
+ maybe_previous_state,
134
+ should_rerun,
135
+ )
136
+
137
+ def _get_github(
138
+ self, registration: AdvisoryRegistration
139
+ ) -> AdvisoryGitHub | AdvisoryState:
140
+ try:
141
+ return self.github_factory(registration.repository)
142
+ except (OSError, RuntimeError):
143
+ return self._save_state(
144
+ registration,
145
+ STATE_STATUS_OFFLINE,
146
+ STATE_REASON_GITHUB_UNAVAILABLE,
147
+ None,
148
+ None,
149
+ )
150
+
151
+ def _discover_candidate(
152
+ self, registration: AdvisoryRegistration, github: AdvisoryGitHub
153
+ ) -> PullRequestCandidate | AdvisoryState:
154
+ try:
155
+ maybe_candidate = self._find_open_candidate(registration, github)
156
+ except (OSError, RuntimeError):
157
+ return self._save_state(
158
+ registration,
159
+ STATE_STATUS_OFFLINE,
160
+ STATE_REASON_GITHUB_UNAVAILABLE,
161
+ None,
162
+ None,
163
+ )
164
+ if maybe_candidate is None:
165
+ if not self._remove_pass_label_safely(registration, github):
166
+ return self._save_state(
167
+ registration,
168
+ STATE_STATUS_ERROR,
169
+ STATE_REASON_PUBLISH_FAILED,
170
+ None,
171
+ None,
172
+ )
173
+ return self._save_state(
174
+ registration,
175
+ STATE_STATUS_CLOSED,
176
+ STATE_REASON_PULL_REQUEST_CLOSED,
177
+ None,
178
+ None,
179
+ )
180
+ return maybe_candidate
181
+
182
+ def _run_ready_candidate(
183
+ self,
184
+ registration: AdvisoryRegistration,
185
+ candidate: PullRequestCandidate,
186
+ maybe_previous_state: AdvisoryState | None,
187
+ should_rerun: bool,
188
+ ) -> AdvisoryState:
189
+ if (
190
+ not should_rerun
191
+ and maybe_previous_state is not None
192
+ and candidate_identity_matches_state(candidate, maybe_previous_state)
193
+ ):
194
+ return self._save_state(
195
+ registration,
196
+ maybe_previous_state.status,
197
+ STATE_REASON_UNCHANGED,
198
+ candidate,
199
+ maybe_previous_state.last_run,
200
+ )
201
+ return self._execute_and_publish(registration, candidate)
202
+
203
+ def _invalidate_changed_identity(
204
+ self,
205
+ registration: AdvisoryRegistration,
206
+ candidate: PullRequestCandidate,
207
+ maybe_previous_state: AdvisoryState | None,
208
+ github: AdvisoryGitHub,
209
+ ) -> AdvisoryState | None:
210
+ if (
211
+ maybe_previous_state is not None
212
+ and maybe_previous_state.status == STATE_STATUS_PASSED
213
+ and candidate_identity_matches_state(candidate, maybe_previous_state)
214
+ ):
215
+ return None
216
+ if self._remove_pass_label_safely(registration, github):
217
+ return None
218
+ return self._save_state(
219
+ registration,
220
+ STATE_STATUS_ERROR,
221
+ STATE_REASON_PUBLISH_FAILED,
222
+ candidate,
223
+ None,
224
+ )
225
+
226
+ def _execute_and_publish(
227
+ self,
228
+ registration: AdvisoryRegistration,
229
+ candidate: PullRequestCandidate,
230
+ ) -> AdvisoryState:
231
+ maybe_child_state = self._run_child(registration, candidate)
232
+ if maybe_child_state is not None:
233
+ return maybe_child_state
234
+ try:
235
+ fresh_github = self.github_factory(registration.repository)
236
+ except (OSError, RuntimeError):
237
+ return self._save_state(
238
+ registration,
239
+ STATE_STATUS_OFFLINE,
240
+ STATE_REASON_GITHUB_UNAVAILABLE,
241
+ candidate,
242
+ self.clock(),
243
+ )
244
+ return self._publish_and_save(
245
+ registration,
246
+ candidate,
247
+ fresh_github,
248
+ )
249
+
250
+ def _run_child(
251
+ self,
252
+ registration: AdvisoryRegistration,
253
+ candidate: PullRequestCandidate,
254
+ ) -> AdvisoryState | None:
255
+ child_outcome = self.child_runner(
256
+ registration,
257
+ GIT_BASE_REF_TEMPLATE.format(pull_request=registration.pull_request_number),
258
+ self.settings.child_timeout_seconds,
259
+ )
260
+ if _child_produced_report(child_outcome, registration):
261
+ return None
262
+ return self._save_state(
263
+ registration,
264
+ STATE_STATUS_ERROR,
265
+ STATE_REASON_CHILD_INCOMPLETE,
266
+ candidate,
267
+ self.clock(),
268
+ )
269
+
270
+ def _prepare_candidate(
271
+ self,
272
+ registration: AdvisoryRegistration,
273
+ candidate: PullRequestCandidate,
274
+ ) -> AdvisoryState | None:
275
+ if not _fetch_base(registration, candidate):
276
+ return self._save_state(
277
+ registration,
278
+ STATE_STATUS_OFFLINE,
279
+ STATE_REASON_BASE_FETCH_FAILED,
280
+ candidate,
281
+ None,
282
+ )
283
+ return self._check_local_checkout(registration, candidate)
284
+
285
+ def _check_local_checkout(
286
+ self,
287
+ registration: AdvisoryRegistration,
288
+ candidate: PullRequestCandidate,
289
+ ) -> AdvisoryState | None:
290
+ local_checkout = _read_local_checkout(registration.checkout_path)
291
+ if not local_checkout.is_clean:
292
+ return self._save_state(
293
+ registration,
294
+ STATE_STATUS_WAITING,
295
+ STATE_REASON_DIRTY_CHECKOUT,
296
+ candidate,
297
+ None,
298
+ )
299
+ if local_checkout.head_sha != candidate.head_sha:
300
+ return self._save_state(
301
+ registration,
302
+ STATE_STATUS_WAITING,
303
+ STATE_REASON_CHECKOUT_MISMATCH,
304
+ candidate,
305
+ None,
306
+ )
307
+ return None
308
+
309
+ def _remove_pass_label_safely(
310
+ self, registration: AdvisoryRegistration, github: AdvisoryGitHub
311
+ ) -> bool:
312
+ try:
313
+ self._remove_pass_label(registration, github)
314
+ except (OSError, RuntimeError):
315
+ return False
316
+ return True
317
+
318
+ def _find_open_candidate(
319
+ self, registration: AdvisoryRegistration, github: AdvisoryGitHub
320
+ ) -> PullRequestCandidate | None:
321
+ all_candidates = github.list_open_candidates(
322
+ registration.repository,
323
+ should_require_merge_commit=False,
324
+ )
325
+ return next(
326
+ (
327
+ each_candidate
328
+ for each_candidate in all_candidates
329
+ if each_candidate.pull_request_number
330
+ == registration.pull_request_number
331
+ ),
332
+ None,
333
+ )
334
+
335
+ def _remove_pass_label(
336
+ self, registration: AdvisoryRegistration, github: AdvisoryGitHub
337
+ ) -> None:
338
+ github.remove_label(
339
+ registration.repository,
340
+ registration.pull_request_number,
341
+ LOCAL_CHECKS_PASSED_LABEL,
342
+ )
343
+
344
+ def _publish_and_save(
345
+ self,
346
+ registration: AdvisoryRegistration,
347
+ candidate: PullRequestCandidate,
348
+ github: AdvisoryGitHub,
349
+ ) -> AdvisoryState:
350
+ try:
351
+ publication = self.publisher(
352
+ github,
353
+ registration.repository,
354
+ registration.pull_request_number,
355
+ registration.checkout_path,
356
+ registration.selected_manifest_path,
357
+ registration.report_path,
358
+ )
359
+ except (OSError, RuntimeError):
360
+ return self._save_state(
361
+ registration,
362
+ STATE_STATUS_ERROR,
363
+ STATE_REASON_PUBLISH_FAILED,
364
+ candidate,
365
+ self.clock(),
366
+ )
367
+ return self._save_state(
368
+ registration,
369
+ _cache_status_for_publication(publication.status),
370
+ publication.description,
371
+ candidate,
372
+ self.clock(),
373
+ )
374
+
375
+ def _save_state(
376
+ self,
377
+ registration: AdvisoryRegistration,
378
+ status: str,
379
+ reason: str,
380
+ maybe_candidate: PullRequestCandidate | None,
381
+ maybe_last_run: str | None,
382
+ ) -> AdvisoryState:
383
+ state = AdvisoryState(
384
+ registration.repository.slug,
385
+ registration.pull_request_number,
386
+ status,
387
+ reason,
388
+ maybe_candidate.head_sha if maybe_candidate else None,
389
+ maybe_candidate.base_sha if maybe_candidate else None,
390
+ self.clock(),
391
+ maybe_last_run,
392
+ str(registration.report_path),
393
+ )
394
+ _write_state(registration.state_path, state)
395
+ return state
396
+
397
+
398
+ def _github_is_unavailable(_repository: RepositorySettings) -> AdvisoryGitHub:
399
+ raise RuntimeError("GitHub client factory is unavailable")
@@ -0,0 +1,116 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ from collections.abc import Mapping
6
+ from datetime import UTC, datetime
7
+ from pathlib import Path
8
+
9
+ from .config.constants import (
10
+ JSON_INDENT_SPACES,
11
+ REPORT_NEWLINE,
12
+ STATE_BASE_SHA_KEY,
13
+ STATE_FILE_SUFFIX,
14
+ STATE_HEAD_SHA_KEY,
15
+ STATE_LAST_POLL_KEY,
16
+ STATE_LAST_RUN_KEY,
17
+ STATE_PULL_REQUEST_KEY,
18
+ STATE_REASON_KEY,
19
+ STATE_REPORT_KEY,
20
+ STATE_REPOSITORY_KEY,
21
+ STATE_STATUS_KEY,
22
+ STATE_VERSION,
23
+ STATE_VERSION_KEY,
24
+ UTF8_ENCODING,
25
+ )
26
+ from .model import AdvisoryState
27
+
28
+
29
+ def read_state(state_path: Path) -> AdvisoryState | None:
30
+ """Read one persisted advisory state when its shape is valid.
31
+
32
+ Args:
33
+ state_path: JSON state file to read.
34
+
35
+ Returns:
36
+ Parsed advisory state, or None when the file is absent or invalid.
37
+ """
38
+ try:
39
+ parsed_state = json.loads(state_path.read_text(encoding=UTF8_ENCODING))
40
+ except (OSError, json.JSONDecodeError):
41
+ return None
42
+ if not isinstance(parsed_state, Mapping):
43
+ return None
44
+ return _state_from_mapping(parsed_state)
45
+
46
+
47
+ def _state_from_mapping(
48
+ all_state_fields: Mapping[str, object],
49
+ ) -> AdvisoryState | None:
50
+ if all_state_fields.get(STATE_VERSION_KEY) != STATE_VERSION:
51
+ return None
52
+ try:
53
+ repository = _require_state_text(all_state_fields.get(STATE_REPOSITORY_KEY))
54
+ status = _require_state_text(all_state_fields.get(STATE_STATUS_KEY))
55
+ reason = _require_state_text(all_state_fields.get(STATE_REASON_KEY))
56
+ last_poll = _require_state_text(all_state_fields.get(STATE_LAST_POLL_KEY))
57
+ report_path = _require_state_text(all_state_fields.get(STATE_REPORT_KEY))
58
+ except TypeError:
59
+ return None
60
+ pull_request_number = all_state_fields.get(STATE_PULL_REQUEST_KEY)
61
+ if not isinstance(pull_request_number, int):
62
+ return None
63
+ return AdvisoryState(
64
+ repository,
65
+ pull_request_number,
66
+ status,
67
+ reason,
68
+ _optional_text(all_state_fields.get(STATE_HEAD_SHA_KEY)),
69
+ _optional_text(all_state_fields.get(STATE_BASE_SHA_KEY)),
70
+ last_poll,
71
+ _optional_text(all_state_fields.get(STATE_LAST_RUN_KEY)),
72
+ report_path,
73
+ )
74
+
75
+
76
+ def _require_state_text(state_field: object) -> str:
77
+ if not isinstance(state_field, str):
78
+ raise TypeError("state field must be text")
79
+ return state_field
80
+
81
+
82
+ def _optional_text(state_field: object) -> str | None:
83
+ return state_field if isinstance(state_field, str) else None
84
+
85
+
86
+ def write_state(state_path: Path, state: AdvisoryState) -> None:
87
+ """Atomically persist one advisory state.
88
+
89
+ Args:
90
+ state_path: Destination JSON state file.
91
+ state: State record to persist.
92
+ """
93
+ state_path.parent.mkdir(parents=True, exist_ok=True)
94
+ state_mapping = {
95
+ STATE_VERSION_KEY: STATE_VERSION,
96
+ STATE_REPOSITORY_KEY: state.repository,
97
+ STATE_PULL_REQUEST_KEY: state.pull_request_number,
98
+ STATE_STATUS_KEY: state.status,
99
+ STATE_REASON_KEY: state.reason,
100
+ STATE_HEAD_SHA_KEY: state.head_sha,
101
+ STATE_BASE_SHA_KEY: state.base_sha,
102
+ STATE_LAST_POLL_KEY: state.last_poll,
103
+ STATE_LAST_RUN_KEY: state.last_run,
104
+ STATE_REPORT_KEY: state.report_path,
105
+ }
106
+ temporary_state_path = state_path.with_name(state_path.name + STATE_FILE_SUFFIX)
107
+ temporary_state_path.write_text(
108
+ json.dumps(state_mapping, indent=JSON_INDENT_SPACES, sort_keys=True)
109
+ + REPORT_NEWLINE,
110
+ encoding=UTF8_ENCODING,
111
+ )
112
+ os.replace(temporary_state_path, state_path)
113
+
114
+
115
+ def _utc_timestamp() -> str:
116
+ return datetime.now(UTC).isoformat()
@@ -0,0 +1,41 @@
1
+ """Windows creation flags that hide the advisory poller and its children.
2
+
3
+ A poller with no console makes each git call and each check open a fresh
4
+ console window. A hidden console is inherited by descendants, so those
5
+ children stay off the screen.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import subprocess
11
+ import sys
12
+
13
+ from .config.constants import (
14
+ CREATE_NEW_PROCESS_GROUP_ATTRIBUTE,
15
+ CREATE_NO_WINDOW_ATTRIBUTE,
16
+ WINDOWS_PLATFORM,
17
+ )
18
+
19
+
20
+ def hidden_window_creation_flags() -> int:
21
+ """Return the flag that runs a Windows child without a visible console.
22
+
23
+ Returns:
24
+ The hidden-console flag on Windows, zero elsewhere.
25
+ """
26
+ if sys.platform != WINDOWS_PLATFORM:
27
+ return 0
28
+ return getattr(subprocess, CREATE_NO_WINDOW_ATTRIBUTE, 0)
29
+
30
+
31
+ def detached_poller_creation_flags() -> int:
32
+ """Return the flags for the long-running poller on Windows.
33
+
34
+ Returns:
35
+ A new process group plus a hidden console on Windows, zero elsewhere.
36
+ """
37
+ if sys.platform != WINDOWS_PLATFORM:
38
+ return 0
39
+ return getattr(subprocess, CREATE_NEW_PROCESS_GROUP_ATTRIBUTE, 0) | getattr(
40
+ subprocess, CREATE_NO_WINDOW_ATTRIBUTE, 0
41
+ )
@@ -0,0 +1,122 @@
1
+ from __future__ import annotations
2
+
3
+ import ctypes
4
+
5
+ from .config.constants import (
6
+ WINDOWS_EXTENDED_LIMIT_INFORMATION_CLASS,
7
+ WINDOWS_JOB_KILL_ON_CLOSE_LIMIT,
8
+ WINDOWS_PROCESS_SET_QUOTA_ACCESS,
9
+ WINDOWS_PROCESS_TERMINATE_ACCESS,
10
+ )
11
+
12
+
13
+ class _JobObjectBasicLimitInformation(ctypes.Structure):
14
+ _fields_ = [
15
+ ("PerProcessUserTimeLimit", ctypes.c_longlong),
16
+ ("PerJobUserTimeLimit", ctypes.c_longlong),
17
+ ("LimitFlags", ctypes.c_uint32),
18
+ ("MinimumWorkingSetSize", ctypes.c_size_t),
19
+ ("MaximumWorkingSetSize", ctypes.c_size_t),
20
+ ("ActiveProcessLimit", ctypes.c_uint32),
21
+ ("Affinity", ctypes.c_size_t),
22
+ ("PriorityClass", ctypes.c_uint32),
23
+ ("SchedulingClass", ctypes.c_uint32),
24
+ ]
25
+
26
+
27
+ class _IoCounters(ctypes.Structure):
28
+ _fields_ = [
29
+ ("ReadOperationCount", ctypes.c_ulonglong),
30
+ ("WriteOperationCount", ctypes.c_ulonglong),
31
+ ("OtherOperationCount", ctypes.c_ulonglong),
32
+ ("ReadTransferCount", ctypes.c_ulonglong),
33
+ ("WriteTransferCount", ctypes.c_ulonglong),
34
+ ("OtherTransferCount", ctypes.c_ulonglong),
35
+ ]
36
+
37
+
38
+ class _JobObjectExtendedLimitInformation(ctypes.Structure):
39
+ _fields_ = [
40
+ ("BasicLimitInformation", _JobObjectBasicLimitInformation),
41
+ ("IoInfo", _IoCounters),
42
+ ("ProcessMemoryLimit", ctypes.c_size_t),
43
+ ("JobMemoryLimit", ctypes.c_size_t),
44
+ ("PeakProcessMemoryUsed", ctypes.c_size_t),
45
+ ("PeakJobMemoryUsed", ctypes.c_size_t),
46
+ ]
47
+
48
+
49
+ def _create_kill_on_close_job() -> int | None:
50
+ create_job = ctypes.windll.kernel32.CreateJobObjectW
51
+ create_job.argtypes = (ctypes.c_void_p, ctypes.c_wchar_p)
52
+ create_job.restype = ctypes.c_void_p
53
+ maybe_job_handle = create_job(None, None)
54
+ if maybe_job_handle is None:
55
+ return None
56
+ job_handle = int(maybe_job_handle)
57
+ if _configure_kill_on_close(job_handle):
58
+ return job_handle
59
+ _close_handle(job_handle)
60
+ return None
61
+
62
+
63
+ def _configure_kill_on_close(job_handle: int) -> bool:
64
+ job_limits = _JobObjectExtendedLimitInformation()
65
+ job_limits.BasicLimitInformation.LimitFlags = WINDOWS_JOB_KILL_ON_CLOSE_LIMIT
66
+ set_job_information = ctypes.windll.kernel32.SetInformationJobObject
67
+ set_job_information.argtypes = (
68
+ ctypes.c_void_p,
69
+ ctypes.c_int,
70
+ ctypes.c_void_p,
71
+ ctypes.c_uint32,
72
+ )
73
+ set_job_information.restype = ctypes.c_int
74
+ return bool(
75
+ set_job_information(
76
+ ctypes.c_void_p(job_handle),
77
+ WINDOWS_EXTENDED_LIMIT_INFORMATION_CLASS,
78
+ ctypes.byref(job_limits),
79
+ ctypes.sizeof(job_limits),
80
+ )
81
+ )
82
+
83
+
84
+ def _assign_process(job_handle: int, process_identifier: int) -> bool:
85
+ process_access = WINDOWS_PROCESS_SET_QUOTA_ACCESS | WINDOWS_PROCESS_TERMINATE_ACCESS
86
+ open_process = ctypes.windll.kernel32.OpenProcess
87
+ open_process.argtypes = (ctypes.c_uint32, ctypes.c_int, ctypes.c_uint32)
88
+ open_process.restype = ctypes.c_void_p
89
+ maybe_process_handle = open_process(process_access, 0, process_identifier)
90
+ if maybe_process_handle is None:
91
+ return False
92
+ process_handle = int(maybe_process_handle)
93
+ try:
94
+ return _assign_process_handle(job_handle, process_handle)
95
+ finally:
96
+ _close_handle(process_handle)
97
+
98
+
99
+ def _assign_process_handle(job_handle: int, process_handle: int) -> bool:
100
+ assign_process_to_job = ctypes.windll.kernel32.AssignProcessToJobObject
101
+ assign_process_to_job.argtypes = (ctypes.c_void_p, ctypes.c_void_p)
102
+ assign_process_to_job.restype = ctypes.c_int
103
+ return bool(
104
+ assign_process_to_job(
105
+ ctypes.c_void_p(job_handle),
106
+ ctypes.c_void_p(process_handle),
107
+ )
108
+ )
109
+
110
+
111
+ def _terminate_job(job_handle: int) -> None:
112
+ terminate_job_object = ctypes.windll.kernel32.TerminateJobObject
113
+ terminate_job_object.argtypes = (ctypes.c_void_p, ctypes.c_uint32)
114
+ terminate_job_object.restype = ctypes.c_int
115
+ terminate_job_object(ctypes.c_void_p(job_handle), 1)
116
+
117
+
118
+ def _close_handle(job_handle: int) -> None:
119
+ close_windows_handle = ctypes.windll.kernel32.CloseHandle
120
+ close_windows_handle.argtypes = (ctypes.c_void_p,)
121
+ close_windows_handle.restype = ctypes.c_int
122
+ close_windows_handle(ctypes.c_void_p(job_handle))
package/scripts/check.ps1 CHANGED
@@ -152,7 +152,6 @@ if (-not $SkipMypy) {
152
152
  copilot_quota.py `
153
153
  fix_hookspath.py `
154
154
  grant_project_claude_permissions.py `
155
- post_audit_thread.py `
156
155
  preflight_self_heal.py `
157
156
  preflight.py `
158
157
  reviewer_availability.py `