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,350 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import signal
6
+ import subprocess
7
+ import sys
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+ from typing import IO
11
+
12
+ from .config.constants import (
13
+ CHILD_BASE_FLAG,
14
+ CHILD_EXECUTOR_FLAG,
15
+ CHILD_OUTPUT_FLAG,
16
+ LOCAL_VERIFICATION_CLI_FILENAME,
17
+ PYTEST_AUTO_WORKERS_ENVIRONMENT_KEY,
18
+ PYTEST_AUTO_WORKERS_LIMIT,
19
+ PYTHON_MODULE_ARGUMENT,
20
+ PYTHONPATH_ENVIRONMENT_KEY,
21
+ SCOPED_VERIFICATION_SCRIPT_PATH,
22
+ WINDOWS_PLATFORM,
23
+ WINDOWS_PRIORITY_CLASS_ATTRIBUTE,
24
+ WINDOWS_PROCESS_HOST_MODULE,
25
+ WINDOWS_PROCESS_START_SIGNAL,
26
+ )
27
+ from .config.timing import CHILD_CLEANUP_TIMEOUT_SECONDS
28
+ from .model import AdvisoryRegistration, ChildOutcome
29
+ from .window_flags import hidden_window_creation_flags
30
+ from .windows_job import (
31
+ _assign_process,
32
+ _close_handle,
33
+ _create_kill_on_close_job,
34
+ _terminate_job,
35
+ )
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class OwnedChildProcess:
40
+ process: subprocess.Popen[str]
41
+ process_group_identifier: int | None
42
+ windows_job_handle: int | None
43
+
44
+
45
+ def run_verification_child(
46
+ registration: AdvisoryRegistration,
47
+ base_ref: str,
48
+ timeout_seconds: float,
49
+ ) -> ChildOutcome:
50
+ """Run the existing local verification CLI with a bounded timeout.
51
+
52
+ Args:
53
+ registration: Checkout, manifest, and report paths for the pair.
54
+ base_ref: Dedicated fetched base revision.
55
+ timeout_seconds: Maximum child runtime.
56
+
57
+ Returns:
58
+ Captured child status and streams.
59
+ """
60
+ scripts_directory = Path(__file__).resolve().parents[1]
61
+ all_arguments = _build_child_arguments(registration, base_ref, scripts_directory)
62
+ child_environment = _build_child_environment(registration, scripts_directory)
63
+ if not _clear_child_artifacts(registration):
64
+ return ChildOutcome(None, "", "child artifacts could not be cleared", False)
65
+ maybe_owned_child = _start_child_process(
66
+ all_arguments, registration, child_environment
67
+ )
68
+ if maybe_owned_child is None:
69
+ return ChildOutcome(None, "", "child process could not start", False)
70
+ return _collect_child_outcome(maybe_owned_child, timeout_seconds)
71
+
72
+
73
+ def _build_child_arguments(
74
+ registration: AdvisoryRegistration,
75
+ base_ref: str,
76
+ scripts_directory: Path,
77
+ ) -> tuple[str, ...]:
78
+ verification_cli_path = (
79
+ scripts_directory / "local_verification" / LOCAL_VERIFICATION_CLI_FILENAME
80
+ )
81
+ return (
82
+ sys.executable,
83
+ str(registration.checkout_path / SCOPED_VERIFICATION_SCRIPT_PATH),
84
+ CHILD_BASE_FLAG,
85
+ base_ref,
86
+ CHILD_EXECUTOR_FLAG,
87
+ str(verification_cli_path),
88
+ CHILD_OUTPUT_FLAG,
89
+ str(registration.report_path),
90
+ )
91
+
92
+
93
+ def _build_child_environment(
94
+ registration: AdvisoryRegistration, scripts_directory: Path
95
+ ) -> dict[str, str]:
96
+ child_environment = os.environ.copy()
97
+ all_python_paths = [str(registration.checkout_path), str(scripts_directory)]
98
+ existing_python_path = child_environment.get(PYTHONPATH_ENVIRONMENT_KEY)
99
+ if existing_python_path:
100
+ all_python_paths.append(existing_python_path)
101
+ child_environment[PYTHONPATH_ENVIRONMENT_KEY] = os.pathsep.join(all_python_paths)
102
+ child_environment[PYTEST_AUTO_WORKERS_ENVIRONMENT_KEY] = PYTEST_AUTO_WORKERS_LIMIT
103
+ return child_environment
104
+
105
+
106
+ def _clear_child_artifacts(registration: AdvisoryRegistration) -> bool:
107
+ try:
108
+ for each_artifact_path in (
109
+ registration.report_path,
110
+ registration.selected_manifest_path,
111
+ ):
112
+ each_artifact_path.unlink(missing_ok=True)
113
+ except OSError:
114
+ return False
115
+ return True
116
+
117
+
118
+ def _child_produced_report(
119
+ child_outcome: ChildOutcome,
120
+ registration: AdvisoryRegistration,
121
+ ) -> bool:
122
+ if child_outcome.exit_code is None or child_outcome.timed_out:
123
+ return False
124
+ if not registration.selected_manifest_path.is_file():
125
+ return False
126
+ try:
127
+ report_fields = json.loads(registration.report_path.read_text(encoding="utf-8"))
128
+ except (OSError, json.JSONDecodeError):
129
+ return False
130
+ return (
131
+ isinstance(report_fields, dict)
132
+ and report_fields.get("exit_code") == child_outcome.exit_code
133
+ )
134
+
135
+
136
+ def _start_child_process(
137
+ all_arguments: tuple[str, ...],
138
+ registration: AdvisoryRegistration,
139
+ all_child_environment: dict[str, str],
140
+ ) -> OwnedChildProcess | None:
141
+ if sys.platform == WINDOWS_PLATFORM:
142
+ return _start_windows_child(
143
+ all_arguments,
144
+ registration,
145
+ all_child_environment,
146
+ )
147
+ return _start_posix_child(
148
+ all_arguments,
149
+ registration,
150
+ all_child_environment,
151
+ )
152
+
153
+
154
+ def _start_posix_child(
155
+ all_arguments: tuple[str, ...],
156
+ registration: AdvisoryRegistration,
157
+ all_child_environment: dict[str, str],
158
+ ) -> OwnedChildProcess | None:
159
+ try:
160
+ child_process = subprocess.Popen(
161
+ all_arguments,
162
+ cwd=registration.checkout_path,
163
+ stdout=subprocess.PIPE,
164
+ stderr=subprocess.PIPE,
165
+ text=True,
166
+ env=all_child_environment,
167
+ start_new_session=True,
168
+ )
169
+ except OSError:
170
+ return None
171
+ return OwnedChildProcess(child_process, child_process.pid, None)
172
+
173
+
174
+ def _start_windows_child(
175
+ all_arguments: tuple[str, ...],
176
+ registration: AdvisoryRegistration,
177
+ all_child_environment: dict[str, str],
178
+ ) -> OwnedChildProcess | None:
179
+ maybe_job_handle = _create_kill_on_close_job()
180
+ if maybe_job_handle is None:
181
+ return None
182
+ maybe_child_process = _spawn_windows_process_host(
183
+ all_arguments,
184
+ registration,
185
+ all_child_environment,
186
+ )
187
+ if maybe_child_process is None:
188
+ _close_handle(maybe_job_handle)
189
+ return None
190
+ if not _assign_process(maybe_job_handle, maybe_child_process.pid):
191
+ _stop_unowned_process(maybe_child_process)
192
+ _close_handle(maybe_job_handle)
193
+ return None
194
+ if not _release_windows_process_host(maybe_child_process):
195
+ _terminate_job(maybe_job_handle)
196
+ _close_handle(maybe_job_handle)
197
+ return None
198
+ return OwnedChildProcess(maybe_child_process, None, maybe_job_handle)
199
+
200
+
201
+ def _spawn_windows_process_host(
202
+ all_arguments: tuple[str, ...],
203
+ registration: AdvisoryRegistration,
204
+ all_child_environment: dict[str, str],
205
+ ) -> subprocess.Popen[str] | None:
206
+ try:
207
+ return subprocess.Popen(
208
+ (
209
+ sys.executable,
210
+ PYTHON_MODULE_ARGUMENT,
211
+ WINDOWS_PROCESS_HOST_MODULE,
212
+ *all_arguments,
213
+ ),
214
+ cwd=registration.checkout_path,
215
+ stdin=subprocess.PIPE,
216
+ stdout=subprocess.PIPE,
217
+ stderr=subprocess.PIPE,
218
+ text=True,
219
+ env=all_child_environment,
220
+ creationflags=hidden_window_creation_flags()
221
+ | getattr(subprocess, WINDOWS_PRIORITY_CLASS_ATTRIBUTE, 0),
222
+ )
223
+ except OSError:
224
+ return None
225
+
226
+
227
+ def _release_windows_process_host(child_process: subprocess.Popen[str]) -> bool:
228
+ stdin_stream = child_process.stdin
229
+ if stdin_stream is None:
230
+ return False
231
+ child_process.stdin = None
232
+ try:
233
+ stdin_stream.write(WINDOWS_PROCESS_START_SIGNAL)
234
+ stdin_stream.flush()
235
+ return True
236
+ except OSError:
237
+ return False
238
+ finally:
239
+ _close_stream_without_raising(stdin_stream)
240
+
241
+
242
+ def _close_stream_without_raising(stream: IO[str]) -> None:
243
+ try:
244
+ stream.close()
245
+ except OSError:
246
+ return
247
+
248
+
249
+ def _collect_child_outcome(
250
+ owned_child: OwnedChildProcess,
251
+ timeout_seconds: float,
252
+ ) -> ChildOutcome:
253
+ child_process = owned_child.process
254
+ try:
255
+ try:
256
+ stdout_text, stderr_text = child_process.communicate(
257
+ timeout=timeout_seconds
258
+ )
259
+ except subprocess.TimeoutExpired as timeout_error:
260
+ return _stop_timed_out_child(owned_child, timeout_error)
261
+ return ChildOutcome(
262
+ child_process.returncode,
263
+ stdout_text,
264
+ stderr_text,
265
+ False,
266
+ )
267
+ finally:
268
+ _close_process_ownership(owned_child)
269
+ _close_child_streams(child_process)
270
+ _reap_child_process(child_process)
271
+
272
+
273
+ def _stop_timed_out_child(
274
+ owned_child: OwnedChildProcess,
275
+ timeout_error: subprocess.TimeoutExpired,
276
+ ) -> ChildOutcome:
277
+ child_process = owned_child.process
278
+ _terminate_owned_process_tree(owned_child)
279
+ try:
280
+ stdout_text, stderr_text = child_process.communicate(
281
+ timeout=CHILD_CLEANUP_TIMEOUT_SECONDS
282
+ )
283
+ except subprocess.TimeoutExpired as cleanup_error:
284
+ stdout_text = str(cleanup_error.stdout or timeout_error.stdout or "")
285
+ stderr_text = str(cleanup_error.stderr or timeout_error.stderr or "")
286
+ return ChildOutcome(None, str(stdout_text), str(stderr_text), True)
287
+
288
+
289
+ def _terminate_owned_process_tree(
290
+ owned_child: OwnedChildProcess,
291
+ ) -> None:
292
+ if owned_child.windows_job_handle is not None:
293
+ _terminate_job(owned_child.windows_job_handle)
294
+ if owned_child.process_group_identifier is not None:
295
+ _kill_posix_process_group(owned_child.process_group_identifier)
296
+ _kill_direct_child(owned_child.process)
297
+
298
+
299
+ def _kill_posix_process_group(process_group_identifier: int) -> None:
300
+ if sys.platform == "win32":
301
+ return
302
+ try:
303
+ os.killpg(process_group_identifier, signal.SIGKILL)
304
+ except OSError:
305
+ return
306
+
307
+
308
+ def _kill_direct_child(child_process: subprocess.Popen[str]) -> None:
309
+ if child_process.poll() is None:
310
+ try:
311
+ child_process.kill()
312
+ except ProcessLookupError:
313
+ pass
314
+
315
+
316
+ def _close_process_ownership(owned_child: OwnedChildProcess) -> None:
317
+ if owned_child.windows_job_handle is None:
318
+ return
319
+ _close_handle(owned_child.windows_job_handle)
320
+
321
+
322
+ def _close_child_streams(child_process: subprocess.Popen[str]) -> None:
323
+ for each_stream in (
324
+ child_process.stdout,
325
+ child_process.stderr,
326
+ child_process.stdin,
327
+ ):
328
+ if each_stream is None:
329
+ continue
330
+ try:
331
+ each_stream.close()
332
+ except OSError:
333
+ pass
334
+
335
+
336
+ def _stop_unowned_process(child_process: subprocess.Popen[str]) -> None:
337
+ try:
338
+ child_process.kill()
339
+ except ProcessLookupError:
340
+ return
341
+ _reap_child_process(child_process)
342
+
343
+
344
+ def _reap_child_process(child_process: subprocess.Popen[str]) -> None:
345
+ if child_process.poll() is not None:
346
+ return
347
+ try:
348
+ child_process.wait(timeout=CHILD_CLEANUP_TIMEOUT_SECONDS)
349
+ except subprocess.TimeoutExpired:
350
+ return
@@ -0,0 +1,69 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import subprocess
5
+
6
+ from pr_verification.model import PullRequestCandidate
7
+
8
+ from .config.constants import (
9
+ GIT_BASE_REFSPEC_TEMPLATE,
10
+ GIT_EXECUTABLE,
11
+ GIT_FETCH_ARGUMENT,
12
+ GIT_FORCE_FLAG,
13
+ GIT_NO_TAGS_FLAG,
14
+ GIT_PROMPT_DISABLED_VALUE,
15
+ GIT_REMOTE_BASE_REFSPEC_TEMPLATE,
16
+ GIT_TERMINAL_PROMPT_ENVIRONMENT_KEY,
17
+ )
18
+ from .config.timing import GIT_FETCH_TIMEOUT_SECONDS
19
+ from .model import AdvisoryRegistration
20
+ from .window_flags import hidden_window_creation_flags
21
+
22
+
23
+ def _fetch_base(
24
+ registration: AdvisoryRegistration,
25
+ candidate: PullRequestCandidate,
26
+ ) -> bool:
27
+ all_fetch_refspecs = _base_fetch_refspecs(registration, candidate)
28
+ try:
29
+ completed_process = subprocess.run(
30
+ (
31
+ GIT_EXECUTABLE,
32
+ GIT_FETCH_ARGUMENT,
33
+ GIT_FORCE_FLAG,
34
+ GIT_NO_TAGS_FLAG,
35
+ registration.remote_name,
36
+ *all_fetch_refspecs,
37
+ ),
38
+ cwd=registration.checkout_path,
39
+ capture_output=True,
40
+ check=False,
41
+ env=_build_git_environment(),
42
+ creationflags=hidden_window_creation_flags(),
43
+ timeout=GIT_FETCH_TIMEOUT_SECONDS,
44
+ )
45
+ except subprocess.TimeoutExpired:
46
+ return False
47
+ return completed_process.returncode == 0
48
+
49
+
50
+ def _base_fetch_refspecs(
51
+ registration: AdvisoryRegistration,
52
+ candidate: PullRequestCandidate,
53
+ ) -> tuple[str, str]:
54
+ return (
55
+ GIT_BASE_REFSPEC_TEMPLATE.format(
56
+ base_ref=candidate.base_ref,
57
+ pull_request=registration.pull_request_number,
58
+ ),
59
+ GIT_REMOTE_BASE_REFSPEC_TEMPLATE.format(
60
+ base_ref=candidate.base_ref,
61
+ remote_name=registration.remote_name,
62
+ ),
63
+ )
64
+
65
+
66
+ def _build_git_environment() -> dict[str, str]:
67
+ git_environment = os.environ.copy()
68
+ git_environment[GIT_TERMINAL_PROMPT_ENVIRONMENT_KEY] = GIT_PROMPT_DISABLED_VALUE
69
+ return git_environment
@@ -0,0 +1,107 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from pathlib import Path, PurePosixPath
5
+
6
+ from pr_verification.model import PullRequestCandidate, RepositorySettings
7
+
8
+ from .config.constants import (
9
+ ALL_TERMINAL_STATUSES,
10
+ POLL_ERROR_LOG_FILE_NAME,
11
+ POLL_LOCK_DIRECTORY_NAME,
12
+ SELECTED_MANIFEST_SUFFIX,
13
+ )
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class AdvisoryRegistration:
18
+ repository: RepositorySettings
19
+ pull_request_number: int
20
+ checkout_path: Path
21
+ manifest_path: PurePosixPath
22
+ report_path: Path
23
+ state_path: Path
24
+ base_ref: str
25
+ remote_name: str
26
+
27
+ @property
28
+ def manifest_absolute_path(self) -> Path:
29
+ return self.checkout_path / Path(self.manifest_path)
30
+
31
+ @property
32
+ def selected_manifest_path(self) -> Path:
33
+ return self.report_path.with_name(
34
+ self.report_path.stem + SELECTED_MANIFEST_SUFFIX
35
+ )
36
+
37
+ @property
38
+ def repository_lock_root(self) -> Path:
39
+ return self.state_path.parent
40
+
41
+
42
+ @dataclass(frozen=True)
43
+ class AdvisorySettings:
44
+ api_url: str
45
+ app_id: int
46
+ installation_id: int
47
+ private_key_path: Path
48
+ poll_seconds: float
49
+ child_timeout_seconds: float
50
+ registrations: tuple[AdvisoryRegistration, ...]
51
+
52
+ @property
53
+ def poll_lock_root(self) -> Path:
54
+ return self.registrations[0].state_path.parent / POLL_LOCK_DIRECTORY_NAME
55
+
56
+ @property
57
+ def poll_error_log_path(self) -> Path:
58
+ return self.registrations[0].state_path.parent / POLL_ERROR_LOG_FILE_NAME
59
+
60
+
61
+ @dataclass(frozen=True)
62
+ class AdvisoryState:
63
+ repository: str
64
+ pull_request_number: int
65
+ status: str
66
+ reason: str
67
+ head_sha: str | None
68
+ base_sha: str | None
69
+ last_poll: str
70
+ last_run: str | None
71
+ report_path: str
72
+
73
+
74
+ @dataclass(frozen=True)
75
+ class ChildOutcome:
76
+ exit_code: int | None
77
+ stdout_text: str
78
+ stderr_text: str
79
+ timed_out: bool
80
+
81
+
82
+ @dataclass(frozen=True)
83
+ class LocalCheckout:
84
+ head_sha: str | None
85
+ is_clean: bool
86
+
87
+
88
+ def candidate_identity_matches_state(
89
+ candidate: PullRequestCandidate,
90
+ maybe_state: AdvisoryState | None,
91
+ ) -> bool:
92
+ """Return whether a terminal state already covers the candidate identity.
93
+
94
+ Args:
95
+ candidate: Current remote pull request identity.
96
+ maybe_state: Recorded advisory state.
97
+
98
+ Returns:
99
+ True when the same head and base already reached a terminal state.
100
+ """
101
+ if maybe_state is None:
102
+ return False
103
+ return (
104
+ maybe_state.head_sha == candidate.head_sha
105
+ and maybe_state.base_sha == candidate.base_sha
106
+ and maybe_state.status in ALL_TERMINAL_STATUSES
107
+ )
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import subprocess
4
+ import sys
5
+ from collections.abc import Sequence
6
+
7
+ from pr_verification.config.constants import INCOMPLETE_EXIT_CODE
8
+
9
+ from .config.constants import WINDOWS_PROCESS_START_SIGNAL
10
+
11
+
12
+ def run_owned_child(all_arguments: Sequence[str]) -> int:
13
+ """Wait for ownership, then run the advisory child.
14
+
15
+ Args:
16
+ all_arguments: Child executable and arguments.
17
+
18
+ Returns:
19
+ Child exit code or the incomplete exit code when ownership is absent.
20
+ """
21
+ if sys.stdin.read(1) != WINDOWS_PROCESS_START_SIGNAL:
22
+ return INCOMPLETE_EXIT_CODE
23
+ completed_process = subprocess.run(
24
+ tuple(all_arguments),
25
+ shell=False,
26
+ check=False,
27
+ )
28
+ return completed_process.returncode
29
+
30
+
31
+ if __name__ == "__main__":
32
+ raise SystemExit(run_owned_child(sys.argv[1:]))
@@ -0,0 +1,84 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from dataclasses import dataclass
5
+ from importlib import import_module
6
+ from pathlib import Path
7
+ from typing import Protocol
8
+
9
+ from pr_verification.config.constants import STATUS_FAILURE, STATUS_SUCCESS
10
+ from pr_verification.model import RepositorySettings
11
+
12
+ from .config.constants import STATE_STATUS_FAILED, STATE_STATUS_PASSED
13
+
14
+
15
+ class Publication(Protocol):
16
+ @property
17
+ def status(self) -> str: ...
18
+
19
+ @property
20
+ def description(self) -> str: ...
21
+
22
+
23
+ class PublicationStatus(Protocol):
24
+ @property
25
+ def value(self) -> str: ...
26
+
27
+
28
+ class PublisherOutcome(Protocol):
29
+ @property
30
+ def status(self) -> PublicationStatus: ...
31
+
32
+ @property
33
+ def description(self) -> str: ...
34
+
35
+
36
+ @dataclass(frozen=True)
37
+ class PublicationRecord:
38
+ status: str
39
+ description: str
40
+
41
+
42
+ def _publish_report(
43
+ github: object,
44
+ repository: RepositorySettings,
45
+ pull_request_number: int,
46
+ checkout_path: Path,
47
+ manifest_path: Path,
48
+ report_path: Path,
49
+ ) -> Publication:
50
+ publisher_module = import_module("local_report_publisher")
51
+ publisher_function: Callable[..., PublisherOutcome] = (
52
+ publisher_module.publish_local_report
53
+ )
54
+ publication_outcome = publisher_function(
55
+ github,
56
+ repository,
57
+ pull_request_number,
58
+ checkout_path,
59
+ manifest_path,
60
+ report_path,
61
+ )
62
+ publication_status = publication_outcome.status
63
+ publication_description = publication_outcome.description
64
+ return PublicationRecord(
65
+ _normalize_publication_status(publication_status),
66
+ publication_description,
67
+ )
68
+
69
+
70
+ def _normalize_publication_status(publication_status: PublicationStatus) -> str:
71
+ status_text = publication_status.value
72
+ if status_text == STATUS_SUCCESS:
73
+ return STATUS_SUCCESS
74
+ if status_text == STATUS_FAILURE:
75
+ return STATUS_FAILURE
76
+ return status_text
77
+
78
+
79
+ def _cache_status_for_publication(publication_status: str) -> str:
80
+ if publication_status == STATUS_SUCCESS:
81
+ return STATE_STATUS_PASSED
82
+ if publication_status == STATUS_FAILURE:
83
+ return STATE_STATUS_FAILED
84
+ return publication_status