adversarial-workflow 0.6.2__tar.gz → 0.6.4__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.
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/PKG-INFO +26 -4
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/README.md +24 -2
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/__init__.py +1 -1
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/__main__.py +1 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/cli.py +85 -137
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/evaluators/config.py +2 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/evaluators/discovery.py +29 -9
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/evaluators/runner.py +2 -7
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/utils/config.py +1 -3
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/utils/file_splitter.py +2 -6
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/utils/validation.py +1 -3
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow.egg-info/PKG-INFO +26 -4
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow.egg-info/SOURCES.txt +1 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/pyproject.toml +2 -2
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_cli_dynamic_commands.py +50 -3
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_config.py +20 -14
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_env_loading.py +1 -3
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_evaluate.py +35 -30
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_evaluator_discovery.py +204 -3
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_file_splitter.py +1 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_python_version.py +1 -0
- adversarial_workflow-0.6.4/tests/test_timeout_integration.py +406 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/LICENSE +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/evaluators/__init__.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/evaluators/builtins.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/.aider.conf.yml.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/.env.example.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/README.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/agent-context/AGENT-SYSTEM-GUIDE.md +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/agent-context/README.md.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/agent-context/agent-handoffs-minimal.json.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/agent-context/agent-handoffs.json.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/agent-context/current-state.json.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/config.yml.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/evaluate_plan.sh.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/example-task.md.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/proofread_content.sh.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/review_implementation.sh.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/templates/validate_tests.sh.template +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/utils/__init__.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/utils/colors.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow.egg-info/dependency_links.txt +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow.egg-info/entry_points.txt +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow.egg-info/requires.txt +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow.egg-info/top_level.txt +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/setup.cfg +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/setup.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_cli.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_evaluator_config.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_evaluator_runner.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_list_evaluators.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_scripts_project.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_split_command.py +0 -0
- {adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/tests/test_utils_validation.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: adversarial-workflow
|
|
3
|
-
Version: 0.6.
|
|
4
|
-
Summary: Multi-stage AI
|
|
3
|
+
Version: 0.6.4
|
|
4
|
+
Summary: Multi-stage AI evaluation system for task plans, code review, and test validation
|
|
5
5
|
Author: Fredrik Matheson
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/movito/adversarial-workflow
|
|
@@ -55,9 +55,30 @@ Evaluate proposals, sort out ideas, and prevent "phantom work" (AI claiming to i
|
|
|
55
55
|
- 🎯 **Tool-agnostic**: Use with Claude Code, Cursor, Aider, manual coding, or any workflow
|
|
56
56
|
- ✨ **Interactive onboarding**: Guided setup wizard gets you started in <5 minutes
|
|
57
57
|
|
|
58
|
-
## What's New in v0.6.
|
|
58
|
+
## What's New in v0.6.3
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
### Upgrade
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install --upgrade adversarial-workflow
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### v0.6.3 - Configurable Timeouts
|
|
67
|
+
|
|
68
|
+
- **Per-evaluator timeout**: Add `timeout: 300` to evaluator YAML for slow models like Mistral Large
|
|
69
|
+
- **CLI override**: Use `--timeout 400` to override YAML config on-the-fly
|
|
70
|
+
- **Timeout logging**: See which timeout source is used (CLI/YAML/default)
|
|
71
|
+
- **Safety limits**: Maximum 600 seconds to prevent runaway processes
|
|
72
|
+
|
|
73
|
+
### v0.6.2 - .env Loading & Stability
|
|
74
|
+
|
|
75
|
+
- **Automatic .env loading**: API keys in `.env` files are now loaded at CLI startup
|
|
76
|
+
- **Custom evaluator support**: Evaluators using `api_key_env: GEMINI_API_KEY` (or other keys) now work with `.env` files
|
|
77
|
+
- **Better diagnostics**: `adversarial check` correctly reports the number of variables loaded from `.env`
|
|
78
|
+
|
|
79
|
+
### v0.6.0 - Plugin Architecture
|
|
80
|
+
|
|
81
|
+
🔌 **Custom Evaluators** - Define your own evaluators without modifying the package:
|
|
61
82
|
|
|
62
83
|
```bash
|
|
63
84
|
# Create a custom evaluator
|
|
@@ -459,6 +480,7 @@ Starting with v0.6.0, you can define project-specific evaluators without modifyi
|
|
|
459
480
|
| `aliases` | No | Alternative command names |
|
|
460
481
|
| `log_prefix` | No | CLI output prefix |
|
|
461
482
|
| `fallback_model` | No | Fallback model if primary fails |
|
|
483
|
+
| `timeout` | No | Timeout in seconds (default: 180, max: 600) |
|
|
462
484
|
| `version` | No | Evaluator version (default: 1.0.0) |
|
|
463
485
|
|
|
464
486
|
### Listing Available Evaluators
|
|
@@ -20,9 +20,30 @@ Evaluate proposals, sort out ideas, and prevent "phantom work" (AI claiming to i
|
|
|
20
20
|
- 🎯 **Tool-agnostic**: Use with Claude Code, Cursor, Aider, manual coding, or any workflow
|
|
21
21
|
- ✨ **Interactive onboarding**: Guided setup wizard gets you started in <5 minutes
|
|
22
22
|
|
|
23
|
-
## What's New in v0.6.
|
|
23
|
+
## What's New in v0.6.3
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
### Upgrade
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install --upgrade adversarial-workflow
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### v0.6.3 - Configurable Timeouts
|
|
32
|
+
|
|
33
|
+
- **Per-evaluator timeout**: Add `timeout: 300` to evaluator YAML for slow models like Mistral Large
|
|
34
|
+
- **CLI override**: Use `--timeout 400` to override YAML config on-the-fly
|
|
35
|
+
- **Timeout logging**: See which timeout source is used (CLI/YAML/default)
|
|
36
|
+
- **Safety limits**: Maximum 600 seconds to prevent runaway processes
|
|
37
|
+
|
|
38
|
+
### v0.6.2 - .env Loading & Stability
|
|
39
|
+
|
|
40
|
+
- **Automatic .env loading**: API keys in `.env` files are now loaded at CLI startup
|
|
41
|
+
- **Custom evaluator support**: Evaluators using `api_key_env: GEMINI_API_KEY` (or other keys) now work with `.env` files
|
|
42
|
+
- **Better diagnostics**: `adversarial check` correctly reports the number of variables loaded from `.env`
|
|
43
|
+
|
|
44
|
+
### v0.6.0 - Plugin Architecture
|
|
45
|
+
|
|
46
|
+
🔌 **Custom Evaluators** - Define your own evaluators without modifying the package:
|
|
26
47
|
|
|
27
48
|
```bash
|
|
28
49
|
# Create a custom evaluator
|
|
@@ -424,6 +445,7 @@ Starting with v0.6.0, you can define project-specific evaluators without modifyi
|
|
|
424
445
|
| `aliases` | No | Alternative command names |
|
|
425
446
|
| `log_prefix` | No | CLI output prefix |
|
|
426
447
|
| `fallback_model` | No | Fallback model if primary fails |
|
|
448
|
+
| `timeout` | No | Timeout in seconds (default: 180, max: 600) |
|
|
427
449
|
| `version` | No | Evaluator version (default: 1.0.0) |
|
|
428
450
|
|
|
429
451
|
### Listing Available Evaluators
|
|
@@ -29,7 +29,7 @@ from typing import Dict, List, Optional, Tuple
|
|
|
29
29
|
import yaml
|
|
30
30
|
from dotenv import dotenv_values, load_dotenv
|
|
31
31
|
|
|
32
|
-
__version__ = "0.6.
|
|
32
|
+
__version__ = "0.6.4"
|
|
33
33
|
|
|
34
34
|
# ANSI color codes for better output
|
|
35
35
|
RESET = "\033[0m"
|
|
@@ -180,7 +180,9 @@ def create_env_file_interactive(
|
|
|
180
180
|
env_content += "# DO NOT COMMIT THIS FILE\n\n"
|
|
181
181
|
|
|
182
182
|
if anthropic_key:
|
|
183
|
-
env_content +=
|
|
183
|
+
env_content += (
|
|
184
|
+
f"# Anthropic API Key (Claude 3.5 Sonnet)\nANTHROPIC_API_KEY={anthropic_key}\n\n"
|
|
185
|
+
)
|
|
184
186
|
|
|
185
187
|
if openai_key:
|
|
186
188
|
env_content += f"# OpenAI API Key (GPT-4o)\nOPENAI_API_KEY={openai_key}\n\n"
|
|
@@ -255,9 +257,7 @@ def init_interactive(project_path: str = ".") -> int:
|
|
|
255
257
|
],
|
|
256
258
|
)
|
|
257
259
|
|
|
258
|
-
anthropic_key = prompt_user(
|
|
259
|
-
"Paste your Anthropic API key (or Enter to skip)", secret=True
|
|
260
|
-
)
|
|
260
|
+
anthropic_key = prompt_user("Paste your Anthropic API key (or Enter to skip)", secret=True)
|
|
261
261
|
|
|
262
262
|
if anthropic_key:
|
|
263
263
|
is_valid, message = validate_api_key(anthropic_key, "anthropic")
|
|
@@ -281,9 +281,7 @@ def init_interactive(project_path: str = ".") -> int:
|
|
|
281
281
|
],
|
|
282
282
|
)
|
|
283
283
|
|
|
284
|
-
openai_key = prompt_user(
|
|
285
|
-
"Paste your OpenAI API key (or Enter to skip)", secret=True
|
|
286
|
-
)
|
|
284
|
+
openai_key = prompt_user("Paste your OpenAI API key (or Enter to skip)", secret=True)
|
|
287
285
|
|
|
288
286
|
if openai_key:
|
|
289
287
|
is_valid, message = validate_api_key(openai_key, "openai")
|
|
@@ -322,16 +320,20 @@ def init_interactive(project_path: str = ".") -> int:
|
|
|
322
320
|
f"{GREEN}✅ Setup Complete!{RESET}",
|
|
323
321
|
[
|
|
324
322
|
"Created:",
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
323
|
+
(
|
|
324
|
+
" ✓ .env (with your API keys - added to .gitignore)"
|
|
325
|
+
if (anthropic_key or openai_key)
|
|
326
|
+
else " ⚠️ .env (skipped - no API keys provided)"
|
|
327
|
+
),
|
|
328
328
|
" ✓ .adversarial/config.yml",
|
|
329
329
|
" ✓ .adversarial/scripts/ (3 workflow scripts)",
|
|
330
330
|
" ✓ .aider.conf.yml (aider configuration)",
|
|
331
331
|
"",
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
332
|
+
(
|
|
333
|
+
"Your configuration:"
|
|
334
|
+
if (anthropic_key or openai_key)
|
|
335
|
+
else "Configuration (no API keys yet):"
|
|
336
|
+
),
|
|
335
337
|
f" Author (implementation): {'Claude 3.5 Sonnet (Anthropic)' if anthropic_key else 'GPT-4o (OpenAI)' if openai_key else 'Not configured'}",
|
|
336
338
|
f" Evaluator: {'GPT-4o (OpenAI)' if openai_key else 'Claude 3.5 Sonnet (Anthropic)' if anthropic_key else 'Not configured'}",
|
|
337
339
|
f" Cost per workflow: {'~$0.02-0.10' if (anthropic_key and openai_key) else '~$0.05-0.15' if (anthropic_key or openai_key) else 'N/A'}",
|
|
@@ -609,9 +611,7 @@ def init(project_path: str = ".", interactive: bool = True) -> int:
|
|
|
609
611
|
print(" 3. Then run: adversarial init")
|
|
610
612
|
print()
|
|
611
613
|
print(f"{BOLD}HELP:{RESET}")
|
|
612
|
-
print(
|
|
613
|
-
" New to git? https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"
|
|
614
|
-
)
|
|
614
|
+
print(" New to git? https://git-scm.com/book/en/v2/Getting-Started-Installing-Git")
|
|
615
615
|
return 1
|
|
616
616
|
|
|
617
617
|
# Pre-flight validation: Check package integrity
|
|
@@ -645,9 +645,7 @@ def init(project_path: str = ".", interactive: bool = True) -> int:
|
|
|
645
645
|
print(f" • {template}")
|
|
646
646
|
print()
|
|
647
647
|
print(f"{BOLD}FIX:{RESET}")
|
|
648
|
-
print(
|
|
649
|
-
" 1. Report this issue: https://github.com/movito/adversarial-workflow/issues"
|
|
650
|
-
)
|
|
648
|
+
print(" 1. Report this issue: https://github.com/movito/adversarial-workflow/issues")
|
|
651
649
|
print(
|
|
652
650
|
" 2. Or try reinstalling: pip install --upgrade --force-reinstall adversarial-workflow"
|
|
653
651
|
)
|
|
@@ -1026,13 +1024,9 @@ def check() -> int:
|
|
|
1026
1024
|
else:
|
|
1027
1025
|
status_parts = []
|
|
1028
1026
|
if error_count > 0:
|
|
1029
|
-
status_parts.append(
|
|
1030
|
-
f"{error_count} error" + ("s" if error_count != 1 else "")
|
|
1031
|
-
)
|
|
1027
|
+
status_parts.append(f"{error_count} error" + ("s" if error_count != 1 else ""))
|
|
1032
1028
|
if warning_count > 0:
|
|
1033
|
-
status_parts.append(
|
|
1034
|
-
f"{warning_count} warning" + ("s" if warning_count != 1 else "")
|
|
1035
|
-
)
|
|
1029
|
+
status_parts.append(f"{warning_count} warning" + ("s" if warning_count != 1 else ""))
|
|
1036
1030
|
if info_count > 0:
|
|
1037
1031
|
status_parts.append(f"{info_count} info")
|
|
1038
1032
|
|
|
@@ -1084,20 +1078,14 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1084
1078
|
# Helper functions for tracking check results
|
|
1085
1079
|
def check_pass(category: str, message: str, detail: str = None):
|
|
1086
1080
|
nonlocal passed
|
|
1087
|
-
results[category].append(
|
|
1088
|
-
{"status": "pass", "message": message, "detail": detail}
|
|
1089
|
-
)
|
|
1081
|
+
results[category].append({"status": "pass", "message": message, "detail": detail})
|
|
1090
1082
|
if not json_output:
|
|
1091
1083
|
print(f" {GREEN}✅{RESET} {message}")
|
|
1092
1084
|
passed += 1
|
|
1093
1085
|
|
|
1094
|
-
def check_warn(
|
|
1095
|
-
category: str, message: str, detail: str = None, recommendation: str = None
|
|
1096
|
-
):
|
|
1086
|
+
def check_warn(category: str, message: str, detail: str = None, recommendation: str = None):
|
|
1097
1087
|
nonlocal warnings
|
|
1098
|
-
results[category].append(
|
|
1099
|
-
{"status": "warn", "message": message, "detail": detail}
|
|
1100
|
-
)
|
|
1088
|
+
results[category].append({"status": "warn", "message": message, "detail": detail})
|
|
1101
1089
|
if not json_output:
|
|
1102
1090
|
print(f" {YELLOW}⚠️{RESET} {message}")
|
|
1103
1091
|
if detail and verbose:
|
|
@@ -1106,9 +1094,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1106
1094
|
recommendations.append(recommendation)
|
|
1107
1095
|
warnings += 1
|
|
1108
1096
|
|
|
1109
|
-
def check_fail(
|
|
1110
|
-
category: str, message: str, fix: str = None, recommendation: str = None
|
|
1111
|
-
):
|
|
1097
|
+
def check_fail(category: str, message: str, fix: str = None, recommendation: str = None):
|
|
1112
1098
|
nonlocal errors
|
|
1113
1099
|
results[category].append({"status": "fail", "message": message, "fix": fix})
|
|
1114
1100
|
if not json_output:
|
|
@@ -1120,9 +1106,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1120
1106
|
errors += 1
|
|
1121
1107
|
|
|
1122
1108
|
def check_info(category: str, message: str, detail: str = None):
|
|
1123
|
-
results[category].append(
|
|
1124
|
-
{"status": "info", "message": message, "detail": detail}
|
|
1125
|
-
)
|
|
1109
|
+
results[category].append({"status": "info", "message": message, "detail": detail})
|
|
1126
1110
|
if not json_output:
|
|
1127
1111
|
print(f" {CYAN}ℹ️{RESET} {message}")
|
|
1128
1112
|
if detail and verbose:
|
|
@@ -1254,23 +1238,13 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1254
1238
|
)
|
|
1255
1239
|
if git_status.returncode == 0:
|
|
1256
1240
|
modified = len(
|
|
1257
|
-
[
|
|
1258
|
-
l
|
|
1259
|
-
for l in git_status.stdout.splitlines()
|
|
1260
|
-
if l.startswith(" M")
|
|
1261
|
-
]
|
|
1241
|
+
[l for l in git_status.stdout.splitlines() if l.startswith(" M")]
|
|
1262
1242
|
)
|
|
1263
1243
|
untracked = len(
|
|
1264
|
-
[
|
|
1265
|
-
l
|
|
1266
|
-
for l in git_status.stdout.splitlines()
|
|
1267
|
-
if l.startswith("??")
|
|
1268
|
-
]
|
|
1244
|
+
[l for l in git_status.stdout.splitlines() if l.startswith("??")]
|
|
1269
1245
|
)
|
|
1270
1246
|
if modified == 0 and untracked == 0:
|
|
1271
|
-
check_pass(
|
|
1272
|
-
"dependencies", f"Git: {version} (working tree clean)"
|
|
1273
|
-
)
|
|
1247
|
+
check_pass("dependencies", f"Git: {version} (working tree clean)")
|
|
1274
1248
|
else:
|
|
1275
1249
|
check_info(
|
|
1276
1250
|
"dependencies",
|
|
@@ -1307,11 +1281,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1307
1281
|
aider_version = subprocess.run(
|
|
1308
1282
|
["aider", "--version"], capture_output=True, text=True, timeout=2
|
|
1309
1283
|
)
|
|
1310
|
-
version = (
|
|
1311
|
-
aider_version.stdout.strip()
|
|
1312
|
-
if aider_version.returncode == 0
|
|
1313
|
-
else "unknown"
|
|
1314
|
-
)
|
|
1284
|
+
version = aider_version.stdout.strip() if aider_version.returncode == 0 else "unknown"
|
|
1315
1285
|
check_pass("dependencies", f"Aider: {version} (functional)")
|
|
1316
1286
|
except:
|
|
1317
1287
|
check_pass("dependencies", "Aider: installed")
|
|
@@ -1455,9 +1425,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1455
1425
|
json.load(f)
|
|
1456
1426
|
check_pass("agent_coordination", "current-state.json - Valid JSON")
|
|
1457
1427
|
except json.JSONDecodeError as e:
|
|
1458
|
-
check_fail(
|
|
1459
|
-
"agent_coordination", f"current-state.json - Invalid JSON: {e}"
|
|
1460
|
-
)
|
|
1428
|
+
check_fail("agent_coordination", f"current-state.json - Invalid JSON: {e}")
|
|
1461
1429
|
else:
|
|
1462
1430
|
check_info("agent_coordination", "current-state.json not found (optional)")
|
|
1463
1431
|
|
|
@@ -1501,9 +1469,7 @@ def health(verbose: bool = False, json_output: bool = False) -> int:
|
|
|
1501
1469
|
with open(script_path) as f:
|
|
1502
1470
|
content = f.read()
|
|
1503
1471
|
if "#!/bin/bash" in content or "#!/usr/bin/env bash" in content:
|
|
1504
|
-
check_pass(
|
|
1505
|
-
"workflow_scripts", f"{script_name} - Executable, valid"
|
|
1506
|
-
)
|
|
1472
|
+
check_pass("workflow_scripts", f"{script_name} - Executable, valid")
|
|
1507
1473
|
else:
|
|
1508
1474
|
check_warn(
|
|
1509
1475
|
"workflow_scripts",
|
|
@@ -1777,9 +1743,7 @@ def verify_token_count(task_file: str, log_file: str) -> None:
|
|
|
1777
1743
|
f" Difference: {expected_tokens - actual_tokens:,} tokens ({100 - int(actual_tokens/expected_tokens*100)}% less)"
|
|
1778
1744
|
)
|
|
1779
1745
|
print()
|
|
1780
|
-
print(
|
|
1781
|
-
f"{BOLD}Note:{RESET} Large files may not be fully processed by evaluator."
|
|
1782
|
-
)
|
|
1746
|
+
print(f"{BOLD}Note:{RESET} Large files may not be fully processed by evaluator.")
|
|
1783
1747
|
print(f" Consider splitting into smaller documents (<1,000 lines).")
|
|
1784
1748
|
print()
|
|
1785
1749
|
|
|
@@ -1960,9 +1924,7 @@ def evaluate(task_file: str) -> int:
|
|
|
1960
1924
|
print(f"{RED}❌ ERROR: OpenAI rate limit exceeded{RESET}")
|
|
1961
1925
|
print()
|
|
1962
1926
|
print(f"{BOLD}WHY:{RESET}")
|
|
1963
|
-
print(
|
|
1964
|
-
" Your task file is too large for your OpenAI organization's rate limit"
|
|
1965
|
-
)
|
|
1927
|
+
print(" Your task file is too large for your OpenAI organization's rate limit")
|
|
1966
1928
|
print()
|
|
1967
1929
|
|
|
1968
1930
|
# Extract file size for helpful message
|
|
@@ -2009,9 +1971,7 @@ def evaluate(task_file: str) -> int:
|
|
|
2009
1971
|
print()
|
|
2010
1972
|
print(f"{BOLD}FIX:{RESET}")
|
|
2011
1973
|
print(" Option 1 (RECOMMENDED): Use WSL (Windows Subsystem for Linux)")
|
|
2012
|
-
print(
|
|
2013
|
-
" 1. Install WSL: https://learn.microsoft.com/windows/wsl/install"
|
|
2014
|
-
)
|
|
1974
|
+
print(" 1. Install WSL: https://learn.microsoft.com/windows/wsl/install")
|
|
2015
1975
|
print(" 2. Open WSL terminal")
|
|
2016
1976
|
print(" 3. Reinstall package in WSL: pip install adversarial-workflow")
|
|
2017
1977
|
print()
|
|
@@ -2182,9 +2142,7 @@ def validate(test_command: Optional[str] = None) -> int:
|
|
|
2182
2142
|
return 1
|
|
2183
2143
|
|
|
2184
2144
|
try:
|
|
2185
|
-
result = subprocess.run(
|
|
2186
|
-
[script, test_command], timeout=600
|
|
2187
|
-
) # 10 minutes for tests
|
|
2145
|
+
result = subprocess.run([script, test_command], timeout=600) # 10 minutes for tests
|
|
2188
2146
|
except subprocess.TimeoutExpired:
|
|
2189
2147
|
print(f"{RED}❌ ERROR: Test validation timed out (>10 minutes){RESET}")
|
|
2190
2148
|
return 1
|
|
@@ -2237,9 +2195,7 @@ def select_agent_template() -> Dict[str, str]:
|
|
|
2237
2195
|
elif choice == "3":
|
|
2238
2196
|
print()
|
|
2239
2197
|
print(f"{CYAN}Custom Template URL:{RESET}")
|
|
2240
|
-
print(
|
|
2241
|
-
" Example: https://raw.githubusercontent.com/user/repo/main/agent-handoffs.json"
|
|
2242
|
-
)
|
|
2198
|
+
print(" Example: https://raw.githubusercontent.com/user/repo/main/agent-handoffs.json")
|
|
2243
2199
|
print()
|
|
2244
2200
|
url = prompt_user("Template URL")
|
|
2245
2201
|
if url:
|
|
@@ -2279,9 +2235,7 @@ def fetch_agent_template(url: str, template_type: str = "standard") -> Optional[
|
|
|
2279
2235
|
with open(template_path, "r") as f:
|
|
2280
2236
|
return f.read()
|
|
2281
2237
|
except Exception as e:
|
|
2282
|
-
print(
|
|
2283
|
-
f"{RED}❌ ERROR: Could not read {template_type} template: {e}{RESET}"
|
|
2284
|
-
)
|
|
2238
|
+
print(f"{RED}❌ ERROR: Could not read {template_type} template: {e}{RESET}")
|
|
2285
2239
|
return None
|
|
2286
2240
|
else:
|
|
2287
2241
|
print(f"{RED}❌ ERROR: {template_type} template not found in package{RESET}")
|
|
@@ -2384,9 +2338,11 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2384
2338
|
return 0
|
|
2385
2339
|
|
|
2386
2340
|
# 3. Interactive questions (4 max)
|
|
2387
|
-
use_delegation = prompt_user(
|
|
2388
|
-
"
|
|
2389
|
-
|
|
2341
|
+
use_delegation = prompt_user("Use delegation/tasks/ structure? (recommended)", "Y").lower() in [
|
|
2342
|
+
"y",
|
|
2343
|
+
"yes",
|
|
2344
|
+
"",
|
|
2345
|
+
]
|
|
2390
2346
|
|
|
2391
2347
|
organize_docs = prompt_user("Organize root docs into docs/?", "n").lower() in [
|
|
2392
2348
|
"y",
|
|
@@ -2463,9 +2419,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2463
2419
|
print(
|
|
2464
2420
|
f" {CYAN}ℹ️{RESET} Original tasks/ preserved (remove manually if desired)"
|
|
2465
2421
|
)
|
|
2466
|
-
print(
|
|
2467
|
-
f" {CYAN}ℹ️{RESET} Rollback: rm -rf tasks && mv tasks.backup tasks"
|
|
2468
|
-
)
|
|
2422
|
+
print(f" {CYAN}ℹ️{RESET} Rollback: rm -rf tasks && mv tasks.backup tasks")
|
|
2469
2423
|
|
|
2470
2424
|
except Exception as e:
|
|
2471
2425
|
print(f" {RED}❌{RESET} Migration failed: {e}")
|
|
@@ -2479,9 +2433,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2479
2433
|
print(f"{BOLD}Documentation Organization:{RESET}")
|
|
2480
2434
|
|
|
2481
2435
|
# Find markdown files in root
|
|
2482
|
-
root_docs = [
|
|
2483
|
-
f for f in os.listdir(".") if f.endswith(".md") and not f.startswith(".")
|
|
2484
|
-
]
|
|
2436
|
+
root_docs = [f for f in os.listdir(".") if f.endswith(".md") and not f.startswith(".")]
|
|
2485
2437
|
|
|
2486
2438
|
if len(root_docs) > 0:
|
|
2487
2439
|
print(f" Found {len(root_docs)} markdown file(s) in root")
|
|
@@ -2501,9 +2453,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2501
2453
|
moved_count += 1
|
|
2502
2454
|
|
|
2503
2455
|
if moved_count > 0:
|
|
2504
|
-
print(
|
|
2505
|
-
f" {GREEN}✅{RESET} Organized {moved_count} doc(s) into docs/"
|
|
2506
|
-
)
|
|
2456
|
+
print(f" {GREEN}✅{RESET} Organized {moved_count} doc(s) into docs/")
|
|
2507
2457
|
else:
|
|
2508
2458
|
print(f" {CYAN}ℹ️{RESET} No docs needed organizing")
|
|
2509
2459
|
|
|
@@ -2556,9 +2506,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2556
2506
|
print(f" {RED}❌{RESET} Failed to fetch agent template")
|
|
2557
2507
|
return 1
|
|
2558
2508
|
else:
|
|
2559
|
-
print(
|
|
2560
|
-
f" {CYAN}ℹ️{RESET} Skipped agent-handoffs.json (manual setup requested)"
|
|
2561
|
-
)
|
|
2509
|
+
print(f" {CYAN}ℹ️{RESET} Skipped agent-handoffs.json (manual setup requested)")
|
|
2562
2510
|
|
|
2563
2511
|
# Render current-state.json
|
|
2564
2512
|
current_state_template = templates_dir / "current-state.json.template"
|
|
@@ -2573,9 +2521,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2573
2521
|
# Render README.md
|
|
2574
2522
|
readme_template = templates_dir / "README.md.template"
|
|
2575
2523
|
if readme_template.exists():
|
|
2576
|
-
render_template(
|
|
2577
|
-
str(readme_template), ".agent-context/README.md", template_vars
|
|
2578
|
-
)
|
|
2524
|
+
render_template(str(readme_template), ".agent-context/README.md", template_vars)
|
|
2579
2525
|
print(f" {GREEN}✅{RESET} Created .agent-context/README.md")
|
|
2580
2526
|
|
|
2581
2527
|
# Copy AGENT-SYSTEM-GUIDE.md if it exists and isn't already there
|
|
@@ -2614,9 +2560,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2614
2560
|
|
|
2615
2561
|
except Exception as e:
|
|
2616
2562
|
print(f" {YELLOW}⚠️{RESET} Could not update config: {e}")
|
|
2617
|
-
print(
|
|
2618
|
-
f" Manually set task_directory: delegation/tasks/ in .adversarial/config.yml"
|
|
2619
|
-
)
|
|
2563
|
+
print(f" Manually set task_directory: delegation/tasks/ in .adversarial/config.yml")
|
|
2620
2564
|
|
|
2621
2565
|
# 9. Update .gitignore
|
|
2622
2566
|
print()
|
|
@@ -2670,9 +2614,7 @@ def agent_onboard(project_path: str = ".") -> int:
|
|
|
2670
2614
|
verification_checks.append((f"current-state.json invalid: {e}", False))
|
|
2671
2615
|
|
|
2672
2616
|
# Check directories exist
|
|
2673
|
-
verification_checks.append(
|
|
2674
|
-
(".agent-context/ exists", os.path.exists(".agent-context"))
|
|
2675
|
-
)
|
|
2617
|
+
verification_checks.append((".agent-context/ exists", os.path.exists(".agent-context")))
|
|
2676
2618
|
|
|
2677
2619
|
if use_delegation:
|
|
2678
2620
|
verification_checks.append(
|
|
@@ -2777,9 +2719,7 @@ def split(
|
|
|
2777
2719
|
|
|
2778
2720
|
# Check if splitting is recommended
|
|
2779
2721
|
if lines <= max_lines:
|
|
2780
|
-
print(
|
|
2781
|
-
f"{GREEN}✅ File is under recommended limit ({max_lines} lines){RESET}"
|
|
2782
|
-
)
|
|
2722
|
+
print(f"{GREEN}✅ File is under recommended limit ({max_lines} lines){RESET}")
|
|
2783
2723
|
print("No splitting needed.")
|
|
2784
2724
|
return 0
|
|
2785
2725
|
|
|
@@ -2797,9 +2737,7 @@ def split(
|
|
|
2797
2737
|
splits = split_by_phases(content)
|
|
2798
2738
|
print(f"\n💡 Suggested splits (by phases):")
|
|
2799
2739
|
else:
|
|
2800
|
-
print(
|
|
2801
|
-
f"{RED}Error: Unknown strategy '{strategy}'. Use 'sections' or 'phases'.{RESET}"
|
|
2802
|
-
)
|
|
2740
|
+
print(f"{RED}Error: Unknown strategy '{strategy}'. Use 'sections' or 'phases'.{RESET}")
|
|
2803
2741
|
return 1
|
|
2804
2742
|
|
|
2805
2743
|
# Display split preview
|
|
@@ -2971,26 +2909,18 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
2971
2909
|
subparsers.add_parser("doctor", help="Alias for 'check'")
|
|
2972
2910
|
|
|
2973
2911
|
# health command
|
|
2974
|
-
health_parser = subparsers.add_parser(
|
|
2975
|
-
"health", help="Comprehensive system health check"
|
|
2976
|
-
)
|
|
2912
|
+
health_parser = subparsers.add_parser("health", help="Comprehensive system health check")
|
|
2977
2913
|
health_parser.add_argument(
|
|
2978
2914
|
"--verbose", "-v", action="store_true", help="Show detailed diagnostics"
|
|
2979
2915
|
)
|
|
2980
|
-
health_parser.add_argument(
|
|
2981
|
-
"--json", action="store_true", help="Output in JSON format"
|
|
2982
|
-
)
|
|
2916
|
+
health_parser.add_argument("--json", action="store_true", help="Output in JSON format")
|
|
2983
2917
|
|
|
2984
2918
|
# agent command (with subcommands)
|
|
2985
2919
|
agent_parser = subparsers.add_parser("agent", help="Agent coordination commands")
|
|
2986
|
-
agent_subparsers = agent_parser.add_subparsers(
|
|
2987
|
-
dest="agent_subcommand", help="Agent subcommand"
|
|
2988
|
-
)
|
|
2920
|
+
agent_subparsers = agent_parser.add_subparsers(dest="agent_subcommand", help="Agent subcommand")
|
|
2989
2921
|
|
|
2990
2922
|
# agent onboard subcommand
|
|
2991
|
-
onboard_parser = agent_subparsers.add_parser(
|
|
2992
|
-
"onboard", help="Set up agent coordination system"
|
|
2993
|
-
)
|
|
2923
|
+
onboard_parser = agent_subparsers.add_parser("onboard", help="Set up agent coordination system")
|
|
2994
2924
|
onboard_parser.add_argument(
|
|
2995
2925
|
"--path", default=".", help="Project path (default: current directory)"
|
|
2996
2926
|
)
|
|
@@ -2999,12 +2929,8 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
2999
2929
|
subparsers.add_parser("review", help="Run Phase 3: Code review")
|
|
3000
2930
|
|
|
3001
2931
|
# validate command
|
|
3002
|
-
validate_parser = subparsers.add_parser(
|
|
3003
|
-
|
|
3004
|
-
)
|
|
3005
|
-
validate_parser.add_argument(
|
|
3006
|
-
"test_command", nargs="?", help="Test command to run (optional)"
|
|
3007
|
-
)
|
|
2932
|
+
validate_parser = subparsers.add_parser("validate", help="Run Phase 4: Test validation")
|
|
2933
|
+
validate_parser.add_argument("test_command", nargs="?", help="Test command to run (optional)")
|
|
3008
2934
|
|
|
3009
2935
|
# split command
|
|
3010
2936
|
split_parser = subparsers.add_parser(
|
|
@@ -3050,9 +2976,7 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
3050
2976
|
# Only warn for user-defined evaluators, not built-ins
|
|
3051
2977
|
# Built-in conflicts are intentional (e.g., 'review' command vs 'review' evaluator)
|
|
3052
2978
|
if getattr(config, "source", None) != "builtin":
|
|
3053
|
-
logger.warning(
|
|
3054
|
-
"Evaluator '%s' conflicts with CLI command; skipping", name
|
|
3055
|
-
)
|
|
2979
|
+
logger.warning("Evaluator '%s' conflicts with CLI command; skipping", name)
|
|
3056
2980
|
# Mark as registered to prevent alias re-registration attempts
|
|
3057
2981
|
registered_configs.add(id(config))
|
|
3058
2982
|
continue
|
|
@@ -3082,8 +3006,8 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
3082
3006
|
"--timeout",
|
|
3083
3007
|
"-t",
|
|
3084
3008
|
type=int,
|
|
3085
|
-
default=
|
|
3086
|
-
help="Timeout in seconds (default: 180)",
|
|
3009
|
+
default=None,
|
|
3010
|
+
help="Timeout in seconds (default: from evaluator config or 180, max: 600)",
|
|
3087
3011
|
)
|
|
3088
3012
|
# Store config for later execution
|
|
3089
3013
|
eval_parser.set_defaults(evaluator_config=config)
|
|
@@ -3096,10 +3020,34 @@ For more information: https://github.com/movito/adversarial-workflow
|
|
|
3096
3020
|
|
|
3097
3021
|
# Check for evaluator command first (has evaluator_config attribute)
|
|
3098
3022
|
if hasattr(args, "evaluator_config"):
|
|
3023
|
+
# Determine timeout: CLI flag > YAML config > default (180s)
|
|
3024
|
+
if args.timeout is not None:
|
|
3025
|
+
timeout = args.timeout
|
|
3026
|
+
source = "CLI override"
|
|
3027
|
+
elif args.evaluator_config.timeout != 180:
|
|
3028
|
+
timeout = args.evaluator_config.timeout
|
|
3029
|
+
source = "evaluator config"
|
|
3030
|
+
else:
|
|
3031
|
+
timeout = args.evaluator_config.timeout # 180 (default)
|
|
3032
|
+
source = "default"
|
|
3033
|
+
|
|
3034
|
+
# Validate CLI timeout (consistent with YAML validation)
|
|
3035
|
+
if timeout <= 0:
|
|
3036
|
+
print(f"{RED}Error: Timeout must be positive (> 0), got {timeout}{RESET}")
|
|
3037
|
+
return 1
|
|
3038
|
+
if timeout > 600:
|
|
3039
|
+
print(
|
|
3040
|
+
f"{YELLOW}Warning: Timeout {timeout}s exceeds maximum (600s), clamping to 600s{RESET}"
|
|
3041
|
+
)
|
|
3042
|
+
timeout = 600
|
|
3043
|
+
|
|
3044
|
+
# Log actual timeout and source
|
|
3045
|
+
print(f"Using timeout: {timeout}s ({source})")
|
|
3046
|
+
|
|
3099
3047
|
return run_evaluator(
|
|
3100
3048
|
args.evaluator_config,
|
|
3101
3049
|
args.file,
|
|
3102
|
-
timeout=
|
|
3050
|
+
timeout=timeout,
|
|
3103
3051
|
)
|
|
3104
3052
|
|
|
3105
3053
|
# Execute static commands
|
{adversarial_workflow-0.6.2 → adversarial_workflow-0.6.4}/adversarial_workflow/evaluators/config.py
RENAMED
|
@@ -26,6 +26,7 @@ class EvaluatorConfig:
|
|
|
26
26
|
fallback_model: Fallback model if primary fails
|
|
27
27
|
aliases: Alternative command names
|
|
28
28
|
version: Evaluator version
|
|
29
|
+
timeout: Timeout in seconds (default: 180, max: 600)
|
|
29
30
|
source: "builtin" or "local" (set internally)
|
|
30
31
|
config_file: Path to YAML file if local (set internally)
|
|
31
32
|
"""
|
|
@@ -43,6 +44,7 @@ class EvaluatorConfig:
|
|
|
43
44
|
fallback_model: str | None = None
|
|
44
45
|
aliases: list[str] = field(default_factory=list)
|
|
45
46
|
version: str = "1.0.0"
|
|
47
|
+
timeout: int = 180 # Timeout in seconds (default: 180, max: 600)
|
|
46
48
|
|
|
47
49
|
# Metadata (set internally during discovery, not from YAML)
|
|
48
50
|
source: str = "builtin"
|