@voria/cli 0.0.2
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 +439 -0
- package/bin/voria +730 -0
- package/docs/ARCHITECTURE.md +419 -0
- package/docs/CHANGELOG.md +189 -0
- package/docs/CONTRIBUTING.md +447 -0
- package/docs/DESIGN_DECISIONS.md +380 -0
- package/docs/DEVELOPMENT.md +535 -0
- package/docs/EXAMPLES.md +434 -0
- package/docs/INSTALL.md +335 -0
- package/docs/IPC_PROTOCOL.md +310 -0
- package/docs/LLM_INTEGRATION.md +416 -0
- package/docs/MODULES.md +470 -0
- package/docs/PERFORMANCE.md +346 -0
- package/docs/PLUGINS.md +432 -0
- package/docs/QUICKSTART.md +184 -0
- package/docs/README.md +133 -0
- package/docs/ROADMAP.md +346 -0
- package/docs/SECURITY.md +334 -0
- package/docs/TROUBLESHOOTING.md +565 -0
- package/docs/USER_GUIDE.md +700 -0
- package/package.json +63 -0
- package/python/voria/__init__.py +8 -0
- package/python/voria/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/voria/__pycache__/engine.cpython-312.pyc +0 -0
- package/python/voria/core/__init__.py +1 -0
- package/python/voria/core/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/voria/core/__pycache__/setup.cpython-312.pyc +0 -0
- package/python/voria/core/agent/__init__.py +9 -0
- package/python/voria/core/agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/voria/core/agent/__pycache__/loop.cpython-312.pyc +0 -0
- package/python/voria/core/agent/loop.py +343 -0
- package/python/voria/core/executor/__init__.py +19 -0
- package/python/voria/core/executor/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/voria/core/executor/__pycache__/executor.cpython-312.pyc +0 -0
- package/python/voria/core/executor/executor.py +431 -0
- package/python/voria/core/github/__init__.py +33 -0
- package/python/voria/core/github/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/voria/core/github/__pycache__/client.cpython-312.pyc +0 -0
- package/python/voria/core/github/client.py +438 -0
- package/python/voria/core/llm/__init__.py +55 -0
- package/python/voria/core/llm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/voria/core/llm/__pycache__/base.cpython-312.pyc +0 -0
- package/python/voria/core/llm/__pycache__/claude_provider.cpython-312.pyc +0 -0
- package/python/voria/core/llm/__pycache__/gemini_provider.cpython-312.pyc +0 -0
- package/python/voria/core/llm/__pycache__/modal_provider.cpython-312.pyc +0 -0
- package/python/voria/core/llm/__pycache__/model_discovery.cpython-312.pyc +0 -0
- package/python/voria/core/llm/__pycache__/openai_provider.cpython-312.pyc +0 -0
- package/python/voria/core/llm/base.py +152 -0
- package/python/voria/core/llm/claude_provider.py +188 -0
- package/python/voria/core/llm/gemini_provider.py +148 -0
- package/python/voria/core/llm/modal_provider.py +228 -0
- package/python/voria/core/llm/model_discovery.py +289 -0
- package/python/voria/core/llm/openai_provider.py +146 -0
- package/python/voria/core/patcher/__init__.py +9 -0
- package/python/voria/core/patcher/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/voria/core/patcher/__pycache__/patcher.cpython-312.pyc +0 -0
- package/python/voria/core/patcher/patcher.py +375 -0
- package/python/voria/core/planner/__init__.py +1 -0
- package/python/voria/core/setup.py +201 -0
- package/python/voria/core/token_manager/__init__.py +29 -0
- package/python/voria/core/token_manager/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/voria/core/token_manager/__pycache__/manager.cpython-312.pyc +0 -0
- package/python/voria/core/token_manager/manager.py +241 -0
- package/python/voria/engine.py +1185 -0
- package/python/voria/plugins/__init__.py +1 -0
- package/python/voria/plugins/python/__init__.py +1 -0
- package/python/voria/plugins/typescript/__init__.py +1 -0
package/docs/MODULES.md
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
# Module Documentation
|
|
2
|
+
|
|
3
|
+
Detailed documentation of voria's core modules and their APIs.
|
|
4
|
+
|
|
5
|
+
## Python Core Modules
|
|
6
|
+
|
|
7
|
+
### `llm/` - LLM Provider Integration
|
|
8
|
+
|
|
9
|
+
**Purpose**: Abstract interface to multiple LLM providers.
|
|
10
|
+
|
|
11
|
+
**Key Classes**:
|
|
12
|
+
- `BaseLLMProvider` - Abstract base class
|
|
13
|
+
- `ModelDiscovery` - Runtime model discovery
|
|
14
|
+
- `ProviderSetup` - Interactive configuration
|
|
15
|
+
- `ModelInfo` - Model metadata
|
|
16
|
+
- Provider implementations:
|
|
17
|
+
- `ModalProvider` - Modal Z.ai backend
|
|
18
|
+
- `OpenAIProvider` - OpenAI API
|
|
19
|
+
- `GeminiProvider` - Google Gemini
|
|
20
|
+
- `ClaudeProvider` - Anthropic Claude
|
|
21
|
+
|
|
22
|
+
**Main Methods**:
|
|
23
|
+
```python
|
|
24
|
+
# Discover available models
|
|
25
|
+
models = await LLMProviderFactory.discover_models("openai", api_key)
|
|
26
|
+
|
|
27
|
+
# Create provider instance
|
|
28
|
+
provider = LLMProviderFactory.create("openai", api_key, "gpt-5.4")
|
|
29
|
+
|
|
30
|
+
# Use provider
|
|
31
|
+
await provider.plan("Issue description")
|
|
32
|
+
await provider.generate_patch(issue_context, plan)
|
|
33
|
+
await provider.analyze_test_failure(test_output, code)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Configuration**:
|
|
37
|
+
- Stored in `~/.voria/providers.json`
|
|
38
|
+
- Supports environment variable fallback
|
|
39
|
+
- Interactive setup via `python3 -m voria.core.setup`
|
|
40
|
+
|
|
41
|
+
**Token Tracking**:
|
|
42
|
+
```python
|
|
43
|
+
response = await provider.call_llm(prompt)
|
|
44
|
+
print(response.token_usage) # {"used": 1000, "max": 4000}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### `patcher/` - Code Patching
|
|
48
|
+
|
|
49
|
+
**Purpose**: Parse and apply unified diffs.
|
|
50
|
+
|
|
51
|
+
**Key Classes**:
|
|
52
|
+
- `UnifiedDiffParser` - Parse diff format
|
|
53
|
+
- `PatchHunk` - Individual hunk data
|
|
54
|
+
- `CodePatcher` - Apply patches with rollback
|
|
55
|
+
|
|
56
|
+
**Main Methods**:
|
|
57
|
+
```python
|
|
58
|
+
# Parse diff
|
|
59
|
+
hunks = UnifiedDiffParser.parse(unified_diff_string)
|
|
60
|
+
|
|
61
|
+
# Create patcher
|
|
62
|
+
patcher = CodePatcher(repo_path)
|
|
63
|
+
|
|
64
|
+
# Apply patch
|
|
65
|
+
result = await patcher.apply_patch(diff_content, strategy="fuzzy")
|
|
66
|
+
|
|
67
|
+
# Rollback if needed
|
|
68
|
+
await patcher.rollback_patch(file_path, backup_path)
|
|
69
|
+
|
|
70
|
+
# Cleanup old backups
|
|
71
|
+
await patcher.cleanup_backups(keep_count=10)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Features**:
|
|
75
|
+
- Auto-backup before applying
|
|
76
|
+
- Strict/fuzzy matching strategies
|
|
77
|
+
- Automatic rollback on failure
|
|
78
|
+
- Backup retention management
|
|
79
|
+
- Located in `~/.voria/backups/`
|
|
80
|
+
|
|
81
|
+
### `executor/` - Test Execution
|
|
82
|
+
|
|
83
|
+
**Purpose**: Detect and run test suites.
|
|
84
|
+
|
|
85
|
+
**Key Classes**:
|
|
86
|
+
- `TestExecutor` - Main coordinator
|
|
87
|
+
- `TestStatus` - Result enum
|
|
88
|
+
- `TestResult` - Individual test result
|
|
89
|
+
- `TestSuiteResult` - Full suite results
|
|
90
|
+
- Framework parsers:
|
|
91
|
+
- `PytestParser` - Python pytest
|
|
92
|
+
- `JestParser` - JavaScript Jest
|
|
93
|
+
- (extensible for others)
|
|
94
|
+
|
|
95
|
+
**Main Methods**:
|
|
96
|
+
```python
|
|
97
|
+
# Create executor
|
|
98
|
+
executor = TestExecutor(repo_path)
|
|
99
|
+
|
|
100
|
+
# Detect framework
|
|
101
|
+
framework = await executor.detect_framework() # "pytest"|"jest"|None
|
|
102
|
+
|
|
103
|
+
# Run tests
|
|
104
|
+
result = await executor.run_tests()
|
|
105
|
+
|
|
106
|
+
# Format results
|
|
107
|
+
output = executor.format_results(result)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Results Structure**:
|
|
111
|
+
```python
|
|
112
|
+
TestSuiteResult(
|
|
113
|
+
framework="pytest",
|
|
114
|
+
total=25,
|
|
115
|
+
passed=24,
|
|
116
|
+
failed=1,
|
|
117
|
+
skipped=0,
|
|
118
|
+
duration=2.5,
|
|
119
|
+
results=[
|
|
120
|
+
TestResult(name="test_api", status=TestStatus.PASSED, duration=0.1),
|
|
121
|
+
TestResult(name="test_db", status=TestStatus.FAILED, message="timeout")
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### `agent/` - Orchestration
|
|
127
|
+
|
|
128
|
+
**Purpose**: Main agent loop for issue fixing.
|
|
129
|
+
|
|
130
|
+
**Key Classes**:
|
|
131
|
+
- `AgentLoop` - Core orchestrator
|
|
132
|
+
- `LoopState` - State tracking
|
|
133
|
+
- `LoopAction` - Action enum
|
|
134
|
+
|
|
135
|
+
**Main Methods**:
|
|
136
|
+
```python
|
|
137
|
+
# Create agent
|
|
138
|
+
loop = AgentLoop(
|
|
139
|
+
provider_name="openai",
|
|
140
|
+
api_key="sk-...",
|
|
141
|
+
repo_path="/repo"
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Initialize (setup provider)
|
|
145
|
+
await loop.initialize("gpt-5.4")
|
|
146
|
+
|
|
147
|
+
# Run full loop
|
|
148
|
+
result = await loop.run(
|
|
149
|
+
issue_id=42,
|
|
150
|
+
issue_description="Fix bug in parser"
|
|
151
|
+
)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Loop Stages**:
|
|
155
|
+
1. `_step_plan()` - Generate fix strategy
|
|
156
|
+
2. `_step_patch()` - Generate diff
|
|
157
|
+
3. `_step_apply()` - Apply changes
|
|
158
|
+
4. `_step_test()` - Run tests
|
|
159
|
+
5. `_analyze_failure()` - Analyze if failed
|
|
160
|
+
6. Loop back or succeed
|
|
161
|
+
|
|
162
|
+
**Result Structure**:
|
|
163
|
+
```python
|
|
164
|
+
{
|
|
165
|
+
"status": "success"|"failure"|"timeout",
|
|
166
|
+
"iterations": 3,
|
|
167
|
+
"plan": "Generated plan...",
|
|
168
|
+
"patch": "Generated diff...",
|
|
169
|
+
"test_results": {...},
|
|
170
|
+
"errors": []
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### `github/` - GitHub Integration
|
|
175
|
+
|
|
176
|
+
**Purpose**: Fetch issues and create PRs.
|
|
177
|
+
|
|
178
|
+
**Key Classes**:
|
|
179
|
+
- `GitHubClient` - Main client
|
|
180
|
+
- GitHub operations:
|
|
181
|
+
- `fetch_issue(id)` - Get issue details
|
|
182
|
+
- `create_pr(head, base, title, body)` - Create PR
|
|
183
|
+
- `add_comment(issue_id, text)` - Add issue comment
|
|
184
|
+
- `list_issues()` - Get issues
|
|
185
|
+
|
|
186
|
+
**Usage**:
|
|
187
|
+
```python
|
|
188
|
+
github = GitHubClient(token="ghp_...")
|
|
189
|
+
issue = await github.fetch_issue(42)
|
|
190
|
+
pr = await github.create_pr(
|
|
191
|
+
head="voria-fix-42",
|
|
192
|
+
base="main",
|
|
193
|
+
title="Fix issue #42",
|
|
194
|
+
body="Automatic fix by voria"
|
|
195
|
+
)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### `token_manager/` - Cost Tracking
|
|
199
|
+
|
|
200
|
+
**Purpose**: Track LLM spending and enforce budgets.
|
|
201
|
+
|
|
202
|
+
**Key Classes**:
|
|
203
|
+
- `TokenManager` - Main tracker
|
|
204
|
+
- `TokenBudget` - Per-provider budgets
|
|
205
|
+
|
|
206
|
+
**Usage**:
|
|
207
|
+
```python
|
|
208
|
+
manager = TokenManager()
|
|
209
|
+
|
|
210
|
+
# Log usage
|
|
211
|
+
manager.log_usage(
|
|
212
|
+
provider="openai",
|
|
213
|
+
tokens_used=1000,
|
|
214
|
+
cost=0.05
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
# Check budget
|
|
218
|
+
if not manager.within_budget("openai"):
|
|
219
|
+
raise BudgetExceededError()
|
|
220
|
+
|
|
221
|
+
# Get stats
|
|
222
|
+
stats = manager.get_stats() # Total cost today, etc.
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Budget Defaults**:
|
|
226
|
+
```
|
|
227
|
+
modal: $0.00/hr (free until Apr 30)
|
|
228
|
+
openai: $5.00/hr
|
|
229
|
+
gemini: $1.00/hr
|
|
230
|
+
claude: $3.00/hr
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### `setup/` - Configuration
|
|
234
|
+
|
|
235
|
+
**Purpose**: Interactive provider setup.
|
|
236
|
+
|
|
237
|
+
**Key Classes**:
|
|
238
|
+
- `ProviderSetup` - Configuration manager
|
|
239
|
+
|
|
240
|
+
**Usage**:
|
|
241
|
+
```python
|
|
242
|
+
setup = ProviderSetup()
|
|
243
|
+
|
|
244
|
+
# Interactive flow
|
|
245
|
+
config = await setup.setup_provider()
|
|
246
|
+
# → Choose provider
|
|
247
|
+
# → Enter API key
|
|
248
|
+
# → Select model
|
|
249
|
+
# → Save to ~/.voria/providers.json
|
|
250
|
+
|
|
251
|
+
# Get saved config
|
|
252
|
+
cfg = setup.get_provider_config("openai")
|
|
253
|
+
|
|
254
|
+
# List configured providers
|
|
255
|
+
providers = setup.list_configured()
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Rust Core Modules
|
|
259
|
+
|
|
260
|
+
### `main.rs` - Entry Point
|
|
261
|
+
|
|
262
|
+
**Responsibilities**:
|
|
263
|
+
- Parse CLI arguments
|
|
264
|
+
- Initialize logging
|
|
265
|
+
- Dispatch to subcommands
|
|
266
|
+
- Exit code handling
|
|
267
|
+
|
|
268
|
+
**Key Functions**:
|
|
269
|
+
```rust
|
|
270
|
+
async fn main() -> Result<()>
|
|
271
|
+
async fn handle_plan(issue_id: u32) -> Result<()>
|
|
272
|
+
async fn handle_issue(issue_id: u32) -> Result<()>
|
|
273
|
+
async fn handle_apply(plan_id: &str) -> Result<()>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### `cli/mod.rs` - Command Dispatch
|
|
277
|
+
|
|
278
|
+
**Responsibilities**:
|
|
279
|
+
- Parse subcommands (plan, issue, apply)
|
|
280
|
+
- Validate arguments
|
|
281
|
+
- Route to handlers
|
|
282
|
+
|
|
283
|
+
**Subcommands**:
|
|
284
|
+
- `plan <issue_id>` - Plan a fix
|
|
285
|
+
- `issue <issue_id>` - Full automation
|
|
286
|
+
- `apply <plan_id>` - Apply saved plan
|
|
287
|
+
|
|
288
|
+
### `ipc/mod.rs` - NDJSON Protocol
|
|
289
|
+
|
|
290
|
+
**Responsibilities**:
|
|
291
|
+
- Spawn Python subprocess
|
|
292
|
+
- Send NDJSON requests
|
|
293
|
+
- Receive NDJSON responses
|
|
294
|
+
- Timeout detection
|
|
295
|
+
|
|
296
|
+
**Key Structs**:
|
|
297
|
+
```rust
|
|
298
|
+
pub struct ProcessManager {
|
|
299
|
+
child: Child,
|
|
300
|
+
stdin: ChildStdin,
|
|
301
|
+
stdout: BufReader<ChildStdout>,
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
impl ProcessManager {
|
|
305
|
+
async fn send_request(&mut self, req: &Value) -> Result<()>
|
|
306
|
+
async fn read_response(&mut self) -> Result<Value>
|
|
307
|
+
async fn with_timeout(&mut self, req: &Value, secs: u64) -> Result<Value>
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### `orchestrator/mod.rs` - Coordination
|
|
312
|
+
|
|
313
|
+
**Responsibilities**:
|
|
314
|
+
- Coordinate Rust-Python workflow
|
|
315
|
+
- Handle multi-step commands
|
|
316
|
+
- Error recovery
|
|
317
|
+
|
|
318
|
+
### `config/mod.rs` - Configuration
|
|
319
|
+
|
|
320
|
+
**Responsibilities**:
|
|
321
|
+
- Load config files
|
|
322
|
+
- Override with CLI flags
|
|
323
|
+
- Merge environment variables
|
|
324
|
+
|
|
325
|
+
### `ui/mod.rs` - Terminal UI
|
|
326
|
+
|
|
327
|
+
**Responsibilities**:
|
|
328
|
+
- Colored output (Blue/Green/Red)
|
|
329
|
+
- Progress display
|
|
330
|
+
- Error formatting
|
|
331
|
+
|
|
332
|
+
**Key Functions**:
|
|
333
|
+
```rust
|
|
334
|
+
fn print_info(msg: &str) // Blue [i]
|
|
335
|
+
fn print_success(msg: &str) // Green [✓]
|
|
336
|
+
fn print_error(msg: &str) // Red [✗]
|
|
337
|
+
fn print_warning(msg: &str) // Yellow [!]
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Plugin Architecture
|
|
341
|
+
|
|
342
|
+
### Language Plugins
|
|
343
|
+
|
|
344
|
+
Location: `python/voria/plugins/`
|
|
345
|
+
|
|
346
|
+
**Plugin Structure**:
|
|
347
|
+
```python
|
|
348
|
+
class PythonPlugin:
|
|
349
|
+
async def parse_code(self, source: str) -> AST
|
|
350
|
+
async def run_tests(self, path: str) -> TestResult
|
|
351
|
+
async def format_code(self, source: str) -> str
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Supported Languages**:
|
|
355
|
+
- Python (pytest)
|
|
356
|
+
- JavaScript/TypeScript (Jest)
|
|
357
|
+
- (Extensible)
|
|
358
|
+
|
|
359
|
+
## Data Structures
|
|
360
|
+
|
|
361
|
+
### LLM Response
|
|
362
|
+
|
|
363
|
+
```python
|
|
364
|
+
class LLMResponse:
|
|
365
|
+
content: str # Response text
|
|
366
|
+
tokens_used: int # Tokens consumed
|
|
367
|
+
finish_reason: str # "stop"|"length"|"error"
|
|
368
|
+
metadata: Dict[str, Any] # Provider-specific
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Patch Hunk
|
|
372
|
+
|
|
373
|
+
```python
|
|
374
|
+
@dataclass
|
|
375
|
+
class PatchHunk:
|
|
376
|
+
old_file: str # File path
|
|
377
|
+
new_file: str
|
|
378
|
+
old_start: int # Starting line (1-indexed)
|
|
379
|
+
old_count: int # Num lines before
|
|
380
|
+
new_start: int # Starting line after
|
|
381
|
+
new_count: int # Num lines after
|
|
382
|
+
lines: List[str] # Diff lines
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Test Result
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
@dataclass
|
|
389
|
+
class TestResult:
|
|
390
|
+
name: str # Test identifier
|
|
391
|
+
status: TestStatus # PASSED|FAILED|SKIPPED|ERROR
|
|
392
|
+
duration: float # Seconds
|
|
393
|
+
message: str # Fail message (if any)
|
|
394
|
+
error_type: Optional[str] # Exception type
|
|
395
|
+
stacktrace: Optional[str] # Full trace
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Usage Patterns
|
|
399
|
+
|
|
400
|
+
### Using an LLM Provider
|
|
401
|
+
|
|
402
|
+
```python
|
|
403
|
+
# 1. Create provider
|
|
404
|
+
provider = LLMProviderFactory.create("openai", api_key, "gpt-5.4")
|
|
405
|
+
|
|
406
|
+
# 2. Call methods
|
|
407
|
+
plan = await provider.plan(issue_description)
|
|
408
|
+
patch = await provider.generate_patch(context, plan)
|
|
409
|
+
|
|
410
|
+
# 3. Check tokens
|
|
411
|
+
print(f"Used: {plan.tokens_used} tokens")
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Using the Agent Loop
|
|
415
|
+
|
|
416
|
+
```python
|
|
417
|
+
# 1. Create loop
|
|
418
|
+
loop = AgentLoop("openai", api_key, repo_path="/repo")
|
|
419
|
+
|
|
420
|
+
# 2. Initialize
|
|
421
|
+
await loop.initialize("gpt-5.4")
|
|
422
|
+
|
|
423
|
+
# 3. Run
|
|
424
|
+
result = await loop.run(issue_id=42, issue_description="...")
|
|
425
|
+
|
|
426
|
+
# 4. Check result
|
|
427
|
+
if result["status"] == "success":
|
|
428
|
+
print("Issue fixed!")
|
|
429
|
+
else:
|
|
430
|
+
print(f"Failed: {result['errors']}")
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Using Patching & Testing
|
|
434
|
+
|
|
435
|
+
```python
|
|
436
|
+
# 1. Create patcher
|
|
437
|
+
patcher = CodePatcher("/repo")
|
|
438
|
+
|
|
439
|
+
# 2. Apply patch
|
|
440
|
+
result = await patcher.apply_patch(diff_text)
|
|
441
|
+
|
|
442
|
+
# 3. Create executor
|
|
443
|
+
executor = TestExecutor("/repo")
|
|
444
|
+
|
|
445
|
+
# 4. Run tests
|
|
446
|
+
test_result = await executor.run_tests()
|
|
447
|
+
|
|
448
|
+
# 5. Check results
|
|
449
|
+
if test_result.passed == test_result.total:
|
|
450
|
+
print("All tests pass!")
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
## Dependencies
|
|
454
|
+
|
|
455
|
+
### Python
|
|
456
|
+
- httpx 0.24.0 - Async HTTP
|
|
457
|
+
- aiofiles 23.0 - Async file I/O
|
|
458
|
+
- pytest - Testing
|
|
459
|
+
|
|
460
|
+
### Rust
|
|
461
|
+
- tokio 1.51 - Async runtime
|
|
462
|
+
- serde_json - JSON
|
|
463
|
+
- colored - Terminal colors
|
|
464
|
+
- clap - CLI args
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
**See Also:**
|
|
469
|
+
- [ARCHITECTURE.md](ARCHITECTURE.md) - System design
|
|
470
|
+
- [DESIGN_DECISIONS.md](DESIGN_DECISIONS.md) - Why these choices
|