claude-dev-env 7.0.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 (210) hide show
  1. package/.agents/skills/pull-request/scripts/pull_request.py +2 -0
  2. package/.agents/skills/pull-request/scripts/test_pull_request.py +34 -0
  3. package/.agents/skills/session-continuity/AGENTS.md +1 -0
  4. package/.agents/skills/session-continuity/CLAUDE.md +1 -0
  5. package/.agents/skills/session-continuity/README.md +189 -0
  6. package/.agents/skills/session-continuity/SKILL.md +114 -0
  7. package/.agents/skills/session-continuity/continuity.mjs +375 -0
  8. package/.agents/skills/session-continuity/continuity.test.mjs +303 -0
  9. package/.agents/skills/syncing-submodules/scripts/test_sync_parent_pointer.py +0 -7
  10. package/.agents/skills/windows-scheduled-task/SKILL.md +153 -0
  11. package/bin/cde.mjs +36 -8
  12. package/bin/cde.test.mjs +48 -0
  13. package/bin/ever-shipped-skills.mjs +2 -20
  14. package/bin/ever-shipped-skills.test.mjs +8 -0
  15. package/bin/expand_home_directory_tokens.mjs +4 -5
  16. package/bin/expand_home_directory_tokens.test.mjs +128 -0
  17. package/bin/git_hooks_installer.mjs +22 -3
  18. package/bin/git_hooks_installer.test.mjs +159 -5
  19. package/bin/install-session-continuity.mjs +78 -0
  20. package/bin/install-session-continuity.test.mjs +42 -0
  21. package/bin/install.codex-rules.test.mjs +5 -2
  22. package/bin/install.cursor-rules.test.mjs +5 -2
  23. package/bin/install.mjs +478 -63
  24. package/bin/install.policy-lint.test.mjs +56 -4
  25. package/bin/install.profiles.test.mjs +10 -0
  26. package/bin/install.prune.test.mjs +227 -17
  27. package/bin/install.test.mjs +500 -120
  28. package/bin/install.transaction.test.mjs +3 -3
  29. package/docs/CODE_RULES.md +1 -1
  30. package/hooks/blocking/code_rules_banned_identifiers.py +3 -0
  31. package/hooks/blocking/precommit_code_rules_gate.py +5 -8
  32. package/hooks/blocking/test_bash_dispatcher_interpreter_starts.py +7 -52
  33. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -69
  34. package/hooks/blocking/test_code_rules_banned_identifiers.py +64 -0
  35. package/hooks/blocking/test_pre_tool_use_dispatcher.py +10 -244
  36. package/hooks/blocking/test_shared_stdin_adoption.py +1 -47
  37. package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +116 -0
  38. package/hooks/git-hooks/post_commit.py +33 -0
  39. package/hooks/git-hooks/pre_commit.py +18 -90
  40. package/hooks/git-hooks/pre_push.py +45 -541
  41. package/hooks/git-hooks/test_installed_policy_lint.py +55 -6
  42. package/hooks/git-hooks/test_native_hook_support.py +129 -0
  43. package/hooks/git-hooks/test_native_policy_commit.py +39 -6
  44. package/hooks/git-hooks/test_post_commit.py +43 -0
  45. package/hooks/git-hooks/test_pre_commit.py +36 -392
  46. package/hooks/git-hooks/test_pre_push.py +48 -1631
  47. package/hooks/git-hooks/test_verification_notice.py +60 -0
  48. package/hooks/git-hooks/test_verification_start.py +173 -0
  49. package/hooks/git-hooks/verification_notice.py +192 -0
  50. package/hooks/git-hooks/verification_notice_context.py +253 -0
  51. package/hooks/git-hooks/verification_notice_state.py +237 -0
  52. package/hooks/git-hooks/verification_start.py +100 -0
  53. package/hooks/hooks.json +0 -119
  54. package/hooks/hooks_constants/banned_identifiers_constants.py +4 -0
  55. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +1 -15
  56. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -4
  57. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +0 -50
  58. package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -4
  59. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +3 -66
  60. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +42 -185
  61. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +3 -25
  62. package/hooks/validation/test_post_tool_use_dispatcher.py +35 -298
  63. package/hooks/validators/run_all_validators.py +5 -1
  64. package/hooks/validators/security_checks.py +57 -2
  65. package/hooks/validators/test_hook_timing_harness.py +2 -5
  66. package/hooks/validators/test_run_all_validators_mutation_tool_parity.py +3 -11
  67. package/hooks/validators/test_run_all_validators_policy_lint.py +36 -0
  68. package/hooks/validators/test_security_checks.py +57 -0
  69. package/package.json +1 -1
  70. package/rules/confirm-implementation-forks.md +2 -0
  71. package/rules/git-workflow.md +12 -0
  72. package/rules/pstack-host-mapping.md +48 -0
  73. package/rules/vault-context.md +3 -5
  74. package/rules/verify-runtime-state.md +7 -0
  75. package/scripts/audit-hooks-cli.mjs +5 -0
  76. package/scripts/audit-hooks.mjs +72 -16
  77. package/scripts/automatic_advisory/__init__.py +1 -0
  78. package/scripts/automatic_advisory/checkout.py +51 -0
  79. package/scripts/automatic_advisory/cli.py +334 -0
  80. package/scripts/automatic_advisory/config/__init__.py +1 -0
  81. package/scripts/automatic_advisory/config/constants.py +93 -0
  82. package/scripts/automatic_advisory/config/timing.py +4 -0
  83. package/scripts/automatic_advisory/configuration.py +197 -0
  84. package/scripts/automatic_advisory/execution.py +350 -0
  85. package/scripts/automatic_advisory/git.py +69 -0
  86. package/scripts/automatic_advisory/model.py +107 -0
  87. package/scripts/automatic_advisory/process_host.py +32 -0
  88. package/scripts/automatic_advisory/publisher.py +84 -0
  89. package/scripts/automatic_advisory/runner.py +399 -0
  90. package/scripts/automatic_advisory/state.py +116 -0
  91. package/scripts/automatic_advisory/window_flags.py +41 -0
  92. package/scripts/automatic_advisory/windows_job.py +122 -0
  93. package/scripts/codex_compat_materializer.py +99 -13
  94. package/scripts/durable_post_lint.py +30 -2
  95. package/scripts/durable_post_lint_config/config/constants.py +10 -0
  96. package/scripts/durable_post_lint_config/config/test_constants.py +13 -0
  97. package/scripts/local_report_cli.py +184 -0
  98. package/scripts/local_report_core.py +247 -0
  99. package/scripts/local_report_publisher.py +12 -0
  100. package/scripts/local_report_validation.py +357 -0
  101. package/scripts/local_verification/__init__.py +23 -0
  102. package/scripts/local_verification/check_runner.py +364 -0
  103. package/scripts/local_verification/check_support.py +99 -0
  104. package/scripts/local_verification/cli.py +158 -0
  105. package/scripts/local_verification/command_runner.py +84 -0
  106. package/scripts/local_verification/config/__init__.py +1 -0
  107. package/scripts/local_verification/config/constants.py +89 -0
  108. package/scripts/local_verification/config/timing.py +1 -0
  109. package/scripts/local_verification/git_state.py +146 -0
  110. package/scripts/local_verification/manifest.py +224 -0
  111. package/scripts/local_verification/model.py +174 -0
  112. package/scripts/local_verification/runner.py +234 -0
  113. package/scripts/policy_lint/adapter_pairing.py +58 -3
  114. package/scripts/policy_lint/config/approved_test_pairs.py +323 -0
  115. package/scripts/pr_verification/__init__.py +1 -0
  116. package/scripts/pr_verification/branch_refs.py +114 -0
  117. package/scripts/pr_verification/config/__init__.py +1 -0
  118. package/scripts/pr_verification/config/constants.py +84 -0
  119. package/scripts/pr_verification/config/timing.py +5 -0
  120. package/scripts/pr_verification/github.py +137 -0
  121. package/scripts/pr_verification/github_api.py +376 -0
  122. package/scripts/pr_verification/github_labels.py +88 -0
  123. package/scripts/pr_verification/github_parsing.py +182 -0
  124. package/scripts/pr_verification/github_transport.py +91 -0
  125. package/scripts/pr_verification/lock.py +122 -0
  126. package/scripts/pr_verification/model.py +43 -0
  127. package/scripts/pr_verification/requirements.txt +1 -0
  128. package/scripts/test_durable_post_lint.py +97 -0
  129. package/scripts/tests/test-audit-hooks-cli.mjs +150 -0
  130. package/scripts/tests/test-audit-hooks.mjs +94 -2
  131. package/scripts/tests/test_automatic_advisory.py +376 -0
  132. package/scripts/tests/test_automatic_advisory_job_cleanup.py +71 -0
  133. package/scripts/tests/test_automatic_advisory_polling.py +216 -0
  134. package/scripts/tests/test_automatic_advisory_recovery.py +320 -0
  135. package/scripts/tests/test_automatic_advisory_repairs.py +400 -0
  136. package/scripts/tests/test_automatic_advisory_settings.py +48 -0
  137. package/scripts/tests/test_automatic_advisory_window_flags.py +163 -0
  138. package/scripts/tests/test_closed_pr_label.py +157 -0
  139. package/scripts/tests/test_codex_compat_materializer.py +189 -6
  140. package/scripts/tests/test_github_labels.py +101 -0
  141. package/scripts/tests/test_github_transport.py +125 -0
  142. package/scripts/tests/test_local_report_publisher.py +396 -0
  143. package/scripts/tests/test_local_report_publisher_cli.py +85 -0
  144. package/scripts/tests/test_local_verification.py +348 -0
  145. package/scripts/tests/test_local_verification_cli.py +98 -0
  146. package/scripts/tests/test_policy_lint_rules_pairing.py +163 -0
  147. package/scripts/tests/test_pr_verification_github.py +392 -0
  148. package/scripts/tests/test_pr_verification_lock.py +168 -0
  149. package/scripts/tests/test_verification_notice.py +347 -0
  150. package/hooks/blocking/ask_user_question_shape_blocker.py +0 -83
  151. package/hooks/blocking/bot_mention_comment_blocker.py +0 -76
  152. package/hooks/blocking/claude_md_orphan_file_blocker.py +0 -129
  153. package/hooks/blocking/cursor_cli_python_misfire_blocker.py +0 -108
  154. package/hooks/blocking/destructive_command_blocker.py +0 -2073
  155. package/hooks/blocking/fable_spawn_gate.py +0 -187
  156. package/hooks/blocking/luna_fast_mode_gate.py +0 -160
  157. package/hooks/blocking/nas_ssh_binary_enforcer.py +0 -163
  158. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +0 -260
  159. package/hooks/blocking/package_inventory_stale_blocker.py +0 -107
  160. package/hooks/blocking/pii_prevention_blocker.py +0 -365
  161. package/hooks/blocking/piped_pytest_blocker.py +0 -1223
  162. package/hooks/blocking/question_to_user_enforcer.py +0 -130
  163. package/hooks/blocking/send_user_file_open_locally_blocker.py +0 -71
  164. package/hooks/blocking/sensitive_file_protector.py +0 -167
  165. package/hooks/blocking/session_edit_stage_gate.py +0 -684
  166. package/hooks/blocking/session_handoff_blocker.py +0 -182
  167. package/hooks/blocking/shell_substitution_blocker.py +0 -350
  168. package/hooks/blocking/test_ask_user_question_shape.py +0 -69
  169. package/hooks/blocking/test_bot_mention_comment_blocker.py +0 -131
  170. package/hooks/blocking/test_claude_md_orphan_file_blocker.py +0 -1277
  171. package/hooks/blocking/test_cursor_cli_python_misfire_blocker.py +0 -208
  172. package/hooks/blocking/test_destructive_command_blocker.py +0 -2024
  173. package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +0 -105
  174. package/hooks/blocking/test_destructive_command_blocker_no_verify.py +0 -122
  175. package/hooks/blocking/test_destructive_command_blocker_patterns.py +0 -133
  176. package/hooks/blocking/test_fable_spawn_gate.py +0 -381
  177. package/hooks/blocking/test_inventory_deadlock_resolution.py +0 -154
  178. package/hooks/blocking/test_luna_fast_mode_gate.py +0 -211
  179. package/hooks/blocking/test_nas_ssh_binary_enforcer.py +0 -225
  180. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +0 -231
  181. package/hooks/blocking/test_package_inventory_stale_blocker.py +0 -382
  182. package/hooks/blocking/test_pii_prevention_blocker.py +0 -1222
  183. package/hooks/blocking/test_pii_prevention_windows_git_path.py +0 -41
  184. package/hooks/blocking/test_pii_write_surface_ephemeral.py +0 -221
  185. package/hooks/blocking/test_piped_pytest_blocker.py +0 -587
  186. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +0 -233
  187. package/hooks/blocking/test_question_to_user_enforcer.py +0 -169
  188. package/hooks/blocking/test_send_user_file_open_locally_blocker.py +0 -118
  189. package/hooks/blocking/test_sensitive_file_protector.py +0 -365
  190. package/hooks/blocking/test_session_edit_stage_gate.py +0 -537
  191. package/hooks/blocking/test_session_edit_stage_gate_staging.py +0 -64
  192. package/hooks/blocking/test_session_edit_stage_gate_support.py +0 -204
  193. package/hooks/blocking/test_session_edit_stage_gate_tracker.py +0 -116
  194. package/hooks/blocking/test_session_handoff_blocker.py +0 -318
  195. package/hooks/blocking/test_shell_substitution_blocker.py +0 -298
  196. package/hooks/blocking/test_unscoped_search_blocker.py +0 -102
  197. package/hooks/blocking/test_write_existing_file_blocker.py +0 -122
  198. package/hooks/blocking/tests/test_pii_prevention_blocker.py +0 -259
  199. package/hooks/blocking/unscoped_search_blocker.py +0 -391
  200. package/hooks/blocking/write_existing_file_blocker.py +0 -124
  201. package/hooks/hooks_constants/bot_mention_comment_blocker_constants.py +0 -19
  202. package/hooks/hooks_constants/cursor_cli_python_misfire_blocker_constants.py +0 -79
  203. package/hooks/hooks_constants/fable_spawn_gate_constants.py +0 -61
  204. package/hooks/hooks_constants/luna_fast_mode_gate_constants.py +0 -45
  205. package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +0 -20
  206. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +0 -57
  207. package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +0 -17
  208. package/hooks/hooks_constants/sensitive_file_protector_constants.py +0 -40
  209. package/hooks/hooks_constants/session_handoff_blocker_constants.py +0 -10
  210. package/hooks/hooks_constants/shell_substitution_blocker_constants.py +0 -80
@@ -34,11 +34,7 @@ from test_hook_subprocess_support import ( # noqa: E402
34
34
  run_hook_as_subprocess,
35
35
  )
36
36
 
37
- ALL_CONVERTED_HOOK_FILENAMES = (
38
- "open_questions_in_plans_blocker.py",
39
- "claude_md_orphan_file_blocker.py",
40
- "package_inventory_stale_blocker.py",
41
- )
37
+ ALL_CONVERTED_HOOK_FILENAMES = ("open_questions_in_plans_blocker.py",)
42
38
 
43
39
  EMPTY_STDIN_PAYLOAD = ""
44
40
  WHITESPACE_STDIN_PAYLOAD = " \n\t "
@@ -126,48 +122,6 @@ def test_open_questions_blocker_still_allows_plan_without_open_questions(
126
122
  assert _decision_from_stdout(completed) is None
127
123
 
128
124
 
129
- def test_package_inventory_blocker_still_denies_uninventoried_new_file(
130
- tmp_path: Path,
131
- ) -> None:
132
- inventory_body = "# package\n\n| File | Role |\n|---|---|\n| `alpha.py` | A |\n| `beta.py` | B |\n"
133
- (tmp_path / "README.md").write_text(inventory_body, encoding="utf-8")
134
- (tmp_path / "alpha.py").write_text("x = 1\n", encoding="utf-8")
135
- (tmp_path / "beta.py").write_text("x = 1\n", encoding="utf-8")
136
- new_file_path = tmp_path / "gamma.py"
137
- payload = json.dumps(
138
- {
139
- "tool_name": "Write",
140
- "tool_input": {"file_path": str(new_file_path), "content": "x = 1\n"},
141
- }
142
- )
143
- completed = _run_hook_script("package_inventory_stale_blocker.py", payload, tmp_path)
144
- assert completed.returncode == 0, completed.stderr
145
- assert _decision_from_stdout(completed) == "deny"
146
- assert_hook_deny_log_contains(tmp_path, "package_inventory_stale_blocker.py")
147
-
148
-
149
- def test_package_inventory_blocker_still_allows_inventoried_new_file(
150
- tmp_path: Path,
151
- ) -> None:
152
- inventory_body = (
153
- "# package\n\n| File | Role |\n|---|---|\n"
154
- "| `alpha.py` | A |\n| `beta.py` | B |\n| `gamma.py` | G |\n"
155
- )
156
- (tmp_path / "README.md").write_text(inventory_body, encoding="utf-8")
157
- (tmp_path / "alpha.py").write_text("x = 1\n", encoding="utf-8")
158
- (tmp_path / "beta.py").write_text("x = 1\n", encoding="utf-8")
159
- new_file_path = tmp_path / "gamma.py"
160
- payload = json.dumps(
161
- {
162
- "tool_name": "Write",
163
- "tool_input": {"file_path": str(new_file_path), "content": "x = 1\n"},
164
- }
165
- )
166
- completed = _run_hook_script("package_inventory_stale_blocker.py", payload, tmp_path)
167
- assert completed.returncode == 0, completed.stderr
168
- assert _decision_from_stdout(completed) is None
169
-
170
-
171
125
  def test_converted_hooks_allow_unrelated_tool_name(tmp_path: Path) -> None:
172
126
  payload = json.dumps({"tool_name": "Bash", "tool_input": {"command": "ls"}})
173
127
  for each_hook_filename in ALL_CONVERTED_HOOK_FILENAMES:
@@ -0,0 +1,116 @@
1
+ from __future__ import annotations
2
+
3
+ NOTICE_EVENT_COMMIT: str = "commit"
4
+ NOTICE_EVENT_PUSH: str = "push"
5
+ ALL_NOTICE_EVENTS: frozenset[str] = frozenset({NOTICE_EVENT_COMMIT, NOTICE_EVENT_PUSH})
6
+ TARGET_REPOSITORY_REMOTE: str = "jonecho/python-automation"
7
+ GIT_CONFIG_SUBCOMMAND: str = "config"
8
+ GIT_REV_PARSE_SUBCOMMAND: str = "rev-parse"
9
+ ALL_GIT_REMOTE_URL_QUERY: tuple[str, ...] = (GIT_CONFIG_SUBCOMMAND, "--get", "remote.origin.url")
10
+ ALL_GIT_REPOSITORY_ROOT_QUERY: tuple[str, ...] = (GIT_REV_PARSE_SUBCOMMAND, "--show-toplevel")
11
+ ALL_GIT_HEAD_QUERY: tuple[str, ...] = (GIT_REV_PARSE_SUBCOMMAND, "--verify", "HEAD")
12
+ ALL_GIT_ABSOLUTE_DIRECTORY_QUERY: tuple[str, ...] = (
13
+ GIT_REV_PARSE_SUBCOMMAND,
14
+ "--absolute-git-dir",
15
+ )
16
+ GIT_COMMAND_SUCCESS_EXIT_CODE: int = 0
17
+ LOCAL_VERIFICATION_DIRECTORY_NAME: str = "local-verification"
18
+ MANIFEST_DIRECTORY_NAME: str = "config"
19
+ MANIFEST_FILE_NAME: str = "local-verification.json"
20
+ REPORT_FILE_NAME: str = "report.json"
21
+ GIT_DIRECTORY_NAME: str = ".git"
22
+ REPOSITORY_ARGUMENT: str = "--repo"
23
+ BASE_ARGUMENT: str = "--base"
24
+ BASE_REFERENCE: str = "origin/main"
25
+ OUTPUT_ARGUMENT: str = "--output"
26
+ PYTHON_COMMAND: str = "python"
27
+ SCOPED_VERIFICATION_SCRIPT_PATH: str = ".github/ci/local_verify.py"
28
+ EXECUTOR_ARGUMENT: str = "--executor"
29
+ EXECUTOR_DIRECTORY_NAME: str = "scripts"
30
+ LOCAL_VERIFICATION_PACKAGE_DIRECTORY_NAME: str = "local_verification"
31
+ EXECUTOR_FILE_NAME: str = "cli.py"
32
+ PACKAGE_ROOT_PARENT_INDEX: int = 2
33
+ POWERSHELL_QUOTE: str = "'"
34
+ POWERSHELL_ESCAPED_QUOTE: str = "''"
35
+ NOTICE_HEADER: str = "=== LOCAL VERIFICATION ADVISORY ==="
36
+ UNKNOWN_SHA: str = "unknown"
37
+ NO_VERIFIED_SHA: str = "none"
38
+ STATUS_PENDING: str = "pending"
39
+ STATUS_UNVERIFIED: str = "unverified"
40
+ STATUS_STALE: str = "stale"
41
+ STATUS_FAILED: str = "failed"
42
+ STATUS_PASSED: str = "passed"
43
+ MINIMUM_REMOTE_PART_COUNT: int = 2
44
+ OWNER_PART_INDEX: int = -2
45
+ REPOSITORY_PART_INDEX: int = -1
46
+ REPORT_HEAD_FIELD: str = "head"
47
+ REPORT_BASE_FIELD: str = "base"
48
+ REPORT_MANIFEST_DIGEST_FIELD: str = "manifest_digest"
49
+ REPORT_STATUS_FIELD: str = "status"
50
+ REPORT_AGGREGATE_FIELD: str = "aggregate"
51
+ REPORT_TOTAL_FIELD: str = "total"
52
+ REPORT_PASSED_FIELD: str = "passed"
53
+ REPORT_FAILED_FIELD: str = "failed"
54
+ REPORT_INCOMPLETE_FIELD: str = "incomplete"
55
+ REPORT_EXIT_CODE_FIELD: str = "exit_code"
56
+ REPORT_WORKTREE_CLEAN_FIELD: str = "worktree_clean"
57
+ REPORT_INPUTS_UNCHANGED_FIELD: str = "inputs_unchanged"
58
+ REPORT_PUBLISHABLE_FIELD: str = "publishable"
59
+ RESOLVED_SHA_LENGTH: int = 40
60
+ HEX_DIGITS: str = "0123456789abcdef"
61
+ JSON_ENCODING: str = "utf-8"
62
+ SHA256_ALGORITHM: str = "sha256"
63
+ NOTICE_LINE_SEPARATOR: str = "\n"
64
+ NOTICE_ADVISORY_LINE: str = "Advisory only. This notice does not block commit or push."
65
+ NOTICE_SETUP_PENDING_LINE: str = "Setup status: pending. The manifest is missing or unreadable."
66
+ NOTICE_NO_PASS_LINE: str = (
67
+ "Do not carry local-checks:passed to this revision. No complete current pass is recorded."
68
+ )
69
+ NOTICE_STALE_LINE: str = "Existing verification evidence belongs to another SHA. Do not carry local-checks:passed forward."
70
+ NOTICE_FAILED_LINE: str = "The recorded local checks failed. This advisory does not block commit or push. Fix the failure before reporting a pass."
71
+ NOTICE_PASSED_LINE: str = (
72
+ "local-checks:passed is valid only for this exact current SHA and manifest."
73
+ )
74
+ NOTICE_RUN_LINE: str = "Run the complete local checks with this canonical command:"
75
+ PROTECTED_BRANCH_PUSH_ADVISORY_MESSAGE: str = (
76
+ "Advisory: push would send local branch {local_branch!r} to protected remote "
77
+ "branch {remote_branch!r}. The native hook permits the push."
78
+ )
79
+ MANIFEST_VERSION_KEY: str = "version"
80
+ MANIFEST_CHECKS_KEY: str = "checks"
81
+ MANIFEST_EXCLUSIONS_KEY: str = "exclusions"
82
+ CHECK_ID_KEY: str = "id"
83
+ CHECK_ARGUMENTS_KEY: str = "argv"
84
+ CHECK_DIRECTORY_KEY: str = "cwd"
85
+ CHECK_TIMEOUT_KEY: str = "timeout_seconds"
86
+ CHECK_MINIMUM_TESTS_KEY: str = "minimum_tests"
87
+ EXCLUSION_SELECTOR_KEY: str = "selector"
88
+ EXCLUSION_REASON_KEY: str = "reason"
89
+ ALL_MANIFEST_DIGEST_SEPARATORS: tuple[str, str] = (",", ":")
90
+ WINDOWS_DIRECTORY_SEPARATOR: str = "\\"
91
+ POSIX_DIRECTORY_SEPARATOR: str = "/"
92
+ PARENT_DIRECTORY_NAME: str = ".."
93
+ ALL_GIT_STATUS_QUERY: tuple[str, ...] = (
94
+ "status",
95
+ "--porcelain=v1",
96
+ "--untracked-files=all",
97
+ )
98
+ ALL_GIT_BASE_QUERY_PREFIX: tuple[str, ...] = ("rev-parse", "--verify")
99
+ GIT_COMMIT_OBJECT_SUFFIX: str = "^{commit}"
100
+ SELECTION_FIELD: str = "selection"
101
+ SELECTED_MANIFEST_PATH_FIELD: str = "selected_manifest_path"
102
+ COMMAND_SEPARATOR: str = " "
103
+ RUNNER_FILE_NAME: str = "runner.json"
104
+ RUNNER_PYTHON_FIELD: str = "python"
105
+ RUNNER_SETTINGS_FIELD: str = "settings"
106
+ ALL_RUNNER_FIELDS: frozenset[str] = frozenset(
107
+ {
108
+ RUNNER_PYTHON_FIELD,
109
+ RUNNER_SETTINGS_FIELD,
110
+ }
111
+ )
112
+ AUTOMATIC_ADVISORY_DIRECTORY_NAME: str = "automatic_advisory"
113
+ AUTOMATIC_ADVISORY_CLI_FILE_NAME: str = "cli.py"
114
+ WINDOWS_PLATFORM: str = "win32"
115
+ CREATE_NO_WINDOW_ATTRIBUTE: str = "CREATE_NO_WINDOW"
116
+ POWERSHELL_CALL_OPERATOR: str = "& "
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env python3
2
+ """Show the local verification reminder after a native Git commit."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ from verification_notice import main as verification_notice_main
10
+ from git_hooks_constants.verification_notice_constants import (
11
+ NOTICE_EVENT_COMMIT,
12
+ REPOSITORY_ARGUMENT,
13
+ )
14
+
15
+
16
+ def main() -> int:
17
+ try:
18
+ verification_notice_main(
19
+ [
20
+ "--event",
21
+ NOTICE_EVENT_COMMIT,
22
+ REPOSITORY_ARGUMENT,
23
+ str(Path.cwd()),
24
+ ],
25
+ stdout=sys.stdout,
26
+ )
27
+ return 0
28
+ except (OSError, UnicodeError, ValueError):
29
+ return 0
30
+
31
+
32
+ if __name__ == "__main__":
33
+ raise SystemExit(main())
@@ -1,106 +1,34 @@
1
1
  #!/usr/bin/env python3
2
- """Run staged policy lint, then the existing staged CODE_RULES gate.
3
-
4
- Git invokes this module through the installed native pre-commit shim. Policy
5
- lint reads the Git index, including GIT_INDEX_FILE when Git supplies an
6
- alternate index. The existing gate still covers checks whose replacement
7
- coverage is unproven.
8
-
9
- A missing linter, launch failure, or timeout is an infrastructure failure.
10
- Linter diagnostics and failed-rule statuses reach Git.
11
- """
2
+ """Show the local verification reminder before a native Git commit."""
12
3
 
13
4
  from __future__ import annotations
14
5
 
15
- import subprocess
16
6
  import sys
17
7
  from pathlib import Path
18
8
 
19
- from gate_utils import is_safe_regular_file, resolve_gate_script_path
20
- from git_hooks_constants import (
21
- GATE_INFRASTRUCTURE_FAILURE_EXIT_CODE,
22
- GATE_SCRIPT_NOT_FOUND_MESSAGE,
23
- IMMEDIATE_SCOPE_ARGUMENT,
24
- INVOKE_GATE_FAILURE_MESSAGE,
25
- )
26
- from git_hooks_constants.staged_policy_lint import (
27
- POLICY_LINT_FAILED_MESSAGE,
28
- POLICY_LINT_INFRASTRUCTURE_EXIT_CODE,
29
- POLICY_LINT_PACKAGE_PARENT_INDEX,
30
- POLICY_LINT_SCRIPT_RELATIVE_PATH,
31
- POLICY_LINT_STAGED_ARGUMENT,
32
- POLICY_LINT_TIMEOUT_SECONDS,
33
- POLICY_LINT_UNAVAILABLE_MESSAGE,
9
+ from verification_notice import main as verification_notice_main
10
+ from git_hooks_constants.verification_notice_constants import (
11
+ NOTICE_EVENT_COMMIT,
12
+ REPOSITORY_ARGUMENT,
34
13
  )
35
14
 
36
15
 
37
- def resolve_policy_lint_script_path() -> Path:
38
- """Return the policy-linter entry point in this package or managed home."""
39
- package_root = Path(__file__).resolve().parents[POLICY_LINT_PACKAGE_PARENT_INDEX]
40
- return package_root / POLICY_LINT_SCRIPT_RELATIVE_PATH
41
-
42
-
43
- def run_staged_policy_lint() -> int:
44
- """Run the staged linter with Git's environment and working directory.
45
-
46
- Returns:
47
- The linter status, or the infrastructure status when it cannot run.
48
- """
49
- try:
50
- script_path = resolve_policy_lint_script_path()
51
- if not script_path.is_file():
52
- sys.stderr.write(POLICY_LINT_UNAVAILABLE_MESSAGE + "\n")
53
- return POLICY_LINT_INFRASTRUCTURE_EXIT_CODE
54
- completion = subprocess.run(
55
- [sys.executable, str(script_path.resolve(strict=True)), POLICY_LINT_STAGED_ARGUMENT],
56
- check=False,
57
- timeout=POLICY_LINT_TIMEOUT_SECONDS,
58
- )
59
- except (OSError, subprocess.TimeoutExpired) as launch_error:
60
- sys.stderr.write(POLICY_LINT_FAILED_MESSAGE.format(error=launch_error) + "\n")
61
- return POLICY_LINT_INFRASTRUCTURE_EXIT_CODE
62
- return completion.returncode
63
-
64
-
65
- def invoke_gate(gate_script_path: Path) -> int:
66
- """Invoke the shared staged gate and return its exit code."""
67
- immediate_scope_argument = IMMEDIATE_SCOPE_ARGUMENT
68
- invoke_gate_failure_message = INVOKE_GATE_FAILURE_MESSAGE
69
- gate_infrastructure_failure_exit_code = GATE_INFRASTRUCTURE_FAILURE_EXIT_CODE
70
- try:
71
- resolved_gate_path = gate_script_path.resolve(strict=True)
72
- completion = subprocess.run(
73
- [sys.executable, str(resolved_gate_path), immediate_scope_argument],
74
- check=False,
75
- )
76
- except OSError as launch_error:
77
- print(
78
- invoke_gate_failure_message.format(error=launch_error),
79
- file=sys.stderr,
80
- )
81
- return gate_infrastructure_failure_exit_code
82
- return completion.returncode
83
-
84
-
85
16
  def main() -> int:
86
- """Run local staged policy lint before the existing native commit checks.
87
-
88
- Returns:
89
- The first failing check's status, or zero when the checks pass.
90
- """
91
- lint_exit_code = run_staged_policy_lint()
92
- if lint_exit_code != 0:
93
- return lint_exit_code
94
- gate_script_not_found_message = GATE_SCRIPT_NOT_FOUND_MESSAGE
95
- gate_script_path, exact_allowed_path = resolve_gate_script_path()
96
- if not is_safe_regular_file(gate_script_path, exact_allowed_path):
97
- print(
98
- gate_script_not_found_message.format(path=gate_script_path),
99
- file=sys.stderr,
17
+ try:
18
+ verification_notice_main(
19
+ [
20
+ "--event",
21
+ NOTICE_EVENT_COMMIT,
22
+ "--notice-only",
23
+ REPOSITORY_ARGUMENT,
24
+ str(Path.cwd()),
25
+ ],
26
+ stdout=sys.stdout,
100
27
  )
101
28
  return 0
102
- return invoke_gate(gate_script_path)
29
+ except (OSError, UnicodeError, ValueError):
30
+ return 0
103
31
 
104
32
 
105
33
  if __name__ == "__main__":
106
- sys.exit(main())
34
+ raise SystemExit(main())