claude-dev-env 1.37.1 → 1.38.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 (92) hide show
  1. package/CLAUDE.md +3 -0
  2. package/_shared/pr-loop/audit-contract.md +4 -3
  3. package/_shared/pr-loop/fix-protocol.md +2 -0
  4. package/_shared/pr-loop/gh-payloads.md +38 -37
  5. package/_shared/pr-loop/scripts/README.md +0 -1
  6. package/_shared/pr-loop/scripts/preflight.py +2 -1
  7. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +2 -2
  8. package/_shared/pr-loop/scripts/tests/test_preflight.py +22 -0
  9. package/_shared/pr-loop/state-schema.md +10 -10
  10. package/agents/clean-coder.md +4 -0
  11. package/agents/code-quality-agent.md +23 -85
  12. package/agents/groq-coder.md +8 -6
  13. package/hooks/blocking/__init__.py +0 -0
  14. package/hooks/blocking/hedging_language_blocker.py +2 -2
  15. package/hooks/blocking/state_description_blocker.py +243 -0
  16. package/hooks/blocking/tdd_enforcer.py +94 -0
  17. package/hooks/blocking/test_hedging_language_blocker.py +1 -1
  18. package/hooks/blocking/test_state_description_blocker.py +618 -0
  19. package/hooks/blocking/test_tdd_enforcer.py +152 -0
  20. package/hooks/config/state_description_blocker_constants.py +130 -0
  21. package/hooks/hooks.json +10 -0
  22. package/package.json +1 -1
  23. package/rules/no-historical-clutter.md +31 -10
  24. package/scripts/config/groq_bugteam_config.py +13 -5
  25. package/skills/bugteam/CONSTRAINTS.md +20 -27
  26. package/skills/bugteam/EXAMPLES.md +1 -1
  27. package/skills/bugteam/PROMPTS.md +60 -31
  28. package/skills/bugteam/SKILL.md +47 -47
  29. package/skills/bugteam/SKILL_EVALS.md +8 -8
  30. package/skills/bugteam/reference/github-pr-reviews.md +31 -31
  31. package/skills/bugteam/reference/team-setup.md +1 -1
  32. package/skills/bugteam/reference/teardown-publish-permissions.md +4 -4
  33. package/skills/copilot-review/SKILL.md +7 -14
  34. package/skills/findbugs/SKILL.md +2 -2
  35. package/skills/fixbugs/SKILL.md +1 -1
  36. package/skills/monitor-open-prs/SKILL.md +6 -6
  37. package/skills/pr-converge/SKILL.md +7 -6
  38. package/skills/pr-converge/reference/convergence-gates.md +28 -30
  39. package/skills/pr-converge/reference/examples.md +4 -4
  40. package/skills/pr-converge/reference/fix-protocol.md +6 -8
  41. package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -10
  42. package/skills/pr-converge/reference/per-tick.md +18 -33
  43. package/skills/pr-converge/reference/stop-conditions.md +7 -7
  44. package/skills/pr-converge/scripts/README.md +65 -117
  45. package/skills/pr-review-responder/EXAMPLES.md +2 -2
  46. package/skills/pr-review-responder/PRINCIPLES.md +2 -8
  47. package/skills/pr-review-responder/README.md +7 -48
  48. package/skills/pr-review-responder/SKILL.md +2 -3
  49. package/skills/pr-review-responder/TESTING.md +8 -65
  50. package/skills/qbug/SKILL.md +10 -16
  51. package/_shared/pr-loop/scripts/config/gh_util_constants.py +0 -31
  52. package/_shared/pr-loop/scripts/gh_util.py +0 -193
  53. package/_shared/pr-loop/scripts/tests/test_gh_util.py +0 -257
  54. package/_shared/pr-loop/scripts/tests/test_gh_util_constants.py +0 -61
  55. package/skills/pr-converge/scripts/check_pr_mergeability.py +0 -78
  56. package/skills/pr-converge/scripts/config/pr_converge_constants.py +0 -134
  57. package/skills/pr-converge/scripts/config/test_pr_converge_constants.py +0 -152
  58. package/skills/pr-converge/scripts/fetch_bugbot_inline_comments.py +0 -70
  59. package/skills/pr-converge/scripts/fetch_bugbot_reviews.py +0 -57
  60. package/skills/pr-converge/scripts/fetch_claude_inline_comments.py +0 -70
  61. package/skills/pr-converge/scripts/fetch_claude_reviews.py +0 -61
  62. package/skills/pr-converge/scripts/fetch_copilot_inline_comments.py +0 -70
  63. package/skills/pr-converge/scripts/fetch_copilot_reviews.py +0 -61
  64. package/skills/pr-converge/scripts/mark_pr_ready.py +0 -54
  65. package/skills/pr-converge/scripts/post-bugbot-run.helpers.ps1 +0 -49
  66. package/skills/pr-converge/scripts/post-bugbot-run.ps1 +0 -33
  67. package/skills/pr-converge/scripts/reply_to_inline_comment.py +0 -84
  68. package/skills/pr-converge/scripts/request_copilot_review.py +0 -71
  69. package/skills/pr-converge/scripts/resolve_pr_head.py +0 -58
  70. package/skills/pr-converge/scripts/review_field_helpers.py +0 -43
  71. package/skills/pr-converge/scripts/reviewer_fetch_core.py +0 -153
  72. package/skills/pr-converge/scripts/reviewer_specs.py +0 -98
  73. package/skills/pr-converge/scripts/test_check_pr_mergeability.py +0 -126
  74. package/skills/pr-converge/scripts/test_fetch_bugbot_inline_comments.py +0 -443
  75. package/skills/pr-converge/scripts/test_fetch_bugbot_reviews.py +0 -299
  76. package/skills/pr-converge/scripts/test_fetch_claude_inline_comments.py +0 -485
  77. package/skills/pr-converge/scripts/test_fetch_claude_reviews.py +0 -368
  78. package/skills/pr-converge/scripts/test_fetch_copilot_inline_comments.py +0 -440
  79. package/skills/pr-converge/scripts/test_fetch_copilot_reviews.py +0 -366
  80. package/skills/pr-converge/scripts/test_mark_pr_ready.py +0 -69
  81. package/skills/pr-converge/scripts/test_post_bugbot_run.py +0 -195
  82. package/skills/pr-converge/scripts/test_reply_to_inline_comment.py +0 -159
  83. package/skills/pr-converge/scripts/test_request_copilot_review.py +0 -101
  84. package/skills/pr-converge/scripts/test_resolve_pr_head.py +0 -79
  85. package/skills/pr-converge/scripts/test_review_field_helpers.py +0 -80
  86. package/skills/pr-converge/scripts/test_reviewer_fetch_core.py +0 -448
  87. package/skills/pr-converge/scripts/test_reviewer_specs.py +0 -107
  88. package/skills/pr-converge/scripts/test_trigger_bugbot.py +0 -139
  89. package/skills/pr-converge/scripts/test_view_pr_context.py +0 -155
  90. package/skills/pr-converge/scripts/trigger_bugbot.py +0 -77
  91. package/skills/pr-converge/scripts/view_pr_context.py +0 -78
  92. package/skills/pr-review-responder/scripts/respond_to_reviews.py +0 -376
@@ -1,134 +0,0 @@
1
- """Configuration constants for the pr-converge skill scripts.
2
-
3
- Path templates accept ``str.format(**kwargs)`` substitution; bugbot strings
4
- match the literal phrasing the Cursor Bugbot reviewer emits.
5
- """
6
-
7
- import re
8
- from pathlib import Path
9
-
10
- CURSOR_BOT_LOGIN: str = "cursor[bot]"
11
-
12
- CURSOR_LOGIN_FILTER_SUBSTRING: str = "cursor"
13
-
14
- COPILOT_REVIEWER_LOGIN: str = "copilot-pull-request-reviewer[bot]"
15
-
16
- COPILOT_REVIEWER_REQUEST_ID: str = COPILOT_REVIEWER_LOGIN
17
-
18
- COPILOT_LOGIN_FILTER_SUBSTRING: str = "copilot"
19
-
20
- COPILOT_CLEAN_REVIEW_STATE: str = "APPROVED"
21
-
22
- ALL_COPILOT_DIRTY_REVIEW_STATES: tuple[str, ...] = ("CHANGES_REQUESTED", "COMMENTED")
23
-
24
- COPILOT_SOFT_DIRTY_REVIEW_STATE: str = "COMMENTED"
25
-
26
- CLAUDE_REVIEWER_LOGIN: str = "claude[bot]"
27
-
28
- CLAUDE_REVIEWER_REQUEST_ID: str = CLAUDE_REVIEWER_LOGIN
29
-
30
- CLAUDE_LOGIN_FILTER_SUBSTRING: str = "claude"
31
-
32
- CLAUDE_CLEAN_REVIEW_STATE: str = "APPROVED"
33
-
34
- ALL_CLAUDE_DIRTY_REVIEW_STATES: tuple[str, ...] = ("CHANGES_REQUESTED", "COMMENTED")
35
-
36
- CLAUDE_SOFT_DIRTY_REVIEW_STATE: str = "COMMENTED"
37
-
38
- BUGBOT_DIRTY_BODY_REGEX: str = (
39
- r"Cursor Bugbot has reviewed your changes and found \d+ potential issue"
40
- )
41
-
42
- GH_REVIEWS_PATH_TEMPLATE: str = (
43
- "repos/{owner}/{repo}/pulls/{number}/reviews?per_page=100"
44
- )
45
-
46
- GH_INLINE_COMMENTS_PATH_TEMPLATE: str = (
47
- "repos/{owner}/{repo}/pulls/{number}/comments?per_page=100"
48
- )
49
-
50
- GH_PR_OBJECT_PATH_TEMPLATE: str = "repos/{owner}/{repo}/pulls/{number}"
51
-
52
- GH_INLINE_COMMENT_REPLY_PATH_TEMPLATE: str = (
53
- "repos/{owner}/{repo}/pulls/{number}/comments/{comment_id}/replies"
54
- )
55
-
56
- GH_REQUESTED_REVIEWERS_PATH_TEMPLATE: str = (
57
- "repos/{owner}/{repo}/pulls/{number}/requested_reviewers"
58
- )
59
-
60
- GH_REQUESTED_REVIEWERS_FIELD_TEMPLATE: str = "reviewers[]={reviewer_id}"
61
-
62
- BUGBOT_RUN_TRIGGER_PHRASE: str = "bugbot run\n"
63
-
64
- BUGBOT_RUN_TEMPFILE_SUFFIX: str = ".md"
65
-
66
- BUGBOT_RUN_TEMPFILE_PREFIX: str = "pr-converge-bugbot-run-"
67
-
68
- PR_CONTEXT_FIELDS: str = "number,url,headRefOid,baseRefName,headRefName,isDraft"
69
-
70
- PR_DETACHED_HEAD_ARGS_ERROR: str = "--owner and --repo require --number; all three must be provided together for detached-HEAD PR resolution"
71
-
72
- PR_NUMBER_ARG_FLAG: str = "--number"
73
-
74
- PR_NUMBER_ARG_HELP: str = "PR number"
75
-
76
- PR_OWNER_ARG_FLAG: str = "--owner"
77
-
78
- PR_OWNER_ARG_HELP: str = "GitHub repository owner"
79
-
80
- PR_REPO_ARG_FLAG: str = "--repo"
81
-
82
- PR_REPO_ARG_HELP: str = "GitHub repository name"
83
-
84
- GH_REPO_FLAG: str = "--repo"
85
-
86
- MERGEABILITY_FIELDS: str = "mergeable,mergeStateStatus,headRefOid"
87
-
88
- GH_FIELD_BODY_AT_PREFIX: str = "body=@"
89
-
90
- GH_REPO_ARG_TEMPLATE: str = "{owner}/{repo}"
91
-
92
- SKILL_REFLOW_MAXIMUM_WIDTH: int = 80
93
-
94
- PR_CONVERGE_SKILL_PATH: Path = Path(__file__).resolve().parent.parent.parent / "SKILL.md"
95
-
96
- MARKDOWN_CODE_FENCE_MARKER: str = "```"
97
-
98
- YAML_FRONT_MATTER_DELIMITER: str = "---"
99
-
100
- YAML_DESCRIPTION_PREFIX: str = "description: >-"
101
-
102
- EXAMPLE_OPEN_TAG: str = "<example>"
103
-
104
- EXAMPLE_CLOSE_TAG: str = "</example>"
105
-
106
- BASH_FENCE_LANGUAGE: str = "bash"
107
-
108
- BASH_LINE_CONTINUATION_SUFFIX: str = " \\"
109
-
110
- BASH_CONTINUATION_INDENT: str = " "
111
-
112
- REFLOW_FRONT_MATTER_ERROR: str = "expected YAML front matter starting with ---"
113
-
114
- ORDERED_MARKDOWN_LIST_PATTERN: re.Pattern[str] = re.compile(
115
- r"^(?P<leading_whitespace>\s*)(?P<marker>\d+\.\s)(?P<body>.*)$"
116
- )
117
-
118
- BULLET_MARKDOWN_LIST_PATTERN: re.Pattern[str] = re.compile(
119
- r"^(?P<leading_whitespace>\s*)(?P<marker>[-*]\s)(?P<body>.*)$"
120
- )
121
-
122
- UNFINISHED_MARKDOWN_LINK_TARGET_PATTERN: re.Pattern[str] = re.compile(r"\]\([^)]*$")
123
-
124
- MARKDOWN_HEADING_PATTERN: re.Pattern[str] = re.compile(r"^#{1,6}\s+.+$")
125
-
126
- MARKDOWN_REFERENCE_DEFINITION_PATTERN: re.Pattern[str] = re.compile(r"^\[[^\]]+\]:\s+\S+")
127
-
128
- BASH_LINE_CONTINUATION_MARKER_WIDTH: int = 2
129
-
130
- CODE_FENCE_MARKER_LENGTH: int = 3
131
-
132
- BASH_MINIMUM_SEGMENT_WIDTH: int = 1
133
-
134
- LONG_ROW_PREVIEW_LIMIT: int = 20
@@ -1,152 +0,0 @@
1
- """Tests for pr_converge_constants.
2
-
3
- Verifies that path templates accept the documented format substitutions
4
- (owner, repo, number, comment_id) and the bugbot regex matches dirty review
5
- bodies but not clean ones.
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- import importlib.util
11
- import re
12
- from pathlib import Path
13
- from types import ModuleType
14
-
15
-
16
- def _load_module() -> ModuleType:
17
- module_path = Path(__file__).parent / "pr_converge_constants.py"
18
- spec = importlib.util.spec_from_file_location("pr_converge_constants", module_path)
19
- assert spec is not None
20
- assert spec.loader is not None
21
- module = importlib.util.module_from_spec(spec)
22
- spec.loader.exec_module(module)
23
- return module
24
-
25
-
26
- pr_converge_constants_module = _load_module()
27
-
28
-
29
- def test_reviews_path_template_accepts_owner_repo_number() -> None:
30
- rendered = pr_converge_constants_module.GH_REVIEWS_PATH_TEMPLATE.format(
31
- owner="acme", repo="widget", number=42
32
- )
33
- assert rendered == "repos/acme/widget/pulls/42/reviews?per_page=100"
34
-
35
-
36
- def test_inline_comments_path_template_accepts_owner_repo_number() -> None:
37
- rendered = pr_converge_constants_module.GH_INLINE_COMMENTS_PATH_TEMPLATE.format(
38
- owner="acme", repo="widget", number=42
39
- )
40
- assert rendered == "repos/acme/widget/pulls/42/comments?per_page=100"
41
-
42
-
43
- def test_pr_object_path_template_accepts_owner_repo_number() -> None:
44
- rendered = pr_converge_constants_module.GH_PR_OBJECT_PATH_TEMPLATE.format(
45
- owner="acme", repo="widget", number=42
46
- )
47
- assert rendered == "repos/acme/widget/pulls/42"
48
-
49
-
50
- def test_inline_comment_reply_path_template_accepts_all_substitutions() -> None:
51
- rendered = (
52
- pr_converge_constants_module.GH_INLINE_COMMENT_REPLY_PATH_TEMPLATE.format(
53
- owner="acme", repo="widget", number=42, comment_id=12345
54
- )
55
- )
56
- assert rendered == "repos/acme/widget/pulls/42/comments/12345/replies"
57
-
58
-
59
- def test_bugbot_dirty_body_regex_distinguishes_findings_from_clean_bodies() -> None:
60
- dirty_body = "Cursor Bugbot has reviewed your changes and found 3 potential issues."
61
- clean_body = "Bugbot reviewed your changes and found no new issues!"
62
- compiled_pattern = re.compile(pr_converge_constants_module.BUGBOT_DIRTY_BODY_REGEX)
63
- dirty_match = compiled_pattern.search(dirty_body)
64
- assert dirty_match is not None
65
- assert "found 3 potential issue" in dirty_match.group(0)
66
- assert compiled_pattern.search(clean_body) is None
67
-
68
-
69
- def test_cursor_bot_login_matches_github_login_string() -> None:
70
- assert pr_converge_constants_module.CURSOR_BOT_LOGIN == "cursor[bot]"
71
-
72
-
73
- def test_bugbot_run_trigger_phrase_ends_with_newline() -> None:
74
- assert pr_converge_constants_module.BUGBOT_RUN_TRIGGER_PHRASE == "bugbot run\n"
75
-
76
-
77
- def test_pr_context_fields_lists_documented_field_names() -> None:
78
- fields_arg = pr_converge_constants_module.PR_CONTEXT_FIELDS
79
- for required_field in (
80
- "number",
81
- "url",
82
- "headRefOid",
83
- "baseRefName",
84
- "headRefName",
85
- "isDraft",
86
- ):
87
- assert required_field in fields_arg
88
-
89
-
90
- def test_gh_field_body_at_prefix_matches_gh_field_from_file_form() -> None:
91
- assert pr_converge_constants_module.GH_FIELD_BODY_AT_PREFIX == "body=@"
92
-
93
-
94
- def test_gh_repo_arg_template_renders_owner_slash_repo() -> None:
95
- rendered = pr_converge_constants_module.GH_REPO_ARG_TEMPLATE.format(
96
- owner="acme", repo="widget"
97
- )
98
- assert rendered == "acme/widget"
99
-
100
-
101
- def test_copilot_reviewer_login_carries_bot_suffix() -> None:
102
- assert (
103
- pr_converge_constants_module.COPILOT_REVIEWER_LOGIN
104
- == "copilot-pull-request-reviewer[bot]"
105
- )
106
-
107
-
108
- def test_copilot_reviewer_request_id_reuses_login_constant() -> None:
109
- request_id = pr_converge_constants_module.COPILOT_REVIEWER_REQUEST_ID
110
- login = pr_converge_constants_module.COPILOT_REVIEWER_LOGIN
111
- assert request_id == login
112
- assert request_id is login
113
-
114
-
115
- def test_copilot_clean_review_state_is_approved() -> None:
116
- assert pr_converge_constants_module.COPILOT_CLEAN_REVIEW_STATE == "APPROVED"
117
-
118
-
119
- def test_copilot_dirty_review_states_lists_changes_requested_and_commented() -> None:
120
- dirty_states = pr_converge_constants_module.ALL_COPILOT_DIRTY_REVIEW_STATES
121
- assert "CHANGES_REQUESTED" in dirty_states
122
- assert "COMMENTED" in dirty_states
123
-
124
-
125
- def test_copilot_soft_dirty_review_state_is_commented() -> None:
126
- assert pr_converge_constants_module.COPILOT_SOFT_DIRTY_REVIEW_STATE == "COMMENTED"
127
-
128
-
129
- def test_mergeability_fields_lists_required_field_names() -> None:
130
- fields_arg = pr_converge_constants_module.MERGEABILITY_FIELDS
131
- for required_field in ("mergeable", "mergeStateStatus", "headRefOid"):
132
- assert required_field in fields_arg
133
-
134
-
135
- def test_requested_reviewers_path_template_accepts_owner_repo_number() -> None:
136
- rendered = (
137
- pr_converge_constants_module.GH_REQUESTED_REVIEWERS_PATH_TEMPLATE.format(
138
- owner="acme", repo="widget", number=42
139
- )
140
- )
141
- assert rendered == "repos/acme/widget/pulls/42/requested_reviewers"
142
-
143
-
144
- def test_requested_reviewers_field_template_accepts_reviewer_id() -> None:
145
- rendered = (
146
- pr_converge_constants_module.GH_REQUESTED_REVIEWERS_FIELD_TEMPLATE.format(
147
- reviewer_id="copilot-pull-request-reviewer[bot]"
148
- )
149
- )
150
- assert rendered == "reviewers[]=copilot-pull-request-reviewer[bot]"
151
-
152
-
@@ -1,70 +0,0 @@
1
- """Fetch unaddressed Cursor Bugbot inline comments for the latest Bugbot review on a commit.
2
-
3
- Thin wrapper around ``reviewer_fetch_core.fetch_reviewer_inline_comments``
4
- parameterised by ``bugbot_spec``. The ``fetch_bugbot_reviews`` call lives here
5
- (rather than inside the core) so tests can patch it on this module to exercise
6
- the inline-comments fetch in isolation.
7
-
8
- Wraps the gh CLI invocation required by the gh-paginate rule for the comments
9
- list: ``gh api`` on ``repos/{owner}/{repo}/pulls/{number}/comments`` with
10
- ``--paginate --slurp`` and external JSON handling.
11
- """
12
-
13
- from __future__ import annotations
14
-
15
- import argparse
16
- import json
17
- import sys
18
- from pathlib import Path
19
-
20
- if str(Path(__file__).resolve().parent) not in sys.path:
21
- sys.path.insert(0, str(Path(__file__).resolve().parent))
22
-
23
- from evict_cached_config_modules import evict_cached_config_modules
24
-
25
- evict_cached_config_modules()
26
-
27
- from fetch_bugbot_reviews import fetch_bugbot_reviews
28
- from reviewer_fetch_core import fetch_reviewer_inline_comments
29
- from reviewer_specs import bugbot_spec
30
-
31
-
32
- def fetch_bugbot_inline_comments(
33
- *,
34
- owner: str,
35
- repo: str,
36
- number: int,
37
- current_head: str,
38
- ) -> list[dict[str, object]]:
39
- """Return Bugbot inline comments for the latest Bugbot review on ``current_head``."""
40
- all_bugbot_reviews = fetch_bugbot_reviews(owner=owner, repo=repo, number=number)
41
- return fetch_reviewer_inline_comments(
42
- bugbot_spec,
43
- owner=owner,
44
- repo=repo,
45
- number=number,
46
- current_head=current_head,
47
- all_reviews=all_bugbot_reviews,
48
- )
49
-
50
-
51
- def main() -> int:
52
- parser = argparse.ArgumentParser(description=__doc__)
53
- parser.add_argument("--owner", required=True)
54
- parser.add_argument("--repo", required=True)
55
- parser.add_argument("--number", required=True, type=int)
56
- parser.add_argument("--commit", required=True, dest="current_head")
57
- parsed_arguments = parser.parse_args()
58
- all_comments = fetch_bugbot_inline_comments(
59
- owner=parsed_arguments.owner,
60
- repo=parsed_arguments.repo,
61
- number=parsed_arguments.number,
62
- current_head=parsed_arguments.current_head,
63
- )
64
- json.dump(all_comments, sys.stdout)
65
- sys.stdout.write("\n")
66
- return 0
67
-
68
-
69
- if __name__ == "__main__":
70
- sys.exit(main())
@@ -1,57 +0,0 @@
1
- """Fetch Cursor Bugbot reviews newest-first, classified as dirty or clean.
2
-
3
- Thin wrapper around ``reviewer_fetch_core.fetch_reviewer_reviews`` parameterised
4
- by ``bugbot_spec``. Wraps the gh CLI invocation required by the gh-paginate
5
- rule: ``gh api '...?per_page=100' --paginate --slurp`` piped through external
6
- Python JSON handling (instead of ``gh --jq``, which runs per-page and breaks
7
- cross-page operations like sort/reverse - see GitHub CLI issue 10459).
8
- """
9
-
10
- from __future__ import annotations
11
-
12
- import argparse
13
- import json
14
- import sys
15
- from pathlib import Path
16
-
17
- if str(Path(__file__).resolve().parent) not in sys.path:
18
- sys.path.insert(0, str(Path(__file__).resolve().parent))
19
-
20
- from evict_cached_config_modules import evict_cached_config_modules
21
-
22
- evict_cached_config_modules()
23
-
24
- from reviewer_fetch_core import fetch_reviewer_reviews
25
- from reviewer_specs import bugbot_spec
26
-
27
-
28
- def fetch_bugbot_reviews(
29
- *,
30
- owner: str,
31
- repo: str,
32
- number: int,
33
- ) -> list[dict[str, object]]:
34
- """Return Cursor Bugbot reviews newest-first, each with a classification."""
35
- return fetch_reviewer_reviews(
36
- bugbot_spec, owner=owner, repo=repo, number=number
37
- )
38
-
39
-
40
- def main() -> int:
41
- parser = argparse.ArgumentParser(description=__doc__)
42
- parser.add_argument("--owner", required=True)
43
- parser.add_argument("--repo", required=True)
44
- parser.add_argument("--number", required=True, type=int)
45
- parsed_arguments = parser.parse_args()
46
- all_reviews = fetch_bugbot_reviews(
47
- owner=parsed_arguments.owner,
48
- repo=parsed_arguments.repo,
49
- number=parsed_arguments.number,
50
- )
51
- json.dump(all_reviews, sys.stdout)
52
- sys.stdout.write("\n")
53
- return 0
54
-
55
-
56
- if __name__ == "__main__":
57
- sys.exit(main())
@@ -1,70 +0,0 @@
1
- """Fetch unaddressed Claude inline comments for the latest Claude review on a commit.
2
-
3
- Thin wrapper around ``reviewer_fetch_core.fetch_reviewer_inline_comments``
4
- parameterised by ``claude_spec``. The ``fetch_claude_reviews`` call lives here
5
- (rather than inside the core) so tests can patch it on this module to exercise
6
- the inline-comments fetch in isolation.
7
-
8
- Wraps the gh CLI invocation required by the gh-paginate rule for the comments
9
- list: ``gh api`` on ``repos/{owner}/{repo}/pulls/{number}/comments`` with
10
- ``--paginate --slurp`` and external JSON handling.
11
- """
12
-
13
- from __future__ import annotations
14
-
15
- import argparse
16
- import json
17
- import sys
18
- from pathlib import Path
19
-
20
- if str(Path(__file__).resolve().parent) not in sys.path:
21
- sys.path.insert(0, str(Path(__file__).resolve().parent))
22
-
23
- from evict_cached_config_modules import evict_cached_config_modules
24
-
25
- evict_cached_config_modules()
26
-
27
- from fetch_claude_reviews import fetch_claude_reviews
28
- from reviewer_fetch_core import fetch_reviewer_inline_comments
29
- from reviewer_specs import claude_spec
30
-
31
-
32
- def fetch_claude_inline_comments(
33
- *,
34
- owner: str,
35
- repo: str,
36
- number: int,
37
- current_head: str,
38
- ) -> list[dict[str, object]]:
39
- """Return Claude inline comments for the latest Claude review on ``current_head``."""
40
- all_claude_reviews = fetch_claude_reviews(owner=owner, repo=repo, number=number)
41
- return fetch_reviewer_inline_comments(
42
- claude_spec,
43
- owner=owner,
44
- repo=repo,
45
- number=number,
46
- current_head=current_head,
47
- all_reviews=all_claude_reviews,
48
- )
49
-
50
-
51
- def main() -> int:
52
- parser = argparse.ArgumentParser(description=__doc__)
53
- parser.add_argument("--owner", required=True)
54
- parser.add_argument("--repo", required=True)
55
- parser.add_argument("--number", required=True, type=int)
56
- parser.add_argument("--commit", required=True, dest="current_head")
57
- parsed_arguments = parser.parse_args()
58
- all_comments = fetch_claude_inline_comments(
59
- owner=parsed_arguments.owner,
60
- repo=parsed_arguments.repo,
61
- number=parsed_arguments.number,
62
- current_head=parsed_arguments.current_head,
63
- )
64
- json.dump(all_comments, sys.stdout)
65
- sys.stdout.write("\n")
66
- return 0
67
-
68
-
69
- if __name__ == "__main__":
70
- sys.exit(main())
@@ -1,61 +0,0 @@
1
- """Fetch Claude reviewer-bot reviews newest-first, classified as dirty or clean.
2
-
3
- Thin wrapper around ``reviewer_fetch_core.fetch_reviewer_reviews`` parameterised
4
- by ``claude_spec``. Classification follows the review's ``state`` field
5
- (``APPROVED`` -> clean; ``CHANGES_REQUESTED`` -> dirty; ``COMMENTED`` with
6
- non-empty body -> dirty; everything else -> clean) - see ``reviewer_specs``.
7
-
8
- Wraps the gh CLI invocation required by the gh-paginate rule:
9
- ``gh api '...?per_page=100' --paginate --slurp`` piped through external Python
10
- JSON handling (instead of ``gh --jq``, which runs per-page and breaks
11
- cross-page operations like sort/reverse - see GitHub CLI issue 10459).
12
- """
13
-
14
- from __future__ import annotations
15
-
16
- import argparse
17
- import json
18
- import sys
19
- from pathlib import Path
20
-
21
- if str(Path(__file__).resolve().parent) not in sys.path:
22
- sys.path.insert(0, str(Path(__file__).resolve().parent))
23
-
24
- from evict_cached_config_modules import evict_cached_config_modules
25
-
26
- evict_cached_config_modules()
27
-
28
- from reviewer_fetch_core import fetch_reviewer_reviews
29
- from reviewer_specs import claude_spec
30
-
31
-
32
- def fetch_claude_reviews(
33
- *,
34
- owner: str,
35
- repo: str,
36
- number: int,
37
- ) -> list[dict[str, object]]:
38
- """Return Claude reviews newest-first, each with a classification."""
39
- return fetch_reviewer_reviews(
40
- claude_spec, owner=owner, repo=repo, number=number
41
- )
42
-
43
-
44
- def main() -> int:
45
- parser = argparse.ArgumentParser(description=__doc__)
46
- parser.add_argument("--owner", required=True)
47
- parser.add_argument("--repo", required=True)
48
- parser.add_argument("--number", required=True, type=int)
49
- parsed_arguments = parser.parse_args()
50
- all_reviews = fetch_claude_reviews(
51
- owner=parsed_arguments.owner,
52
- repo=parsed_arguments.repo,
53
- number=parsed_arguments.number,
54
- )
55
- json.dump(all_reviews, sys.stdout)
56
- sys.stdout.write("\n")
57
- return 0
58
-
59
-
60
- if __name__ == "__main__":
61
- sys.exit(main())
@@ -1,70 +0,0 @@
1
- """Fetch unaddressed Copilot inline comments for the latest Copilot review on a commit.
2
-
3
- Thin wrapper around ``reviewer_fetch_core.fetch_reviewer_inline_comments``
4
- parameterised by ``copilot_spec``. The ``fetch_copilot_reviews`` call lives
5
- here (rather than inside the core) so tests can patch it on this module to
6
- exercise the inline-comments fetch in isolation.
7
-
8
- Wraps the gh CLI invocation required by the gh-paginate rule for the comments
9
- list: ``gh api`` on ``repos/{owner}/{repo}/pulls/{number}/comments`` with
10
- ``--paginate --slurp`` and external JSON handling.
11
- """
12
-
13
- from __future__ import annotations
14
-
15
- import argparse
16
- import json
17
- import sys
18
- from pathlib import Path
19
-
20
- if str(Path(__file__).resolve().parent) not in sys.path:
21
- sys.path.insert(0, str(Path(__file__).resolve().parent))
22
-
23
- from evict_cached_config_modules import evict_cached_config_modules
24
-
25
- evict_cached_config_modules()
26
-
27
- from fetch_copilot_reviews import fetch_copilot_reviews
28
- from reviewer_fetch_core import fetch_reviewer_inline_comments
29
- from reviewer_specs import copilot_spec
30
-
31
-
32
- def fetch_copilot_inline_comments(
33
- *,
34
- owner: str,
35
- repo: str,
36
- number: int,
37
- current_head: str,
38
- ) -> list[dict[str, object]]:
39
- """Return Copilot inline comments for the latest Copilot review on ``current_head``."""
40
- all_copilot_reviews = fetch_copilot_reviews(owner=owner, repo=repo, number=number)
41
- return fetch_reviewer_inline_comments(
42
- copilot_spec,
43
- owner=owner,
44
- repo=repo,
45
- number=number,
46
- current_head=current_head,
47
- all_reviews=all_copilot_reviews,
48
- )
49
-
50
-
51
- def main() -> int:
52
- parser = argparse.ArgumentParser(description=__doc__)
53
- parser.add_argument("--owner", required=True)
54
- parser.add_argument("--repo", required=True)
55
- parser.add_argument("--number", required=True, type=int)
56
- parser.add_argument("--commit", required=True, dest="current_head")
57
- parsed_arguments = parser.parse_args()
58
- all_comments = fetch_copilot_inline_comments(
59
- owner=parsed_arguments.owner,
60
- repo=parsed_arguments.repo,
61
- number=parsed_arguments.number,
62
- current_head=parsed_arguments.current_head,
63
- )
64
- json.dump(all_comments, sys.stdout)
65
- sys.stdout.write("\n")
66
- return 0
67
-
68
-
69
- if __name__ == "__main__":
70
- sys.exit(main())
@@ -1,61 +0,0 @@
1
- """Fetch GitHub Copilot reviewer reviews newest-first, classified as dirty or clean.
2
-
3
- Thin wrapper around ``reviewer_fetch_core.fetch_reviewer_reviews`` parameterised
4
- by ``copilot_spec``. Classification follows the review's ``state`` field
5
- (``APPROVED`` -> clean; ``CHANGES_REQUESTED`` -> dirty; ``COMMENTED`` with
6
- non-empty body -> dirty; everything else -> clean) - see ``reviewer_specs``.
7
-
8
- Wraps the gh CLI invocation required by the gh-paginate rule:
9
- ``gh api '...?per_page=100' --paginate --slurp`` piped through external Python
10
- JSON handling (instead of ``gh --jq``, which runs per-page and breaks
11
- cross-page operations like sort/reverse - see GitHub CLI issue 10459).
12
- """
13
-
14
- from __future__ import annotations
15
-
16
- import argparse
17
- import json
18
- import sys
19
- from pathlib import Path
20
-
21
- if str(Path(__file__).resolve().parent) not in sys.path:
22
- sys.path.insert(0, str(Path(__file__).resolve().parent))
23
-
24
- from evict_cached_config_modules import evict_cached_config_modules
25
-
26
- evict_cached_config_modules()
27
-
28
- from reviewer_fetch_core import fetch_reviewer_reviews
29
- from reviewer_specs import copilot_spec
30
-
31
-
32
- def fetch_copilot_reviews(
33
- *,
34
- owner: str,
35
- repo: str,
36
- number: int,
37
- ) -> list[dict[str, object]]:
38
- """Return Copilot reviews newest-first, each with a classification."""
39
- return fetch_reviewer_reviews(
40
- copilot_spec, owner=owner, repo=repo, number=number
41
- )
42
-
43
-
44
- def main() -> int:
45
- parser = argparse.ArgumentParser(description=__doc__)
46
- parser.add_argument("--owner", required=True)
47
- parser.add_argument("--repo", required=True)
48
- parser.add_argument("--number", required=True, type=int)
49
- parsed_arguments = parser.parse_args()
50
- all_reviews = fetch_copilot_reviews(
51
- owner=parsed_arguments.owner,
52
- repo=parsed_arguments.repo,
53
- number=parsed_arguments.number,
54
- )
55
- json.dump(all_reviews, sys.stdout)
56
- sys.stdout.write("\n")
57
- return 0
58
-
59
-
60
- if __name__ == "__main__":
61
- sys.exit(main())