anvil-dev-framework 0.1.6
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/README.md +719 -0
- package/VERSION +1 -0
- package/docs/ANVIL-REPO-IMPLEMENTATION-PLAN.md +441 -0
- package/docs/FIRST-SKILL-TUTORIAL.md +408 -0
- package/docs/INSTALLATION-RETRO-NOTES.md +458 -0
- package/docs/INSTALLATION.md +984 -0
- package/docs/anvil-hud.md +469 -0
- package/docs/anvil-init.md +255 -0
- package/docs/anvil-state.md +210 -0
- package/docs/boris-cherny-ralph-wiggum-insights.md +608 -0
- package/docs/command-reference.md +2022 -0
- package/docs/hooks-tts.md +368 -0
- package/docs/implementation-guide.md +810 -0
- package/docs/linear-github-integration.md +247 -0
- package/docs/local-issues.md +677 -0
- package/docs/patterns/README.md +419 -0
- package/docs/planning-responsibilities.md +139 -0
- package/docs/session-workflow.md +573 -0
- package/docs/simplification-plan-template.md +297 -0
- package/docs/simplification-principles.md +129 -0
- package/docs/specifications/CCS-RALPH-INTEGRATION-DESIGN.md +633 -0
- package/docs/specifications/CCS-RESEARCH-REPORT.md +169 -0
- package/docs/specifications/PLAN-ANV-verification-ralph-wiggum.md +403 -0
- package/docs/specifications/PLAN-parallel-tracks-anvil-memory-ccs.md +494 -0
- package/docs/specifications/SPEC-ANV-VRW/component-01-verify.md +208 -0
- package/docs/specifications/SPEC-ANV-VRW/component-02-stop-gate.md +226 -0
- package/docs/specifications/SPEC-ANV-VRW/component-03-posttooluse.md +209 -0
- package/docs/specifications/SPEC-ANV-VRW/component-04-ralph-wiggum.md +604 -0
- package/docs/specifications/SPEC-ANV-VRW/component-05-atomic-actions.md +311 -0
- package/docs/specifications/SPEC-ANV-VRW/component-06-verify-subagent.md +264 -0
- package/docs/specifications/SPEC-ANV-VRW/component-07-claude-md.md +363 -0
- package/docs/specifications/SPEC-ANV-VRW/index.md +182 -0
- package/docs/specifications/SPEC-ANV-anvil-memory.md +573 -0
- package/docs/specifications/SPEC-ANV-context-checkpoints.md +781 -0
- package/docs/specifications/SPEC-ANV-verification-ralph-wiggum.md +789 -0
- package/docs/sync.md +122 -0
- package/global/CLAUDE.md +140 -0
- package/global/agents/verify-app.md +164 -0
- package/global/commands/anvil-settings.md +527 -0
- package/global/commands/anvil-sync.md +121 -0
- package/global/commands/change.md +197 -0
- package/global/commands/clarify.md +252 -0
- package/global/commands/cleanup.md +292 -0
- package/global/commands/commit-push-pr.md +207 -0
- package/global/commands/decay-review.md +127 -0
- package/global/commands/discover.md +158 -0
- package/global/commands/doc-coverage.md +122 -0
- package/global/commands/evidence.md +307 -0
- package/global/commands/explore.md +121 -0
- package/global/commands/force-exit.md +135 -0
- package/global/commands/handoff.md +191 -0
- package/global/commands/healthcheck.md +302 -0
- package/global/commands/hud.md +84 -0
- package/global/commands/insights.md +319 -0
- package/global/commands/linear-setup.md +184 -0
- package/global/commands/lint-fix.md +198 -0
- package/global/commands/orient.md +510 -0
- package/global/commands/plan.md +228 -0
- package/global/commands/ralph.md +346 -0
- package/global/commands/ready.md +182 -0
- package/global/commands/release.md +305 -0
- package/global/commands/retro.md +96 -0
- package/global/commands/shard.md +166 -0
- package/global/commands/spec.md +227 -0
- package/global/commands/sprint.md +184 -0
- package/global/commands/tasks.md +228 -0
- package/global/commands/test-and-commit.md +151 -0
- package/global/commands/validate.md +132 -0
- package/global/commands/verify.md +251 -0
- package/global/commands/weekly-review.md +156 -0
- package/global/hooks/__pycache__/ralph_context_monitor.cpython-314.pyc +0 -0
- package/global/hooks/__pycache__/statusline_agent_sync.cpython-314.pyc +0 -0
- package/global/hooks/anvil_memory_observe.ts +322 -0
- package/global/hooks/anvil_memory_session.ts +166 -0
- package/global/hooks/anvil_memory_stop.ts +187 -0
- package/global/hooks/parse_transcript.py +116 -0
- package/global/hooks/post_merge_cleanup.sh +132 -0
- package/global/hooks/post_tool_format.sh +215 -0
- package/global/hooks/ralph_context_monitor.py +240 -0
- package/global/hooks/ralph_stop.sh +502 -0
- package/global/hooks/statusline.sh +1110 -0
- package/global/hooks/statusline_agent_sync.py +224 -0
- package/global/hooks/stop_gate.sh +250 -0
- package/global/lib/.claude/anvil-state.json +21 -0
- package/global/lib/__pycache__/agent_registry.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/claim_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coderabbit_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/config_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coordination_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/doc_coverage_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/gate_logger.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/github_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/hygiene_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_data_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/local_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/quality_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/transcript_parser.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verification_runner.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_iteration.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_subagent.cpython-314.pyc +0 -0
- package/global/lib/agent_registry.py +995 -0
- package/global/lib/anvil-state.sh +435 -0
- package/global/lib/claim_service.py +515 -0
- package/global/lib/coderabbit_service.py +314 -0
- package/global/lib/config_service.py +423 -0
- package/global/lib/coordination_service.py +331 -0
- package/global/lib/doc_coverage_service.py +1305 -0
- package/global/lib/gate_logger.py +316 -0
- package/global/lib/github_service.py +310 -0
- package/global/lib/handoff_generator.py +775 -0
- package/global/lib/hygiene_service.py +712 -0
- package/global/lib/issue_models.py +257 -0
- package/global/lib/issue_provider.py +339 -0
- package/global/lib/linear_data_service.py +210 -0
- package/global/lib/linear_provider.py +987 -0
- package/global/lib/linear_provider.py.backup +671 -0
- package/global/lib/local_provider.py +486 -0
- package/global/lib/orient_fast.py +457 -0
- package/global/lib/quality_service.py +470 -0
- package/global/lib/ralph_prompt_generator.py +563 -0
- package/global/lib/ralph_state.py +1202 -0
- package/global/lib/state_manager.py +417 -0
- package/global/lib/transcript_parser.py +597 -0
- package/global/lib/verification_runner.py +557 -0
- package/global/lib/verify_iteration.py +490 -0
- package/global/lib/verify_subagent.py +250 -0
- package/global/skills/README.md +155 -0
- package/global/skills/quality-gates/SKILL.md +252 -0
- package/global/skills/skill-template/SKILL.md +109 -0
- package/global/skills/testing-strategies/SKILL.md +337 -0
- package/global/templates/CHANGE-template.md +105 -0
- package/global/templates/HANDOFF-template.md +63 -0
- package/global/templates/PLAN-template.md +111 -0
- package/global/templates/SPEC-template.md +93 -0
- package/global/templates/ralph/PROMPT.md.template +89 -0
- package/global/templates/ralph/fix_plan.md.template +31 -0
- package/global/templates/ralph/progress.txt.template +23 -0
- package/global/tests/__pycache__/test_doc_coverage.cpython-314.pyc +0 -0
- package/global/tests/test_doc_coverage.py +520 -0
- package/global/tests/test_issue_models.py +299 -0
- package/global/tests/test_local_provider.py +323 -0
- package/global/tools/README.md +178 -0
- package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
- package/global/tools/anvil-hud.py +3622 -0
- package/global/tools/anvil-hud.py.bak +3318 -0
- package/global/tools/anvil-issue.py +432 -0
- package/global/tools/anvil-memory/CLAUDE.md +49 -0
- package/global/tools/anvil-memory/README.md +42 -0
- package/global/tools/anvil-memory/bun.lock +25 -0
- package/global/tools/anvil-memory/bunfig.toml +9 -0
- package/global/tools/anvil-memory/package.json +23 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +535 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/edge-cases.test.ts +645 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +363 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +8 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/integration.test.ts +417 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +571 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +440 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +252 -0
- package/global/tools/anvil-memory/src/__tests__/commands.test.ts +657 -0
- package/global/tools/anvil-memory/src/__tests__/db.test.ts +641 -0
- package/global/tools/anvil-memory/src/__tests__/hooks.test.ts +272 -0
- package/global/tools/anvil-memory/src/__tests__/performance.test.ts +427 -0
- package/global/tools/anvil-memory/src/__tests__/test-utils.ts +113 -0
- package/global/tools/anvil-memory/src/commands/checkpoint.ts +197 -0
- package/global/tools/anvil-memory/src/commands/get.ts +115 -0
- package/global/tools/anvil-memory/src/commands/init.ts +94 -0
- package/global/tools/anvil-memory/src/commands/observe.ts +163 -0
- package/global/tools/anvil-memory/src/commands/search.ts +112 -0
- package/global/tools/anvil-memory/src/db.ts +638 -0
- package/global/tools/anvil-memory/src/index.ts +205 -0
- package/global/tools/anvil-memory/src/types.ts +122 -0
- package/global/tools/anvil-memory/tsconfig.json +29 -0
- package/global/tools/ralph-loop.sh +359 -0
- package/package.json +45 -0
- package/scripts/anvil +822 -0
- package/scripts/extract_patterns.py +222 -0
- package/scripts/init-project.sh +541 -0
- package/scripts/install.sh +229 -0
- package/scripts/postinstall.js +41 -0
- package/scripts/rollback.sh +188 -0
- package/scripts/sync.sh +623 -0
- package/scripts/test-statusline.sh +248 -0
- package/scripts/update_claude_md.py +224 -0
- package/scripts/verify.sh +255 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
coderabbit_service.py - CodeRabbit CLI integration for HUD (ANV-114-115)
|
|
4
|
+
|
|
5
|
+
Wraps the CodeRabbit CLI to fetch review status for PRs.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from coderabbit_service import CodeRabbitService
|
|
9
|
+
|
|
10
|
+
service = CodeRabbitService()
|
|
11
|
+
status = service.get_review_status(pr_number=45, repo_path="/path/to/repo")
|
|
12
|
+
print(status["review_status"], status["issues_count"])
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
import subprocess
|
|
17
|
+
import time
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any, Dict, List, Optional, TypedDict
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ReviewIssue(TypedDict, total=False):
|
|
23
|
+
"""A CodeRabbit review issue."""
|
|
24
|
+
severity: str # error, warning, suggestion
|
|
25
|
+
file: str # File path
|
|
26
|
+
line: int # Line number
|
|
27
|
+
message: str # Issue message
|
|
28
|
+
resolved: bool # Whether resolved
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class CodeRabbitStatus(TypedDict, total=False):
|
|
32
|
+
"""CodeRabbit review status for a PR."""
|
|
33
|
+
pr_number: int
|
|
34
|
+
review_status: str # reviewing, approved, changes_requested, pending
|
|
35
|
+
issues_count: int # Total issues found
|
|
36
|
+
suggestions_count: int # Total suggestions
|
|
37
|
+
resolved_count: int # Resolved issues/suggestions
|
|
38
|
+
pending_count: int # Pending issues
|
|
39
|
+
review_url: str # Link to review
|
|
40
|
+
issues: List[ReviewIssue]
|
|
41
|
+
last_updated: float
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Cache TTL in seconds
|
|
45
|
+
CACHE_TTL = 60.0
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class CodeRabbitService:
|
|
49
|
+
"""Service for fetching CodeRabbit review status (ANV-114-115)."""
|
|
50
|
+
|
|
51
|
+
def __init__(self):
|
|
52
|
+
"""Initialize the CodeRabbit service."""
|
|
53
|
+
self._cache: Dict[str, CodeRabbitStatus] = {}
|
|
54
|
+
self._cache_timestamps: Dict[str, float] = {}
|
|
55
|
+
self._cli_available: Optional[bool] = None
|
|
56
|
+
|
|
57
|
+
def is_available(self) -> bool:
|
|
58
|
+
"""Check if CodeRabbit CLI is available."""
|
|
59
|
+
if self._cli_available is None:
|
|
60
|
+
try:
|
|
61
|
+
result = subprocess.run(
|
|
62
|
+
["coderabbit", "--version"],
|
|
63
|
+
capture_output=True,
|
|
64
|
+
text=True,
|
|
65
|
+
timeout=5,
|
|
66
|
+
)
|
|
67
|
+
self._cli_available = result.returncode == 0
|
|
68
|
+
except Exception:
|
|
69
|
+
self._cli_available = False
|
|
70
|
+
return self._cli_available
|
|
71
|
+
|
|
72
|
+
def get_review_status(
|
|
73
|
+
self,
|
|
74
|
+
pr_number: int,
|
|
75
|
+
repo_path: Optional[str] = None,
|
|
76
|
+
force_refresh: bool = False,
|
|
77
|
+
) -> Optional[CodeRabbitStatus]:
|
|
78
|
+
"""Get CodeRabbit review status for a PR.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
pr_number: PR number to check
|
|
82
|
+
repo_path: Path to repository (for cwd context)
|
|
83
|
+
force_refresh: Force refresh even if cache is fresh
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
CodeRabbitStatus or None if not available
|
|
87
|
+
"""
|
|
88
|
+
cache_key = f"{repo_path or 'default'}:{pr_number}"
|
|
89
|
+
now = time.time()
|
|
90
|
+
|
|
91
|
+
# Check cache
|
|
92
|
+
if not force_refresh and cache_key in self._cache:
|
|
93
|
+
if now - self._cache_timestamps.get(cache_key, 0) < CACHE_TTL:
|
|
94
|
+
return self._cache[cache_key]
|
|
95
|
+
|
|
96
|
+
# Fetch fresh status
|
|
97
|
+
status = self._fetch_review_status(pr_number, repo_path)
|
|
98
|
+
if status:
|
|
99
|
+
self._cache[cache_key] = status
|
|
100
|
+
self._cache_timestamps[cache_key] = now
|
|
101
|
+
|
|
102
|
+
return status
|
|
103
|
+
|
|
104
|
+
def get_status_for_prs(
|
|
105
|
+
self,
|
|
106
|
+
github_status: Dict[str, Any],
|
|
107
|
+
) -> Dict[str, CodeRabbitStatus]:
|
|
108
|
+
"""Get CodeRabbit status for all PRs from GitHub status.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
github_status: Dictionary of project_path -> GitHub PRStatus
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Dictionary of project_path -> CodeRabbitStatus
|
|
115
|
+
"""
|
|
116
|
+
results: Dict[str, CodeRabbitStatus] = {}
|
|
117
|
+
|
|
118
|
+
for project_path, gh_status in github_status.items():
|
|
119
|
+
pr_number = gh_status.get("pr_number")
|
|
120
|
+
if pr_number:
|
|
121
|
+
status = self.get_review_status(pr_number, project_path)
|
|
122
|
+
if status:
|
|
123
|
+
results[project_path] = status
|
|
124
|
+
|
|
125
|
+
return results
|
|
126
|
+
|
|
127
|
+
def _fetch_review_status(
|
|
128
|
+
self,
|
|
129
|
+
pr_number: int,
|
|
130
|
+
repo_path: Optional[str] = None,
|
|
131
|
+
) -> Optional[CodeRabbitStatus]:
|
|
132
|
+
"""Fetch review status from CodeRabbit CLI."""
|
|
133
|
+
if not self.is_available():
|
|
134
|
+
return self._create_unavailable_status(pr_number)
|
|
135
|
+
|
|
136
|
+
cwd = repo_path if repo_path and Path(repo_path).exists() else None
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
# Try to get status via CLI
|
|
140
|
+
result = subprocess.run(
|
|
141
|
+
["coderabbit", "status", "--pr", str(pr_number), "--json"],
|
|
142
|
+
cwd=cwd,
|
|
143
|
+
capture_output=True,
|
|
144
|
+
text=True,
|
|
145
|
+
timeout=30,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if result.returncode != 0:
|
|
149
|
+
# CLI failed, return empty status
|
|
150
|
+
return self._create_pending_status(pr_number)
|
|
151
|
+
|
|
152
|
+
data = json.loads(result.stdout)
|
|
153
|
+
return self._parse_cli_output(data, pr_number)
|
|
154
|
+
|
|
155
|
+
except subprocess.TimeoutExpired:
|
|
156
|
+
return self._create_pending_status(pr_number)
|
|
157
|
+
except json.JSONDecodeError:
|
|
158
|
+
# Try parsing as prompt-only output
|
|
159
|
+
# result is guaranteed to be defined here since JSONDecodeError
|
|
160
|
+
# only happens after json.loads(result.stdout) succeeds in parsing
|
|
161
|
+
if 'result' in locals():
|
|
162
|
+
return self._parse_prompt_output(result.stdout, pr_number)
|
|
163
|
+
return self._create_pending_status(pr_number)
|
|
164
|
+
except Exception:
|
|
165
|
+
return self._create_pending_status(pr_number)
|
|
166
|
+
|
|
167
|
+
def _parse_cli_output(self, data: Dict[str, Any], pr_number: int) -> CodeRabbitStatus:
|
|
168
|
+
"""Parse CodeRabbit CLI JSON output."""
|
|
169
|
+
issues: List[ReviewIssue] = []
|
|
170
|
+
issues_count = 0
|
|
171
|
+
suggestions_count = 0
|
|
172
|
+
resolved_count = 0
|
|
173
|
+
|
|
174
|
+
# Parse issues/suggestions from CLI output
|
|
175
|
+
for item in data.get("issues", []):
|
|
176
|
+
issue: ReviewIssue = {
|
|
177
|
+
"severity": item.get("severity", "suggestion"),
|
|
178
|
+
"file": item.get("file", ""),
|
|
179
|
+
"line": item.get("line", 0),
|
|
180
|
+
"message": item.get("message", ""),
|
|
181
|
+
"resolved": item.get("resolved", False),
|
|
182
|
+
}
|
|
183
|
+
issues.append(issue)
|
|
184
|
+
|
|
185
|
+
if issue["severity"] in ("error", "warning"):
|
|
186
|
+
issues_count += 1
|
|
187
|
+
else:
|
|
188
|
+
suggestions_count += 1
|
|
189
|
+
|
|
190
|
+
if issue["resolved"]:
|
|
191
|
+
resolved_count += 1
|
|
192
|
+
|
|
193
|
+
# Determine review status
|
|
194
|
+
review_status = data.get("status", "pending")
|
|
195
|
+
if review_status == "approved":
|
|
196
|
+
review_status = "approved"
|
|
197
|
+
elif issues_count > 0:
|
|
198
|
+
review_status = "changes_requested"
|
|
199
|
+
elif suggestions_count > 0:
|
|
200
|
+
review_status = "reviewing"
|
|
201
|
+
else:
|
|
202
|
+
review_status = "pending"
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
"pr_number": pr_number,
|
|
206
|
+
"review_status": review_status,
|
|
207
|
+
"issues_count": issues_count,
|
|
208
|
+
"suggestions_count": suggestions_count,
|
|
209
|
+
"resolved_count": resolved_count,
|
|
210
|
+
"pending_count": issues_count + suggestions_count - resolved_count,
|
|
211
|
+
"review_url": data.get("url", ""),
|
|
212
|
+
"issues": issues,
|
|
213
|
+
"last_updated": time.time(),
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
def _parse_prompt_output(self, output: str, pr_number: int) -> CodeRabbitStatus:
|
|
217
|
+
"""Parse CodeRabbit --prompt-only output (CR-006)."""
|
|
218
|
+
# Basic parsing of text output
|
|
219
|
+
issues_count = 0
|
|
220
|
+
suggestions_count = 0
|
|
221
|
+
|
|
222
|
+
lines = output.lower()
|
|
223
|
+
if "issue" in lines or "error" in lines or "warning" in lines:
|
|
224
|
+
# Try to count issues
|
|
225
|
+
import re
|
|
226
|
+
match = re.search(r"(\d+)\s*issue", lines)
|
|
227
|
+
if match:
|
|
228
|
+
issues_count = int(match.group(1))
|
|
229
|
+
|
|
230
|
+
if "suggestion" in lines:
|
|
231
|
+
match = re.search(r"(\d+)\s*suggestion", lines)
|
|
232
|
+
if match:
|
|
233
|
+
suggestions_count = int(match.group(1))
|
|
234
|
+
|
|
235
|
+
review_status = "pending"
|
|
236
|
+
if "approved" in lines:
|
|
237
|
+
review_status = "approved"
|
|
238
|
+
elif issues_count > 0:
|
|
239
|
+
review_status = "changes_requested"
|
|
240
|
+
elif suggestions_count > 0:
|
|
241
|
+
review_status = "reviewing"
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
"pr_number": pr_number,
|
|
245
|
+
"review_status": review_status,
|
|
246
|
+
"issues_count": issues_count,
|
|
247
|
+
"suggestions_count": suggestions_count,
|
|
248
|
+
"resolved_count": 0,
|
|
249
|
+
"pending_count": issues_count + suggestions_count,
|
|
250
|
+
"review_url": "",
|
|
251
|
+
"issues": [],
|
|
252
|
+
"last_updated": time.time(),
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
def _create_pending_status(self, pr_number: int) -> CodeRabbitStatus:
|
|
256
|
+
"""Create a pending status when review hasn't started."""
|
|
257
|
+
return {
|
|
258
|
+
"pr_number": pr_number,
|
|
259
|
+
"review_status": "pending",
|
|
260
|
+
"issues_count": 0,
|
|
261
|
+
"suggestions_count": 0,
|
|
262
|
+
"resolved_count": 0,
|
|
263
|
+
"pending_count": 0,
|
|
264
|
+
"review_url": "",
|
|
265
|
+
"issues": [],
|
|
266
|
+
"last_updated": time.time(),
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
def _create_unavailable_status(self, pr_number: int) -> CodeRabbitStatus:
|
|
270
|
+
"""Create status when CLI is not available."""
|
|
271
|
+
return {
|
|
272
|
+
"pr_number": pr_number,
|
|
273
|
+
"review_status": "unavailable",
|
|
274
|
+
"issues_count": 0,
|
|
275
|
+
"suggestions_count": 0,
|
|
276
|
+
"resolved_count": 0,
|
|
277
|
+
"pending_count": 0,
|
|
278
|
+
"review_url": "",
|
|
279
|
+
"issues": [],
|
|
280
|
+
"last_updated": time.time(),
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
def clear_cache(self) -> None:
|
|
284
|
+
"""Clear cached status."""
|
|
285
|
+
self._cache.clear()
|
|
286
|
+
self._cache_timestamps.clear()
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
# Singleton instance
|
|
290
|
+
_service: Optional[CodeRabbitService] = None
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def get_coderabbit_service() -> CodeRabbitService:
|
|
294
|
+
"""Get singleton service instance."""
|
|
295
|
+
global _service
|
|
296
|
+
if _service is None:
|
|
297
|
+
_service = CodeRabbitService()
|
|
298
|
+
return _service
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
if __name__ == "__main__":
|
|
302
|
+
# Simple test
|
|
303
|
+
service = CodeRabbitService()
|
|
304
|
+
print(f"CodeRabbit CLI available: {service.is_available()}")
|
|
305
|
+
|
|
306
|
+
if service.is_available():
|
|
307
|
+
import sys
|
|
308
|
+
pr_number = int(sys.argv[1]) if len(sys.argv) > 1 else 1
|
|
309
|
+
status = service.get_review_status(pr_number)
|
|
310
|
+
if status:
|
|
311
|
+
print(f"PR: #{status['pr_number']}")
|
|
312
|
+
print(f"Status: {status['review_status']}")
|
|
313
|
+
print(f"Issues: {status['issues_count']}")
|
|
314
|
+
print(f"Suggestions: {status['suggestions_count']}")
|