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,396 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import subprocess
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ SCRIPTS_DIRECTORY = Path(__file__).resolve().parents[1]
9
+ if str(SCRIPTS_DIRECTORY) not in sys.path:
10
+ sys.path.insert(0, str(SCRIPTS_DIRECTORY))
11
+
12
+ from local_report_publisher import PublicationOutcome, publish_local_report
13
+ from local_verification.config import BASE_PLACEHOLDER
14
+ from local_verification.manifest import load_manifest
15
+ from local_verification.runner import run_verification
16
+ from pr_verification.github import GitHubApi, HttpReply
17
+ from pr_verification.model import RepositorySettings, StatusState
18
+
19
+
20
+ class RecordingRequester:
21
+ def __init__(self, all_replies: list[HttpReply]) -> None:
22
+ self.all_replies = all_replies
23
+ self.all_requests: list[tuple[str, str, dict[str, str], bytes | None]] = []
24
+
25
+ def __call__(
26
+ self,
27
+ method: str,
28
+ url: str,
29
+ headers: dict[str, str],
30
+ body: bytes | None,
31
+ ) -> HttpReply:
32
+ self.all_requests.append((method, url, headers, body))
33
+ return self.all_replies.pop(0)
34
+
35
+
36
+ def _assert_request_methods(
37
+ requester: RecordingRequester, expected_methods: str
38
+ ) -> None:
39
+ request_methods = " ".join(
40
+ each_request[0] for each_request in requester.all_requests
41
+ )
42
+ assert request_methods == expected_methods
43
+
44
+
45
+ def _run_git(repository_path: Path, *all_arguments: str) -> str:
46
+ completed_process = subprocess.run(
47
+ ["git", "-C", str(repository_path), *all_arguments],
48
+ capture_output=True,
49
+ check=False,
50
+ text=True,
51
+ )
52
+ assert completed_process.returncode == 0, completed_process.stderr
53
+ return completed_process.stdout.strip()
54
+
55
+
56
+ def _create_git_repository(tmp_path: Path) -> tuple[Path, str]:
57
+ repository_path = tmp_path / "repository"
58
+ repository_path.mkdir()
59
+ _run_git(repository_path, "init", "--quiet")
60
+ _run_git(repository_path, "config", "user.email", "tests@example.com")
61
+ _run_git(repository_path, "config", "user.name", "Local Verification Tests")
62
+ (repository_path / "tracked.txt").write_text("stable\n", encoding="utf-8")
63
+ _run_git(repository_path, "add", "tracked.txt")
64
+ _run_git(repository_path, "commit", "--quiet", "-m", "initial")
65
+ return repository_path, _run_git(repository_path, "rev-parse", "HEAD")
66
+
67
+
68
+ def _repository() -> RepositorySettings:
69
+ return RepositorySettings("owner/repository", "https://github.test/repository.git")
70
+
71
+
72
+ def _pull_payload(
73
+ head_sha: str, base_sha: str, merge_sha: str | None = "merge"
74
+ ) -> bytes:
75
+ return json.dumps(
76
+ {
77
+ "number": 7,
78
+ "draft": False,
79
+ "merge_commit_sha": merge_sha,
80
+ "base": {"ref": "main", "sha": base_sha},
81
+ "head": {"sha": head_sha},
82
+ }
83
+ ).encode("utf-8")
84
+
85
+
86
+ def _candidate_replies(
87
+ head_sha: str, base_sha: str, merge_sha: str | None = "merge"
88
+ ) -> list[HttpReply]:
89
+ return [
90
+ HttpReply(200, {}, _pull_payload(head_sha, base_sha, merge_sha)),
91
+ HttpReply(
92
+ 200,
93
+ {},
94
+ json.dumps({"object": {"sha": base_sha}}).encode("utf-8"),
95
+ ),
96
+ ]
97
+
98
+
99
+ def _advisory_replies(
100
+ head_sha: str, base_sha: str, merge_sha: str | None = "merge"
101
+ ) -> list[HttpReply]:
102
+ return [
103
+ *_candidate_replies(head_sha, base_sha, merge_sha),
104
+ HttpReply(200, {}, b'[{"name":"local-checks:passed"}]'),
105
+ HttpReply(204, {}, b""),
106
+ HttpReply(201, {}, b"{}"),
107
+ ]
108
+
109
+
110
+ def _write_manifest(
111
+ manifest_path: Path,
112
+ check_arguments: list[str],
113
+ minimum_tests: int | None = None,
114
+ timeout_seconds: float = 10.0,
115
+ ) -> None:
116
+ manifest_path.write_text(
117
+ json.dumps(
118
+ {
119
+ "version": 1,
120
+ "checks": [
121
+ {
122
+ "id": "selected",
123
+ "argv": check_arguments,
124
+ "cwd": ".",
125
+ "timeout_seconds": timeout_seconds,
126
+ **(
127
+ {"minimum_tests": minimum_tests}
128
+ if minimum_tests is not None
129
+ else {}
130
+ ),
131
+ }
132
+ ],
133
+ }
134
+ ),
135
+ encoding="utf-8",
136
+ )
137
+
138
+
139
+ def _run_report(
140
+ tmp_path: Path,
141
+ check_arguments: list[str],
142
+ minimum_tests: int | None = None,
143
+ timeout_seconds: float = 10.0,
144
+ base_revision: str | None = None,
145
+ ) -> tuple[Path, Path, str, str]:
146
+ repository_path, base_sha = _create_git_repository(tmp_path)
147
+ manifest_path = tmp_path / "manifest.json"
148
+ _write_manifest(manifest_path, check_arguments, minimum_tests, timeout_seconds)
149
+ manifest = load_manifest(manifest_path)
150
+ report_path = tmp_path / "report.json"
151
+ report = run_verification(
152
+ manifest, repository_path, base_revision or base_sha, report_path
153
+ )
154
+ assert report.head_revision is not None
155
+ return repository_path, manifest_path, base_sha, report.head_revision
156
+
157
+
158
+ def _base_check_arguments() -> list[str]:
159
+ return [
160
+ sys.executable,
161
+ "-c",
162
+ "import sys; assert len(sys.argv[1]) == 40",
163
+ BASE_PLACEHOLDER,
164
+ ]
165
+
166
+
167
+ def _assert_recorded_base(report_path: Path, base_sha: str) -> None:
168
+ report_fields = json.loads(report_path.read_text(encoding="utf-8"))
169
+ assert report_fields["checks"][0]["argv"][-1] == base_sha
170
+
171
+
172
+ def _publish_report(
173
+ repository_path: Path,
174
+ manifest_path: Path,
175
+ report_path: Path,
176
+ requester: RecordingRequester,
177
+ ) -> PublicationOutcome:
178
+ return publish_local_report(
179
+ GitHubApi("https://api.github.test", "token", requester),
180
+ _repository(),
181
+ 7,
182
+ repository_path,
183
+ manifest_path,
184
+ report_path,
185
+ )
186
+
187
+
188
+ def _missing_key_arguments(tmp_path: Path) -> list[str]:
189
+ return [
190
+ "--api-url",
191
+ "https://api.github.test",
192
+ "--app-id",
193
+ "42",
194
+ "--installation-id",
195
+ "84",
196
+ "--private-key-path",
197
+ str(tmp_path / "missing.pem"),
198
+ "--repository",
199
+ "owner/repository",
200
+ "--pull-number",
201
+ "7",
202
+ "--local-repo",
203
+ str(tmp_path),
204
+ "--manifest",
205
+ str(tmp_path / "manifest.json"),
206
+ "--report",
207
+ str(tmp_path / "report.json"),
208
+ ]
209
+
210
+
211
+ def test_publishes_success_for_matching_clean_report(tmp_path: Path) -> None:
212
+ repository_path, manifest_path, base_sha, head_sha = _run_report(
213
+ tmp_path, _base_check_arguments(), base_revision="HEAD"
214
+ )
215
+ _assert_recorded_base(tmp_path / "report.json", base_sha)
216
+ requester = RecordingRequester(
217
+ [
218
+ *_candidate_replies(head_sha, base_sha),
219
+ *_candidate_replies(head_sha, base_sha),
220
+ HttpReply(201, {}, b"{}"),
221
+ HttpReply(200, {}, b"[]"),
222
+ *_candidate_replies(head_sha, base_sha),
223
+ ]
224
+ )
225
+ outcome = _publish_report(
226
+ repository_path, manifest_path, tmp_path / "report.json", requester
227
+ )
228
+
229
+ assert outcome.status == StatusState.SUCCESS
230
+ assert outcome.publishable is True
231
+ assert "Selected local checks passed (1 checks)" == outcome.description
232
+ _assert_request_methods(requester, "GET GET GET GET POST POST GET GET")
233
+ assert requester.all_requests[1][1].endswith("/git/ref/heads/main")
234
+ assert requester.all_requests[4][1].endswith(f"/statuses/{head_sha}")
235
+
236
+
237
+ def test_failed_report_removes_pass_label_and_posts_failure(tmp_path: Path) -> None:
238
+ repository_path, manifest_path, base_sha, head_sha = _run_report(
239
+ tmp_path, [sys.executable, "-c", "raise SystemExit(4)"]
240
+ )
241
+ requester = RecordingRequester(_advisory_replies(head_sha, base_sha))
242
+ outcome = _publish_report(
243
+ repository_path, manifest_path, tmp_path / "report.json", requester
244
+ )
245
+
246
+ assert outcome.status == StatusState.FAILURE
247
+ assert outcome.publishable is False
248
+ _assert_request_methods(requester, "GET GET GET DELETE POST")
249
+ assert requester.all_requests[2][1].endswith(
250
+ "/issues/7/labels?per_page=100&page=1"
251
+ )
252
+ assert requester.all_requests[3][1].endswith(
253
+ "/issues/7/labels/local-checks%3Apassed"
254
+ )
255
+
256
+
257
+ def test_failed_execution_with_collection_floor_posts_failure(tmp_path: Path) -> None:
258
+ failing_test_path = tmp_path / "test_failure.py"
259
+ failing_test_path.write_text(
260
+ "def test_selected():\n assert False\n",
261
+ encoding="utf-8",
262
+ )
263
+ repository_path, manifest_path, base_sha, head_sha = _run_report(
264
+ tmp_path,
265
+ [sys.executable, "-m", "pytest", str(failing_test_path)],
266
+ 1,
267
+ )
268
+ requester = RecordingRequester(_advisory_replies(head_sha, base_sha))
269
+ outcome = _publish_report(
270
+ repository_path, manifest_path, tmp_path / "report.json", requester
271
+ )
272
+
273
+ assert outcome.status == StatusState.FAILURE
274
+ assert outcome.publishable is False
275
+
276
+
277
+ def test_incomplete_report_posts_error_without_pass_label(tmp_path: Path) -> None:
278
+ repository_path, manifest_path, base_sha, head_sha = _run_report(
279
+ tmp_path, ["missing-command"]
280
+ )
281
+ requester = RecordingRequester(_advisory_replies(head_sha, base_sha))
282
+ outcome = _publish_report(
283
+ repository_path, manifest_path, tmp_path / "report.json", requester
284
+ )
285
+
286
+ assert outcome.status == StatusState.ERROR
287
+ assert outcome.publishable is False
288
+ assert [each_request[0] for each_request in requester.all_requests[-3:]] == [
289
+ "GET",
290
+ "DELETE",
291
+ "POST",
292
+ ]
293
+
294
+
295
+ def test_timeout_after_collection_posts_error(tmp_path: Path) -> None:
296
+ sleeping_test_path = tmp_path / "test_timeout.py"
297
+ sleeping_test_path.write_text(
298
+ "import time\ndef test_slow():\n time.sleep(1)\n",
299
+ encoding="utf-8",
300
+ )
301
+ repository_path, manifest_path, base_sha, head_sha = _run_report(
302
+ tmp_path,
303
+ [sys.executable, "-m", "pytest", str(sleeping_test_path)],
304
+ 1,
305
+ 0.1,
306
+ )
307
+ requester = RecordingRequester(_advisory_replies(head_sha, base_sha))
308
+ outcome = _publish_report(
309
+ repository_path, manifest_path, tmp_path / "report.json", requester
310
+ )
311
+
312
+ assert outcome.status == StatusState.ERROR
313
+ assert outcome.publishable is False
314
+
315
+
316
+ def test_collection_failure_posts_error(tmp_path: Path) -> None:
317
+ repository_path, manifest_path, base_sha, head_sha = _run_report(
318
+ tmp_path,
319
+ [sys.executable, "-m", "pytest", str(tmp_path / "missing_tests.py")],
320
+ 1,
321
+ )
322
+ requester = RecordingRequester(_advisory_replies(head_sha, base_sha))
323
+ outcome = _publish_report(
324
+ repository_path, manifest_path, tmp_path / "report.json", requester
325
+ )
326
+
327
+ assert outcome.status == StatusState.ERROR
328
+ assert outcome.publishable is False
329
+
330
+
331
+ def test_advisory_reads_pull_request_without_merge_commit(tmp_path: Path) -> None:
332
+ repository_path, manifest_path, base_sha, head_sha = _run_report(
333
+ tmp_path, [sys.executable, "-c", "raise SystemExit(4)"]
334
+ )
335
+ requester = RecordingRequester(
336
+ _advisory_replies(head_sha, base_sha, merge_sha=None)
337
+ )
338
+ outcome = _publish_report(
339
+ repository_path, manifest_path, tmp_path / "report.json", requester
340
+ )
341
+
342
+ assert outcome.status == StatusState.FAILURE
343
+ assert outcome.publishable is False
344
+
345
+
346
+ def test_wrong_manifest_removes_pass_label_and_posts_error(tmp_path: Path) -> None:
347
+ repository_path, _manifest_path, base_sha, head_sha = _run_report(
348
+ tmp_path, [sys.executable, "-c", "pass"]
349
+ )
350
+ wrong_manifest_path = tmp_path / "wrong-manifest.json"
351
+ _write_manifest(wrong_manifest_path, [sys.executable, "-c", "pass"])
352
+ wrong_manifest_text = wrong_manifest_path.read_text(encoding="utf-8")
353
+ wrong_manifest_path.write_text(
354
+ wrong_manifest_text.replace('"selected"', '"other"'),
355
+ encoding="utf-8",
356
+ )
357
+ requester = RecordingRequester(_advisory_replies(head_sha, base_sha))
358
+ outcome = _publish_report(
359
+ repository_path, wrong_manifest_path, tmp_path / "report.json", requester
360
+ )
361
+
362
+ assert outcome.status == StatusState.ERROR
363
+ assert outcome.publishable is False
364
+ _assert_request_methods(requester, "GET GET GET DELETE POST")
365
+
366
+
367
+ def test_success_drift_after_label_removes_label_and_posts_error(
368
+ tmp_path: Path,
369
+ ) -> None:
370
+ repository_path, manifest_path, base_sha, head_sha = _run_report(
371
+ tmp_path, [sys.executable, "-c", "pass"]
372
+ )
373
+ changed_head = "changed-head"
374
+ requester = RecordingRequester(
375
+ [
376
+ *_candidate_replies(head_sha, base_sha),
377
+ *_candidate_replies(head_sha, base_sha),
378
+ HttpReply(201, {}, b"{}"),
379
+ HttpReply(200, {}, b"[]"),
380
+ *_candidate_replies(changed_head, base_sha),
381
+ HttpReply(200, {}, b'[{"name":"local-checks:passed"}]'),
382
+ HttpReply(204, {}, b""),
383
+ HttpReply(201, {}, b"{}"),
384
+ ]
385
+ )
386
+ outcome = _publish_report(
387
+ repository_path, manifest_path, tmp_path / "report.json", requester
388
+ )
389
+
390
+ assert outcome.status == StatusState.ERROR
391
+ assert outcome.publishable is False
392
+ assert [each_request[0] for each_request in requester.all_requests[-3:]] == [
393
+ "GET",
394
+ "DELETE",
395
+ "POST",
396
+ ]
@@ -0,0 +1,85 @@
1
+ from __future__ import annotations
2
+
3
+ import io
4
+ import json
5
+ import subprocess
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ SCRIPTS_DIRECTORY = Path(__file__).resolve().parents[1]
10
+ if str(SCRIPTS_DIRECTORY) not in sys.path:
11
+ sys.path.insert(0, str(SCRIPTS_DIRECTORY))
12
+ TESTS_DIRECTORY = Path(__file__).resolve().parent
13
+ if str(TESTS_DIRECTORY) not in sys.path:
14
+ sys.path.insert(0, str(TESTS_DIRECTORY))
15
+
16
+ from local_report_publisher import main
17
+ from pr_verification.model import StatusState
18
+ from test_local_report_publisher import (
19
+ RecordingRequester,
20
+ _advisory_replies,
21
+ _assert_request_methods,
22
+ _missing_key_arguments,
23
+ _publish_report,
24
+ _run_report,
25
+ )
26
+
27
+
28
+ def test_tampered_command_removes_pass_label_and_posts_error(tmp_path: Path) -> None:
29
+ repository_path, manifest_path, base_sha, head_sha = _run_report(
30
+ tmp_path, [sys.executable, "-c", "pass"]
31
+ )
32
+ report_path = tmp_path / "report.json"
33
+ report_fields = json.loads(report_path.read_text(encoding="utf-8"))
34
+ report_fields["checks"][0]["argv"] = [sys.executable, "-c", "raise SystemExit(9)"]
35
+ report_path.write_text(json.dumps(report_fields), encoding="utf-8")
36
+ requester = RecordingRequester(_advisory_replies(head_sha, base_sha))
37
+
38
+ outcome = _publish_report(repository_path, manifest_path, report_path, requester)
39
+
40
+ assert outcome.status == StatusState.ERROR
41
+ assert outcome.publishable is False
42
+ _assert_request_methods(requester, "GET GET GET DELETE POST")
43
+
44
+
45
+ def test_cli_reports_missing_key_without_network_access(tmp_path: Path) -> None:
46
+ standard_output = io.StringIO()
47
+ standard_error = io.StringIO()
48
+
49
+ exit_code = main(
50
+ _missing_key_arguments(tmp_path),
51
+ stdout=standard_output,
52
+ stderr=standard_error,
53
+ )
54
+
55
+ assert exit_code == 3
56
+ assert standard_output.getvalue() == ""
57
+ assert "missing.pem" in standard_error.getvalue()
58
+
59
+
60
+ def test_cli_rejects_malformed_repository_without_network_access(
61
+ tmp_path: Path,
62
+ ) -> None:
63
+ all_arguments = _missing_key_arguments(tmp_path)
64
+ repository_index = all_arguments.index("--repository") + 1
65
+ all_arguments[repository_index] = "owner"
66
+ standard_error = io.StringIO()
67
+
68
+ exit_code = main(all_arguments, stderr=standard_error)
69
+
70
+ assert exit_code == 3
71
+ assert "owner/name" in standard_error.getvalue()
72
+ assert "Traceback" not in standard_error.getvalue()
73
+
74
+
75
+ def test_publisher_script_displays_help_without_authentication() -> None:
76
+ publisher_path = Path(__file__).resolve().parents[1] / "local_report_publisher.py"
77
+ completed_process = subprocess.run(
78
+ [sys.executable, str(publisher_path), "--help"],
79
+ capture_output=True,
80
+ text=True,
81
+ check=False,
82
+ )
83
+
84
+ assert completed_process.returncode == 0
85
+ assert "usage:" in completed_process.stdout