devagent-ai 0.8.3__tar.gz → 0.8.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.
Files changed (88) hide show
  1. {devagent_ai-0.8.3/devagent_ai.egg-info → devagent_ai-0.8.4}/PKG-INFO +34 -1
  2. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/README.md +33 -0
  3. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/__init__.py +1 -1
  4. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/cli.py +91 -4
  5. {devagent_ai-0.8.3 → devagent_ai-0.8.4/devagent_ai.egg-info}/PKG-INFO +34 -1
  6. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/SOURCES.txt +1 -0
  7. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/pyproject.toml +1 -1
  8. devagent_ai-0.8.4/tests/test_cli_progress.py +91 -0
  9. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_production_v040.py +1 -1
  10. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/LICENSE +0 -0
  11. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/NOTICE +0 -0
  12. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/__init__.py +0 -0
  13. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/llm.py +0 -0
  14. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/loop.py +0 -0
  15. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/memory.py +0 -0
  16. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/prompts.py +0 -0
  17. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/tools.py +0 -0
  18. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/__main__.py +0 -0
  19. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/artifacts.py +0 -0
  20. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/automations.py +0 -0
  21. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/autonomy.py +0 -0
  22. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/browser.py +0 -0
  23. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/config.py +0 -0
  24. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/discovery.py +0 -0
  25. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/evaluation.py +0 -0
  26. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/memory.py +0 -0
  27. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/models.py +0 -0
  28. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/orchestrator.py +0 -0
  29. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/provider_benchmark.py +0 -0
  30. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/providers.py +0 -0
  31. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/qualification.py +0 -0
  32. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/realworld.py +0 -0
  33. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/report.py +0 -0
  34. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/retrieval.py +0 -0
  35. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/routing.py +0 -0
  36. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/runtime.py +0 -0
  37. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/safety.py +0 -0
  38. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/skills.py +0 -0
  39. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/source_control.py +0 -0
  40. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/state_machine.py +0 -0
  41. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/tasking.py +0 -0
  42. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/technical_review.py +0 -0
  43. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/workspace.py +0 -0
  44. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/worktree.py +0 -0
  45. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/dependency_links.txt +0 -0
  46. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/entry_points.txt +0 -0
  47. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/requires.txt +0 -0
  48. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/top_level.txt +0 -0
  49. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/setup.cfg +0 -0
  50. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_acceptance_contract.py +0 -0
  51. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_benchmark_catalog.py +0 -0
  52. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_browser_verification.py +0 -0
  53. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_capability_discovery.py +0 -0
  54. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_cli.py +0 -0
  55. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_developer_review_report.py +0 -0
  56. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_discovery_memory.py +0 -0
  57. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_e2e_fake_provider.py +0 -0
  58. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_evaluation_harness.py +0 -0
  59. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_evaluation_matrix.py +0 -0
  60. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_evaluation_regression_evidence.py +0 -0
  61. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_functional_qualification.py +0 -0
  62. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_huge_monorepo_v070.py +0 -0
  63. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_migration_e2e_v070.py +0 -0
  64. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_model_routing.py +0 -0
  65. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_multilang_technical_review.py +0 -0
  66. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_multistack_devagent_e2e.py +0 -0
  67. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_multistack_qualification.py +0 -0
  68. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_packaging_metadata.py +0 -0
  69. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_plan_verification_normalization.py +0 -0
  70. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_preservation_contradiction.py +0 -0
  71. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_production_hardening.py +0 -0
  72. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_realworld_benchmark.py +0 -0
  73. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_requirement_compiler_v082.py +0 -0
  74. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_requirement_intelligence_v083.py +0 -0
  75. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_retrieval.py +0 -0
  76. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_runtime_sandbox.py +0 -0
  77. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_safety_workspace.py +0 -0
  78. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_source_control_publish.py +0 -0
  79. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_structural_devagent_e2e_v070.py +0 -0
  80. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_structural_operations.py +0 -0
  81. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_structured_provider_contract.py +0 -0
  82. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_tasking_state.py +0 -0
  83. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_v070_engineering_breadth.py +0 -0
  84. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_v080_autonomy.py +0 -0
  85. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_v080_provider_benchmark.py +0 -0
  86. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_v080_skills_automations.py +0 -0
  87. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_workspace_environment.py +0 -0
  88. {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_worktree.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devagent-ai
3
- Version: 0.8.3
3
+ Version: 0.8.4
4
4
  Summary: Evidence-driven local autonomous software engineering agent
5
5
  Author: Tom Ha
6
6
  Maintainer: Tom Ha
@@ -152,6 +152,39 @@ reviewer → independently review final diff
152
152
 
153
153
  The deterministic harness remains responsible for safety, tool execution, verification validity, acceptance adjudication, final status, reporting, and source-control publication regardless of which model handles a role.
154
154
 
155
+ #### Example: use multiple AI models in one DevAgent run
156
+
157
+ You do not have to use one AI model for every reasoning step. If you believe different models are better suited to different engineering roles, configure a default model plus any role-specific overrides. Roles that are not explicitly configured fall back to the default model.
158
+
159
+ ```bash
160
+ # Keep credentials in environment variables; DevAgent does not store the keys.
161
+ export OPENAI_API_KEY=...
162
+ export GEMINI_API_KEY=...
163
+ export ANTHROPIC_API_KEY=...
164
+ export XAI_API_KEY=...
165
+
166
+ # Default/fallback model.
167
+ devagent setup --provider openai --model YOUR_OPENAI_MODEL
168
+
169
+ # Optional per-role models.
170
+ devagent setup --role investigator --provider gemini --model YOUR_GEMINI_MODEL
171
+ devagent setup --role planner --provider anthropic --model YOUR_CLAUDE_MODEL
172
+ devagent setup --role implementer --provider openai --model YOUR_OPENAI_MODEL
173
+ devagent setup --role reviewer --provider xai --model YOUR_GROK_MODEL
174
+
175
+ # Inspect routing and optionally probe every configured cloud model.
176
+ devagent models
177
+ devagent doctor --live
178
+
179
+ # Run normally; saved role routing is applied automatically.
180
+ cd my-repo
181
+ devagent "Fix the checkout race condition and add regression coverage."
182
+ ```
183
+
184
+ For example, a user may choose a fast or lower-cost model for repository investigation, a different model for planning, a preferred coding model for implementation, and another provider for independent review. This can be useful for cost, latency, provider diversity, or model-strength preferences, but it does not guarantee a better result. DevAgent still requires the same repository evidence, acceptance gates, deterministic verification, and publication rules.
185
+
186
+ When using saved role routing, run the task without run-level `--provider`, `--model`, or `--base-url` overrides. Supplying those flags explicitly selects one provider/model for that run instead of the saved per-role routing.
187
+
155
188
  ## Run
156
189
 
157
190
  From the application repository:
@@ -121,6 +121,39 @@ reviewer → independently review final diff
121
121
 
122
122
  The deterministic harness remains responsible for safety, tool execution, verification validity, acceptance adjudication, final status, reporting, and source-control publication regardless of which model handles a role.
123
123
 
124
+ #### Example: use multiple AI models in one DevAgent run
125
+
126
+ You do not have to use one AI model for every reasoning step. If you believe different models are better suited to different engineering roles, configure a default model plus any role-specific overrides. Roles that are not explicitly configured fall back to the default model.
127
+
128
+ ```bash
129
+ # Keep credentials in environment variables; DevAgent does not store the keys.
130
+ export OPENAI_API_KEY=...
131
+ export GEMINI_API_KEY=...
132
+ export ANTHROPIC_API_KEY=...
133
+ export XAI_API_KEY=...
134
+
135
+ # Default/fallback model.
136
+ devagent setup --provider openai --model YOUR_OPENAI_MODEL
137
+
138
+ # Optional per-role models.
139
+ devagent setup --role investigator --provider gemini --model YOUR_GEMINI_MODEL
140
+ devagent setup --role planner --provider anthropic --model YOUR_CLAUDE_MODEL
141
+ devagent setup --role implementer --provider openai --model YOUR_OPENAI_MODEL
142
+ devagent setup --role reviewer --provider xai --model YOUR_GROK_MODEL
143
+
144
+ # Inspect routing and optionally probe every configured cloud model.
145
+ devagent models
146
+ devagent doctor --live
147
+
148
+ # Run normally; saved role routing is applied automatically.
149
+ cd my-repo
150
+ devagent "Fix the checkout race condition and add regression coverage."
151
+ ```
152
+
153
+ For example, a user may choose a fast or lower-cost model for repository investigation, a different model for planning, a preferred coding model for implementation, and another provider for independent review. This can be useful for cost, latency, provider diversity, or model-strength preferences, but it does not guarantee a better result. DevAgent still requires the same repository evidence, acceptance gates, deterministic verification, and publication rules.
154
+
155
+ When using saved role routing, run the task without run-level `--provider`, `--model`, or `--base-url` overrides. Supplying those flags explicitly selects one provider/model for that run instead of the saved per-role routing.
156
+
124
157
  ## Run
125
158
 
126
159
  From the application repository:
@@ -1,3 +1,3 @@
1
1
  """DevAgent: evidence-driven local software engineering automation."""
2
2
 
3
- __version__ = "0.8.3"
3
+ __version__ = "0.8.4"
@@ -4,10 +4,11 @@ import argparse
4
4
  import importlib.util
5
5
  import json
6
6
  import os
7
+ import re
7
8
  import shutil
8
9
  import sys
9
10
  from pathlib import Path
10
- from typing import Sequence
11
+ from typing import Callable, Sequence
11
12
 
12
13
  from devagent import __version__
13
14
  from devagent.config import (
@@ -37,6 +38,84 @@ _LIVE_PROBE_SCHEMA = {
37
38
  "additionalProperties": False,
38
39
  }
39
40
 
41
+ _PROGRESS_STAGES: dict[str, tuple[int, str]] = {
42
+ "DISCOVER": (1, "DISCOVER / UNDERSTAND"),
43
+ "UNDERSTAND": (1, "DISCOVER / UNDERSTAND"),
44
+ "TASK_SPEC": (2, "REQUIREMENTS / PLAN"),
45
+ "BASELINE": (2, "REQUIREMENTS / PLAN"),
46
+ "PLAN": (2, "REQUIREMENTS / PLAN"),
47
+ "GATHER_CONTEXT": (2, "REQUIREMENTS / PLAN"),
48
+ "REPRODUCE": (2, "REQUIREMENTS / PLAN"),
49
+ "IMPLEMENT": (3, "IMPLEMENT"),
50
+ "VERIFY_TARGETED": (4, "VERIFY / REPAIR IF NEEDED"),
51
+ "VERIFY_BROAD": (4, "VERIFY / REPAIR IF NEEDED"),
52
+ "REVIEW": (5, "INDEPENDENT REVIEW"),
53
+ "QUALITY_CHECK": (6, "FINAL VERIFICATION"),
54
+ "FINAL_VERIFY": (6, "FINAL VERIFICATION"),
55
+ }
56
+ _STATE_LINE = re.compile(r"^\[([A-Z_]+)\]$")
57
+
58
+
59
+ class _ProgressStatus:
60
+ """Render stable user-facing milestones while keeping full diagnostics opt-in."""
61
+
62
+ def __init__(
63
+ self,
64
+ sink: Callable[[str], None] = print,
65
+ *,
66
+ verbose: bool = False,
67
+ ) -> None:
68
+ self.sink = sink
69
+ self.verbose = verbose
70
+ self._last_stage = 0
71
+ self._plan_seen = False
72
+ self._implement_seen = False
73
+ self._review_seen = False
74
+
75
+ def __call__(self, message: str) -> None:
76
+ if self.verbose:
77
+ self.sink(message)
78
+ return
79
+
80
+ match = _STATE_LINE.fullmatch(message)
81
+ if match is None:
82
+ return
83
+ state = match.group(1)
84
+
85
+ if state == "DIAGNOSE":
86
+ self.sink(" ↳ DIAGNOSE")
87
+ return
88
+ if state == "PLAN":
89
+ if self._plan_seen:
90
+ self.sink(" ↳ REPLAN")
91
+ return
92
+ self._plan_seen = True
93
+ if state == "IMPLEMENT":
94
+ if self._implement_seen:
95
+ label = "APPLY REVIEW FIXES" if self._review_seen else "APPLY CORRECTION"
96
+ self.sink(f" ↳ {label}")
97
+ return
98
+ self._implement_seen = True
99
+ if state == "REVIEW":
100
+ self._review_seen = True
101
+
102
+ stage = _PROGRESS_STAGES.get(state)
103
+ if stage is None:
104
+ return
105
+ number, label = stage
106
+ if number <= self._last_stage:
107
+ return
108
+ self._last_stage = number
109
+ self.sink(f"[{number}/7] {label}")
110
+
111
+ def report(self) -> None:
112
+ if self.verbose:
113
+ self.sink("[ENGINEERING_REPORT]")
114
+ return
115
+ if self._last_stage < 7:
116
+ self._last_stage = 7
117
+ self.sink("[7/7] ENGINEERING REPORT")
118
+
40
119
 
41
120
  def _top_parser() -> argparse.ArgumentParser:
42
121
  parser = argparse.ArgumentParser(prog="devagent", description="Evidence-driven local software engineering agent")
@@ -53,7 +132,11 @@ def _top_parser() -> argparse.ArgumentParser:
53
132
  parser.add_argument("--provider", choices=_PROVIDER_CHOICES)
54
133
  parser.add_argument("--model")
55
134
  parser.add_argument("--base-url")
56
- parser.add_argument("--verbose", action="store_true", help="Show state transitions")
135
+ parser.add_argument(
136
+ "--verbose",
137
+ action="store_true",
138
+ help="Show internal state transitions and diagnostics instead of concise progress stages",
139
+ )
57
140
  parser.add_argument("--no-isolation", action="store_true", help="Work in place instead of creating a local detached worktree")
58
141
  parser.add_argument(
59
142
  "--publish",
@@ -337,11 +420,14 @@ def _run(argv: Sequence[str]) -> int:
337
420
  from devagent.orchestrator import DevAgent
338
421
  from devagent.report import recommendations_for, render_report
339
422
 
423
+ progress = _ProgressStatus(print, verbose=args.verbose)
340
424
  result = DevAgent(
341
425
  model_provider,
342
426
  isolate=not args.no_isolation,
343
- verbose=args.verbose,
344
- status=print,
427
+ # Internal status events are always emitted. The progress reporter keeps normal
428
+ # CLI output concise and passes the full state/diagnostic stream only in --verbose.
429
+ verbose=True,
430
+ status=progress,
345
431
  base_commit=publication_plan.base_commit if publication_plan else None,
346
432
  ).run(args.repo, requirement)
347
433
 
@@ -361,6 +447,7 @@ def _run(argv: Sequence[str]) -> int:
361
447
 
362
448
  # The full engineering report is intentionally emitted before any Git commit/push.
363
449
  result.recommendations = recommendations_for(result)
450
+ progress.report()
364
451
  print(render_report(result))
365
452
 
366
453
  if publish_requested:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devagent-ai
3
- Version: 0.8.3
3
+ Version: 0.8.4
4
4
  Summary: Evidence-driven local autonomous software engineering agent
5
5
  Author: Tom Ha
6
6
  Maintainer: Tom Ha
@@ -152,6 +152,39 @@ reviewer → independently review final diff
152
152
 
153
153
  The deterministic harness remains responsible for safety, tool execution, verification validity, acceptance adjudication, final status, reporting, and source-control publication regardless of which model handles a role.
154
154
 
155
+ #### Example: use multiple AI models in one DevAgent run
156
+
157
+ You do not have to use one AI model for every reasoning step. If you believe different models are better suited to different engineering roles, configure a default model plus any role-specific overrides. Roles that are not explicitly configured fall back to the default model.
158
+
159
+ ```bash
160
+ # Keep credentials in environment variables; DevAgent does not store the keys.
161
+ export OPENAI_API_KEY=...
162
+ export GEMINI_API_KEY=...
163
+ export ANTHROPIC_API_KEY=...
164
+ export XAI_API_KEY=...
165
+
166
+ # Default/fallback model.
167
+ devagent setup --provider openai --model YOUR_OPENAI_MODEL
168
+
169
+ # Optional per-role models.
170
+ devagent setup --role investigator --provider gemini --model YOUR_GEMINI_MODEL
171
+ devagent setup --role planner --provider anthropic --model YOUR_CLAUDE_MODEL
172
+ devagent setup --role implementer --provider openai --model YOUR_OPENAI_MODEL
173
+ devagent setup --role reviewer --provider xai --model YOUR_GROK_MODEL
174
+
175
+ # Inspect routing and optionally probe every configured cloud model.
176
+ devagent models
177
+ devagent doctor --live
178
+
179
+ # Run normally; saved role routing is applied automatically.
180
+ cd my-repo
181
+ devagent "Fix the checkout race condition and add regression coverage."
182
+ ```
183
+
184
+ For example, a user may choose a fast or lower-cost model for repository investigation, a different model for planning, a preferred coding model for implementation, and another provider for independent review. This can be useful for cost, latency, provider diversity, or model-strength preferences, but it does not guarantee a better result. DevAgent still requires the same repository evidence, acceptance gates, deterministic verification, and publication rules.
185
+
186
+ When using saved role routing, run the task without run-level `--provider`, `--model`, or `--base-url` overrides. Supplying those flags explicitly selects one provider/model for that run instead of the saved per-role routing.
187
+
155
188
  ## Run
156
189
 
157
190
  From the application repository:
@@ -48,6 +48,7 @@ tests/test_benchmark_catalog.py
48
48
  tests/test_browser_verification.py
49
49
  tests/test_capability_discovery.py
50
50
  tests/test_cli.py
51
+ tests/test_cli_progress.py
51
52
  tests/test_developer_review_report.py
52
53
  tests/test_discovery_memory.py
53
54
  tests/test_e2e_fake_provider.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devagent-ai"
7
- version = "0.8.3"
7
+ version = "0.8.4"
8
8
  description = "Evidence-driven local autonomous software engineering agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ from devagent.cli import _ProgressStatus
4
+
5
+
6
+ def test_default_progress_reports_only_stable_engineering_milestones() -> None:
7
+ output: list[str] = []
8
+ progress = _ProgressStatus(output.append)
9
+
10
+ events = [
11
+ "[PREFLIGHT]",
12
+ "[WORKTREE] source: /tmp/repo",
13
+ "[DISCOVER]",
14
+ "[DISCOVER] repository files: 120",
15
+ "[UNDERSTAND]",
16
+ "[RETRIEVAL] selected: src/service.py",
17
+ "[TASK_SPEC]",
18
+ "[BASELINE]",
19
+ "[PLAN]",
20
+ "[GATHER_CONTEXT]",
21
+ "[REPRODUCE]",
22
+ "[IMPLEMENT]",
23
+ "[VERIFY_TARGETED]",
24
+ "[DIAGNOSE]",
25
+ "[PLAN]",
26
+ "[GATHER_CONTEXT]",
27
+ "[IMPLEMENT]",
28
+ "[VERIFY_TARGETED]",
29
+ "[VERIFY_BROAD]",
30
+ "[REVIEW]",
31
+ "[QUALITY_CHECK]",
32
+ "[FINAL_VERIFY]",
33
+ "[REPORT]",
34
+ ]
35
+ for event in events:
36
+ progress(event)
37
+ progress.report()
38
+
39
+ assert output == [
40
+ "[1/7] DISCOVER / UNDERSTAND",
41
+ "[2/7] REQUIREMENTS / PLAN",
42
+ "[3/7] IMPLEMENT",
43
+ "[4/7] VERIFY / REPAIR IF NEEDED",
44
+ " ↳ DIAGNOSE",
45
+ " ↳ REPLAN",
46
+ " ↳ APPLY CORRECTION",
47
+ "[5/7] INDEPENDENT REVIEW",
48
+ "[6/7] FINAL VERIFICATION",
49
+ "[7/7] ENGINEERING REPORT",
50
+ ]
51
+
52
+
53
+ def test_review_correction_is_named_without_replaying_completed_stages() -> None:
54
+ output: list[str] = []
55
+ progress = _ProgressStatus(output.append)
56
+
57
+ for event in (
58
+ "[DISCOVER]",
59
+ "[TASK_SPEC]",
60
+ "[PLAN]",
61
+ "[IMPLEMENT]",
62
+ "[VERIFY_TARGETED]",
63
+ "[REVIEW]",
64
+ "[IMPLEMENT]",
65
+ "[VERIFY_TARGETED]",
66
+ "[REVIEW]",
67
+ "[FINAL_VERIFY]",
68
+ ):
69
+ progress(event)
70
+ progress.report()
71
+
72
+ assert " ↳ APPLY REVIEW FIXES" in output
73
+ assert output.count("[3/7] IMPLEMENT") == 1
74
+ assert output.count("[4/7] VERIFY / REPAIR IF NEEDED") == 1
75
+ assert output.count("[5/7] INDEPENDENT REVIEW") == 1
76
+
77
+
78
+ def test_verbose_progress_preserves_internal_state_and_diagnostics() -> None:
79
+ output: list[str] = []
80
+ progress = _ProgressStatus(output.append, verbose=True)
81
+
82
+ events = [
83
+ "[DISCOVER]",
84
+ "[WORKTREE] source: /tmp/repo",
85
+ "[RETRIEVAL] selected: src/service.py",
86
+ ]
87
+ for event in events:
88
+ progress(event)
89
+ progress.report()
90
+
91
+ assert output == [*events, "[ENGINEERING_REPORT]"]
@@ -62,7 +62,7 @@ def test_release_version_is_semver_and_consistent() -> None:
62
62
  version = match.group(1)
63
63
  assert re.fullmatch(r"\d+\.\d+\.\d+", version)
64
64
  assert version == __version__
65
- assert version == "0.8.3"
65
+ assert version == "0.8.4"
66
66
 
67
67
 
68
68
  def test_release_workflow_requires_green_exact_main_revision() -> None:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes