anvil-dev-framework 0.1.7 → 0.1.9

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 (143) hide show
  1. package/README.md +71 -22
  2. package/VERSION +1 -1
  3. package/docs/ANV-263-hook-logging-investigation.md +116 -0
  4. package/docs/command-reference.md +398 -17
  5. package/docs/session-workflow.md +62 -9
  6. package/docs/system-architecture.md +584 -0
  7. package/global/api/__pycache__/ralph_api.cpython-314.pyc +0 -0
  8. package/global/api/openapi.yaml +357 -0
  9. package/global/api/ralph_api.py +528 -0
  10. package/global/commands/anvil-settings.md +47 -19
  11. package/global/commands/audit.md +163 -0
  12. package/global/commands/checklist.md +180 -0
  13. package/global/commands/coderabbit-fix.md +282 -0
  14. package/global/commands/efficiency.md +356 -0
  15. package/global/commands/evidence.md +117 -33
  16. package/global/commands/hud.md +24 -0
  17. package/global/commands/insights.md +101 -3
  18. package/global/commands/orient.md +22 -21
  19. package/global/commands/patterns.md +115 -0
  20. package/global/commands/ralph.md +47 -1
  21. package/global/commands/token-budget.md +214 -0
  22. package/global/commands/weekly-review.md +21 -1
  23. package/global/config/notifications.yaml.template +50 -0
  24. package/global/hooks/ralph_stop.sh +33 -1
  25. package/global/hooks/statusline.sh +67 -2
  26. package/global/lib/__pycache__/coderabbit_metrics.cpython-314.pyc +0 -0
  27. package/global/lib/__pycache__/command_tracker.cpython-314.pyc +0 -0
  28. package/global/lib/__pycache__/context_optimizer.cpython-314.pyc +0 -0
  29. package/global/lib/__pycache__/git_utils.cpython-314.pyc +0 -0
  30. package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
  31. package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
  32. package/global/lib/__pycache__/optimization_applier.cpython-314.pyc +0 -0
  33. package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
  34. package/global/lib/__pycache__/ralph_webhooks.cpython-314.pyc +0 -0
  35. package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
  36. package/global/lib/__pycache__/token_analyzer.cpython-314.pyc +0 -0
  37. package/global/lib/__pycache__/token_metrics.cpython-314.pyc +0 -0
  38. package/global/lib/coderabbit_metrics.py +647 -0
  39. package/global/lib/command_tracker.py +147 -0
  40. package/global/lib/context_optimizer.py +323 -0
  41. package/global/lib/linear_provider.py +210 -16
  42. package/global/lib/log_rotation.py +287 -0
  43. package/global/lib/optimization_applier.py +582 -0
  44. package/global/lib/ralph_events.py +398 -0
  45. package/global/lib/ralph_notifier.py +366 -0
  46. package/global/lib/ralph_state.py +264 -24
  47. package/global/lib/ralph_webhooks.py +470 -0
  48. package/global/lib/state_manager.py +121 -0
  49. package/global/lib/token_analyzer.py +1383 -0
  50. package/global/lib/token_metrics.py +919 -0
  51. package/global/tests/__pycache__/test_command_tracker.cpython-314-pytest-9.0.2.pyc +0 -0
  52. package/global/tests/__pycache__/test_context_optimizer.cpython-314-pytest-9.0.2.pyc +0 -0
  53. package/global/tests/__pycache__/test_doc_coverage.cpython-314-pytest-9.0.2.pyc +0 -0
  54. package/global/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
  55. package/global/tests/__pycache__/test_issue_models.cpython-314-pytest-9.0.2.pyc +0 -0
  56. package/global/tests/__pycache__/test_linear_filtering.cpython-314-pytest-9.0.2.pyc +0 -0
  57. package/global/tests/__pycache__/test_linear_provider.cpython-314-pytest-9.0.2.pyc +0 -0
  58. package/global/tests/__pycache__/test_local_provider.cpython-314-pytest-9.0.2.pyc +0 -0
  59. package/global/tests/__pycache__/test_optimization_applier.cpython-314-pytest-9.0.2.pyc +0 -0
  60. package/global/tests/__pycache__/test_token_analyzer.cpython-314-pytest-9.0.2.pyc +0 -0
  61. package/global/tests/__pycache__/test_token_analyzer_phase6.cpython-314-pytest-9.0.2.pyc +0 -0
  62. package/global/tests/__pycache__/test_token_metrics.cpython-314-pytest-9.0.2.pyc +0 -0
  63. package/global/tests/test_command_tracker.py +172 -0
  64. package/global/tests/test_context_optimizer.py +321 -0
  65. package/global/tests/test_linear_filtering.py +319 -0
  66. package/global/tests/test_linear_provider.py +40 -1
  67. package/global/tests/test_optimization_applier.py +508 -0
  68. package/global/tests/test_token_analyzer.py +735 -0
  69. package/global/tests/test_token_analyzer_phase6.py +537 -0
  70. package/global/tests/test_token_metrics.py +829 -0
  71. package/global/tools/README.md +153 -0
  72. package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
  73. package/global/tools/__pycache__/orient_linear.cpython-314.pyc +0 -0
  74. package/global/tools/__pycache__/ralph-watchcpython-314.pyc +0 -0
  75. package/global/tools/anvil-hud.py +86 -1
  76. package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +472 -0
  77. package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +405 -0
  78. package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +36 -0
  79. package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +653 -0
  80. package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +727 -0
  81. package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +340 -0
  82. package/global/tools/anvil-memory/src/__tests__/commands.test.ts +218 -0
  83. package/global/tools/anvil-memory/src/commands/context.ts +322 -0
  84. package/global/tools/anvil-memory/src/db.ts +108 -0
  85. package/global/tools/anvil-memory/src/index.ts +2 -8
  86. package/global/tools/orient_linear.py +159 -0
  87. package/global/tools/ralph-watch +423 -0
  88. package/package.json +2 -1
  89. package/project/.anvil-project.yaml.template +93 -0
  90. package/project/CLAUDE.md.template +343 -0
  91. package/project/agents/README.md +119 -0
  92. package/project/agents/cross-layer-debugger.md +217 -0
  93. package/project/agents/security-code-reviewer.md +162 -0
  94. package/project/constitution.md.template +235 -0
  95. package/project/coordination.md +103 -0
  96. package/project/docs/background-tasks.md +258 -0
  97. package/project/docs/skills-frontmatter.md +243 -0
  98. package/project/examples/README.md +106 -0
  99. package/project/examples/api-route-template.ts +171 -0
  100. package/project/examples/component-template.tsx +110 -0
  101. package/project/examples/hook-template.ts +152 -0
  102. package/project/examples/service-template.ts +207 -0
  103. package/project/examples/test-template.test.tsx +249 -0
  104. package/project/hooks/README.md +491 -0
  105. package/project/hooks/__pycache__/notification.cpython-314.pyc +0 -0
  106. package/project/hooks/__pycache__/post_tool_use.cpython-314.pyc +0 -0
  107. package/project/hooks/__pycache__/pre_tool_use.cpython-314.pyc +0 -0
  108. package/project/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
  109. package/project/hooks/__pycache__/stop.cpython-314.pyc +0 -0
  110. package/project/hooks/notification.py +183 -0
  111. package/project/hooks/permission_request.py +438 -0
  112. package/project/hooks/post_tool_use.py +397 -0
  113. package/project/hooks/pre_compact.py +126 -0
  114. package/project/hooks/pre_tool_use.py +454 -0
  115. package/project/hooks/session_start.py +656 -0
  116. package/project/hooks/stop.py +356 -0
  117. package/project/hooks/subagent_start.py +223 -0
  118. package/project/hooks/subagent_stop.py +215 -0
  119. package/project/hooks/user_prompt_submit.py +110 -0
  120. package/project/hooks/utils/llm/anth.py +114 -0
  121. package/project/hooks/utils/llm/oai.py +114 -0
  122. package/project/hooks/utils/tts/elevenlabs_tts.py +63 -0
  123. package/project/hooks/utils/tts/mlx_audio_tts.py +86 -0
  124. package/project/hooks/utils/tts/openai_tts.py +92 -0
  125. package/project/hooks/utils/tts/pyttsx3_tts.py +75 -0
  126. package/project/linear.yaml.template +23 -0
  127. package/project/product.md.template +238 -0
  128. package/project/retros/README.md +126 -0
  129. package/project/rules/README.md +90 -0
  130. package/project/rules/debugging.md +139 -0
  131. package/project/rules/security-review.md +115 -0
  132. package/project/settings.yaml.template +185 -0
  133. package/project/specs/SPEC-ANV-72-hud-kanban.md +525 -0
  134. package/project/templates/api-python/CLAUDE.md +547 -0
  135. package/project/templates/generic/CLAUDE.md +260 -0
  136. package/project/templates/saas/CLAUDE.md +478 -0
  137. package/project/tests/README.md +140 -0
  138. package/project/tests/__pycache__/test_transcript_parser.cpython-314-pytest-9.0.2.pyc +0 -0
  139. package/project/tests/fixtures/sample-transcript.jsonl +21 -0
  140. package/project/tests/test-hooks.sh +259 -0
  141. package/project/tests/test-lib.sh +248 -0
  142. package/project/tests/test-statusline.sh +165 -0
  143. package/project/tests/test_transcript_parser.py +323 -0
@@ -176,3 +176,156 @@ uv run global/tools/anvil-hud.py
176
176
  **Context not updating**
177
177
  - Verify `post_tool_use.py` has `--update-agent` flag
178
178
  - Check that hook is receiving context_window data from Claude Code
179
+
180
+ ---
181
+
182
+ ## ralph-watch
183
+
184
+ Live terminal monitor for Ralph autonomous execution sessions. Shows real-time progress, event stream, and Linear subtask status.
185
+
186
+ ### Usage
187
+
188
+ ```bash
189
+ # Watch current directory session
190
+ python3 global/tools/ralph-watch
191
+
192
+ # Compact single-line display
193
+ python3 global/tools/ralph-watch --compact
194
+
195
+ # Custom state file location
196
+ python3 global/tools/ralph-watch --state /path/to/.claude/ralph-state.json
197
+
198
+ # Hide event stream
199
+ python3 global/tools/ralph-watch --no-events
200
+ ```
201
+
202
+ ### Keybindings
203
+
204
+ | Key | Action |
205
+ |-----|--------|
206
+ | `q` | Quit |
207
+ | `r` | Force refresh |
208
+ | `e` | Toggle event stream |
209
+ | `c` | Toggle compact mode |
210
+
211
+ ### Display Modes
212
+
213
+ **Full Mode** (default)
214
+ - Progress bar with completion percentage
215
+ - Linear subtask status (if enabled)
216
+ - Recent event stream
217
+ - Warnings for circuit breaker and checkpoints
218
+
219
+ **Compact Mode** (`--compact` or press `c`)
220
+ - Single-line status display
221
+ - Shows: task name, status, iteration, progress, duration
222
+ - Ideal for embedding in tmux status bar
223
+
224
+ ### Features
225
+
226
+ - **Real-time Updates**: 1-second polling of Ralph state file
227
+ - **Progress Tracking**: Visual progress bar with subtask counts
228
+ - **Linear Integration**: Shows Linear subtask completion status
229
+ - **Event Stream**: Recent events with timestamps and icons
230
+ - **Warning Indicators**: Circuit breaker and checkpoint alerts
231
+
232
+ ### Example Output
233
+
234
+ ```
235
+ ╔═══════════════════════════════════════════════════════════════════╗
236
+ ║ 🐺 Ralph Session Monitor ║
237
+ ╠═══════════════════════════════════════════════════════════════════╣
238
+ ║ Task: Migration Task
239
+ ║ Status: RUNNING │ Iteration: 5 │ Duration: 12:34
240
+ ║ Progress: [================ ] 67% (4/6)
241
+ ╠───────────────────────────────────────────────────────────────────╣
242
+ ║ Linear Subtasks:
243
+ ║ ✅ ANV-101: Phase 1 Setup
244
+ ║ ✅ ANV-102: Core Implementation
245
+ ║ ⬜ ANV-103: Testing
246
+ ╠───────────────────────────────────────────────────────────────────╣
247
+ ║ Recent Events:
248
+ ║ ✅ 2026-01-17T17:30:00 subtask_complete
249
+ ║ 🔄 2026-01-17T17:25:00 iteration_complete
250
+ ╠═══════════════════════════════════════════════════════════════════╣
251
+ ║ q:quit r:refresh e:events c:compact ║
252
+ ╚═══════════════════════════════════════════════════════════════════╝
253
+ ```
254
+
255
+ ### Integration with Ralph
256
+
257
+ The watcher reads from:
258
+ - `.claude/ralph-state.json` - Current session state
259
+ - `~/.anvil/events/current-session.jsonl` - Event stream
260
+
261
+ Start the watcher in a split terminal while running Ralph:
262
+
263
+ ```bash
264
+ # Terminal 1: Run Ralph
265
+ while :; do cat PROMPT.md | npx @anthropic-ai/claude-code --print; done
266
+
267
+ # Terminal 2: Watch progress
268
+ python3 global/tools/ralph-watch
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Ralph Notification System
274
+
275
+ Additional tools for Ralph visibility:
276
+
277
+ ### ralph_notifier.py
278
+
279
+ Dispatches notifications for Ralph events.
280
+
281
+ ```bash
282
+ # Show current config
283
+ python3 global/lib/ralph_notifier.py --config
284
+
285
+ # Toggle notifications
286
+ python3 global/lib/ralph_notifier.py --disable tts
287
+ python3 global/lib/ralph_notifier.py --enable macos
288
+ python3 global/lib/ralph_notifier.py --disable all
289
+
290
+ # Test notifications
291
+ python3 global/lib/ralph_notifier.py --test-macos "Test message"
292
+ python3 global/lib/ralph_notifier.py --test-tts "Hello from Ralph"
293
+
294
+ # Dispatch pending events
295
+ python3 global/lib/ralph_notifier.py --dispatch
296
+ ```
297
+
298
+ ### ralph_webhooks.py
299
+
300
+ Sends Ralph events to Slack/Discord webhooks.
301
+
302
+ ```bash
303
+ # Test webhooks
304
+ python3 global/lib/ralph_webhooks.py --test-slack $SLACK_WEBHOOK_URL
305
+ python3 global/lib/ralph_webhooks.py --test-discord $DISCORD_WEBHOOK_URL
306
+
307
+ # Dispatch to configured webhooks
308
+ python3 global/lib/ralph_webhooks.py --dispatch
309
+ ```
310
+
311
+ ### ralph_api.py
312
+
313
+ HTTP API server with SSE for real-time events.
314
+
315
+ ```bash
316
+ # Start API server
317
+ python3 global/api/ralph_api.py --port 8765
318
+
319
+ # With API key authentication
320
+ python3 global/api/ralph_api.py --api-key "your-secret-key"
321
+ ```
322
+
323
+ **Endpoints:**
324
+ - `GET /health` - Server health check
325
+ - `GET /status` - Current session status
326
+ - `GET /events` - SSE event stream
327
+ - `GET /history` - Recent event history
328
+ - `GET /sessions` - Past session summaries
329
+ - `POST /control` - Control commands (stop)
330
+
331
+ See `global/api/openapi.yaml` for full API documentation.
@@ -82,6 +82,13 @@ try:
82
82
  except ImportError:
83
83
  CodeRabbitService = None
84
84
 
85
+ # ANV-277: CodeRabbit Metrics for weekly stats in HUD
86
+ try:
87
+ from coderabbit_metrics import CodeRabbitMetrics, WeeklySummary
88
+ except ImportError:
89
+ CodeRabbitMetrics = None
90
+ WeeklySummary = None
91
+
85
92
  try:
86
93
  from config_service import get_config, get_config_service, HUDConfig
87
94
  except ImportError:
@@ -290,12 +297,13 @@ class TaskPanel(Static):
290
297
 
291
298
 
292
299
  class QualityPanel(Static):
293
- """Widget displaying quality gate status (ANV-103/104/105, ANV-111-115)."""
300
+ """Widget displaying quality gate status (ANV-103/104/105, ANV-111-115, ANV-277)."""
294
301
 
295
302
  agents: reactive[Dict[str, Any]] = reactive({})
296
303
  quality_results: reactive[Dict[str, Any]] = reactive({})
297
304
  github_status: reactive[Dict[str, Any]] = reactive({}) # ANV-111-113
298
305
  coderabbit_status: reactive[Dict[str, Any]] = reactive({}) # ANV-114-115
306
+ weekly_metrics: reactive[Dict[str, Any]] = reactive({}) # ANV-277: Weekly CR metrics
299
307
 
300
308
  def compose(self) -> ComposeResult:
301
309
  yield Static(id="quality-panel-content")
@@ -316,6 +324,10 @@ class QualityPanel(Static):
316
324
  """Update display when CodeRabbit status changes."""
317
325
  self._refresh_display()
318
326
 
327
+ def watch_weekly_metrics(self, metrics: Dict[str, Any]) -> None:
328
+ """Update display when weekly metrics change (ANV-277)."""
329
+ self._refresh_display()
330
+
319
331
  def _refresh_display(self) -> None:
320
332
  """Refresh the quality panel display."""
321
333
  content = self.query_one("#quality-panel-content", Static)
@@ -478,6 +490,43 @@ class QualityPanel(Static):
478
490
 
479
491
  text.append("\n")
480
492
 
493
+ # ANV-277: CodeRabbit Weekly Metrics Summary
494
+ if self.weekly_metrics:
495
+ text.append("─" * 36 + "\n", style="dim")
496
+ text.append("CODERABBIT WEEKLY\n", style="bold cyan")
497
+
498
+ total_reviews = self.weekly_metrics.get("total_reviews", 0)
499
+ total_issues = self.weekly_metrics.get("total_issues_found", 0)
500
+ total_fixed = self.weekly_metrics.get("total_issues_fixed", 0)
501
+ avg_issues = self.weekly_metrics.get("avg_issues_per_review", 0)
502
+ pass_rate = self.weekly_metrics.get("pass_rate", 0)
503
+ trend = self.weekly_metrics.get("trend", "stable")
504
+
505
+ text.append(f" Reviews: ", style="dim")
506
+ text.append(f"{total_reviews}\n", style="white")
507
+
508
+ text.append(f" Issues: ", style="dim")
509
+ text.append(f"{total_issues} found", style="yellow" if total_issues > 0 else "green")
510
+ text.append(f" / {total_fixed} fixed\n", style="green" if total_fixed > 0 else "dim")
511
+
512
+ text.append(f" Avg/Review: ", style="dim")
513
+ avg_color = "green" if avg_issues < 2 else "yellow" if avg_issues < 5 else "red"
514
+ text.append(f"{avg_issues:.1f}\n", style=avg_color)
515
+
516
+ text.append(f" Pass Rate: ", style="dim")
517
+ pass_color = "green" if pass_rate >= 50 else "yellow" if pass_rate >= 25 else "red"
518
+ text.append(f"{pass_rate:.0f}%\n", style=pass_color)
519
+
520
+ text.append(f" Trend: ", style="dim")
521
+ if trend == "improving":
522
+ text.append("↑ improving\n", style="green")
523
+ elif trend == "degrading":
524
+ text.append("↓ degrading\n", style="red")
525
+ else:
526
+ text.append("→ stable\n", style="dim")
527
+
528
+ text.append("\n")
529
+
481
530
  # Summary
482
531
  text.append("─" * 36 + "\n", style="dim")
483
532
  ready_count = sum(1 for r in self.quality_results.values() if r.get("ready_to_merge"))
@@ -2377,6 +2426,7 @@ class AnvilHUD(App):
2377
2426
  self.coordination_service: Optional["CoordinationService"] = None
2378
2427
  self.github_service: Optional["GitHubService"] = None # ANV-111-113
2379
2428
  self.coderabbit_service: Optional["CodeRabbitService"] = None # ANV-114-115
2429
+ self.coderabbit_metrics: Optional["CodeRabbitMetrics"] = None # ANV-277: Weekly metrics
2380
2430
  self.issue_provider = None # ANV-76: Issue provider for Kanban
2381
2431
  self.refresh_timer: Optional[Timer] = None
2382
2432
 
@@ -2393,6 +2443,12 @@ class AnvilHUD(App):
2393
2443
  if not self.demo_mode and CodeRabbitService:
2394
2444
  if not self.config or self.config.integrations.enable_coderabbit:
2395
2445
  self.coderabbit_service = CodeRabbitService()
2446
+ # ANV-277: Initialize CodeRabbit metrics for weekly stats
2447
+ if not self.demo_mode and CodeRabbitMetrics:
2448
+ try:
2449
+ self.coderabbit_metrics = CodeRabbitMetrics()
2450
+ except Exception:
2451
+ self.coderabbit_metrics = None
2396
2452
  # ANV-76: Initialize issue provider
2397
2453
  if not self.demo_mode and get_provider:
2398
2454
  try:
@@ -2731,6 +2787,24 @@ class AnvilHUD(App):
2731
2787
  quality_panel.github_status
2732
2788
  )
2733
2789
 
2790
+ # ANV-277: Update CodeRabbit weekly metrics
2791
+ if self.demo_mode:
2792
+ quality_panel.weekly_metrics = self._get_demo_weekly_metrics()
2793
+ elif self.coderabbit_metrics:
2794
+ try:
2795
+ summary = self.coderabbit_metrics.get_weekly_summary()
2796
+ if summary:
2797
+ quality_panel.weekly_metrics = {
2798
+ "total_reviews": summary.total_reviews,
2799
+ "total_issues_found": summary.total_issues_found,
2800
+ "total_issues_fixed": summary.total_issues_fixed,
2801
+ "avg_issues_per_review": summary.avg_issues_per_review,
2802
+ "pass_rate": summary.pass_rate,
2803
+ "trend": summary.trend,
2804
+ }
2805
+ except Exception:
2806
+ pass # Keep previous metrics on error
2807
+
2734
2808
  # Update coordination panel (ANV-106-110)
2735
2809
  coordination_panel = self.query_one("#coordination-panel", CoordinationPanel)
2736
2810
  coordination_panel.agents = agents
@@ -3422,6 +3496,17 @@ class AnvilHUD(App):
3422
3496
  },
3423
3497
  }
3424
3498
 
3499
+ def _get_demo_weekly_metrics(self) -> Dict[str, Any]:
3500
+ """Generate demo CodeRabbit weekly metrics for testing (ANV-277)."""
3501
+ return {
3502
+ "total_reviews": 12,
3503
+ "total_issues_found": 28,
3504
+ "total_issues_fixed": 24,
3505
+ "avg_issues_per_review": 2.3,
3506
+ "pass_rate": 42.0,
3507
+ "trend": "improving",
3508
+ }
3509
+
3425
3510
  def _get_demo_agents(self) -> Dict[str, Any]:
3426
3511
  """Generate demo agent data for testing."""
3427
3512
  now = datetime.now(timezone.utc).isoformat()