claude-dev-env 1.35.0 → 1.36.1

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 (115) hide show
  1. package/agents/clean-coder.md +109 -1
  2. package/bin/install.mjs +28 -8
  3. package/bin/install.test.mjs +9 -1
  4. package/docs/CODE_RULES.md +3 -0
  5. package/docs/agents-md-alignment-plan.md +123 -0
  6. package/hooks/blocking/code_rules_enforcer.py +451 -39
  7. package/hooks/blocking/es_exe_path_rewriter.py +10 -4
  8. package/hooks/blocking/test_code_rules_enforcer.py +182 -0
  9. package/hooks/blocking/test_code_rules_enforcer_banned_identifier.py +106 -0
  10. package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +173 -0
  11. package/hooks/blocking/test_code_rules_enforcer_collection_prefix.py +191 -0
  12. package/hooks/blocking/test_code_rules_enforcer_constant_equality.py +40 -0
  13. package/hooks/blocking/test_code_rules_enforcer_hardcoded_user_path.py +291 -0
  14. package/hooks/blocking/test_code_rules_enforcer_loop_variable_naming.py +87 -3
  15. package/hooks/blocking/test_code_rules_enforcer_naming_pattern.py +49 -0
  16. package/hooks/blocking/test_code_rules_enforcer_sys_path_insert.py +157 -0
  17. package/hooks/blocking/test_code_rules_enforcer_unused_imports.py +244 -0
  18. package/hooks/blocking/test_es_exe_path_rewriter.py +81 -3
  19. package/hooks/blocking/test_windows_rmtree_blocker.py +120 -8
  20. package/hooks/blocking/windows_rmtree_blocker.py +23 -6
  21. package/hooks/config/banned_identifiers_constants.py +24 -0
  22. package/hooks/config/hardcoded_user_path_constants.py +12 -0
  23. package/hooks/config/hook_log_extractor_constants.py +1 -1
  24. package/hooks/config/pre_tool_use_stdin.py +48 -0
  25. package/hooks/config/setup_project_paths_constants.py +4 -0
  26. package/hooks/config/stuttering_check_config.py +14 -0
  27. package/hooks/config/stuttering_import_binding_constants.py +11 -0
  28. package/hooks/config/sys_path_insert_constants.py +4 -0
  29. package/hooks/config/test_banned_identifiers_constants.py +48 -0
  30. package/hooks/config/test_hardcoded_user_path_constants.py +78 -0
  31. package/hooks/config/test_hook_log_extractor_constants.py +3 -3
  32. package/hooks/config/test_pre_tool_use_stdin.py +80 -0
  33. package/hooks/config/unused_module_import_constants.py +7 -0
  34. package/hooks/config/windows_rmtree_blocker_constants.py +3 -0
  35. package/hooks/diagnostic/hook_log_stop_wrapper.py +7 -4
  36. package/hooks/git-hooks/config.py +3 -3
  37. package/hooks/git-hooks/test_gate_utils.py +10 -10
  38. package/hooks/mypy.ini +2 -0
  39. package/package.json +1 -1
  40. package/rules/gh-paginate.md +125 -0
  41. package/skills/bugteam/CONSTRAINTS.md +12 -6
  42. package/skills/bugteam/SKILL.md +364 -154
  43. package/skills/bugteam/SKILL_EVALS.md +25 -23
  44. package/skills/bugteam/reference/README.md +2 -0
  45. package/skills/bugteam/reference/audit-and-teammates.md +2 -2
  46. package/skills/bugteam/reference/teardown-publish-permissions.md +1 -1
  47. package/skills/bugteam/reference/workflow-path-a-orchestrated-teams.md +113 -0
  48. package/skills/bugteam/reference/workflow-path-b-task-harness.md +48 -0
  49. package/skills/bugteam/scripts/reflow_skill_md.py +298 -0
  50. package/skills/bugteam/test_skill_additions.py +13 -4
  51. package/skills/bugteam/test_team_lifecycle.py +103 -0
  52. package/skills/findbugs/SKILL.md +3 -3
  53. package/skills/fixbugs/SKILL.md +4 -4
  54. package/skills/monitor-open-prs/SKILL.md +32 -2
  55. package/skills/monitor-open-prs/test_team_lifecycle.py +46 -0
  56. package/skills/pr-converge/SKILL.md +1206 -131
  57. package/skills/pr-converge/scripts/README.md +145 -0
  58. package/skills/pr-converge/scripts/caller-window-pid.ps1 +86 -0
  59. package/skills/pr-converge/scripts/check_pr_mergeability.py +79 -0
  60. package/skills/pr-converge/scripts/config/pr_converge_constants.py +65 -0
  61. package/skills/pr-converge/scripts/config/test_pr_converge_constants.py +176 -0
  62. package/skills/pr-converge/scripts/cursor-agents-continue-caller.cmd +9 -0
  63. package/skills/pr-converge/scripts/cursor-agents-continue-stop-others.ps1 +16 -0
  64. package/skills/pr-converge/scripts/cursor-agents-continue.ahk +172 -0
  65. package/skills/pr-converge/scripts/cursor-agents-continue.cmd +2 -0
  66. package/skills/pr-converge/scripts/evict_cached_config_modules.py +20 -0
  67. package/skills/pr-converge/scripts/fetch_bugbot_inline_comments.py +110 -0
  68. package/skills/pr-converge/scripts/fetch_bugbot_reviews.py +103 -0
  69. package/skills/pr-converge/scripts/fetch_copilot_inline_comments.py +112 -0
  70. package/skills/pr-converge/scripts/fetch_copilot_reviews.py +121 -0
  71. package/skills/pr-converge/scripts/mark_pr_ready.py +54 -0
  72. package/skills/pr-converge/scripts/open_followup_copilot_pr.py +136 -0
  73. package/skills/pr-converge/scripts/post-bugbot-run.helpers.ps1 +49 -0
  74. package/skills/pr-converge/scripts/post-bugbot-run.ps1 +33 -0
  75. package/skills/pr-converge/scripts/reflow_skill_md.py +288 -0
  76. package/skills/pr-converge/scripts/reply_to_inline_comment.py +84 -0
  77. package/skills/pr-converge/scripts/request_copilot_review.py +71 -0
  78. package/skills/pr-converge/scripts/resolve_pr_head.py +58 -0
  79. package/skills/pr-converge/scripts/review_field_helpers.py +43 -0
  80. package/skills/pr-converge/scripts/test_check_pr_mergeability.py +126 -0
  81. package/skills/pr-converge/scripts/test_evict_cached_config_modules.py +22 -0
  82. package/skills/pr-converge/scripts/test_fetch_bugbot_inline_comments.py +342 -0
  83. package/skills/pr-converge/scripts/test_fetch_bugbot_reviews.py +220 -0
  84. package/skills/pr-converge/scripts/test_fetch_copilot_inline_comments.py +372 -0
  85. package/skills/pr-converge/scripts/test_fetch_copilot_reviews.py +280 -0
  86. package/skills/pr-converge/scripts/test_mark_pr_ready.py +69 -0
  87. package/skills/pr-converge/scripts/test_open_followup_copilot_pr.py +236 -0
  88. package/skills/pr-converge/scripts/test_post_bugbot_run.py +195 -0
  89. package/skills/pr-converge/scripts/test_reply_to_inline_comment.py +159 -0
  90. package/skills/pr-converge/scripts/test_request_copilot_review.py +101 -0
  91. package/skills/pr-converge/scripts/test_resolve_pr_head.py +79 -0
  92. package/skills/pr-converge/scripts/test_review_field_helpers.py +80 -0
  93. package/skills/pr-converge/scripts/test_trigger_bugbot.py +139 -0
  94. package/skills/pr-converge/scripts/test_view_pr_context.py +111 -0
  95. package/skills/pr-converge/scripts/trigger_bugbot.py +77 -0
  96. package/skills/pr-converge/scripts/view_pr_context.py +47 -0
  97. package/skills/pr-converge/test_team_lifecycle.py +56 -0
  98. package/skills/pr-converge/workflows/ahk-auto-continue-loop.md +108 -0
  99. package/skills/pr-converge/workflows/schedule-wakeup-loop.md +37 -0
  100. package/skills/qbug/SKILL.md +4 -4
  101. package/skills/qbug/test_qbug_skill_post_fix_audit.py +2 -2
  102. package/skills/resume-review/SKILL.md +261 -0
  103. package/skills/bugteam/scripts/README.md +0 -58
  104. package/skills/bugteam/scripts/_claude_permissions_common.py +0 -219
  105. package/skills/bugteam/scripts/bugteam_code_rules_gate.py +0 -633
  106. package/skills/bugteam/scripts/bugteam_fix_hookspath.py +0 -260
  107. package/skills/bugteam/scripts/bugteam_preflight.py +0 -201
  108. package/skills/bugteam/scripts/config/bugteam_fix_hookspath_constants.py +0 -17
  109. package/skills/bugteam/scripts/grant_project_claude_permissions.py +0 -109
  110. package/skills/bugteam/scripts/revoke_project_claude_permissions.py +0 -135
  111. package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +0 -271
  112. package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +0 -267
  113. package/skills/bugteam/scripts/test_bugteam_preflight.py +0 -189
  114. package/skills/bugteam/scripts/test_claude_permissions_common.py +0 -44
  115. /package/skills/{bugteam → pr-converge}/scripts/config/__init__.py +0 -0
@@ -1,189 +0,0 @@
1
- """Tests for bugteam_preflight git hooks path verification.
2
-
3
- Covers:
4
- - core.hooksPath unset: exits non-zero with correction message
5
- - core.hooksPath pointing to the correct claude hooks dir: exits zero
6
- - core.hooksPath pointing elsewhere (husky override): exits non-zero
7
- - core.hooksPath with trailing slash: must still pass after normalization
8
- """
9
-
10
- from __future__ import annotations
11
-
12
- import importlib.util
13
- import subprocess
14
- from pathlib import Path
15
- from types import ModuleType
16
- from unittest.mock import MagicMock, patch
17
-
18
- import pytest
19
-
20
-
21
- def _load_preflight_module() -> ModuleType:
22
- module_path = Path(__file__).parent / "bugteam_preflight.py"
23
- spec = importlib.util.spec_from_file_location("bugteam_preflight", module_path)
24
- assert spec is not None
25
- assert spec.loader is not None
26
- module = importlib.util.module_from_spec(spec)
27
- spec.loader.exec_module(module)
28
- return module
29
-
30
-
31
- bugteam_preflight = _load_preflight_module()
32
-
33
-
34
- def _make_completed_process(
35
- stdout: str, returncode: int
36
- ) -> subprocess.CompletedProcess:
37
- process = MagicMock(spec=subprocess.CompletedProcess)
38
- process.stdout = stdout
39
- process.returncode = returncode
40
- return process
41
-
42
-
43
- def test_should_exit_nonzero_when_core_hooks_path_unset(capsys: pytest.CaptureFixture[str]) -> None:
44
- with patch("subprocess.run") as mock_run:
45
- mock_run.return_value = _make_completed_process("", returncode=1)
46
- exit_code = bugteam_preflight.verify_git_hooks_path()
47
- assert exit_code != 0
48
- captured = capsys.readouterr()
49
- assert "core.hooksPath" in captured.err
50
- assert "npx claude-dev-env" in captured.err or "git config" in captured.err
51
-
52
-
53
- def test_should_exit_zero_when_core_hooks_path_points_to_claude_hooks(tmp_path: Path) -> None:
54
- claude_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
55
- claude_hooks_path.mkdir(parents=True)
56
- with patch("subprocess.run") as mock_run:
57
- mock_run.return_value = _make_completed_process(
58
- str(claude_hooks_path) + "\n", returncode=0
59
- )
60
- exit_code = bugteam_preflight.verify_git_hooks_path()
61
- assert exit_code == 0
62
-
63
-
64
- def test_should_exit_nonzero_when_core_hooks_path_points_elsewhere(capsys: pytest.CaptureFixture[str]) -> None:
65
- with patch("subprocess.run") as mock_run:
66
- mock_run.return_value = _make_completed_process(
67
- "/some/other/path/.husky\n", returncode=0
68
- )
69
- exit_code = bugteam_preflight.verify_git_hooks_path()
70
- assert exit_code != 0
71
- captured = capsys.readouterr()
72
- assert "core.hooksPath" in captured.err
73
-
74
-
75
- def test_should_include_correction_commands_in_error_message(capsys: pytest.CaptureFixture[str]) -> None:
76
- with patch("subprocess.run") as mock_run:
77
- mock_run.return_value = _make_completed_process("", returncode=1)
78
- bugteam_preflight.verify_git_hooks_path()
79
- captured = capsys.readouterr()
80
- assert (
81
- "npx claude-dev-env" in captured.err
82
- or "git config --global core.hooksPath" in captured.err
83
- )
84
-
85
-
86
- def test_main_should_exit_nonzero_when_hooks_path_unset() -> None:
87
- with patch("subprocess.run") as mock_run:
88
- mock_run.return_value = _make_completed_process("", returncode=1)
89
- exit_code = bugteam_preflight.main(["--no-pytest"])
90
- assert exit_code != 0
91
-
92
-
93
- def test_main_should_continue_when_hooks_path_valid(tmp_path: Path) -> None:
94
- claude_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
95
- claude_hooks_path.mkdir(parents=True)
96
- with patch("subprocess.run") as mock_run:
97
- mock_run.return_value = _make_completed_process(
98
- str(claude_hooks_path) + "\n", returncode=0
99
- )
100
- exit_code = bugteam_preflight.main(["--no-pytest"])
101
- assert exit_code == 0
102
-
103
-
104
- def test_should_accept_hooks_path_with_trailing_slash() -> None:
105
- with patch("subprocess.run") as mock_run:
106
- mock_run.return_value = _make_completed_process(
107
- "/home/user/.claude/hooks/git-hooks/\n", returncode=0
108
- )
109
- exit_code = bugteam_preflight.verify_git_hooks_path()
110
- assert exit_code == 0, (
111
- "hooksPath with trailing slash must pass verification after normalization"
112
- )
113
-
114
-
115
- def test_should_exit_zero_when_hooks_path_set_at_repo_scope(tmp_path: Path) -> None:
116
- claude_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
117
- claude_hooks_path.mkdir(parents=True)
118
- repo_root = tmp_path / "my-repo"
119
- repo_root.mkdir()
120
- with patch("subprocess.run") as mock_run:
121
- mock_run.return_value = _make_completed_process(
122
- str(claude_hooks_path) + "\n", returncode=0
123
- )
124
- exit_code = bugteam_preflight.verify_git_hooks_path(repo_root)
125
- assert exit_code == 0, (
126
- "verify_git_hooks_path must accept a valid path returned by effective "
127
- "config query (not restricted to --global scope)"
128
- )
129
- called_command = mock_run.call_args[0][0]
130
- assert "--global" not in called_command, (
131
- "verify_git_hooks_path must query effective config, not --global only"
132
- )
133
- assert "-C" in called_command, (
134
- "verify_git_hooks_path must use git -C <repo_root> for repo-effective config"
135
- )
136
- dash_c_index = called_command.index("-C")
137
- assert called_command[dash_c_index + 1] == str(repo_root), (
138
- "git -C must receive the resolved repository root path"
139
- )
140
-
141
-
142
- def test_should_accept_hooks_path_with_backslash_and_trailing_slash() -> None:
143
- with patch("subprocess.run") as mock_run:
144
- mock_run.return_value = _make_completed_process(
145
- "C:\\Users\\user\\.claude\\hooks\\git-hooks\\\n", returncode=0
146
- )
147
- exit_code = bugteam_preflight.verify_git_hooks_path()
148
- assert exit_code == 0, (
149
- "Windows hooksPath with trailing backslash must pass after normalization"
150
- )
151
-
152
-
153
- def test_should_exit_nonzero_when_git_executable_not_found(
154
- capsys: pytest.CaptureFixture[str],
155
- ) -> None:
156
- """Preflight must not crash with a traceback when git is missing from PATH."""
157
- with patch("subprocess.run", side_effect=FileNotFoundError()):
158
- exit_code = bugteam_preflight.verify_git_hooks_path()
159
- assert exit_code != 0, (
160
- "FileNotFoundError from subprocess.run must produce a non-zero exit, "
161
- "not a propagated traceback"
162
- )
163
- captured = capsys.readouterr()
164
- assert "git" in captured.err.lower(), (
165
- "Error message must mention git so the user knows what is missing"
166
- )
167
- assert (
168
- "npx claude-dev-env" in captured.err
169
- or "git config --global core.hooksPath" in captured.err
170
- ), "Error message must include the enforcement-absent remediation hints"
171
-
172
-
173
- def test_should_exit_nonzero_when_subprocess_run_raises_os_error(
174
- capsys: pytest.CaptureFixture[str],
175
- ) -> None:
176
- """Preflight must surface a clean error for other OS-level git launch failures."""
177
- with patch("subprocess.run", side_effect=OSError("permission denied")):
178
- exit_code = bugteam_preflight.verify_git_hooks_path()
179
- assert exit_code != 0, (
180
- "OSError from subprocess.run must produce a non-zero exit, "
181
- "not a propagated traceback"
182
- )
183
- captured = capsys.readouterr()
184
- assert "bugteam_preflight" in captured.err, (
185
- "Error message must be prefixed with the preflight tool name for context"
186
- )
187
- assert "permission denied" in captured.err, (
188
- "Error message must include the underlying OSError detail for diagnosis"
189
- )
@@ -1,44 +0,0 @@
1
- import sys
2
- from pathlib import Path
3
-
4
- import pytest
5
-
6
- sys.path.insert(0, str(Path(__file__).resolve().parent))
7
-
8
- from _claude_permissions_common import (
9
- build_permission_rule,
10
- get_current_project_path,
11
- path_contains_glob_metacharacters,
12
- )
13
-
14
-
15
- def test_return_normalized_path_when_cwd_contains_spaces(
16
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch
17
- ) -> None:
18
- directory_with_spaces = tmp_path / "dir with spaces"
19
- directory_with_spaces.mkdir()
20
- monkeypatch.chdir(directory_with_spaces)
21
- returned_project_path = get_current_project_path()
22
- expected_suffix = "/dir with spaces"
23
- assert returned_project_path.endswith(expected_suffix)
24
- assert "\\" not in returned_project_path
25
- built_rule = build_permission_rule("Edit", returned_project_path)
26
- assert built_rule.startswith("Edit(")
27
- assert built_rule.endswith("/.claude/**)")
28
- assert "dir with spaces" in built_rule
29
-
30
-
31
- def test_raise_when_cwd_contains_glob_metacharacters(
32
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch
33
- ) -> None:
34
- directory_with_star = tmp_path / "weird[dir]"
35
- directory_with_star.mkdir()
36
- monkeypatch.chdir(directory_with_star)
37
- with pytest.raises(ValueError, match="glob metacharacters"):
38
- get_current_project_path()
39
-
40
-
41
- def test_flag_glob_metacharacters_in_any_position() -> None:
42
- assert path_contains_glob_metacharacters("/home/user/[dir]/project")
43
- assert path_contains_glob_metacharacters("/home/user/project*")
44
- assert not path_contains_glob_metacharacters("/home/user/dir with spaces")