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.
Files changed (190) hide show
  1. package/README.md +719 -0
  2. package/VERSION +1 -0
  3. package/docs/ANVIL-REPO-IMPLEMENTATION-PLAN.md +441 -0
  4. package/docs/FIRST-SKILL-TUTORIAL.md +408 -0
  5. package/docs/INSTALLATION-RETRO-NOTES.md +458 -0
  6. package/docs/INSTALLATION.md +984 -0
  7. package/docs/anvil-hud.md +469 -0
  8. package/docs/anvil-init.md +255 -0
  9. package/docs/anvil-state.md +210 -0
  10. package/docs/boris-cherny-ralph-wiggum-insights.md +608 -0
  11. package/docs/command-reference.md +2022 -0
  12. package/docs/hooks-tts.md +368 -0
  13. package/docs/implementation-guide.md +810 -0
  14. package/docs/linear-github-integration.md +247 -0
  15. package/docs/local-issues.md +677 -0
  16. package/docs/patterns/README.md +419 -0
  17. package/docs/planning-responsibilities.md +139 -0
  18. package/docs/session-workflow.md +573 -0
  19. package/docs/simplification-plan-template.md +297 -0
  20. package/docs/simplification-principles.md +129 -0
  21. package/docs/specifications/CCS-RALPH-INTEGRATION-DESIGN.md +633 -0
  22. package/docs/specifications/CCS-RESEARCH-REPORT.md +169 -0
  23. package/docs/specifications/PLAN-ANV-verification-ralph-wiggum.md +403 -0
  24. package/docs/specifications/PLAN-parallel-tracks-anvil-memory-ccs.md +494 -0
  25. package/docs/specifications/SPEC-ANV-VRW/component-01-verify.md +208 -0
  26. package/docs/specifications/SPEC-ANV-VRW/component-02-stop-gate.md +226 -0
  27. package/docs/specifications/SPEC-ANV-VRW/component-03-posttooluse.md +209 -0
  28. package/docs/specifications/SPEC-ANV-VRW/component-04-ralph-wiggum.md +604 -0
  29. package/docs/specifications/SPEC-ANV-VRW/component-05-atomic-actions.md +311 -0
  30. package/docs/specifications/SPEC-ANV-VRW/component-06-verify-subagent.md +264 -0
  31. package/docs/specifications/SPEC-ANV-VRW/component-07-claude-md.md +363 -0
  32. package/docs/specifications/SPEC-ANV-VRW/index.md +182 -0
  33. package/docs/specifications/SPEC-ANV-anvil-memory.md +573 -0
  34. package/docs/specifications/SPEC-ANV-context-checkpoints.md +781 -0
  35. package/docs/specifications/SPEC-ANV-verification-ralph-wiggum.md +789 -0
  36. package/docs/sync.md +122 -0
  37. package/global/CLAUDE.md +140 -0
  38. package/global/agents/verify-app.md +164 -0
  39. package/global/commands/anvil-settings.md +527 -0
  40. package/global/commands/anvil-sync.md +121 -0
  41. package/global/commands/change.md +197 -0
  42. package/global/commands/clarify.md +252 -0
  43. package/global/commands/cleanup.md +292 -0
  44. package/global/commands/commit-push-pr.md +207 -0
  45. package/global/commands/decay-review.md +127 -0
  46. package/global/commands/discover.md +158 -0
  47. package/global/commands/doc-coverage.md +122 -0
  48. package/global/commands/evidence.md +307 -0
  49. package/global/commands/explore.md +121 -0
  50. package/global/commands/force-exit.md +135 -0
  51. package/global/commands/handoff.md +191 -0
  52. package/global/commands/healthcheck.md +302 -0
  53. package/global/commands/hud.md +84 -0
  54. package/global/commands/insights.md +319 -0
  55. package/global/commands/linear-setup.md +184 -0
  56. package/global/commands/lint-fix.md +198 -0
  57. package/global/commands/orient.md +510 -0
  58. package/global/commands/plan.md +228 -0
  59. package/global/commands/ralph.md +346 -0
  60. package/global/commands/ready.md +182 -0
  61. package/global/commands/release.md +305 -0
  62. package/global/commands/retro.md +96 -0
  63. package/global/commands/shard.md +166 -0
  64. package/global/commands/spec.md +227 -0
  65. package/global/commands/sprint.md +184 -0
  66. package/global/commands/tasks.md +228 -0
  67. package/global/commands/test-and-commit.md +151 -0
  68. package/global/commands/validate.md +132 -0
  69. package/global/commands/verify.md +251 -0
  70. package/global/commands/weekly-review.md +156 -0
  71. package/global/hooks/__pycache__/ralph_context_monitor.cpython-314.pyc +0 -0
  72. package/global/hooks/__pycache__/statusline_agent_sync.cpython-314.pyc +0 -0
  73. package/global/hooks/anvil_memory_observe.ts +322 -0
  74. package/global/hooks/anvil_memory_session.ts +166 -0
  75. package/global/hooks/anvil_memory_stop.ts +187 -0
  76. package/global/hooks/parse_transcript.py +116 -0
  77. package/global/hooks/post_merge_cleanup.sh +132 -0
  78. package/global/hooks/post_tool_format.sh +215 -0
  79. package/global/hooks/ralph_context_monitor.py +240 -0
  80. package/global/hooks/ralph_stop.sh +502 -0
  81. package/global/hooks/statusline.sh +1110 -0
  82. package/global/hooks/statusline_agent_sync.py +224 -0
  83. package/global/hooks/stop_gate.sh +250 -0
  84. package/global/lib/.claude/anvil-state.json +21 -0
  85. package/global/lib/__pycache__/agent_registry.cpython-314.pyc +0 -0
  86. package/global/lib/__pycache__/claim_service.cpython-314.pyc +0 -0
  87. package/global/lib/__pycache__/coderabbit_service.cpython-314.pyc +0 -0
  88. package/global/lib/__pycache__/config_service.cpython-314.pyc +0 -0
  89. package/global/lib/__pycache__/coordination_service.cpython-314.pyc +0 -0
  90. package/global/lib/__pycache__/doc_coverage_service.cpython-314.pyc +0 -0
  91. package/global/lib/__pycache__/gate_logger.cpython-314.pyc +0 -0
  92. package/global/lib/__pycache__/github_service.cpython-314.pyc +0 -0
  93. package/global/lib/__pycache__/hygiene_service.cpython-314.pyc +0 -0
  94. package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
  95. package/global/lib/__pycache__/issue_provider.cpython-314.pyc +0 -0
  96. package/global/lib/__pycache__/linear_data_service.cpython-314.pyc +0 -0
  97. package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
  98. package/global/lib/__pycache__/local_provider.cpython-314.pyc +0 -0
  99. package/global/lib/__pycache__/quality_service.cpython-314.pyc +0 -0
  100. package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
  101. package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
  102. package/global/lib/__pycache__/transcript_parser.cpython-314.pyc +0 -0
  103. package/global/lib/__pycache__/verification_runner.cpython-314.pyc +0 -0
  104. package/global/lib/__pycache__/verify_iteration.cpython-314.pyc +0 -0
  105. package/global/lib/__pycache__/verify_subagent.cpython-314.pyc +0 -0
  106. package/global/lib/agent_registry.py +995 -0
  107. package/global/lib/anvil-state.sh +435 -0
  108. package/global/lib/claim_service.py +515 -0
  109. package/global/lib/coderabbit_service.py +314 -0
  110. package/global/lib/config_service.py +423 -0
  111. package/global/lib/coordination_service.py +331 -0
  112. package/global/lib/doc_coverage_service.py +1305 -0
  113. package/global/lib/gate_logger.py +316 -0
  114. package/global/lib/github_service.py +310 -0
  115. package/global/lib/handoff_generator.py +775 -0
  116. package/global/lib/hygiene_service.py +712 -0
  117. package/global/lib/issue_models.py +257 -0
  118. package/global/lib/issue_provider.py +339 -0
  119. package/global/lib/linear_data_service.py +210 -0
  120. package/global/lib/linear_provider.py +987 -0
  121. package/global/lib/linear_provider.py.backup +671 -0
  122. package/global/lib/local_provider.py +486 -0
  123. package/global/lib/orient_fast.py +457 -0
  124. package/global/lib/quality_service.py +470 -0
  125. package/global/lib/ralph_prompt_generator.py +563 -0
  126. package/global/lib/ralph_state.py +1202 -0
  127. package/global/lib/state_manager.py +417 -0
  128. package/global/lib/transcript_parser.py +597 -0
  129. package/global/lib/verification_runner.py +557 -0
  130. package/global/lib/verify_iteration.py +490 -0
  131. package/global/lib/verify_subagent.py +250 -0
  132. package/global/skills/README.md +155 -0
  133. package/global/skills/quality-gates/SKILL.md +252 -0
  134. package/global/skills/skill-template/SKILL.md +109 -0
  135. package/global/skills/testing-strategies/SKILL.md +337 -0
  136. package/global/templates/CHANGE-template.md +105 -0
  137. package/global/templates/HANDOFF-template.md +63 -0
  138. package/global/templates/PLAN-template.md +111 -0
  139. package/global/templates/SPEC-template.md +93 -0
  140. package/global/templates/ralph/PROMPT.md.template +89 -0
  141. package/global/templates/ralph/fix_plan.md.template +31 -0
  142. package/global/templates/ralph/progress.txt.template +23 -0
  143. package/global/tests/__pycache__/test_doc_coverage.cpython-314.pyc +0 -0
  144. package/global/tests/test_doc_coverage.py +520 -0
  145. package/global/tests/test_issue_models.py +299 -0
  146. package/global/tests/test_local_provider.py +323 -0
  147. package/global/tools/README.md +178 -0
  148. package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
  149. package/global/tools/anvil-hud.py +3622 -0
  150. package/global/tools/anvil-hud.py.bak +3318 -0
  151. package/global/tools/anvil-issue.py +432 -0
  152. package/global/tools/anvil-memory/CLAUDE.md +49 -0
  153. package/global/tools/anvil-memory/README.md +42 -0
  154. package/global/tools/anvil-memory/bun.lock +25 -0
  155. package/global/tools/anvil-memory/bunfig.toml +9 -0
  156. package/global/tools/anvil-memory/package.json +23 -0
  157. package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +535 -0
  158. package/global/tools/anvil-memory/src/__tests__/ccs/edge-cases.test.ts +645 -0
  159. package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +363 -0
  160. package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +8 -0
  161. package/global/tools/anvil-memory/src/__tests__/ccs/integration.test.ts +417 -0
  162. package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +571 -0
  163. package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +440 -0
  164. package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +252 -0
  165. package/global/tools/anvil-memory/src/__tests__/commands.test.ts +657 -0
  166. package/global/tools/anvil-memory/src/__tests__/db.test.ts +641 -0
  167. package/global/tools/anvil-memory/src/__tests__/hooks.test.ts +272 -0
  168. package/global/tools/anvil-memory/src/__tests__/performance.test.ts +427 -0
  169. package/global/tools/anvil-memory/src/__tests__/test-utils.ts +113 -0
  170. package/global/tools/anvil-memory/src/commands/checkpoint.ts +197 -0
  171. package/global/tools/anvil-memory/src/commands/get.ts +115 -0
  172. package/global/tools/anvil-memory/src/commands/init.ts +94 -0
  173. package/global/tools/anvil-memory/src/commands/observe.ts +163 -0
  174. package/global/tools/anvil-memory/src/commands/search.ts +112 -0
  175. package/global/tools/anvil-memory/src/db.ts +638 -0
  176. package/global/tools/anvil-memory/src/index.ts +205 -0
  177. package/global/tools/anvil-memory/src/types.ts +122 -0
  178. package/global/tools/anvil-memory/tsconfig.json +29 -0
  179. package/global/tools/ralph-loop.sh +359 -0
  180. package/package.json +45 -0
  181. package/scripts/anvil +822 -0
  182. package/scripts/extract_patterns.py +222 -0
  183. package/scripts/init-project.sh +541 -0
  184. package/scripts/install.sh +229 -0
  185. package/scripts/postinstall.js +41 -0
  186. package/scripts/rollback.sh +188 -0
  187. package/scripts/sync.sh +623 -0
  188. package/scripts/test-statusline.sh +248 -0
  189. package/scripts/update_claude_md.py +224 -0
  190. 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']}")