devloop 0.4.1__tar.gz → 0.5.0__tar.gz

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 (117) hide show
  1. {devloop-0.4.1 → devloop-0.5.0}/PKG-INFO +61 -5
  2. {devloop-0.4.1 → devloop-0.5.0}/README.md +58 -4
  3. {devloop-0.4.1 → devloop-0.5.0}/pyproject.toml +10 -2
  4. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/ci_monitor.py +71 -97
  5. devloop-0.5.0/src/devloop/cli/commands/release.py +213 -0
  6. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/main.py +214 -30
  7. devloop-0.5.0/src/devloop/cli/pre_push_check.py +66 -0
  8. devloop-0.5.0/src/devloop/cli/templates/devloop_agents_template.md +317 -0
  9. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/templates/git_hooks/pre-push +34 -11
  10. devloop-0.5.0/src/devloop/cli/templates/supervisor/devloop.conf +25 -0
  11. devloop-0.5.0/src/devloop/cli/templates/systemd/devloop.service +35 -0
  12. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/collectors/filesystem.py +44 -1
  13. devloop-0.5.0/src/devloop/core/__init__.py +90 -0
  14. devloop-0.5.0/src/devloop/core/action_logger.py +265 -0
  15. devloop-0.5.0/src/devloop/core/amp_thread_mapper.py +589 -0
  16. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/config.py +82 -7
  17. devloop-0.5.0/src/devloop/core/config_schema.py +400 -0
  18. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/context_store.py +41 -3
  19. devloop-0.5.0/src/devloop/core/daemon_health.py +159 -0
  20. devloop-0.5.0/src/devloop/core/pattern_analyzer.py +411 -0
  21. devloop-0.5.0/src/devloop/core/pattern_detector.py +285 -0
  22. devloop-0.5.0/src/devloop/core/transactional_io.py +486 -0
  23. devloop-0.5.0/src/devloop/integrations/__init__.py +16 -0
  24. devloop-0.5.0/src/devloop/integrations/beads_integration.py +324 -0
  25. devloop-0.5.0/src/devloop/lsp/__init__.py +5 -0
  26. devloop-0.5.0/src/devloop/lsp/__main__.py +6 -0
  27. devloop-0.5.0/src/devloop/lsp/mapper.py +130 -0
  28. devloop-0.5.0/src/devloop/lsp/server.py +366 -0
  29. devloop-0.5.0/src/devloop/providers/__init__.py +37 -0
  30. devloop-0.5.0/src/devloop/providers/ci_provider.py +158 -0
  31. devloop-0.5.0/src/devloop/providers/circleci_provider.py +330 -0
  32. devloop-0.5.0/src/devloop/providers/github_actions_provider.py +232 -0
  33. devloop-0.5.0/src/devloop/providers/gitlab_ci_provider.py +248 -0
  34. devloop-0.5.0/src/devloop/providers/jenkins_provider.py +288 -0
  35. devloop-0.5.0/src/devloop/providers/provider_manager.py +190 -0
  36. devloop-0.5.0/src/devloop/providers/pypi_registry.py +192 -0
  37. devloop-0.5.0/src/devloop/providers/registry_provider.py +117 -0
  38. devloop-0.5.0/src/devloop/release/__init__.py +5 -0
  39. devloop-0.5.0/src/devloop/release/release_manager.py +454 -0
  40. devloop-0.5.0/src/devloop/security/__init__.py +49 -0
  41. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/security/bubblewrap_sandbox.py +24 -2
  42. devloop-0.5.0/src/devloop/security/path_validator.py +352 -0
  43. devloop-0.5.0/src/devloop/security/token_manager.py +419 -0
  44. devloop-0.4.1/src/devloop/core/__init__.py +0 -21
  45. devloop-0.4.1/src/devloop/security/__init__.py +0 -15
  46. {devloop-0.4.1 → devloop-0.5.0}/LICENSE +0 -0
  47. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/__init__.py +0 -0
  48. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/__init__.py +0 -0
  49. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/agent_health_monitor.py +0 -0
  50. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/code_rabbit.py +0 -0
  51. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/doc_lifecycle.py +0 -0
  52. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/echo.py +0 -0
  53. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/file_logger.py +0 -0
  54. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/formatter.py +0 -0
  55. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/git_commit_assistant.py +0 -0
  56. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/linter.py +0 -0
  57. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/performance_profiler.py +0 -0
  58. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/sandbox_helper.py +0 -0
  59. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/security_scanner.py +0 -0
  60. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/snyk.py +0 -0
  61. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/test_runner.py +0 -0
  62. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/agents/type_checker.py +0 -0
  63. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/__init__.py +0 -0
  64. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/commands/__init__.py +0 -0
  65. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/commands/audit.py +0 -0
  66. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/commands/custom_agents.py +0 -0
  67. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/commands/feedback.py +0 -0
  68. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/commands/summary.py +0 -0
  69. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/commands/telemetry.py +0 -0
  70. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/main_v1.py +0 -0
  71. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/prerequisites.py +0 -0
  72. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/pyodide_installer.py +0 -0
  73. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/templates/claude_commands/README.md +0 -0
  74. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/templates/claude_commands/agent-summary.md +0 -0
  75. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/templates/claude_commands/devloop-findings.md +0 -0
  76. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/templates/claude_commands/devloop-status.md +0 -0
  77. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/templates/claude_commands/extract-findings.md +0 -0
  78. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/templates/claude_commands/verify-work.md +0 -0
  79. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/templates/git_hooks/pre-commit +0 -0
  80. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/cli/templates/git_hooks/pre-commit-checks +0 -0
  81. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/collectors/__init__.py +0 -0
  82. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/collectors/base.py +0 -0
  83. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/collectors/git.py +0 -0
  84. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/collectors/manager.py +0 -0
  85. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/collectors/process.py +0 -0
  86. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/collectors/system.py +0 -0
  87. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/agent.py +0 -0
  88. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/agent_audit_logger.py +0 -0
  89. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/agent_template.py +0 -0
  90. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/amp_integration.py +0 -0
  91. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/auto_fix.py +0 -0
  92. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/backup_manager.py +0 -0
  93. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/claude_adapter.py +0 -0
  94. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/context.py +0 -0
  95. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/contextual_feedback.py +0 -0
  96. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/custom_agent.py +0 -0
  97. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/debug_trace.py +0 -0
  98. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/event.py +0 -0
  99. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/event_store.py +0 -0
  100. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/feedback.py +0 -0
  101. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/file_lock_manager.py +0 -0
  102. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/learning.py +0 -0
  103. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/manager.py +0 -0
  104. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/operational_health.py +0 -0
  105. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/performance.py +0 -0
  106. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/proactive_feedback.py +0 -0
  107. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/summary_formatter.py +0 -0
  108. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/summary_generator.py +0 -0
  109. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/core/telemetry.py +0 -0
  110. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/security/audit_logger.py +0 -0
  111. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/security/cgroups_helper.py +0 -0
  112. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/security/factory.py +0 -0
  113. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/security/no_sandbox.py +0 -0
  114. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/security/package.json +0 -0
  115. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/security/pyodide_runner.js +0 -0
  116. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/security/pyodide_sandbox.py +0 -0
  117. {devloop-0.4.1 → devloop-0.5.0}/src/devloop/security/sandbox.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devloop
3
- Version: 0.4.1
3
+ Version: 0.5.0
4
4
  Summary: Intelligent background agents for development workflow automation
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -26,8 +26,10 @@ Provides-Extra: ci-monitor
26
26
  Provides-Extra: code-rabbit
27
27
  Provides-Extra: snyk
28
28
  Requires-Dist: aiofiles (>=23.2,<24.0)
29
+ Requires-Dist: lsprotocol (>=2023.0.0,<2024.0.0)
29
30
  Requires-Dist: psutil (>=5.9,<6.0)
30
31
  Requires-Dist: pydantic (>=2.5,<3.0)
32
+ Requires-Dist: pygls (>=1.3.0,<2.0.0)
31
33
  Requires-Dist: rich (>=13.7,<14.0)
32
34
  Requires-Dist: typer (>=0.15,<1.0)
33
35
  Requires-Dist: watchdog (>=3.0,<4.0)
@@ -214,7 +216,9 @@ All agents run **non-intrusively in the background**, respecting your workflow.
214
216
 
215
217
  ### Installation
216
218
 
217
- **Prerequisites:** Python 3.11+
219
+ **Prerequisites:**
220
+ - Python 3.11 or later
221
+ - For release workflow: Poetry 1.7+ and GitHub CLI 2.78+
218
222
 
219
223
  #### Option 1: From PyPI (Recommended)
220
224
 
@@ -250,13 +254,27 @@ DevLoop automatically detects and uses several system tools. Install them for fu
250
254
 
251
255
  **For Pre-Push CI Verification (Optional but Recommended):**
252
256
  ```bash
253
- # GitHub CLI (for checking CI status before push)
257
+ # GitHub CLI 2.78+ (for checking CI status before push)
254
258
  # Ubuntu/Debian:
255
259
  sudo apt-get install -y gh
256
260
 
257
261
  # macOS:
258
262
  brew install gh
259
263
 
264
+ # Verify installation
265
+ gh --version
266
+ ```
267
+
268
+ **For Release Management (Optional but Recommended for Publishing):**
269
+ ```bash
270
+ # Poetry 1.7+ (for package management and publishing)
271
+ curl -sSL https://install.python-poetry.org | python3 -
272
+
273
+ # Verify installation
274
+ poetry --version
275
+
276
+ # Configure PyPI credentials (get token from https://pypi.org/account/)
277
+ poetry config pypi-token.pypi "pypi-AgEIcHlwaS5vcmc..."
260
278
  ```
261
279
 
262
280
  **For Task Management Integration (Optional):**
@@ -266,8 +284,9 @@ pip install beads-mcp
266
284
  ```
267
285
 
268
286
  **What happens if missing:**
269
- - `gh`: Pre-push CI verification is skipped (but DevLoop still works)
270
- - `bd`: Pre-push hook won't create task queue issues (but DevLoop still works)
287
+ - `gh` (2.78+): Pre-push CI verification is skipped (but DevLoop still works)
288
+ - `poetry` (1.7+): Release workflow unavailable (but development still works)
289
+ - `bd`: Task creation on push won't work (but DevLoop still works)
271
290
 
272
291
  DevLoop will warn you during `devloop init` if any tools are missing and provide installation instructions. You can install them later and they'll be detected automatically.
273
292
 
@@ -343,6 +362,43 @@ devloop custom-create my_agent pattern_matcher
343
362
 
344
363
  [View all CLI commands →](./docs/cli-commands.md)
345
364
 
365
+ ### Verify Installation & Version Compatibility
366
+
367
+ After installation, verify everything is working:
368
+
369
+ ```bash
370
+ # Check DevLoop version
371
+ devloop --version
372
+
373
+ # Verify system dependencies are detected
374
+ devloop init --check-requirements
375
+
376
+ # Check daemon status (if running)
377
+ devloop status
378
+
379
+ # Verify git hooks are installed (in your project)
380
+ cat .git/hooks/pre-commit # Should exist
381
+ cat .git/hooks/pre-push # Should exist
382
+ ```
383
+
384
+ **Version compatibility:**
385
+ - DevLoop 0.4.1+ requires Python 3.11+
386
+ - Release workflow requires Poetry 1.7+ and GitHub CLI 2.78+
387
+ - AGENTS.md template was updated in DevLoop 0.4.0+
388
+
389
+ **If you're upgrading DevLoop:**
390
+ ```bash
391
+ # Upgrade to latest
392
+ pip install --upgrade devloop
393
+
394
+ # Update your project's AGENTS.md (templates may have changed)
395
+ devloop init --merge-templates /path/to/your/project
396
+
397
+ # Restart the daemon
398
+ devloop stop
399
+ devloop watch .
400
+ ```
401
+
346
402
  ---
347
403
 
348
404
  ## Architecture
@@ -176,7 +176,9 @@ All agents run **non-intrusively in the background**, respecting your workflow.
176
176
 
177
177
  ### Installation
178
178
 
179
- **Prerequisites:** Python 3.11+
179
+ **Prerequisites:**
180
+ - Python 3.11 or later
181
+ - For release workflow: Poetry 1.7+ and GitHub CLI 2.78+
180
182
 
181
183
  #### Option 1: From PyPI (Recommended)
182
184
 
@@ -212,13 +214,27 @@ DevLoop automatically detects and uses several system tools. Install them for fu
212
214
 
213
215
  **For Pre-Push CI Verification (Optional but Recommended):**
214
216
  ```bash
215
- # GitHub CLI (for checking CI status before push)
217
+ # GitHub CLI 2.78+ (for checking CI status before push)
216
218
  # Ubuntu/Debian:
217
219
  sudo apt-get install -y gh
218
220
 
219
221
  # macOS:
220
222
  brew install gh
221
223
 
224
+ # Verify installation
225
+ gh --version
226
+ ```
227
+
228
+ **For Release Management (Optional but Recommended for Publishing):**
229
+ ```bash
230
+ # Poetry 1.7+ (for package management and publishing)
231
+ curl -sSL https://install.python-poetry.org | python3 -
232
+
233
+ # Verify installation
234
+ poetry --version
235
+
236
+ # Configure PyPI credentials (get token from https://pypi.org/account/)
237
+ poetry config pypi-token.pypi "pypi-AgEIcHlwaS5vcmc..."
222
238
  ```
223
239
 
224
240
  **For Task Management Integration (Optional):**
@@ -228,8 +244,9 @@ pip install beads-mcp
228
244
  ```
229
245
 
230
246
  **What happens if missing:**
231
- - `gh`: Pre-push CI verification is skipped (but DevLoop still works)
232
- - `bd`: Pre-push hook won't create task queue issues (but DevLoop still works)
247
+ - `gh` (2.78+): Pre-push CI verification is skipped (but DevLoop still works)
248
+ - `poetry` (1.7+): Release workflow unavailable (but development still works)
249
+ - `bd`: Task creation on push won't work (but DevLoop still works)
233
250
 
234
251
  DevLoop will warn you during `devloop init` if any tools are missing and provide installation instructions. You can install them later and they'll be detected automatically.
235
252
 
@@ -305,6 +322,43 @@ devloop custom-create my_agent pattern_matcher
305
322
 
306
323
  [View all CLI commands →](./docs/cli-commands.md)
307
324
 
325
+ ### Verify Installation & Version Compatibility
326
+
327
+ After installation, verify everything is working:
328
+
329
+ ```bash
330
+ # Check DevLoop version
331
+ devloop --version
332
+
333
+ # Verify system dependencies are detected
334
+ devloop init --check-requirements
335
+
336
+ # Check daemon status (if running)
337
+ devloop status
338
+
339
+ # Verify git hooks are installed (in your project)
340
+ cat .git/hooks/pre-commit # Should exist
341
+ cat .git/hooks/pre-push # Should exist
342
+ ```
343
+
344
+ **Version compatibility:**
345
+ - DevLoop 0.4.1+ requires Python 3.11+
346
+ - Release workflow requires Poetry 1.7+ and GitHub CLI 2.78+
347
+ - AGENTS.md template was updated in DevLoop 0.4.0+
348
+
349
+ **If you're upgrading DevLoop:**
350
+ ```bash
351
+ # Upgrade to latest
352
+ pip install --upgrade devloop
353
+
354
+ # Update your project's AGENTS.md (templates may have changed)
355
+ devloop init --merge-templates /path/to/your/project
356
+
357
+ # Restart the daemon
358
+ devloop stop
359
+ devloop watch .
360
+ ```
361
+
308
362
  ---
309
363
 
310
364
  ## Architecture
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "devloop"
3
- version = "0.4.1"
3
+ version = "0.5.0"
4
4
  description = "Intelligent background agents for development workflow automation"
5
5
  authors = ["DevLoop Contributors <devloop@example.com>"]
6
6
  license = "MIT"
@@ -47,6 +47,8 @@ typer = ">=0.15,<1.0"
47
47
  rich = "^13.7"
48
48
  aiofiles = "^23.2"
49
49
  psutil = "^5.9"
50
+ pygls = "^1.3.0"
51
+ lsprotocol = "^2023.0.0"
50
52
 
51
53
  [tool.poetry.group.dev.dependencies]
52
54
  pytest = "^7.4"
@@ -77,12 +79,18 @@ target-version = ['py311']
77
79
 
78
80
  [tool.ruff]
79
81
  line-length = 88
80
- target-version = "0.4.1"
82
+ target-version = "py311"
81
83
 
82
84
  [tool.pytest.ini_options]
83
85
  asyncio_mode = "auto"
84
86
  testpaths = ["tests"]
85
87
  pythonpath = ["src"]
88
+ markers = [
89
+ "integration: marks tests as integration tests",
90
+ "performance: marks tests as performance benchmarks",
91
+ "security: marks tests as security tests",
92
+ "benchmark: marks tests as benchmarks",
93
+ ]
86
94
 
87
95
  [tool.mypy]
88
96
  python_version = "0.4.1"
@@ -1,6 +1,5 @@
1
- """CI Monitor Agent - Monitors GitHub Actions CI status."""
1
+ """CI Monitor Agent - Monitors CI system status (platform-agnostic)."""
2
2
 
3
- import json
4
3
  import subprocess
5
4
  from datetime import datetime, timedelta
6
5
  from typing import Any, Dict, List, Optional
@@ -8,10 +7,12 @@ from typing import Any, Dict, List, Optional
8
7
  from devloop.core.agent import Agent, AgentResult
9
8
  from devloop.core.context_store import Finding, Severity
10
9
  from devloop.core.event import Event
10
+ from devloop.providers.ci_provider import CIProvider, RunConclusion, RunStatus
11
+ from devloop.providers.provider_manager import get_provider_manager
11
12
 
12
13
 
13
14
  class CIMonitorAgent(Agent):
14
- """Monitors GitHub Actions CI status and reports failures."""
15
+ """Monitors CI status and reports failures (provider-agnostic)."""
15
16
 
16
17
  def __init__(
17
18
  self,
@@ -19,7 +20,9 @@ class CIMonitorAgent(Agent):
19
20
  triggers: List[str],
20
21
  event_bus: Any,
21
22
  check_interval: int = 300,
22
- ): # 5 minutes default
23
+ ci_provider: Optional[CIProvider] = None,
24
+ provider_name: str = "github",
25
+ ):
23
26
  """
24
27
  Initialize CI monitor agent.
25
28
 
@@ -28,14 +31,36 @@ class CIMonitorAgent(Agent):
28
31
  triggers: Event triggers for this agent
29
32
  event_bus: Event bus for publishing events
30
33
  check_interval: How often to check CI status (in seconds)
34
+ ci_provider: Optional pre-configured CIProvider. If not provided, auto-detects.
35
+ provider_name: CI provider name (e.g., "github", "gitlab") if ci_provider not provided
31
36
  """
32
37
  super().__init__(name, triggers, event_bus)
33
38
  self.check_interval = check_interval
34
39
  self.last_check: Optional[datetime] = None
35
40
  self.last_status: Optional[dict] = None
36
41
 
42
+ # Use provided provider or auto-detect
43
+ if ci_provider:
44
+ self.provider: Optional[CIProvider] = ci_provider
45
+ else:
46
+ manager = get_provider_manager()
47
+ provider = manager.get_ci_provider(provider_name)
48
+ if provider:
49
+ self.provider = provider
50
+ else:
51
+ # Fall back to auto-detection
52
+ self.provider = manager.auto_detect_ci_provider()
53
+
37
54
  async def handle(self, event: Event) -> AgentResult:
38
55
  """Handle events and check CI status."""
56
+ if not self.provider:
57
+ return AgentResult(
58
+ agent_name=self.name,
59
+ success=False,
60
+ duration=0,
61
+ error="No CI provider available",
62
+ )
63
+
39
64
  # Check if it's time for periodic check
40
65
  should_check = False
41
66
 
@@ -55,11 +80,29 @@ class CIMonitorAgent(Agent):
55
80
 
56
81
  # Check CI status
57
82
  try:
58
- status = await self._check_ci_status()
83
+ branch = self._get_current_branch()
84
+ if not branch:
85
+ return AgentResult(
86
+ agent_name=self.name,
87
+ success=False,
88
+ duration=0,
89
+ error="Could not determine current branch",
90
+ )
91
+
92
+ # Check if provider is available
93
+ if not self.provider.is_available():
94
+ return AgentResult(
95
+ agent_name=self.name,
96
+ success=True,
97
+ duration=0,
98
+ message=f"CI provider '{self.provider.get_provider_name()}' not available",
99
+ )
100
+
101
+ # Get latest runs
102
+ runs = self.provider.list_runs(branch, limit=5)
59
103
  self.last_check = datetime.now()
60
- self.last_status = status
61
104
 
62
- if not status:
105
+ if not runs:
63
106
  return AgentResult(
64
107
  agent_name=self.name,
65
108
  success=True,
@@ -68,7 +111,7 @@ class CIMonitorAgent(Agent):
68
111
  )
69
112
 
70
113
  # Analyze status and create findings
71
- findings = self._analyze_ci_status(status)
114
+ findings = self._analyze_runs(runs)
72
115
 
73
116
  if findings:
74
117
  return AgentResult(
@@ -102,40 +145,8 @@ class CIMonitorAgent(Agent):
102
145
  time_since_check = datetime.now() - self.last_check
103
146
  return time_since_check > timedelta(seconds=self.check_interval)
104
147
 
105
- async def _check_ci_status(self) -> Optional[dict]:
106
- """
107
- Check CI status using gh CLI.
108
-
109
- Returns:
110
- CI status dict or None if unavailable
111
- """
112
- # Check if gh CLI is available
113
- try:
114
- result = subprocess.run(
115
- ["gh", "--version"],
116
- capture_output=True,
117
- text=True,
118
- timeout=5,
119
- )
120
- if result.returncode != 0:
121
- return None
122
- except (FileNotFoundError, subprocess.TimeoutExpired):
123
- return None
124
-
125
- # Check if authenticated
126
- try:
127
- result = subprocess.run(
128
- ["gh", "auth", "status"],
129
- capture_output=True,
130
- text=True,
131
- timeout=5,
132
- )
133
- if result.returncode != 0:
134
- return None
135
- except subprocess.TimeoutExpired:
136
- return None
137
-
138
- # Get current branch
148
+ def _get_current_branch(self) -> Optional[str]:
149
+ """Get the current git branch."""
139
150
  try:
140
151
  result = subprocess.run(
141
152
  ["git", "rev-parse", "--abbrev-ref", "HEAD"],
@@ -144,92 +155,55 @@ class CIMonitorAgent(Agent):
144
155
  check=True,
145
156
  timeout=5,
146
157
  )
147
- branch = result.stdout.strip()
158
+ return result.stdout.strip()
148
159
  except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
149
160
  return None
150
161
 
151
- # Get latest workflow runs
152
- try:
153
- result = subprocess.run(
154
- [
155
- "gh",
156
- "run",
157
- "list",
158
- "--branch",
159
- branch,
160
- "--limit",
161
- "5",
162
- "--json",
163
- "status,conclusion,name,databaseId,createdAt,workflowName",
164
- ],
165
- capture_output=True,
166
- text=True,
167
- check=True,
168
- timeout=10,
169
- )
170
-
171
- if result.stdout.strip():
172
- runs = json.loads(result.stdout)
173
- return {
174
- "branch": branch,
175
- "runs": runs,
176
- "checked_at": datetime.now().isoformat(),
177
- }
178
- except (
179
- subprocess.CalledProcessError,
180
- subprocess.TimeoutExpired,
181
- json.JSONDecodeError,
182
- ):
183
- return None
184
-
185
- return None
162
+ def _analyze_runs(self, runs: List) -> list[Finding]:
163
+ """Analyze CI runs and create findings for issues."""
164
+ findings: list[Finding] = []
186
165
 
187
- def _analyze_ci_status(self, status: dict) -> list[Finding]:
188
- """Analyze CI status and create findings for issues."""
189
- findings = []
190
- runs = status.get("runs", [])
191
- branch = status.get("branch", "unknown")
166
+ # Ensure provider is available for messages
167
+ if not self.provider:
168
+ return findings
192
169
 
193
- # Group runs by workflow
170
+ # Group runs by workflow name
194
171
  workflows: Dict[str, list] = {}
195
172
  for run in runs:
196
- workflow_name = run.get("workflowName", run.get("name", "Unknown"))
173
+ workflow_name = run.name
197
174
  if workflow_name not in workflows:
198
175
  workflows[workflow_name] = []
199
176
  workflows[workflow_name].append(run)
200
177
 
201
178
  # Check each workflow's latest run
202
179
  for workflow_name, workflow_runs in workflows.items():
203
- latest_run = workflow_runs[0] # Already sorted by createdAt descending
204
- conclusion = latest_run.get("conclusion")
205
- status_val = latest_run.get("status")
206
- run_id = latest_run.get("databaseId", "unknown")
180
+ latest_run = workflow_runs[0]
207
181
 
208
- if conclusion == "failure":
182
+ if latest_run.conclusion == RunConclusion.FAILURE:
209
183
  findings.append(
210
184
  Finding(
211
- id=f"ci-{run_id}",
185
+ id=f"ci-{latest_run.id}",
212
186
  agent="ci-monitor",
213
187
  timestamp=datetime.now().isoformat(),
214
188
  file=".github/workflows/ci.yml",
215
189
  category="ci",
216
190
  severity=Severity.ERROR,
217
- message=f"CI workflow '{workflow_name}' failed on branch '{branch}' (Run #{run_id})",
218
- suggestion=f"View details: gh run view {run_id}\nRerun: gh run rerun {run_id}",
191
+ message=f"CI workflow '{workflow_name}' failed on branch '{latest_run.branch}' (Run #{latest_run.id})",
192
+ suggestion=f"View details: {latest_run.url}\nProvider: {self.provider.get_provider_name()}",
219
193
  auto_fixable=False,
220
194
  )
221
195
  )
222
- elif status_val == "in_progress":
196
+ elif latest_run.status == RunStatus.IN_PROGRESS:
223
197
  findings.append(
224
198
  Finding(
225
- id=f"ci-{run_id}",
199
+ id=f"ci-{latest_run.id}",
226
200
  agent="ci-monitor",
227
201
  timestamp=datetime.now().isoformat(),
228
202
  file=".github/workflows/ci.yml",
229
203
  category="ci",
230
204
  severity=Severity.INFO,
231
- message=f"CI workflow '{workflow_name}' is running on branch '{branch}' (Run #{run_id})",
232
- suggestion=f"Watch progress: gh run watch {run_id}",
205
+ message=f"CI workflow '{workflow_name}' is running on branch '{latest_run.branch}' (Run #{latest_run.id})",
206
+ suggestion=f"Watch progress at: {latest_run.url}",
233
207
  auto_fixable=False,
234
208
  )
235
209
  )