devloop 0.2.1__tar.gz → 0.2.2__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.
- {devloop-0.2.1 → devloop-0.2.2}/PKG-INFO +57 -10
- {devloop-0.2.1 → devloop-0.2.2}/README.md +56 -9
- {devloop-0.2.1 → devloop-0.2.2}/pyproject.toml +1 -1
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/__init__.py +1 -1
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/cli/main.py +84 -9
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/context_store.py +42 -0
- {devloop-0.2.1 → devloop-0.2.2}/LICENSE +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/__init__.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/agent_health_monitor.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/ci_monitor.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/code_rabbit.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/doc_lifecycle.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/echo.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/file_logger.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/formatter.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/git_commit_assistant.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/linter.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/performance_profiler.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/security_scanner.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/snyk.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/test_runner.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/agents/type_checker.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/cli/__init__.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/cli/commands/__init__.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/cli/commands/custom_agents.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/cli/commands/feedback.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/cli/commands/summary.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/cli/main_v1.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/collectors/__init__.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/collectors/base.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/collectors/filesystem.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/collectors/git.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/collectors/manager.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/collectors/process.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/collectors/system.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/__init__.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/agent.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/agent_template.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/amp_integration.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/auto_fix.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/config.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/context.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/contextual_feedback.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/custom_agent.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/debug_trace.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/event.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/event_store.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/feedback.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/learning.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/manager.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/performance.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/proactive_feedback.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/summary_formatter.py +0 -0
- {devloop-0.2.1 → devloop-0.2.2}/src/devloop/core/summary_generator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devloop
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Intelligent background agents for development workflow automation
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -38,12 +38,32 @@ Description-Content-Type: text/markdown
|
|
|
38
38
|
|
|
39
39
|
[](https://www.python.org/downloads/)
|
|
40
40
|
[](#testing)
|
|
41
|
-
[](#status)
|
|
42
42
|
[](LICENSE)
|
|
43
43
|
|
|
44
|
+
## ⚠️ ALPHA SOFTWARE - NOT FOR PRODUCTION
|
|
45
|
+
|
|
46
|
+
**DevLoop is currently in active development and is not recommended for production use.**
|
|
47
|
+
|
|
48
|
+
This is **research-quality software**. Use at your own risk. See [Known Limitations & Risks](./history/RISK_ASSESSMENT.md) for details on:
|
|
49
|
+
|
|
50
|
+
- ✗ Subprocess execution not sandboxed (security risk)
|
|
51
|
+
- ✗ Auto-fix may corrupt code (enable only if willing to review changes)
|
|
52
|
+
- ✗ Race conditions possible in file operations (concurrent agent modifications)
|
|
53
|
+
- ✗ Limited error recovery (daemon may not restart automatically)
|
|
54
|
+
- ✗ Configuration migrations not yet supported
|
|
55
|
+
- ✗ No process supervision (manual daemon management)
|
|
56
|
+
|
|
57
|
+
**Suitable for:** Development on side projects, testing automation, research
|
|
58
|
+
**Not suitable for:** Critical code, production systems, untrusted projects
|
|
59
|
+
|
|
60
|
+
[View complete risk assessment →](./history/RISK_ASSESSMENT.md)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
44
64
|
## Status
|
|
45
65
|
|
|
46
|
-
|
|
66
|
+
🔬 **ALPHA** — Full-featured development automation system in active development. [View detailed implementation status →](./IMPLEMENTATION_STATUS.md)
|
|
47
67
|
|
|
48
68
|
---
|
|
49
69
|
|
|
@@ -68,6 +88,15 @@ All agents run **non-intrusively in the background**, respecting your workflow.
|
|
|
68
88
|
|
|
69
89
|
## Quick Start
|
|
70
90
|
|
|
91
|
+
### ⚠️ Before You Start
|
|
92
|
+
|
|
93
|
+
**ALPHA SOFTWARE DISCLAIMER:**
|
|
94
|
+
- This is research-quality code. Data loss is possible.
|
|
95
|
+
- Only use on projects you can afford to lose or easily recover.
|
|
96
|
+
- Make sure to commit your code to git before enabling DevLoop.
|
|
97
|
+
- Do not enable auto-fix on important code.
|
|
98
|
+
- Some agents may fail silently (see logs for details).
|
|
99
|
+
|
|
71
100
|
### Installation
|
|
72
101
|
|
|
73
102
|
**Prerequisites:** Python 3.11+
|
|
@@ -324,7 +353,7 @@ Configure agent behavior in `.devloop/agents.json`:
|
|
|
324
353
|
{
|
|
325
354
|
"global": {
|
|
326
355
|
"autonomousFixes": {
|
|
327
|
-
"enabled":
|
|
356
|
+
"enabled": false,
|
|
328
357
|
"safetyLevel": "safe_only"
|
|
329
358
|
},
|
|
330
359
|
"maxConcurrentAgents": 5,
|
|
@@ -346,11 +375,13 @@ Configure agent behavior in `.devloop/agents.json`:
|
|
|
346
375
|
}
|
|
347
376
|
```
|
|
348
377
|
|
|
349
|
-
**Safety levels:**
|
|
350
|
-
- `safe_only` — Only fix whitespace/indentation
|
|
378
|
+
**Safety levels (Auto-fix):**
|
|
379
|
+
- `safe_only` — Only fix whitespace/indentation (default, recommended)
|
|
351
380
|
- `medium_risk` — Include import/formatting fixes
|
|
352
381
|
- `all` — Apply all fixes (use with caution)
|
|
353
382
|
|
|
383
|
+
⚠️ **Auto-fix Warning:** Currently auto-fixes run without backups or review. **DO NOT enable auto-fix in production** or on critical code. Track [secure auto-fix with backups issue](https://github.com/wioota/devloop/issues/emc).
|
|
384
|
+
|
|
354
385
|
[Full configuration reference →](./docs/configuration.md)
|
|
355
386
|
|
|
356
387
|
---
|
|
@@ -560,17 +591,26 @@ DevLoop follows these core principles:
|
|
|
560
591
|
|
|
561
592
|
## Troubleshooting
|
|
562
593
|
|
|
594
|
+
### ⚠️ If Something Goes Wrong
|
|
595
|
+
|
|
596
|
+
**Recovery steps:**
|
|
597
|
+
1. Stop the daemon: `devloop stop .`
|
|
598
|
+
2. Check the logs: `tail -100 .devloop/devloop.log`
|
|
599
|
+
3. Verify your code in git: `git status`
|
|
600
|
+
4. Recover from git if files were modified: `git checkout <file>`
|
|
601
|
+
5. Report the issue: [GitHub Issues](https://github.com/wioota/devloop/issues)
|
|
602
|
+
|
|
563
603
|
### Agents not running
|
|
564
604
|
|
|
565
605
|
```bash
|
|
566
606
|
# Check status
|
|
567
607
|
devloop status
|
|
568
608
|
|
|
569
|
-
# View logs
|
|
570
|
-
tail -f .devloop/
|
|
609
|
+
# View logs (useful for debugging)
|
|
610
|
+
tail -f .devloop/devloop.log
|
|
571
611
|
|
|
572
|
-
# Enable verbose mode
|
|
573
|
-
devloop watch . --verbose
|
|
612
|
+
# Enable verbose mode for more details
|
|
613
|
+
devloop watch . --foreground --verbose
|
|
574
614
|
```
|
|
575
615
|
|
|
576
616
|
### Performance issues
|
|
@@ -599,6 +639,13 @@ devloop custom-list
|
|
|
599
639
|
ls -la .devloop/custom_agents/
|
|
600
640
|
```
|
|
601
641
|
|
|
642
|
+
### Agent modified my files unexpectedly
|
|
643
|
+
|
|
644
|
+
1. Check git diff: `git diff`
|
|
645
|
+
2. Revert changes: `git checkout -- .`
|
|
646
|
+
3. Disable the problematic agent in `.devloop/agents.json`
|
|
647
|
+
4. Report issue with: `git show HEAD:.devloop/agents.json`
|
|
648
|
+
|
|
602
649
|
[Full troubleshooting guide →](./docs/troubleshooting.md)
|
|
603
650
|
|
|
604
651
|
---
|
|
@@ -4,12 +4,32 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.python.org/downloads/)
|
|
6
6
|
[](#testing)
|
|
7
|
-
[](#status)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
|
|
10
|
+
## ⚠️ ALPHA SOFTWARE - NOT FOR PRODUCTION
|
|
11
|
+
|
|
12
|
+
**DevLoop is currently in active development and is not recommended for production use.**
|
|
13
|
+
|
|
14
|
+
This is **research-quality software**. Use at your own risk. See [Known Limitations & Risks](./history/RISK_ASSESSMENT.md) for details on:
|
|
15
|
+
|
|
16
|
+
- ✗ Subprocess execution not sandboxed (security risk)
|
|
17
|
+
- ✗ Auto-fix may corrupt code (enable only if willing to review changes)
|
|
18
|
+
- ✗ Race conditions possible in file operations (concurrent agent modifications)
|
|
19
|
+
- ✗ Limited error recovery (daemon may not restart automatically)
|
|
20
|
+
- ✗ Configuration migrations not yet supported
|
|
21
|
+
- ✗ No process supervision (manual daemon management)
|
|
22
|
+
|
|
23
|
+
**Suitable for:** Development on side projects, testing automation, research
|
|
24
|
+
**Not suitable for:** Critical code, production systems, untrusted projects
|
|
25
|
+
|
|
26
|
+
[View complete risk assessment →](./history/RISK_ASSESSMENT.md)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
10
30
|
## Status
|
|
11
31
|
|
|
12
|
-
|
|
32
|
+
🔬 **ALPHA** — Full-featured development automation system in active development. [View detailed implementation status →](./IMPLEMENTATION_STATUS.md)
|
|
13
33
|
|
|
14
34
|
---
|
|
15
35
|
|
|
@@ -34,6 +54,15 @@ All agents run **non-intrusively in the background**, respecting your workflow.
|
|
|
34
54
|
|
|
35
55
|
## Quick Start
|
|
36
56
|
|
|
57
|
+
### ⚠️ Before You Start
|
|
58
|
+
|
|
59
|
+
**ALPHA SOFTWARE DISCLAIMER:**
|
|
60
|
+
- This is research-quality code. Data loss is possible.
|
|
61
|
+
- Only use on projects you can afford to lose or easily recover.
|
|
62
|
+
- Make sure to commit your code to git before enabling DevLoop.
|
|
63
|
+
- Do not enable auto-fix on important code.
|
|
64
|
+
- Some agents may fail silently (see logs for details).
|
|
65
|
+
|
|
37
66
|
### Installation
|
|
38
67
|
|
|
39
68
|
**Prerequisites:** Python 3.11+
|
|
@@ -290,7 +319,7 @@ Configure agent behavior in `.devloop/agents.json`:
|
|
|
290
319
|
{
|
|
291
320
|
"global": {
|
|
292
321
|
"autonomousFixes": {
|
|
293
|
-
"enabled":
|
|
322
|
+
"enabled": false,
|
|
294
323
|
"safetyLevel": "safe_only"
|
|
295
324
|
},
|
|
296
325
|
"maxConcurrentAgents": 5,
|
|
@@ -312,11 +341,13 @@ Configure agent behavior in `.devloop/agents.json`:
|
|
|
312
341
|
}
|
|
313
342
|
```
|
|
314
343
|
|
|
315
|
-
**Safety levels:**
|
|
316
|
-
- `safe_only` — Only fix whitespace/indentation
|
|
344
|
+
**Safety levels (Auto-fix):**
|
|
345
|
+
- `safe_only` — Only fix whitespace/indentation (default, recommended)
|
|
317
346
|
- `medium_risk` — Include import/formatting fixes
|
|
318
347
|
- `all` — Apply all fixes (use with caution)
|
|
319
348
|
|
|
349
|
+
⚠️ **Auto-fix Warning:** Currently auto-fixes run without backups or review. **DO NOT enable auto-fix in production** or on critical code. Track [secure auto-fix with backups issue](https://github.com/wioota/devloop/issues/emc).
|
|
350
|
+
|
|
320
351
|
[Full configuration reference →](./docs/configuration.md)
|
|
321
352
|
|
|
322
353
|
---
|
|
@@ -526,17 +557,26 @@ DevLoop follows these core principles:
|
|
|
526
557
|
|
|
527
558
|
## Troubleshooting
|
|
528
559
|
|
|
560
|
+
### ⚠️ If Something Goes Wrong
|
|
561
|
+
|
|
562
|
+
**Recovery steps:**
|
|
563
|
+
1. Stop the daemon: `devloop stop .`
|
|
564
|
+
2. Check the logs: `tail -100 .devloop/devloop.log`
|
|
565
|
+
3. Verify your code in git: `git status`
|
|
566
|
+
4. Recover from git if files were modified: `git checkout <file>`
|
|
567
|
+
5. Report the issue: [GitHub Issues](https://github.com/wioota/devloop/issues)
|
|
568
|
+
|
|
529
569
|
### Agents not running
|
|
530
570
|
|
|
531
571
|
```bash
|
|
532
572
|
# Check status
|
|
533
573
|
devloop status
|
|
534
574
|
|
|
535
|
-
# View logs
|
|
536
|
-
tail -f .devloop/
|
|
575
|
+
# View logs (useful for debugging)
|
|
576
|
+
tail -f .devloop/devloop.log
|
|
537
577
|
|
|
538
|
-
# Enable verbose mode
|
|
539
|
-
devloop watch . --verbose
|
|
578
|
+
# Enable verbose mode for more details
|
|
579
|
+
devloop watch . --foreground --verbose
|
|
540
580
|
```
|
|
541
581
|
|
|
542
582
|
### Performance issues
|
|
@@ -565,6 +605,13 @@ devloop custom-list
|
|
|
565
605
|
ls -la .devloop/custom_agents/
|
|
566
606
|
```
|
|
567
607
|
|
|
608
|
+
### Agent modified my files unexpectedly
|
|
609
|
+
|
|
610
|
+
1. Check git diff: `git diff`
|
|
611
|
+
2. Revert changes: `git checkout -- .`
|
|
612
|
+
3. Disable the problematic agent in `.devloop/agents.json`
|
|
613
|
+
4. Report issue with: `git show HEAD:.devloop/agents.json`
|
|
614
|
+
|
|
568
615
|
[Full troubleshooting guide →](./docs/troubleshooting.md)
|
|
569
616
|
|
|
570
617
|
---
|
|
@@ -98,10 +98,44 @@ def setup_logging(verbose: bool = False):
|
|
|
98
98
|
)
|
|
99
99
|
|
|
100
100
|
|
|
101
|
+
def setup_logging_with_rotation(verbose: bool = False, project_dir: Path | None = None):
|
|
102
|
+
"""Setup logging configuration with file rotation for daemon mode."""
|
|
103
|
+
from logging.handlers import RotatingFileHandler
|
|
104
|
+
|
|
105
|
+
if project_dir is None:
|
|
106
|
+
project_dir = Path.cwd()
|
|
107
|
+
|
|
108
|
+
level = logging.DEBUG if verbose else logging.INFO
|
|
109
|
+
log_file = project_dir / ".devloop" / "devloop.log"
|
|
110
|
+
log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
|
|
112
|
+
# Create rotating file handler
|
|
113
|
+
# maxBytes: 10MB per file
|
|
114
|
+
# backupCount: keep 3 rotated files (total ~40MB max)
|
|
115
|
+
rotating_handler = RotatingFileHandler(
|
|
116
|
+
filename=str(log_file),
|
|
117
|
+
maxBytes=10 * 1024 * 1024, # 10MB
|
|
118
|
+
backupCount=3,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Format: timestamp | level | logger | message
|
|
122
|
+
formatter = logging.Formatter(
|
|
123
|
+
"%(asctime)s | %(levelname)-8s | %(name)-20s | %(message)s",
|
|
124
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
125
|
+
)
|
|
126
|
+
rotating_handler.setFormatter(formatter)
|
|
127
|
+
|
|
128
|
+
# Configure root logger
|
|
129
|
+
root_logger = logging.getLogger()
|
|
130
|
+
root_logger.setLevel(level)
|
|
131
|
+
root_logger.addHandler(rotating_handler)
|
|
132
|
+
|
|
133
|
+
|
|
101
134
|
def run_daemon(path: Path, config_path: Path | None, verbose: bool):
|
|
102
135
|
"""Run devloop in daemon/background mode."""
|
|
103
136
|
import os
|
|
104
137
|
import sys
|
|
138
|
+
from logging.handlers import RotatingFileHandler
|
|
105
139
|
|
|
106
140
|
# Fork to background
|
|
107
141
|
try:
|
|
@@ -125,16 +159,11 @@ def run_daemon(path: Path, config_path: Path | None, verbose: bool):
|
|
|
125
159
|
os.setsid()
|
|
126
160
|
os.umask(0)
|
|
127
161
|
|
|
128
|
-
#
|
|
129
|
-
|
|
130
|
-
log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
162
|
+
# Setup logging with rotation BEFORE redirecting file descriptors
|
|
163
|
+
setup_logging_with_rotation(verbose, project_dir)
|
|
131
164
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
os.dup2(f.fileno(), sys.stderr.fileno())
|
|
135
|
-
|
|
136
|
-
# Setup logging for daemon
|
|
137
|
-
setup_logging(verbose)
|
|
165
|
+
# Don't redirect stdout/stderr - let logging handlers manage it
|
|
166
|
+
# This prevents unbounded log file growth
|
|
138
167
|
|
|
139
168
|
# Write PID file
|
|
140
169
|
pid_file = project_dir / ".devloop" / "devloop.pid"
|
|
@@ -200,6 +229,42 @@ def watch(
|
|
|
200
229
|
console.print("\n[yellow]Shutting down...[/yellow]")
|
|
201
230
|
|
|
202
231
|
|
|
232
|
+
async def _cleanup_old_data(context_store, event_store, interval_hours: int = 1):
|
|
233
|
+
"""Periodically clean up old findings and events to prevent disk fill-up.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
context_store: Context store instance
|
|
237
|
+
event_store: Event store instance
|
|
238
|
+
interval_hours: How often to run cleanup (default: 1 hour)
|
|
239
|
+
"""
|
|
240
|
+
cleanup_interval = interval_hours * 60 * 60 # Convert to seconds
|
|
241
|
+
context_retention_hours = 7 * 24 # Keep 7 days of findings
|
|
242
|
+
event_retention_days = 30 # Keep 30 days of events
|
|
243
|
+
|
|
244
|
+
while True:
|
|
245
|
+
try:
|
|
246
|
+
await asyncio.sleep(cleanup_interval)
|
|
247
|
+
|
|
248
|
+
# Clean up old context findings
|
|
249
|
+
findings_removed = await context_store.cleanup_old_findings(
|
|
250
|
+
hours_to_keep=context_retention_hours
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# Clean up old events
|
|
254
|
+
events_removed = await event_store.cleanup_old_events(
|
|
255
|
+
days_to_keep=event_retention_days
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
console.print(
|
|
259
|
+
f"[dim]Cleanup: removed {findings_removed} old findings, {events_removed} old events[/dim]"
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
except asyncio.CancelledError:
|
|
263
|
+
break
|
|
264
|
+
except Exception as e:
|
|
265
|
+
console.print(f"[yellow]Cleanup error: {e}[/yellow]")
|
|
266
|
+
|
|
267
|
+
|
|
203
268
|
async def watch_async(path: Path, config_path: Path | None):
|
|
204
269
|
"""Async watch implementation."""
|
|
205
270
|
# Load configuration
|
|
@@ -232,6 +297,9 @@ async def watch_async(path: Path, config_path: Path | None):
|
|
|
232
297
|
fs_config = {"watch_paths": [str(path)]}
|
|
233
298
|
fs_collector = FileSystemCollector(event_bus=event_bus, config=fs_config)
|
|
234
299
|
|
|
300
|
+
# Start cleanup task (run every hour to remove old findings/events)
|
|
301
|
+
cleanup_task = asyncio.create_task(_cleanup_old_data(context_store, event_store))
|
|
302
|
+
|
|
235
303
|
# Create and register agents based on configuration
|
|
236
304
|
if config.is_agent_enabled("linter"):
|
|
237
305
|
linter_config = config.get_agent_config("linter") or {}
|
|
@@ -324,8 +392,15 @@ async def watch_async(path: Path, config_path: Path | None):
|
|
|
324
392
|
await shutdown_event.wait()
|
|
325
393
|
|
|
326
394
|
# Stop everything
|
|
395
|
+
cleanup_task.cancel()
|
|
327
396
|
await agent_manager.stop_all()
|
|
328
397
|
await fs_collector.stop()
|
|
398
|
+
|
|
399
|
+
# Wait for cleanup task to finish
|
|
400
|
+
try:
|
|
401
|
+
await cleanup_task
|
|
402
|
+
except asyncio.CancelledError:
|
|
403
|
+
pass
|
|
329
404
|
|
|
330
405
|
|
|
331
406
|
@app.command()
|
|
@@ -525,6 +525,48 @@ class ContextStore:
|
|
|
525
525
|
logger.error(f"Failed to load {tier_file}: {e}")
|
|
526
526
|
# Continue with other tiers
|
|
527
527
|
|
|
528
|
+
async def cleanup_old_findings(self, hours_to_keep: int = 168) -> int:
|
|
529
|
+
"""
|
|
530
|
+
Clean up findings older than specified hours.
|
|
531
|
+
|
|
532
|
+
Args:
|
|
533
|
+
hours_to_keep: Number of hours to retain findings (default: 7 days = 168 hours)
|
|
534
|
+
|
|
535
|
+
Returns:
|
|
536
|
+
Number of findings removed
|
|
537
|
+
"""
|
|
538
|
+
from datetime import datetime, UTC, timedelta
|
|
539
|
+
|
|
540
|
+
cutoff_time = datetime.now(UTC) - timedelta(hours=hours_to_keep)
|
|
541
|
+
cutoff_iso = cutoff_time.isoformat()
|
|
542
|
+
|
|
543
|
+
count = 0
|
|
544
|
+
async with self._lock:
|
|
545
|
+
for tier in Tier:
|
|
546
|
+
original_count = len(self._findings[tier])
|
|
547
|
+
|
|
548
|
+
# Filter out old findings
|
|
549
|
+
self._findings[tier] = [
|
|
550
|
+
f
|
|
551
|
+
for f in self._findings[tier]
|
|
552
|
+
if f.timestamp > cutoff_iso # ISO strings compare correctly
|
|
553
|
+
]
|
|
554
|
+
|
|
555
|
+
count += original_count - len(self._findings[tier])
|
|
556
|
+
|
|
557
|
+
# Write cleaned tier to disk
|
|
558
|
+
await self._write_tier(tier)
|
|
559
|
+
|
|
560
|
+
# Update index after cleanup
|
|
561
|
+
await self._update_index()
|
|
562
|
+
|
|
563
|
+
if count > 0:
|
|
564
|
+
logger.info(
|
|
565
|
+
f"Cleaned up {count} findings older than {hours_to_keep} hours"
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
return count
|
|
569
|
+
|
|
528
570
|
|
|
529
571
|
# Global instance
|
|
530
572
|
context_store = ContextStore()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|