adversarial-workflow 0.6.6__tar.gz → 0.7.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 (56) hide show
  1. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/PKG-INFO +3 -1
  2. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/__init__.py +1 -1
  3. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/cli.py +159 -1
  4. adversarial_workflow-0.7.0/adversarial_workflow/utils/citations.py +643 -0
  5. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow.egg-info/PKG-INFO +3 -1
  6. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow.egg-info/SOURCES.txt +2 -0
  7. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow.egg-info/requires.txt +2 -0
  8. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/pyproject.toml +4 -1
  9. adversarial_workflow-0.7.0/tests/test_citations.py +525 -0
  10. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/LICENSE +0 -0
  11. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/README.md +0 -0
  12. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/__main__.py +0 -0
  13. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/evaluators/__init__.py +0 -0
  14. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/evaluators/builtins.py +0 -0
  15. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/evaluators/config.py +0 -0
  16. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/evaluators/discovery.py +0 -0
  17. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/evaluators/runner.py +0 -0
  18. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/.aider.conf.yml.template +0 -0
  19. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/.env.example.template +0 -0
  20. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/README.template +0 -0
  21. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/agent-context/AGENT-SYSTEM-GUIDE.md +0 -0
  22. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/agent-context/README.md.template +0 -0
  23. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/agent-context/agent-handoffs-minimal.json.template +0 -0
  24. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/agent-context/agent-handoffs.json.template +0 -0
  25. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/agent-context/current-state.json.template +0 -0
  26. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/config.yml.template +0 -0
  27. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/evaluate_plan.sh.template +0 -0
  28. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/example-task.md.template +0 -0
  29. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/proofread_content.sh.template +0 -0
  30. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/review_implementation.sh.template +0 -0
  31. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/templates/validate_tests.sh.template +0 -0
  32. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/utils/__init__.py +0 -0
  33. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/utils/colors.py +0 -0
  34. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/utils/config.py +0 -0
  35. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/utils/file_splitter.py +0 -0
  36. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow/utils/validation.py +0 -0
  37. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow.egg-info/dependency_links.txt +0 -0
  38. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow.egg-info/entry_points.txt +0 -0
  39. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/adversarial_workflow.egg-info/top_level.txt +0 -0
  40. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/setup.cfg +0 -0
  41. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/setup.py +0 -0
  42. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_cli.py +0 -0
  43. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_cli_dynamic_commands.py +0 -0
  44. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_config.py +0 -0
  45. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_env_loading.py +0 -0
  46. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_evaluate.py +0 -0
  47. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_evaluator_config.py +0 -0
  48. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_evaluator_discovery.py +0 -0
  49. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_evaluator_runner.py +0 -0
  50. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_file_splitter.py +0 -0
  51. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_list_evaluators.py +0 -0
  52. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_python_version.py +0 -0
  53. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_scripts_project.py +0 -0
  54. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_split_command.py +0 -0
  55. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_timeout_integration.py +0 -0
  56. {adversarial_workflow-0.6.6 → adversarial_workflow-0.7.0}/tests/test_utils_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: adversarial-workflow
3
- Version: 0.6.6
3
+ Version: 0.7.0
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
@@ -24,9 +24,11 @@ License-File: LICENSE
24
24
  Requires-Dist: pyyaml>=6.0
25
25
  Requires-Dist: python-dotenv>=0.19.0
26
26
  Requires-Dist: aider-chat>=0.86.0
27
+ Requires-Dist: aiohttp>=3.8.0
27
28
  Provides-Extra: dev
28
29
  Requires-Dist: pytest>=7.0; extra == "dev"
29
30
  Requires-Dist: pytest-cov>=3.0; extra == "dev"
31
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
30
32
  Requires-Dist: black>=22.0; extra == "dev"
31
33
  Requires-Dist: isort>=5.0; extra == "dev"
32
34
  Requires-Dist: flake8>=4.0; extra == "dev"
@@ -12,7 +12,7 @@ Usage:
12
12
  adversarial validate "pytest"
13
13
  """
14
14
 
15
- __version__ = "0.6.6"
15
+ __version__ = "0.7.0"
16
16
  __author__ = "Fredrik Matheson"
17
17
  __license__ = "MIT"
18
18
 
@@ -13,6 +13,7 @@ Commands:
13
13
  review - Run Phase 3: Code review
14
14
  validate - Run Phase 4: Test validation
15
15
  split - Split large task files into smaller evaluable chunks
16
+ check-citations - Verify URLs in documents before evaluation
16
17
  """
17
18
 
18
19
  import argparse
@@ -29,7 +30,7 @@ from typing import Dict, List, Optional, Tuple
29
30
  import yaml
30
31
  from dotenv import dotenv_values, load_dotenv
31
32
 
32
- __version__ = "0.6.6"
33
+ __version__ = "0.7.0"
33
34
 
34
35
  # ANSI color codes for better output
35
36
  RESET = "\033[0m"
@@ -2819,6 +2820,106 @@ def list_evaluators() -> int:
2819
2820
  return 0
2820
2821
 
2821
2822
 
2823
+ def check_citations(
2824
+ file_path: str,
2825
+ output_tasks: Optional[str] = None,
2826
+ mark_inline: bool = False,
2827
+ concurrency: int = 10,
2828
+ timeout: int = 10,
2829
+ ) -> int:
2830
+ """
2831
+ Check citations (URLs) in a document.
2832
+
2833
+ Args:
2834
+ file_path: Path to document to check
2835
+ output_tasks: Optional path to write blocked URL tasks
2836
+ mark_inline: Whether to mark URLs inline with status badges
2837
+ concurrency: Maximum concurrent URL checks
2838
+ timeout: Timeout per URL in seconds
2839
+
2840
+ Returns:
2841
+ 0 on success, 1 on error
2842
+ """
2843
+ from adversarial_workflow.utils.citations import (
2844
+ URLStatus,
2845
+ check_urls,
2846
+ extract_urls,
2847
+ generate_blocked_tasks,
2848
+ mark_urls_inline,
2849
+ print_verification_summary,
2850
+ )
2851
+
2852
+ # Check file exists
2853
+ if not os.path.exists(file_path):
2854
+ print(f"{RED}Error: File not found: {file_path}{RESET}")
2855
+ return 1
2856
+
2857
+ # Validate parameters
2858
+ if concurrency < 1:
2859
+ print(f"{RED}Error: Concurrency must be at least 1, got {concurrency}{RESET}")
2860
+ return 1
2861
+ if timeout < 1:
2862
+ print(f"{RED}Error: Timeout must be at least 1 second, got {timeout}{RESET}")
2863
+ return 1
2864
+
2865
+ print(f"🔗 Checking citations in: {file_path}")
2866
+ print()
2867
+
2868
+ # Read document
2869
+ with open(file_path, encoding="utf-8") as f:
2870
+ document = f.read()
2871
+
2872
+ # Extract URLs
2873
+ extracted = extract_urls(document)
2874
+ urls = [e.url for e in extracted]
2875
+
2876
+ if not urls:
2877
+ print(f"{YELLOW}No URLs found in document.{RESET}")
2878
+ return 0
2879
+
2880
+ print(f" Found {len(urls)} URLs to check")
2881
+ print(f" Checking with concurrency={concurrency}, timeout={timeout}s...")
2882
+ print()
2883
+
2884
+ # Check URLs
2885
+ results = check_urls(
2886
+ urls,
2887
+ concurrency=concurrency,
2888
+ timeout=timeout,
2889
+ )
2890
+
2891
+ # Print summary
2892
+ print_verification_summary(results)
2893
+
2894
+ # Count blocked/broken
2895
+ blocked_count = sum(1 for r in results if r.status in (URLStatus.BLOCKED, URLStatus.BROKEN))
2896
+
2897
+ # Mark document inline if requested
2898
+ if mark_inline and results:
2899
+ marked_document = mark_urls_inline(document, results)
2900
+ if marked_document != document:
2901
+ with open(file_path, "w", encoding="utf-8") as f:
2902
+ f.write(marked_document)
2903
+ print("\n ✅ Updated document with status badges")
2904
+
2905
+ # Generate blocked tasks if requested or if there are blocked URLs
2906
+ if blocked_count > 0:
2907
+ if output_tasks:
2908
+ output_path = Path(output_tasks)
2909
+ else:
2910
+ # Default to .adversarial/blocked-citations/
2911
+ output_dir = Path.cwd() / ".adversarial" / "blocked-citations"
2912
+ output_dir.mkdir(parents=True, exist_ok=True)
2913
+ base_name = Path(file_path).stem
2914
+ output_path = output_dir / f"{base_name}-blocked-urls.md"
2915
+
2916
+ task_content = generate_blocked_tasks(results, file_path, output_path)
2917
+ if task_content:
2918
+ print(f" 📋 Blocked URL tasks: {output_path}")
2919
+
2920
+ return 0
2921
+
2922
+
2822
2923
  def main():
2823
2924
  """Main CLI entry point."""
2824
2925
  import logging
@@ -2862,6 +2963,7 @@ def main():
2862
2963
  "validate",
2863
2964
  "review",
2864
2965
  "list-evaluators",
2966
+ "check-citations",
2865
2967
  }
2866
2968
 
2867
2969
  parser = argparse.ArgumentParser(
@@ -2879,6 +2981,7 @@ Examples:
2879
2981
  adversarial review # Review implementation
2880
2982
  adversarial validate "npm test" # Validate with tests
2881
2983
  adversarial split large-task.md # Split large files
2984
+ adversarial check-citations doc.md # Verify URLs in document
2882
2985
 
2883
2986
  For more information: https://github.com/movito/adversarial-workflow
2884
2987
  """,
@@ -2961,6 +3064,38 @@ For more information: https://github.com/movito/adversarial-workflow
2961
3064
  help="List all available evaluators (built-in and local)",
2962
3065
  )
2963
3066
 
3067
+ # check-citations command
3068
+ citations_parser = subparsers.add_parser(
3069
+ "check-citations",
3070
+ help="Verify URLs in a document before evaluation",
3071
+ )
3072
+ citations_parser.add_argument("file", help="Document to check citations in")
3073
+ citations_parser.add_argument(
3074
+ "--output-tasks",
3075
+ "-o",
3076
+ help="Output file for blocked URL tasks (markdown)",
3077
+ )
3078
+ citations_parser.add_argument(
3079
+ "--mark-inline",
3080
+ action="store_true",
3081
+ default=False,
3082
+ help="Mark URLs inline with status badges (modifies document)",
3083
+ )
3084
+ citations_parser.add_argument(
3085
+ "--concurrency",
3086
+ "-c",
3087
+ type=int,
3088
+ default=10,
3089
+ help="Maximum concurrent URL checks (default: 10)",
3090
+ )
3091
+ citations_parser.add_argument(
3092
+ "--timeout",
3093
+ "-t",
3094
+ type=int,
3095
+ default=10,
3096
+ help="Timeout per URL in seconds (default: 10)",
3097
+ )
3098
+
2964
3099
  # Dynamic evaluator registration
2965
3100
  try:
2966
3101
  evaluators = get_all_evaluators()
@@ -3009,6 +3144,11 @@ For more information: https://github.com/movito/adversarial-workflow
3009
3144
  default=None,
3010
3145
  help="Timeout in seconds (default: from evaluator config or 180, max: 600)",
3011
3146
  )
3147
+ eval_parser.add_argument(
3148
+ "--check-citations",
3149
+ action="store_true",
3150
+ help="Verify URLs in document before evaluation",
3151
+ )
3012
3152
  # Store config for later execution
3013
3153
  eval_parser.set_defaults(evaluator_config=config)
3014
3154
 
@@ -3044,6 +3184,16 @@ For more information: https://github.com/movito/adversarial-workflow
3044
3184
  # Log actual timeout and source
3045
3185
  print(f"Using timeout: {timeout}s ({source})")
3046
3186
 
3187
+ # Check citations first if requested (read-only, doesn't modify file)
3188
+ if getattr(args, "check_citations", False):
3189
+ print()
3190
+ result = check_citations(args.file, mark_inline=False)
3191
+ if result != 0:
3192
+ print(
3193
+ f"{YELLOW}Warning: Citation check had issues, continuing with evaluation...{RESET}"
3194
+ )
3195
+ print()
3196
+
3047
3197
  return run_evaluator(
3048
3198
  args.evaluator_config,
3049
3199
  args.file,
@@ -3083,6 +3233,14 @@ For more information: https://github.com/movito/adversarial-workflow
3083
3233
  )
3084
3234
  elif args.command == "list-evaluators":
3085
3235
  return list_evaluators()
3236
+ elif args.command == "check-citations":
3237
+ return check_citations(
3238
+ args.file,
3239
+ output_tasks=args.output_tasks,
3240
+ mark_inline=args.mark_inline,
3241
+ concurrency=args.concurrency,
3242
+ timeout=args.timeout,
3243
+ )
3086
3244
  else:
3087
3245
  parser.print_help()
3088
3246
  return 1