claude-dev-env 7.4.1 → 7.6.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.
- package/.agents/skills/everything-search/scripts/everything_search.py +11 -0
- package/.agents/skills/everything-search/scripts/test_everything_search.py +1 -0
- package/.agents/skills/fresh-branch/SKILL.md +1 -0
- package/.agents/skills/fresh-branch/scripts/fresh_branch_git_commands.py +3 -0
- package/.agents/skills/fresh-branch/scripts/subprocess_window_access.py +43 -0
- package/.agents/skills/syncing-submodules/SKILL.md +1 -0
- package/.agents/skills/syncing-submodules/scripts/submodule_sync.py +4 -0
- package/.agents/skills/syncing-submodules/scripts/subprocess_window_access.py +43 -0
- package/.agents/skills/test-runner/SKILL.md +1 -0
- package/.agents/skills/test-runner/scripts/preflight_checks.py +5 -0
- package/.agents/skills/test-runner/scripts/run_tests.py +11 -0
- package/.agents/skills/test-runner/scripts/subprocess_window_access.py +43 -0
- package/.agents/skills/test-runner/scripts/test_run_tests.py +9 -7
- package/_shared/pr-loop/scripts/check_bugbot_ci.py +3 -0
- package/_shared/pr-loop/scripts/check_convergence_gates.py +3 -0
- package/_shared/pr-loop/scripts/check_pending_reviews.py +3 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/added_line_maps.py +3 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/baseline_import_isolation.py +3 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +5 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_file_sets.py +4 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +3 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +3 -0
- package/_shared/pr-loop/scripts/codex_usage_probe.py +3 -0
- package/_shared/pr-loop/scripts/copilot_quota.py +3 -0
- package/_shared/pr-loop/scripts/fetch_copilot_reviews.py +3 -0
- package/_shared/pr-loop/scripts/fix_hookspath.py +7 -0
- package/_shared/pr-loop/scripts/post_fix_reply.py +4 -0
- package/_shared/pr-loop/scripts/preflight.py +7 -0
- package/_shared/pr-loop/scripts/preflight_self_heal.py +5 -0
- package/_shared/pr-loop/scripts/run_codex_review.py +3 -0
- package/_shared/pr-loop/scripts/subprocess_window_access.py +41 -0
- package/_shared/pr-loop/scripts/terminology_sweep.py +5 -0
- package/_shared/process-tree/scripts/process_tree_kill.py +3 -0
- package/_shared/process-tree/scripts/subprocess_window_access.py +41 -0
- package/bin/install-constants.mjs +4 -2
- package/bin/install.cursor-rules.test.mjs +57 -15
- package/bin/install.mjs +10 -16
- package/bin/install.policy-lint.test.mjs +1 -2
- package/bin/install.test.mjs +0 -1
- package/bin/pstack-model-preferences.claude.json +23 -0
- package/hooks/advisory/msys_path_conversion_advisor.py +200 -0
- package/hooks/advisory/pr_done_reminder.py +14 -13
- package/hooks/advisory/refactor_guard.py +8 -0
- package/hooks/advisory/test_msys_path_conversion_advisor.py +223 -0
- package/hooks/advisory/test_pr_done_reminder.py +22 -0
- package/hooks/advisory/test_refactor_guard.py +40 -0
- package/hooks/blocking/bash_post_call_dispatcher.py +6 -11
- package/hooks/blocking/block_main_commit.py +4 -0
- package/hooks/blocking/code_rules_comments.py +39 -5
- package/hooks/blocking/msys_rev_path_rewriter.py +192 -0
- package/hooks/blocking/pii_prevention_blocker_parts/repository_exemption.py +3 -0
- package/hooks/blocking/precommit_code_rules_gate.py +3 -0
- package/hooks/blocking/tdd_enforcer_parts/content_analysis.py +19 -3
- package/hooks/blocking/tdd_enforcer_parts/git_tracking.py +4 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_content_analysis.py +25 -0
- package/hooks/blocking/test_bash_dispatcher_interpreter_starts.py +16 -3
- package/hooks/blocking/test_bash_post_call_dispatcher.py +2 -0
- package/hooks/blocking/test_code_rules_enforcer_comment_string_awareness.py +27 -0
- package/hooks/blocking/test_code_rules_enforcer_exempt_marker_chained.py +10 -0
- package/hooks/blocking/test_msys_rev_path_rewriter.py +141 -0
- package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +0 -2
- package/hooks/git-hooks/pull_request_handoff.py +3 -0
- package/hooks/git-hooks/subprocess_window_access.py +41 -0
- package/hooks/git-hooks/test_verification_start.py +4 -0
- package/hooks/git-hooks/verification_notice_context.py +3 -0
- package/hooks/git-hooks/verification_start.py +7 -8
- package/hooks/hooks.json +10 -0
- package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +9 -0
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +6 -1
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +2 -0
- package/hooks/hooks_constants/msys_path_conversion_advisor_constants.py +48 -0
- package/hooks/hooks_constants/msys_rev_path_rewriter_constants.py +37 -0
- package/hooks/hooks_constants/post_tool_use_context.py +34 -0
- package/hooks/hooks_constants/pr_done_reminder_constants.py +0 -2
- package/hooks/hooks_constants/pre_tool_use_allow_output.py +48 -0
- package/hooks/hooks_constants/subprocess_window.py +141 -0
- package/hooks/hooks_constants/subprocess_window_constants.py +9 -0
- package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +9 -2
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +9 -2
- package/hooks/hooks_constants/test_code_rules_enforcer_constants.py +6 -0
- package/hooks/hooks_constants/test_failure_recorder_constants.py +1 -2
- package/hooks/hooks_constants/test_post_tool_use_context.py +22 -0
- package/hooks/hooks_constants/test_pre_tool_use_allow_output.py +27 -0
- package/hooks/hooks_constants/test_subprocess_window.py +128 -0
- package/hooks/lifecycle/enter_worktree_origin_prefetch.py +3 -0
- package/hooks/observability/test_failure_recorder.py +3 -1
- package/hooks/validation/mypy_validator.py +4 -0
- package/hooks/validators/README.md +1 -0
- package/hooks/validators/git_checks.py +4 -0
- package/hooks/validators/health_check.py +3 -0
- package/hooks/validators/hook_timing_harness.py +3 -0
- package/hooks/validators/mypy_integration.py +4 -0
- package/hooks/validators/ruff_integration.py +6 -0
- package/hooks/validators/run_all_validators.py +7 -0
- package/hooks/validators/subprocess_window_access.py +41 -0
- package/hooks/workflow/auto_formatter.py +8 -0
- package/hooks/workflow/test_auto_formatter.py +39 -0
- package/package.json +1 -1
- package/rules/ask-user-question-required.md +3 -3
- package/rules/code-standards.md +3 -2
- package/rules/confirm-implementation-forks.md +2 -0
- package/rules/destructive-commands.md +19 -19
- package/rules/doc-inventory-integrity.md +4 -4
- package/rules/docstring-prose-matches-implementation.md +2 -2
- package/rules/failure-blast-radius.md +4 -2
- package/rules/filesystem-search.md +1 -1
- package/rules/git-workflow.md +34 -0
- package/rules/long-horizon-autonomy.md +2 -0
- package/rules/nas-ssh-invocation.md +3 -3
- package/rules/no-cross-skill-duplicate-helpers.md +6 -6
- package/rules/orphan-css-class.md +5 -5
- package/rules/paired-test-coverage.md +6 -6
- package/rules/plain-illustrative-docstrings.md +3 -3
- package/rules/pstack-models.md +4 -3
- package/rules/re-stage-before-commit.md +7 -7
- package/rules/retired-hook-prose.md +16 -0
- package/rules/shell-invocation.md +17 -1
- package/rules/testing.md +3 -5
- package/rules/verify-runtime-state.md +1 -1
- package/rules/windows-filesystem-safe.md +2 -2
- package/rules/workflow-substitution-slots.md +1 -1
- package/scripts/automatic_advisory/checkout.py +8 -1
- package/scripts/automatic_advisory/cli.py +9 -3
- package/scripts/automatic_advisory/config/constants.py +0 -2
- package/scripts/automatic_advisory/execution.py +7 -1
- package/scripts/automatic_advisory/git.py +9 -1
- package/scripts/automatic_advisory/process_host.py +3 -0
- package/scripts/claude_chain_runner.py +3 -0
- package/scripts/durable_post_lint_config/config/constants.py +0 -3
- package/scripts/durable_post_lint_config/config/test_constants.py +5 -0
- package/scripts/gh_artifact_upload.py +3 -0
- package/scripts/grok_headless_runner.py +3 -0
- package/scripts/grok_patch_artifacts.py +4 -0
- package/scripts/grok_worker_preflight.py +3 -0
- package/scripts/invoke_code_review.py +3 -0
- package/scripts/local_verification/command_runner.py +3 -0
- package/scripts/local_verification/git_state.py +3 -0
- package/scripts/policy_lint/adapter_configuration.py +24 -0
- package/scripts/policy_lint/adapter_detectors.py +48 -2
- package/scripts/policy_lint/adapter_pairing.py +150 -2
- package/scripts/policy_lint/adapter_retired_hook_prose.py +201 -0
- package/scripts/policy_lint/adapters.py +82 -5
- package/scripts/policy_lint/config/approved_test_pairs.py +25 -9
- package/scripts/policy_lint/config/constants.py +77 -0
- package/scripts/policy_lint/registry.py +6 -1
- package/scripts/policy_lint/selection.py +37 -18
- package/scripts/policy_lint/selection_git.py +17 -2
- package/scripts/repository_checks/config/constants.py +5 -0
- package/scripts/repository_checks/config/policy_document.py +19 -0
- package/scripts/repository_checks/email_exemptions.py +14 -71
- package/scripts/repository_checks/path_exemptions.py +35 -0
- package/scripts/repository_checks/policy_document.py +120 -0
- package/scripts/repository_checks/tracked_secrets.py +27 -4
- package/scripts/setup_project_paths.py +3 -0
- package/scripts/spawn_grok_batch.py +3 -0
- package/scripts/subprocess_window_access.py +41 -0
- package/scripts/test_dispatcher_profile_import.py +4 -0
- package/scripts/test_durable_post_lint.py +42 -9
- package/scripts/tests/test_adapter_configuration.py +8 -0
- package/scripts/tests/test_automatic_advisory_window_flags.py +17 -11
- package/scripts/tests/test_email_exemptions.py +37 -0
- package/scripts/tests/test_path_exemptions.py +164 -0
- package/scripts/tests/test_policy_document.py +104 -0
- package/scripts/tests/test_policy_lint_rules_function_length_scope.py +101 -0
- package/scripts/tests/test_policy_lint_rules_pairing.py +375 -0
- package/scripts/tests/test_policy_lint_rules_registry.py +116 -0
- package/scripts/tests/test_policy_lint_rules_retired_hook_prose.py +197 -0
- package/scripts/tests/test_policy_lint_selection.py +141 -0
- package/scripts/tests/test_subprocess_window_access.py +118 -0
- package/scripts/tests/test_tracked_secrets.py +79 -0
- package/scripts/validate_instruction_pairs.py +3 -0
- package/scripts/verify_installable_package.py +5 -0
- package/hooks/hooks_constants/convergence_branch_constants.py +0 -8
- package/hooks/hooks_constants/destructive_command_environment_constants.py +0 -18
- package/hooks/hooks_constants/test_text_stripping.py +0 -39
- package/hooks/hooks_constants/text_stripping.py +0 -36
- package/scripts/automatic_advisory/window_flags.py +0 -41
- package/scripts/repository_checks/config/email_exemptions.py +0 -10
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import hashlib
|
|
6
|
+
import json
|
|
6
7
|
import sys
|
|
8
|
+
from collections.abc import Callable
|
|
7
9
|
from pathlib import Path
|
|
8
10
|
|
|
9
11
|
import pytest
|
|
@@ -12,6 +14,7 @@ from repository_checks.config.constants import (
|
|
|
12
14
|
CHECK_ID_TRACKED_PERSONAL_DATA,
|
|
13
15
|
FAILED_CHECK_EXIT_CODE,
|
|
14
16
|
FINDINGS_EXIT_CODE,
|
|
17
|
+
SUCCESS_EXIT_CODE,
|
|
15
18
|
)
|
|
16
19
|
from repository_checks.hook_modules import load_hooks_module
|
|
17
20
|
from repository_checks.tracked_secrets import collect_tracked_secret_findings
|
|
@@ -35,6 +38,8 @@ _OTHER_FIXTURE_EMAIL = "other-owner@company.io"
|
|
|
35
38
|
_OTHER_FIXTURE_HOME_PATH = "C:/Users/realname/notes.txt"
|
|
36
39
|
_FIXTURE_NOTES_RELATIVE_PATH = "src/notes.py"
|
|
37
40
|
_OTHER_NOTES_RELATIVE_PATH = "src/other_notes.py"
|
|
41
|
+
_FROZEN_RELATIVE_PATH = "evidence/manifest.json"
|
|
42
|
+
_STALE_DIGEST = hashlib.sha256(b"different bytes").hexdigest()
|
|
38
43
|
_PII_PREVENTION_CONSTANTS = load_hooks_module(
|
|
39
44
|
"hooks_constants.pii_prevention_constants"
|
|
40
45
|
)
|
|
@@ -151,6 +156,80 @@ def test_should_keep_owned_checker_modules_free_of_tracked_secret_findings() ->
|
|
|
151
156
|
assert collect_tracked_secret_findings(_REPOSITORY_ROOT, all_relative_paths) == []
|
|
152
157
|
|
|
153
158
|
|
|
159
|
+
def test_should_skip_every_category_in_a_frozen_file_whose_digest_matches(
|
|
160
|
+
tmp_path: Path,
|
|
161
|
+
) -> None:
|
|
162
|
+
"""One recorded digest silences the whole file, not one matched value."""
|
|
163
|
+
repository_root = tmp_path / "repo"
|
|
164
|
+
initialize_repository(repository_root)
|
|
165
|
+
_write_frozen_path_exemption_fixture(repository_root, _matching_digest)
|
|
166
|
+
commit_tracked_files(repository_root)
|
|
167
|
+
exit_code, stdout_text, _stderr_text = run_policy(repository_root)
|
|
168
|
+
assert exit_code == SUCCESS_EXIT_CODE
|
|
169
|
+
assert _pii_categories_for_path(stdout_text, _FROZEN_RELATIVE_PATH) == []
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_should_keep_reporting_a_frozen_file_whose_digest_is_stale(
|
|
173
|
+
tmp_path: Path,
|
|
174
|
+
) -> None:
|
|
175
|
+
repository_root = tmp_path / "repo"
|
|
176
|
+
initialize_repository(repository_root)
|
|
177
|
+
_write_frozen_path_exemption_fixture(repository_root, _stale_digest)
|
|
178
|
+
commit_tracked_files(repository_root)
|
|
179
|
+
exit_code, stdout_text, _stderr_text = run_policy(repository_root)
|
|
180
|
+
assert exit_code == FINDINGS_EXIT_CODE
|
|
181
|
+
assert _pii_categories_for_path(stdout_text, _FROZEN_RELATIVE_PATH) == [
|
|
182
|
+
_PII_CATEGORY_HOME_PATH,
|
|
183
|
+
_PII_PREVENTION_CONSTANTS.CATEGORY_SECRET,
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def test_should_exempt_a_frozen_file_named_by_a_windows_tracked_path(
|
|
188
|
+
tmp_path: Path,
|
|
189
|
+
) -> None:
|
|
190
|
+
"""Git on Windows can hand back backslashes, and the entry records slashes."""
|
|
191
|
+
repository_root = tmp_path / "repo"
|
|
192
|
+
repository_root.mkdir()
|
|
193
|
+
_write_frozen_path_exemption_fixture(repository_root, _matching_digest)
|
|
194
|
+
windows_tracked_path = _FROZEN_RELATIVE_PATH.replace("/", "\\")
|
|
195
|
+
assert (
|
|
196
|
+
collect_tracked_secret_findings(repository_root, [windows_tracked_path]) == []
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _write_frozen_path_exemption_fixture(
|
|
201
|
+
repository_root: Path, choose_digest: Callable[[Path], str]
|
|
202
|
+
) -> None:
|
|
203
|
+
frozen_path = repository_root / _FROZEN_RELATIVE_PATH
|
|
204
|
+
write_text(
|
|
205
|
+
frozen_path,
|
|
206
|
+
f"home = '{_OTHER_FIXTURE_HOME_PATH}'\ntoken = '{_SYNTHETIC_GITHUB_TOKEN}'\n",
|
|
207
|
+
)
|
|
208
|
+
write_text(
|
|
209
|
+
repository_root / "config" / "repository-policy.json",
|
|
210
|
+
json.dumps(
|
|
211
|
+
{
|
|
212
|
+
"version": 1,
|
|
213
|
+
"path_exemptions": [
|
|
214
|
+
{
|
|
215
|
+
"path": _FROZEN_RELATIVE_PATH,
|
|
216
|
+
"sha256": choose_digest(frozen_path),
|
|
217
|
+
"reason": "Frozen evidence file pinned by its consumers",
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
}
|
|
221
|
+
),
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _matching_digest(frozen_path: Path) -> str:
|
|
226
|
+
return hashlib.sha256(frozen_path.read_bytes()).hexdigest()
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _stale_digest(_frozen_path: Path) -> str:
|
|
230
|
+
return _STALE_DIGEST
|
|
231
|
+
|
|
232
|
+
|
|
154
233
|
def _write_exact_exemption_fixture(repository_root: Path) -> None:
|
|
155
234
|
write_text(
|
|
156
235
|
repository_root / _FIXTURE_NOTES_RELATIVE_PATH,
|
|
@@ -9,6 +9,8 @@ import stat
|
|
|
9
9
|
import subprocess
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
+
from subprocess_window_access import hidden_window_creation_flags
|
|
13
|
+
|
|
12
14
|
git_directory_name = ".git"
|
|
13
15
|
git_listing_commands = (
|
|
14
16
|
(("git", "ls-files", "--stage", "-z"), True),
|
|
@@ -32,6 +34,7 @@ def _read_git_paths_and_modes(
|
|
|
32
34
|
cwd=repository_root,
|
|
33
35
|
capture_output=True,
|
|
34
36
|
check=True,
|
|
37
|
+
creationflags=hidden_window_creation_flags(),
|
|
35
38
|
)
|
|
36
39
|
for each_record in completed_process.stdout.split(b"\0"):
|
|
37
40
|
if not each_record:
|
|
@@ -68,6 +68,8 @@ from dev_env_scripts_constants.verify_installable_package_constants import (
|
|
|
68
68
|
VERIFICATION_PASSED_MESSAGE,
|
|
69
69
|
)
|
|
70
70
|
|
|
71
|
+
from subprocess_window_access import hidden_window_creation_flags
|
|
72
|
+
|
|
71
73
|
|
|
72
74
|
def package_root_path() -> Path:
|
|
73
75
|
"""Return the claude-dev-env package root that holds package.json."""
|
|
@@ -303,6 +305,7 @@ def run_npm_pack(into_directory: Path, from_package_root: Path) -> Path:
|
|
|
303
305
|
capture_output=True,
|
|
304
306
|
text=True,
|
|
305
307
|
encoding=UTF8_ENCODING,
|
|
308
|
+
creationflags=hidden_window_creation_flags(),
|
|
306
309
|
)
|
|
307
310
|
tarball_name = _npm_pack_filename_from_json(completed.stdout)
|
|
308
311
|
return into_directory / tarball_name
|
|
@@ -439,6 +442,7 @@ def list_git_tracked_paths_under(
|
|
|
439
442
|
capture_output=True,
|
|
440
443
|
text=True,
|
|
441
444
|
encoding=UTF8_ENCODING,
|
|
445
|
+
creationflags=hidden_window_creation_flags(),
|
|
442
446
|
)
|
|
443
447
|
return frozenset(
|
|
444
448
|
each_line.replace("\\", "/")
|
|
@@ -520,6 +524,7 @@ def smoke_check_install_entrypoint(from_package_root: Path) -> str | None:
|
|
|
520
524
|
capture_output=True,
|
|
521
525
|
text=True,
|
|
522
526
|
encoding=UTF8_ENCODING,
|
|
527
|
+
creationflags=hidden_window_creation_flags(),
|
|
523
528
|
)
|
|
524
529
|
if completed.returncode == 0:
|
|
525
530
|
return None
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"""Convergence branch naming policy constants.
|
|
2
|
-
|
|
3
|
-
Shared by destructive_command_blocker convergence-branch exemptions
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
ALL_CONVERGENCE_BRANCH_PREFIXES: tuple[str, ...] = ("claude/", "worktree-")
|
|
7
|
-
CONVERGENCE_BRANCH_SUFFIX_PATTERN: str = r"pr-.*-converge$"
|
|
8
|
-
CONVERGENCE_FORCE_PUSH_DETECTION_PATTERN: str = r"\bgit\s+push\b\s+(.*(?:--force|-f)\b.*)"
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"""Environment keys and values used by destructive-command hooks."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
ALL_KNOWN_TEMPORARY_ENVIRONMENT_VARIABLE_NAMES: frozenset[str] = frozenset(
|
|
6
|
-
{
|
|
7
|
-
"TEMP",
|
|
8
|
-
"TMP",
|
|
9
|
-
"TMPDIR",
|
|
10
|
-
"CLAUDE_JOB_DIR",
|
|
11
|
-
}
|
|
12
|
-
)
|
|
13
|
-
ALL_TRUTHY_ENV_VALUES: frozenset[str] = frozenset({"1", "true", "yes", "on"})
|
|
14
|
-
DESTRUCTIVE_DENY_MODE_ENV_VAR: str = "CLAUDE_DESTRUCTIVE_DENY_MODE"
|
|
15
|
-
EPHEMERAL_AUTO_ALLOW_DISABLE_ENV_VAR: str = (
|
|
16
|
-
"CLAUDE_DESTRUCTIVE_DISABLE_EPHEMERAL_AUTO_ALLOW"
|
|
17
|
-
)
|
|
18
|
-
GH_REDIRECT_ACTIVE_ENV_VAR: str = "CLAUDE_GH_REDIRECT_ACTIVE"
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"""Tests for the shared strip_code_and_quotes helper."""
|
|
2
|
-
|
|
3
|
-
import pathlib
|
|
4
|
-
import sys
|
|
5
|
-
|
|
6
|
-
_HOOKS_ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
7
|
-
if str(_HOOKS_ROOT) not in sys.path:
|
|
8
|
-
sys.path.insert(0, str(_HOOKS_ROOT))
|
|
9
|
-
|
|
10
|
-
from hooks_constants.text_stripping import strip_code_and_quotes
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def test_removes_fenced_code_block() -> None:
|
|
14
|
-
text = "before\n```python\nshould I run this?\n```\nafter"
|
|
15
|
-
stripped = strip_code_and_quotes(text)
|
|
16
|
-
assert "should I run this?" not in stripped
|
|
17
|
-
assert "before" in stripped
|
|
18
|
-
assert "after" in stripped
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def test_removes_inline_code_span() -> None:
|
|
22
|
-
text = "the function `would you like` is named oddly"
|
|
23
|
-
stripped = strip_code_and_quotes(text)
|
|
24
|
-
assert "would you like" not in stripped
|
|
25
|
-
assert "the function" in stripped
|
|
26
|
-
assert "is named oddly" in stripped
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def test_removes_leading_blockquote_lines() -> None:
|
|
30
|
-
text = "real line\n> should I proceed?\nfinal line"
|
|
31
|
-
stripped = strip_code_and_quotes(text)
|
|
32
|
-
assert "should I proceed?" not in stripped
|
|
33
|
-
assert "real line" in stripped
|
|
34
|
-
assert "final line" in stripped
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def test_leaves_plain_prose_unchanged() -> None:
|
|
38
|
-
text = "This sentence carries no code or quotes."
|
|
39
|
-
assert strip_code_and_quotes(text) == text
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"""Shared text-stripping helper for the Stop-hook prose blockers.
|
|
2
|
-
|
|
3
|
-
Several Stop hooks judge the prose of an assistant message and must ignore
|
|
4
|
-
fenced code blocks, inline code spans, and leading blockquotes so a phrase that
|
|
5
|
-
appears only inside code or a quote never trips the detector. The stripping
|
|
6
|
-
logic is identical across those blockers, so it lives here once and is imported
|
|
7
|
-
from each.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
import re
|
|
13
|
-
|
|
14
|
-
__all__ = [
|
|
15
|
-
"strip_code_and_quotes",
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
CODE_BLOCK_PATTERN = re.compile(r"```[\s\S]*?```", re.MULTILINE)
|
|
19
|
-
INLINE_CODE_PATTERN = re.compile(r"`[^`]+`")
|
|
20
|
-
QUOTED_BLOCK_PATTERN = re.compile(r"^>.*$", re.MULTILINE)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def strip_code_and_quotes(text: str) -> str:
|
|
24
|
-
"""Remove fenced code blocks, inline code, and blockquotes from prose.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
text: The raw assistant message to clean of code and quoted lines.
|
|
28
|
-
|
|
29
|
-
Returns:
|
|
30
|
-
The text with every fenced code block, inline code span, and leading
|
|
31
|
-
blockquote line removed, so only the prose a reader sees remains.
|
|
32
|
-
"""
|
|
33
|
-
text = CODE_BLOCK_PATTERN.sub("", text)
|
|
34
|
-
text = INLINE_CODE_PATTERN.sub("", text)
|
|
35
|
-
text = QUOTED_BLOCK_PATTERN.sub("", text)
|
|
36
|
-
return text
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"""Windows creation flags that hide the advisory poller and its children.
|
|
2
|
-
|
|
3
|
-
A poller with no console makes each git call and each check open a fresh
|
|
4
|
-
console window. A hidden console is inherited by descendants, so those
|
|
5
|
-
children stay off the screen.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import subprocess
|
|
11
|
-
import sys
|
|
12
|
-
|
|
13
|
-
from .config.constants import (
|
|
14
|
-
CREATE_NEW_PROCESS_GROUP_ATTRIBUTE,
|
|
15
|
-
CREATE_NO_WINDOW_ATTRIBUTE,
|
|
16
|
-
WINDOWS_PLATFORM,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def hidden_window_creation_flags() -> int:
|
|
21
|
-
"""Return the flag that runs a Windows child without a visible console.
|
|
22
|
-
|
|
23
|
-
Returns:
|
|
24
|
-
The hidden-console flag on Windows, zero elsewhere.
|
|
25
|
-
"""
|
|
26
|
-
if sys.platform != WINDOWS_PLATFORM:
|
|
27
|
-
return 0
|
|
28
|
-
return getattr(subprocess, CREATE_NO_WINDOW_ATTRIBUTE, 0)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def detached_poller_creation_flags() -> int:
|
|
32
|
-
"""Return the flags for the long-running poller on Windows.
|
|
33
|
-
|
|
34
|
-
Returns:
|
|
35
|
-
A new process group plus a hidden console on Windows, zero elsewhere.
|
|
36
|
-
"""
|
|
37
|
-
if sys.platform != WINDOWS_PLATFORM:
|
|
38
|
-
return 0
|
|
39
|
-
return getattr(subprocess, CREATE_NEW_PROCESS_GROUP_ATTRIBUTE, 0) | getattr(
|
|
40
|
-
subprocess, CREATE_NO_WINDOW_ATTRIBUTE, 0
|
|
41
|
-
)
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"""Repository public-email exception schema."""
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
|
|
5
|
-
CONFIG_RELATIVE_PATH = "config/repository-policy.json"
|
|
6
|
-
DIGEST_PATTERN = re.compile(r"[0-9a-f]{64}")
|
|
7
|
-
FORBIDDEN_PATH_CHARACTERS = frozenset("\\:*?[]")
|
|
8
|
-
ALL_ENTRY_FIELDS = frozenset({"path", "sha256", "reason"})
|
|
9
|
-
ALL_FORBIDDEN_PATH_SEGMENTS = frozenset({"", ".", ".."})
|
|
10
|
-
FIRST_PRINTABLE_CODEPOINT = 32
|