claude-dev-env 4.2.0 → 4.3.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/_shared/pr-loop/scripts/durable_post_lint.py +242 -0
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py +106 -0
- package/.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint.py +332 -0
- package/.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py +25 -0
- package/.agents/skills/issue-tracker/SKILL.md +6 -0
- package/.agents/skills/pull-request/SKILL.md +218 -0
- package/.agents/skills/pull-request/reference/publication-tasks.md +18 -0
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/__init__.py +1 -0
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/__init__.py +1 -0
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +61 -0
- package/.agents/skills/pull-request/scripts/pull_request.py +276 -0
- package/.agents/skills/pull-request/scripts/recover_legacy_author.py +251 -0
- package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +49 -0
- package/.agents/skills/pull-request/scripts/test_pull_request.py +398 -0
- package/.agents/skills/pull-request/scripts/test_recover_legacy_author.py +221 -0
- package/.agents/skills/test-runner/SKILL.md +69 -0
- package/.agents/skills/test-runner/scripts/preflight_checks.py +365 -0
- package/.agents/skills/test-runner/scripts/run_tests.py +316 -0
- package/.agents/skills/test-runner/scripts/test_preflight_checks.py +185 -0
- package/.agents/skills/test-runner/scripts/test_run_tests.py +281 -0
- package/.agents/skills/test-runner/scripts/test_runner_constants/__init__.py +1 -0
- package/.agents/skills/test-runner/scripts/test_runner_constants/config/__init__.py +1 -0
- package/.agents/skills/test-runner/scripts/test_runner_constants/config/constants.py +96 -0
- package/.agents/skills-archived/pr-loop-cloud-transport/reference/identity-and-hooks.md +1 -1
- package/bin/ever-shipped-skills.mjs +2 -0
- package/bin/ever-shipped-skills.test.mjs +8 -0
- package/bin/install.mjs +9 -1
- package/bin/install.prune.test.mjs +90 -0
- package/bin/install.test.mjs +24 -7
- package/hooks/blocking/pii_prevention_blocker.py +32 -51
- package/hooks/blocking/test_bash_post_call_dispatcher.py +5 -28
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +1 -4
- package/hooks/blocking/test_code_rules_command_dispatch.py +2 -2
- package/hooks/blocking/test_pii_prevention_blocker.py +37 -89
- package/hooks/gh_post_body_texts.py +195 -0
- package/hooks/hooks.json +0 -15
- package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +0 -1
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -8
- package/hooks/hooks_constants/gh_post_body_texts_constants.py +12 -0
- package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +0 -7
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +0 -7
- package/hooks/hooks_constants/test_failure_recorder_constants.py +3 -3
- package/hooks/hooks_constants/test_gh_post_body_texts_constants.py +19 -0
- package/hooks/observability/test_failure_recorder.py +1 -1
- package/hooks/pyproject.toml +1 -1
- package/hooks/test_gh_post_body_texts.py +79 -0
- package/package.json +1 -1
- package/rules/durable-post-artifacts.md +31 -20
- package/rules/gh-cli-conventions.md +23 -13
- package/rules/git-workflow.md +21 -8
- package/scripts/policy_lint/adapter_configuration.py +53 -12
- package/scripts/repository_checks/config/constants.py +0 -5
- package/scripts/tests/test_adapter_configuration.py +54 -0
- package/hooks/_gh_pr_author_swap_utils.py +0 -1225
- package/hooks/blocking/conventional_pr_title_gate.py +0 -443
- package/hooks/blocking/gh_body_arg_blocker.py +0 -176
- package/hooks/blocking/gh_pr_author_enforcer.py +0 -487
- package/hooks/blocking/gh_pr_author_restore.py +0 -105
- package/hooks/blocking/pr_description_writer_gate.py +0 -256
- package/hooks/blocking/test_conventional_pr_title_gate.py +0 -640
- package/hooks/blocking/test_gh_body_arg_blocker.py +0 -441
- package/hooks/blocking/test_gh_pr_author_enforcer.py +0 -1166
- package/hooks/blocking/test_gh_pr_author_restore.py +0 -513
- package/hooks/blocking/test_gh_pr_author_swap_utils.py +0 -910
- package/hooks/blocking/test_pr_description_writer_gate.py +0 -234
- package/hooks/blocking/test_preflight_check.py +0 -343
- package/hooks/blocking/test_test_preflight_check.py +0 -80
- package/hooks/blocking/test_volatile_path_in_post_blocker.py +0 -322
- package/hooks/blocking/volatile_path_in_post_blocker.py +0 -461
- package/hooks/hooks_constants/conventional_pr_title_gate_constants.py +0 -58
- package/hooks/hooks_constants/gh_pr_author_swap_constants.py +0 -76
- package/hooks/hooks_constants/pr_description_writer_gate_constants.py +0 -73
- package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +0 -55
- package/hooks/observability/pr_description_writer_spawn_tracker.py +0 -113
- package/hooks/observability/test_pr_description_writer_spawn_tracker.py +0 -150
- package/hooks/session/gh_pr_author_session_cleanup.py +0 -175
- package/hooks/session/test_gh_pr_author_session_cleanup.py +0 -576
- package/hooks/test__gh_pr_author_swap_utils.py +0 -333
|
@@ -23,30 +23,69 @@ def hook_configuration_diagnostics(
|
|
|
23
23
|
adapter_support._document_path(repository_root, document)
|
|
24
24
|
if document.path.name != "hooks.json":
|
|
25
25
|
return ()
|
|
26
|
-
all_messages = _hook_configuration_messages(document.text)
|
|
26
|
+
all_messages = _hook_configuration_messages(document.text, document.prior_text)
|
|
27
27
|
return adapter_support._diagnostics_for_messages(
|
|
28
28
|
document, "hook-configuration", all_messages
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def
|
|
32
|
+
def _parsed_configuration(
|
|
33
|
+
configuration_text: str,
|
|
34
|
+
invalid_json_message: str,
|
|
35
|
+
invalid_object_message: str,
|
|
36
|
+
) -> dict[object, object]:
|
|
33
37
|
try:
|
|
34
38
|
parsed_configuration = json.loads(configuration_text)
|
|
35
|
-
except json.JSONDecodeError:
|
|
36
|
-
|
|
39
|
+
except json.JSONDecodeError as error:
|
|
40
|
+
raise ValueError(invalid_json_message) from error
|
|
37
41
|
if not isinstance(parsed_configuration, dict):
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
raise TypeError(invalid_object_message)
|
|
43
|
+
return parsed_configuration
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _action_boundary_strings(
|
|
47
|
+
all_configuration_entries: dict[object, object],
|
|
48
|
+
) -> frozenset[str]:
|
|
49
|
+
return frozenset(
|
|
50
|
+
each_string
|
|
51
|
+
for each_string in _registered_hook_strings(all_configuration_entries)
|
|
52
|
+
if _contains_action_boundary_marker(each_string)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _hook_configuration_messages(
|
|
57
|
+
configuration_text: str,
|
|
58
|
+
prior_configuration_text: str | None,
|
|
59
|
+
) -> tuple[str, ...]:
|
|
60
|
+
try:
|
|
61
|
+
current_configuration = _parsed_configuration(
|
|
62
|
+
configuration_text,
|
|
63
|
+
"Hook configuration is not valid JSON",
|
|
64
|
+
"Hook configuration must be an object",
|
|
65
|
+
)
|
|
66
|
+
all_current_action_boundary_strings = _action_boundary_strings(
|
|
67
|
+
current_configuration
|
|
68
|
+
)
|
|
69
|
+
if prior_configuration_text is None:
|
|
70
|
+
all_prior_action_boundary_strings: frozenset[str] = frozenset()
|
|
71
|
+
else:
|
|
72
|
+
prior_configuration = _parsed_configuration(
|
|
73
|
+
prior_configuration_text,
|
|
74
|
+
"Prior hook configuration is not valid JSON",
|
|
75
|
+
"Prior hook configuration must be an object",
|
|
76
|
+
)
|
|
77
|
+
all_prior_action_boundary_strings = _action_boundary_strings(
|
|
78
|
+
prior_configuration
|
|
79
|
+
)
|
|
80
|
+
except (TypeError, ValueError) as error:
|
|
81
|
+
return (str(error),)
|
|
82
|
+
if all_current_action_boundary_strings - all_prior_action_boundary_strings:
|
|
44
83
|
return ("Hook configuration registers a deny, block, or ask policy path",)
|
|
45
84
|
return ()
|
|
46
85
|
|
|
47
86
|
|
|
48
87
|
def _registered_hook_strings(
|
|
49
|
-
all_configuration_entries: dict[object, object]
|
|
88
|
+
all_configuration_entries: dict[object, object],
|
|
50
89
|
) -> tuple[str, ...]:
|
|
51
90
|
all_registered_strings: list[str] = []
|
|
52
91
|
for each_key, each_entry in all_configuration_entries.items():
|
|
@@ -62,7 +101,9 @@ def _registered_strings_for_entry(
|
|
|
62
101
|
all_registered_strings: list[str] = []
|
|
63
102
|
if each_key in constants.ALL_HOOK_REGISTRATION_KEYS and isinstance(each_entry, str):
|
|
64
103
|
all_registered_strings.append(each_entry)
|
|
65
|
-
if each_key in constants.ALL_DECISION_REGISTRATION_KEYS and isinstance(
|
|
104
|
+
if each_key in constants.ALL_DECISION_REGISTRATION_KEYS and isinstance(
|
|
105
|
+
each_entry, str
|
|
106
|
+
):
|
|
66
107
|
all_registered_strings.append(each_entry)
|
|
67
108
|
all_registered_strings.extend(_registered_nested_strings(each_entry))
|
|
68
109
|
return tuple(all_registered_strings)
|
|
@@ -131,11 +131,6 @@ ALL_TRACKED_SECRET_EXACT_EXEMPTIONS: frozenset[tuple[str, str, str]] = frozenset
|
|
|
131
131
|
"home-path",
|
|
132
132
|
"09f83c224a02c370d3d63de5c330e1a830fc92866330fc7963b5b5fd20ffcb91",
|
|
133
133
|
),
|
|
134
|
-
(
|
|
135
|
-
"packages/claude-dev-env/hooks/blocking/volatile_path_in_post_blocker.py",
|
|
136
|
-
"home-path",
|
|
137
|
-
"ed9203c8078e4c6b832600085f28f24656d679aa8dca82ecc2557afc3df25036",
|
|
138
|
-
),
|
|
139
134
|
(
|
|
140
135
|
"packages/claude-dev-env/hooks/hooks_constants/hardcoded_user_path_constants.py",
|
|
141
136
|
"home-path",
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Incremental migration tests for the hook-configuration lint rule."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from dataclasses import replace
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from policy_lint import adapters
|
|
10
|
+
from policy_lint.model import Document
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _hook_document(all_commands: list[str], prior_text: str) -> Document:
|
|
14
|
+
current_text = json.dumps(
|
|
15
|
+
{
|
|
16
|
+
"hooks": {
|
|
17
|
+
"PreToolUse": [
|
|
18
|
+
{
|
|
19
|
+
"hooks": [
|
|
20
|
+
{"command": each_command} for each_command in all_commands
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
return replace(
|
|
28
|
+
Document.from_text("hooks/hooks.json", current_text),
|
|
29
|
+
prior_text=prior_text,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_incremental_blocker_removal_is_clean(tmp_path: Path) -> None:
|
|
34
|
+
prior_text = _hook_document(
|
|
35
|
+
["hooks/blocking/first.py", "hooks/blocking/second.py"],
|
|
36
|
+
'{"hooks": {}}',
|
|
37
|
+
).text
|
|
38
|
+
current_document = _hook_document(
|
|
39
|
+
["hooks/blocking/second.py"],
|
|
40
|
+
prior_text,
|
|
41
|
+
)
|
|
42
|
+
assert adapters.hook_configuration_diagnostics(current_document, tmp_path) == ()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_new_blocker_in_staged_change_is_rejected(tmp_path: Path) -> None:
|
|
46
|
+
current_document = _hook_document(
|
|
47
|
+
["hooks/blocking/new.py"],
|
|
48
|
+
'{"hooks": {}}',
|
|
49
|
+
)
|
|
50
|
+
all_diagnostics = adapters.hook_configuration_diagnostics(
|
|
51
|
+
current_document, tmp_path
|
|
52
|
+
)
|
|
53
|
+
assert len(all_diagnostics) == 1
|
|
54
|
+
assert all_diagnostics[0].rule_id == "hook-configuration"
|