devcouncil 0.1.0 → 0.1.1
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/LICENSE +201 -201
- package/README.md +62 -543
- package/package.json +1 -1
- package/pyproject.toml +29 -26
- package/src/devcouncil/__main__.py +4 -4
- package/src/devcouncil/app/__init__.py +28 -28
- package/src/devcouncil/app/config.py +135 -108
- package/src/devcouncil/app/errors.py +23 -23
- package/src/devcouncil/app/events.py +44 -44
- package/src/devcouncil/app/orchestrator.py +67 -67
- package/src/devcouncil/app/project_status.py +29 -0
- package/src/devcouncil/app/run_context.py +39 -39
- package/src/devcouncil/app/state_machine.py +108 -108
- package/src/devcouncil/artifacts/__init__.py +1 -1
- package/src/devcouncil/artifacts/coverage.py +96 -96
- package/src/devcouncil/artifacts/graph.py +143 -143
- package/src/devcouncil/artifacts/migrations.py +20 -20
- package/src/devcouncil/artifacts/schemas.py +23 -23
- package/src/devcouncil/artifacts/serializer.py +21 -21
- package/src/devcouncil/artifacts/validators.py +27 -27
- package/src/devcouncil/cli/commands/artifacts.py +51 -48
- package/src/devcouncil/cli/commands/ast.py +22 -0
- package/src/devcouncil/cli/commands/baseline.py +35 -32
- package/src/devcouncil/cli/commands/config.py +76 -54
- package/src/devcouncil/cli/commands/dashboard.py +26 -0
- package/src/devcouncil/cli/commands/doctor.py +86 -42
- package/src/devcouncil/cli/commands/go.py +237 -0
- package/src/devcouncil/cli/commands/hook.py +96 -29
- package/src/devcouncil/cli/commands/init.py +67 -56
- package/src/devcouncil/cli/commands/integrate.py +320 -14
- package/src/devcouncil/cli/commands/lsp.py +20 -0
- package/src/devcouncil/cli/commands/map.py +25 -21
- package/src/devcouncil/cli/commands/plan.py +257 -206
- package/src/devcouncil/cli/commands/prompt.py +36 -33
- package/src/devcouncil/cli/commands/repair.py +72 -69
- package/src/devcouncil/cli/commands/report.py +112 -54
- package/src/devcouncil/cli/commands/reset_demo_state.py +31 -28
- package/src/devcouncil/cli/commands/rollback.py +49 -47
- package/src/devcouncil/cli/commands/run.py +252 -207
- package/src/devcouncil/cli/commands/setup.py +159 -18
- package/src/devcouncil/cli/commands/show.py +76 -57
- package/src/devcouncil/cli/commands/status.py +117 -105
- package/src/devcouncil/cli/commands/tasks.py +55 -41
- package/src/devcouncil/cli/commands/trace.py +2 -1
- package/src/devcouncil/cli/commands/verify.py +158 -128
- package/src/devcouncil/cli/commands/version.py +20 -20
- package/src/devcouncil/cli/commands/watch.py +574 -0
- package/src/devcouncil/cli/main.py +42 -24
- package/src/devcouncil/council/prompts/arbiter.md +19 -19
- package/src/devcouncil/council/prompts/critic_a.md +10 -10
- package/src/devcouncil/council/prompts/critic_b.md +10 -10
- package/src/devcouncil/council/prompts/implementation_reviewer.md +16 -16
- package/src/devcouncil/council/prompts/planner_a.md +16 -16
- package/src/devcouncil/council/prompts/planner_b.md +16 -16
- package/src/devcouncil/council/prompts/rebuttal.md +10 -10
- package/src/devcouncil/council/prompts/spec_writer.md +12 -12
- package/src/devcouncil/domain/assumption.py +17 -17
- package/src/devcouncil/domain/critique.py +32 -32
- package/src/devcouncil/domain/evidence.py +27 -27
- package/src/devcouncil/domain/gap.py +26 -26
- package/src/devcouncil/domain/requirement.py +22 -22
- package/src/devcouncil/domain/task.py +26 -26
- package/src/devcouncil/execution/__init__.py +1 -1
- package/src/devcouncil/execution/context_builder.py +54 -54
- package/src/devcouncil/execution/executor.py +15 -15
- package/src/devcouncil/execution/hook_policy.py +24 -3
- package/src/devcouncil/execution/patch.py +28 -28
- package/src/devcouncil/execution/permissions.py +44 -44
- package/src/devcouncil/execution/prompt_builder.py +23 -23
- package/src/devcouncil/execution/task_runner.py +63 -63
- package/src/devcouncil/executors/__init__.py +1 -1
- package/src/devcouncil/executors/coding_cli.py +112 -0
- package/src/devcouncil/executors/mini_swe.py +63 -63
- package/src/devcouncil/executors/native/agent.py +81 -81
- package/src/devcouncil/executors/openhands.py +56 -56
- package/src/devcouncil/gating/__init__.py +1 -1
- package/src/devcouncil/gating/checks/clean_git.py +50 -45
- package/src/devcouncil/gating/checks/planned_files_check.py +32 -32
- package/src/devcouncil/gating/checks/requirement_coverage.py +26 -26
- package/src/devcouncil/gating/checks/secret_scan_check.py +34 -34
- package/src/devcouncil/gating/policy.py +157 -157
- package/src/devcouncil/indexing/__init__.py +1 -1
- package/src/devcouncil/indexing/ast_matcher.py +168 -0
- package/src/devcouncil/indexing/graph_index.py +48 -48
- package/src/devcouncil/indexing/lsp.py +120 -0
- package/src/devcouncil/indexing/repo_mapper.py +208 -204
- package/src/devcouncil/integrations/github.py +35 -35
- package/src/devcouncil/integrations/gitnexus.py +27 -27
- package/src/devcouncil/integrations/graphify.py +34 -34
- package/src/devcouncil/integrations/mcp/server.py +549 -96
- package/src/devcouncil/integrations/pr_comments.py +62 -0
- package/src/devcouncil/live/__init__.py +2 -0
- package/src/devcouncil/live/cards.py +207 -0
- package/src/devcouncil/live/models.py +63 -0
- package/src/devcouncil/live/repair_prompt.py +83 -0
- package/src/devcouncil/live/reviewer.py +70 -0
- package/src/devcouncil/live/signals.py +135 -0
- package/src/devcouncil/live/summary.py +34 -0
- package/src/devcouncil/live/tasks.py +18 -0
- package/src/devcouncil/live/transcripts.py +138 -0
- package/src/devcouncil/llm/__init__.py +1 -1
- package/src/devcouncil/llm/cache.py +38 -38
- package/src/devcouncil/llm/provider.py +146 -125
- package/src/devcouncil/llm/router.py +111 -111
- package/src/devcouncil/planning/__init__.py +1 -1
- package/src/devcouncil/planning/arbiter_service.py +57 -57
- package/src/devcouncil/planning/critique_service.py +66 -66
- package/src/devcouncil/planning/plan_service.py +46 -46
- package/src/devcouncil/planning/prompt_enhancer_service.py +86 -0
- package/src/devcouncil/planning/repair_service.py +39 -39
- package/src/devcouncil/planning/spec_service.py +44 -44
- package/src/devcouncil/reporting/github_check.py +32 -32
- package/src/devcouncil/reporting/json_report.py +20 -17
- package/src/devcouncil/reporting/markdown_report.py +68 -46
- package/src/devcouncil/reporting/report_builder.py +14 -14
- package/src/devcouncil/storage/db.py +66 -66
- package/src/devcouncil/storage/models.py +83 -83
- package/src/devcouncil/storage/repositories.py +299 -222
- package/src/devcouncil/telemetry/cost.py +34 -34
- package/src/devcouncil/telemetry/tracker.py +49 -49
- package/src/devcouncil/ui/__init__.py +1 -0
- package/src/devcouncil/ui/dashboard.py +122 -0
- package/src/devcouncil/utils/__init__.py +1 -1
- package/src/devcouncil/utils/redaction.py +141 -141
- package/src/devcouncil/verification/__init__.py +1 -1
- package/src/devcouncil/verification/implementation_reviewer.py +55 -55
- package/src/devcouncil/verification/verifier.py +319 -302
- package/uv.lock +1 -1
|
@@ -1,224 +1,269 @@
|
|
|
1
1
|
import typer
|
|
2
2
|
import json
|
|
3
|
-
from rich.console import Console
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from devcouncil.storage.db import get_db
|
|
6
|
-
from devcouncil.storage.repositories import TaskRepository, RequirementRepository
|
|
7
|
-
from devcouncil.executors.mini_swe import MiniSWEExecutor
|
|
8
|
-
from devcouncil.executors.openhands import OpenHandsExecutor
|
|
9
|
-
from devcouncil.executors.
|
|
10
|
-
from devcouncil.
|
|
11
|
-
from devcouncil.llm.
|
|
12
|
-
from devcouncil.
|
|
13
|
-
from devcouncil.
|
|
14
|
-
from devcouncil.
|
|
15
|
-
from devcouncil.
|
|
16
|
-
from devcouncil.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from devcouncil.storage.db import get_db
|
|
6
|
+
from devcouncil.storage.repositories import TaskRepository, RequirementRepository
|
|
7
|
+
from devcouncil.executors.mini_swe import MiniSWEExecutor
|
|
8
|
+
from devcouncil.executors.openhands import OpenHandsExecutor
|
|
9
|
+
from devcouncil.executors.coding_cli import CodingCliExecutor
|
|
10
|
+
from devcouncil.executors.native.agent import NativeAgent
|
|
11
|
+
from devcouncil.llm.provider import create_provider, validate_model_provider
|
|
12
|
+
from devcouncil.llm.router import ModelRouter
|
|
13
|
+
from devcouncil.app.config import load_config, get_api_key
|
|
14
|
+
from devcouncil.domain.evidence import CommandResult, DiffEvidence, TestEvidence
|
|
15
|
+
from devcouncil.storage.repositories import GapRepository, EvidenceRepository, StateRepository
|
|
16
|
+
from devcouncil.verification.verifier import Verifier
|
|
17
|
+
from devcouncil.app.state_machine import ProjectPhase
|
|
18
|
+
from devcouncil.cli.commands.init import initialize_project
|
|
19
|
+
|
|
20
|
+
console = Console()
|
|
21
|
+
CODING_EXECUTOR_ALIASES = {
|
|
22
|
+
"codex": "codex",
|
|
23
|
+
"codex-cli": "codex",
|
|
24
|
+
"gemini": "gemini",
|
|
25
|
+
"gemini-cli": "gemini",
|
|
26
|
+
"claude": "claude",
|
|
27
|
+
"claude-code": "claude",
|
|
28
|
+
"claude-cli": "claude",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
CODING_EXECUTORS = set(CODING_EXECUTOR_ALIASES.keys())
|
|
32
|
+
|
|
33
|
+
def _current_changed_files(project_root: Path = Path(".")) -> list[str]:
|
|
34
|
+
from devcouncil.verification.verifier import Verifier
|
|
35
|
+
|
|
36
|
+
return Verifier(project_root).get_changed_files()
|
|
37
|
+
|
|
38
|
+
def _capture_after_patch(task_id: str, project_root: Path = Path(".")):
|
|
26
39
|
"""Capture the diff after task execution for use by rollback."""
|
|
27
40
|
try:
|
|
28
41
|
from devcouncil.verification.verifier import Verifier
|
|
29
42
|
|
|
30
|
-
checkpoint_dir =
|
|
43
|
+
checkpoint_dir = project_root / ".devcouncil" / "checkpoints"
|
|
31
44
|
checkpoint_dir.mkdir(exist_ok=True)
|
|
32
|
-
diff = Verifier(
|
|
45
|
+
diff = Verifier(project_root).get_diff()
|
|
33
46
|
if diff:
|
|
34
47
|
with open(checkpoint_dir / f"{task_id}-after.patch", "w", encoding="utf-8") as f:
|
|
35
48
|
f.write(diff)
|
|
36
|
-
except Exception:
|
|
37
|
-
pass # Non-critical — don't block execution
|
|
38
|
-
|
|
39
|
-
def _capture_before_snapshot(task_id: str):
|
|
40
|
-
checkpoint_dir =
|
|
41
|
-
checkpoint_dir.mkdir(exist_ok=True)
|
|
42
|
-
snapshot = {
|
|
43
|
-
"task_id": task_id,
|
|
44
|
-
"changed_files": _current_changed_files(),
|
|
45
|
-
}
|
|
46
|
-
(checkpoint_dir / f"{task_id}-before.json").write_text(
|
|
47
|
-
json.dumps(snapshot, indent=2),
|
|
48
|
-
encoding="utf-8",
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
def _record_project_phase(session, phase: ProjectPhase):
|
|
52
|
-
StateRepository(session).record_phase(phase.value)
|
|
53
|
-
|
|
54
|
-
def _verify_after_execution(session, task, reqs, router=None) -> bool:
|
|
55
|
-
"""Run deterministic verification after an automated executor finishes."""
|
|
56
|
-
import asyncio
|
|
57
|
-
|
|
58
|
-
verifier = Verifier(
|
|
59
|
-
gaps, evidence = asyncio.run(verifier.verify_task(task, reqs))
|
|
60
|
-
|
|
61
|
-
gap_repo = GapRepository(session)
|
|
62
|
-
evidence_repo = EvidenceRepository(session)
|
|
63
|
-
gap_repo.delete_for_task(task.id)
|
|
64
|
-
evidence_repo.delete_for_task(task.id)
|
|
65
|
-
|
|
66
|
-
for gap in gaps:
|
|
67
|
-
gap_repo.save(gap)
|
|
68
|
-
|
|
69
|
-
for ev in evidence:
|
|
70
|
-
if isinstance(ev, CommandResult):
|
|
71
|
-
evidence_repo.save_command_result(task.id, ev)
|
|
72
|
-
elif isinstance(ev, DiffEvidence):
|
|
73
|
-
evidence_repo.save_diff_evidence(ev)
|
|
74
|
-
elif isinstance(ev, TestEvidence):
|
|
75
|
-
evidence_repo.save_test_evidence(ev, task.id)
|
|
76
|
-
|
|
77
|
-
task.status = "blocked" if any(g.blocking for g in gaps) else "verified"
|
|
78
|
-
return task.status == "verified"
|
|
79
|
-
|
|
80
|
-
def run(
|
|
81
|
-
task_id: str = typer.Argument(..., help="ID of the task to run"),
|
|
82
|
-
executor: str = typer.Option(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
49
|
+
except Exception:
|
|
50
|
+
pass # Non-critical — don't block execution
|
|
51
|
+
|
|
52
|
+
def _capture_before_snapshot(task_id: str, project_root: Path = Path(".")):
|
|
53
|
+
checkpoint_dir = project_root / ".devcouncil" / "checkpoints"
|
|
54
|
+
checkpoint_dir.mkdir(exist_ok=True)
|
|
55
|
+
snapshot = {
|
|
56
|
+
"task_id": task_id,
|
|
57
|
+
"changed_files": _current_changed_files(project_root),
|
|
58
|
+
}
|
|
59
|
+
(checkpoint_dir / f"{task_id}-before.json").write_text(
|
|
60
|
+
json.dumps(snapshot, indent=2),
|
|
61
|
+
encoding="utf-8",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def _record_project_phase(session, phase: ProjectPhase):
|
|
65
|
+
StateRepository(session).record_phase(phase.value)
|
|
66
|
+
|
|
67
|
+
def _verify_after_execution(session, task, reqs, router=None, project_root: Path = Path(".")) -> bool:
|
|
68
|
+
"""Run deterministic verification after an automated executor finishes."""
|
|
69
|
+
import asyncio
|
|
70
|
+
|
|
71
|
+
verifier = Verifier(project_root, router=router)
|
|
72
|
+
gaps, evidence = asyncio.run(verifier.verify_task(task, reqs))
|
|
73
|
+
|
|
74
|
+
gap_repo = GapRepository(session)
|
|
75
|
+
evidence_repo = EvidenceRepository(session)
|
|
76
|
+
gap_repo.delete_for_task(task.id)
|
|
77
|
+
evidence_repo.delete_for_task(task.id)
|
|
78
|
+
|
|
79
|
+
for gap in gaps:
|
|
80
|
+
gap_repo.save(gap)
|
|
81
|
+
|
|
82
|
+
for ev in evidence:
|
|
83
|
+
if isinstance(ev, CommandResult):
|
|
84
|
+
evidence_repo.save_command_result(task.id, ev)
|
|
85
|
+
elif isinstance(ev, DiffEvidence):
|
|
86
|
+
evidence_repo.save_diff_evidence(ev)
|
|
87
|
+
elif isinstance(ev, TestEvidence):
|
|
88
|
+
evidence_repo.save_test_evidence(ev, task.id)
|
|
89
|
+
|
|
90
|
+
task.status = "blocked" if any(g.blocking for g in gaps) else "verified"
|
|
91
|
+
return task.status == "verified"
|
|
92
|
+
|
|
93
|
+
def run(
|
|
94
|
+
task_id: str = typer.Argument(..., help="ID of the task to run"),
|
|
95
|
+
executor: str = typer.Option(
|
|
96
|
+
"manual",
|
|
97
|
+
"--executor",
|
|
98
|
+
"-e",
|
|
99
|
+
help="Executor to use (manual, mini, openhands, native, codex, codex-cli, gemini, gemini-cli, claude, claude-code, claude-cli)",
|
|
100
|
+
),
|
|
101
|
+
project_root: Path = typer.Option(Path("."), "--project-root", help="Repository root containing .devcouncil/."),
|
|
102
|
+
):
|
|
103
|
+
"""
|
|
104
|
+
Execute a specific task.
|
|
105
|
+
"""
|
|
106
|
+
root = project_root.expanduser().resolve()
|
|
107
|
+
initialize_project(root, quiet=True)
|
|
108
|
+
db = get_db(root)
|
|
109
|
+
if not db:
|
|
110
|
+
console.print("[red]DevCouncil state is unavailable in this directory.[/red]")
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
with db.get_session() as session:
|
|
114
|
+
task_repo = TaskRepository(session)
|
|
115
|
+
task = task_repo.get_by_id(task_id)
|
|
116
|
+
if not task:
|
|
117
|
+
console.print(f"[red]Task {task_id} not found.[/red]")
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
from devcouncil.gating.policy import GatePolicy
|
|
121
|
+
policy = GatePolicy()
|
|
122
|
+
gate_result = policy.check_task_ready(task, root)
|
|
123
|
+
if not gate_result.passed:
|
|
124
|
+
console.print(f"[red]Task {task_id} is not ready for execution.[/red]")
|
|
125
|
+
for gap in gate_result.gaps:
|
|
126
|
+
if gap.blocking:
|
|
127
|
+
console.print(f" - [red][BLOCKING][/red] {gap.description} (Fix: {gap.recommended_fix})")
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
console.print(f"Running task [bold]{task_id}[/bold] using [bold]{executor}[/bold] executor...")
|
|
131
|
+
|
|
132
|
+
# 1. Create Git checkpoint
|
|
112
133
|
try:
|
|
113
134
|
from devcouncil.verification.verifier import Verifier
|
|
114
135
|
|
|
115
|
-
checkpoint_dir =
|
|
136
|
+
checkpoint_dir = root / ".devcouncil" / "checkpoints"
|
|
116
137
|
checkpoint_dir.mkdir(exist_ok=True)
|
|
117
|
-
_capture_before_snapshot(task_id)
|
|
118
|
-
diff = Verifier(
|
|
138
|
+
_capture_before_snapshot(task_id, root)
|
|
139
|
+
diff = Verifier(root).get_diff()
|
|
119
140
|
if diff:
|
|
120
141
|
with open(checkpoint_dir / f"{task_id}-before.patch", "w", encoding="utf-8") as f:
|
|
121
142
|
f.write(diff)
|
|
122
|
-
console.print(f"Created git checkpoint at {checkpoint_dir}/{task_id}-before.patch")
|
|
123
|
-
except Exception as e:
|
|
124
|
-
console.print(f"[yellow]Warning: Failed to create git checkpoint: {e}[/yellow]")
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
console.print("
|
|
132
|
-
console.print("
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
_record_project_phase(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
console.print(f"\n[
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
_record_project_phase(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
console.print(f"\n[
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
143
|
+
console.print(f"Created git checkpoint at {checkpoint_dir}/{task_id}-before.patch")
|
|
144
|
+
except Exception as e:
|
|
145
|
+
console.print(f"[yellow]Warning: Failed to create git checkpoint: {e}[/yellow]")
|
|
146
|
+
|
|
147
|
+
executor = executor.strip().lower().replace("_", "-")
|
|
148
|
+
if executor == "manual":
|
|
149
|
+
_record_project_phase(session, ProjectPhase.TASK_EXECUTING)
|
|
150
|
+
task.status = "running"
|
|
151
|
+
task_repo.save(task)
|
|
152
|
+
console.print(f"\n[green]Task {task_id} is now marked as RUNNING.[/green]")
|
|
153
|
+
console.print("Use 'dev prompt TASK-ID' to get the prompt for this task.")
|
|
154
|
+
console.print("When finished, use 'dev verify TASK-ID' to check the results.")
|
|
155
|
+
elif executor in CODING_EXECUTORS:
|
|
156
|
+
_record_project_phase(session, ProjectPhase.TASK_EXECUTING)
|
|
157
|
+
req_repo = RequirementRepository(session)
|
|
158
|
+
reqs = req_repo.get_all()
|
|
159
|
+
cli_client = CODING_EXECUTOR_ALIASES[executor]
|
|
160
|
+
cli_executor = CodingCliExecutor(root, cli_client)
|
|
161
|
+
exec_result = cli_executor.run_task(task, reqs)
|
|
162
|
+
_capture_after_patch(task_id, root)
|
|
163
|
+
if exec_result.success:
|
|
164
|
+
_record_project_phase(session, ProjectPhase.TASK_VERIFYING)
|
|
165
|
+
verified = _verify_after_execution(session, task, reqs, project_root=root)
|
|
166
|
+
_record_project_phase(
|
|
167
|
+
session,
|
|
168
|
+
ProjectPhase.TASK_VERIFIED if verified else ProjectPhase.TASK_BLOCKED,
|
|
169
|
+
)
|
|
170
|
+
task_repo.save(task)
|
|
171
|
+
if verified:
|
|
172
|
+
console.print(f"\n[green]{executor.upper()} finished and task {task_id} verified.[/green]")
|
|
173
|
+
else:
|
|
174
|
+
console.print(f"\n[yellow]{executor.upper()} finished, but task {task_id} is blocked by verification gaps.[/yellow]")
|
|
175
|
+
else:
|
|
176
|
+
console.print(f"\n[red]{executor.upper()} failed to start or execute: {exec_result.message}[/red]")
|
|
177
|
+
elif executor == "mini":
|
|
178
|
+
_record_project_phase(session, ProjectPhase.TASK_EXECUTING)
|
|
179
|
+
req_repo = RequirementRepository(session)
|
|
180
|
+
reqs = req_repo.get_all()
|
|
181
|
+
mini_executor = MiniSWEExecutor(root)
|
|
182
|
+
exec_result = mini_executor.run_task(task, reqs)
|
|
183
|
+
_capture_after_patch(task_id, root)
|
|
184
|
+
if exec_result.success:
|
|
185
|
+
_record_project_phase(session, ProjectPhase.TASK_VERIFYING)
|
|
186
|
+
verified = _verify_after_execution(session, task, reqs, project_root=root)
|
|
187
|
+
_record_project_phase(
|
|
188
|
+
session,
|
|
189
|
+
ProjectPhase.TASK_VERIFIED if verified else ProjectPhase.TASK_BLOCKED,
|
|
190
|
+
)
|
|
191
|
+
task_repo.save(task)
|
|
192
|
+
if verified:
|
|
193
|
+
console.print(f"\n[green]mini-SWE-agent finished and task {task_id} verified.[/green]")
|
|
194
|
+
else:
|
|
195
|
+
console.print(f"\n[yellow]mini-SWE-agent finished, but task {task_id} is blocked by verification gaps.[/yellow]")
|
|
196
|
+
else:
|
|
197
|
+
console.print("\n[red]mini-SWE-agent failed to start or execute.[/red]")
|
|
198
|
+
elif executor == "openhands":
|
|
199
|
+
_record_project_phase(session, ProjectPhase.TASK_EXECUTING)
|
|
200
|
+
req_repo = RequirementRepository(session)
|
|
201
|
+
reqs = req_repo.get_all()
|
|
202
|
+
oh_executor = OpenHandsExecutor(root)
|
|
203
|
+
exec_result = oh_executor.run_task(task, reqs)
|
|
204
|
+
_capture_after_patch(task_id, root)
|
|
205
|
+
if exec_result.success:
|
|
206
|
+
_record_project_phase(session, ProjectPhase.TASK_VERIFYING)
|
|
207
|
+
verified = _verify_after_execution(session, task, reqs, project_root=root)
|
|
208
|
+
_record_project_phase(
|
|
209
|
+
session,
|
|
210
|
+
ProjectPhase.TASK_VERIFIED if verified else ProjectPhase.TASK_BLOCKED,
|
|
211
|
+
)
|
|
212
|
+
task_repo.save(task)
|
|
213
|
+
if verified:
|
|
214
|
+
console.print(f"\n[green]OpenHands finished and task {task_id} verified.[/green]")
|
|
215
|
+
else:
|
|
216
|
+
console.print(f"\n[yellow]OpenHands finished, but task {task_id} is blocked by verification gaps.[/yellow]")
|
|
217
|
+
else:
|
|
218
|
+
console.print("\n[red]OpenHands failed to start or execute.[/red]")
|
|
219
|
+
elif executor == "native":
|
|
220
|
+
# Load config for model routing and permissions
|
|
221
|
+
try:
|
|
222
|
+
config = load_config(root)
|
|
223
|
+
validate_model_provider(config.models.provider)
|
|
224
|
+
api_key = get_api_key(config.models.provider, root)
|
|
225
|
+
except (FileNotFoundError, ValueError) as e:
|
|
226
|
+
console.print(f"[red]{e}[/red]")
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
provider = create_provider(config.models.provider, api_key)
|
|
230
|
+
role_config = {name: role.model_dump() for name, role in config.models.roles.items()}
|
|
231
|
+
router = ModelRouter(provider, role_config)
|
|
232
|
+
|
|
233
|
+
# Setup Permission System
|
|
234
|
+
from devcouncil.execution.permissions import PermissionPolicy, PermissionManager
|
|
235
|
+
from devcouncil.execution.task_runner import TaskRunner
|
|
236
|
+
|
|
237
|
+
# Populate policy from config commands
|
|
238
|
+
allowed_cmds = config.commands.test + config.commands.lint + config.commands.typecheck
|
|
239
|
+
policy = PermissionPolicy(
|
|
240
|
+
allowed_shell_commands=allowed_cmds,
|
|
241
|
+
)
|
|
242
|
+
perm_manager = PermissionManager(policy, root)
|
|
243
|
+
task_runner = TaskRunner(root, perm_manager)
|
|
244
|
+
|
|
245
|
+
req_repo = RequirementRepository(session)
|
|
246
|
+
reqs = req_repo.get_all()
|
|
247
|
+
|
|
248
|
+
import asyncio
|
|
249
|
+
_record_project_phase(session, ProjectPhase.TASK_EXECUTING)
|
|
250
|
+
agent = NativeAgent(router, task_runner)
|
|
251
|
+
exec_result = asyncio.run(agent.run_task(task, reqs))
|
|
252
|
+
_capture_after_patch(task_id, root)
|
|
253
|
+
|
|
254
|
+
if exec_result.success:
|
|
255
|
+
_record_project_phase(session, ProjectPhase.TASK_VERIFYING)
|
|
256
|
+
verified = _verify_after_execution(session, task, reqs, router=router, project_root=root)
|
|
257
|
+
_record_project_phase(
|
|
258
|
+
session,
|
|
259
|
+
ProjectPhase.TASK_VERIFIED if verified else ProjectPhase.TASK_BLOCKED,
|
|
260
|
+
)
|
|
261
|
+
task_repo.save(task)
|
|
262
|
+
if verified:
|
|
263
|
+
console.print(f"\n[green]Native agent finished and task {task_id} verified.[/green]")
|
|
264
|
+
else:
|
|
265
|
+
console.print(f"\n[yellow]Native agent finished, but task {task_id} is blocked by verification gaps.[/yellow]")
|
|
266
|
+
else:
|
|
267
|
+
console.print("\n[red]Native agent failed during execution.[/red]")
|
|
268
|
+
else:
|
|
269
|
+
console.print(f"[red]Executor {executor} not yet implemented.[/red]")
|