devcouncil 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -30
- package/package.json +6 -2
- package/packages/codeintel-grammars/hatch_build.py +43 -0
- package/packages/codeintel-grammars/pyproject.toml +16 -0
- package/packages/codeintel-grammars/src/devcouncil_codeintel_grammars/__init__.py +93 -0
- package/pyproject.toml +99 -4
- package/src/devcouncil/app/config.py +512 -20
- package/src/devcouncil/app/events.py +4 -23
- package/src/devcouncil/app/orchestrator.py +5 -0
- package/src/devcouncil/app/run_context.py +3 -3
- package/src/devcouncil/assets/__init__.py +4 -1
- package/src/devcouncil/assets/vendor/force-graph.min.js +5 -0
- package/src/devcouncil/campaign/__init__.py +71 -0
- package/src/devcouncil/campaign/bloom.py +137 -0
- package/src/devcouncil/campaign/dashboard.py +123 -0
- package/src/devcouncil/campaign/mailbox.py +305 -0
- package/src/devcouncil/campaign/notify.py +91 -0
- package/src/devcouncil/campaign/orchestrator.py +592 -0
- package/src/devcouncil/campaign/prompts/coordinator.md +29 -0
- package/src/devcouncil/campaign/prompts/director.md +21 -0
- package/src/devcouncil/campaign/prompts/protocol.md +46 -0
- package/src/devcouncil/campaign/prompts/reviewer.md +24 -0
- package/src/devcouncil/campaign/prompts/worker.md +24 -0
- package/src/devcouncil/campaign/roles.py +202 -0
- package/src/devcouncil/campaign/watcher.py +153 -0
- package/src/devcouncil/cli/commands/agents.py +24 -17
- package/src/devcouncil/cli/commands/artifacts.py +36 -27
- package/src/devcouncil/cli/commands/ast.py +12 -3
- package/src/devcouncil/cli/commands/baseline.py +21 -12
- package/src/devcouncil/cli/commands/boot.py +218 -0
- package/src/devcouncil/cli/commands/campaign.py +302 -0
- package/src/devcouncil/cli/commands/check.py +225 -12
- package/src/devcouncil/cli/commands/config.py +221 -74
- package/src/devcouncil/cli/commands/cost.py +137 -28
- package/src/devcouncil/cli/commands/dashboard.py +12 -4
- package/src/devcouncil/cli/commands/debug_cmd.py +249 -0
- package/src/devcouncil/cli/commands/design.py +27 -17
- package/src/devcouncil/cli/commands/doctor.py +790 -8
- package/src/devcouncil/cli/commands/evidence.py +41 -20
- package/src/devcouncil/cli/commands/export.py +73 -0
- package/src/devcouncil/cli/commands/gaps.py +175 -0
- package/src/devcouncil/cli/commands/gated_write.py +76 -0
- package/src/devcouncil/cli/commands/go.py +220 -68
- package/src/devcouncil/cli/commands/graph_cmd.py +1192 -0
- package/src/devcouncil/cli/commands/handoff.py +45 -34
- package/src/devcouncil/cli/commands/hook.py +630 -85
- package/src/devcouncil/cli/commands/init.py +89 -30
- package/src/devcouncil/cli/commands/integrate.py +296 -1385
- package/src/devcouncil/cli/commands/lease.py +120 -0
- package/src/devcouncil/cli/commands/logs.py +12 -5
- package/src/devcouncil/cli/commands/lsp.py +40 -5
- package/src/devcouncil/cli/commands/map.py +317 -74
- package/src/devcouncil/cli/commands/mcp_server.py +12 -2
- package/src/devcouncil/cli/commands/okf.py +44 -6
- package/src/devcouncil/cli/commands/plan.py +184 -69
- package/src/devcouncil/cli/commands/prompt.py +26 -17
- package/src/devcouncil/cli/commands/provenance.py +79 -0
- package/src/devcouncil/cli/commands/repair.py +60 -49
- package/src/devcouncil/cli/commands/report.py +148 -40
- package/src/devcouncil/cli/commands/requirements.py +104 -0
- package/src/devcouncil/cli/commands/reset_demo_state.py +13 -4
- package/src/devcouncil/cli/commands/rollback.py +46 -35
- package/src/devcouncil/cli/commands/run.py +173 -8
- package/src/devcouncil/cli/commands/runs.py +298 -68
- package/src/devcouncil/cli/commands/scaffold.py +33 -12
- package/src/devcouncil/cli/commands/semantic.py +29 -14
- package/src/devcouncil/cli/commands/setup.py +103 -93
- package/src/devcouncil/cli/commands/shell.py +51 -42
- package/src/devcouncil/cli/commands/show.py +56 -42
- package/src/devcouncil/cli/commands/skills.py +29 -20
- package/src/devcouncil/cli/commands/status.py +80 -67
- package/src/devcouncil/cli/commands/task_gate.py +295 -0
- package/src/devcouncil/cli/commands/tasks.py +248 -19
- package/src/devcouncil/cli/commands/trace.py +14 -8
- package/src/devcouncil/cli/commands/verify.py +33 -8
- package/src/devcouncil/cli/commands/version.py +14 -6
- package/src/devcouncil/cli/commands/watch.py +49 -30
- package/src/devcouncil/cli/commands/watch_fs.py +30 -19
- package/src/devcouncil/cli/commands/wiki.py +278 -0
- package/src/devcouncil/cli/main.py +58 -1
- package/src/devcouncil/codeintel/__init__.py +16 -0
- package/src/devcouncil/codeintel/build_control.py +429 -0
- package/src/devcouncil/codeintel/build_worker.py +78 -0
- package/src/devcouncil/codeintel/debug/__init__.py +17 -0
- package/src/devcouncil/codeintel/debug/broker.py +114 -0
- package/src/devcouncil/codeintel/debug/broker_client.py +61 -0
- package/src/devcouncil/codeintel/debug/consent.py +36 -0
- package/src/devcouncil/codeintel/debug/discovery.py +132 -0
- package/src/devcouncil/codeintel/debug/fingerprint.py +85 -0
- package/src/devcouncil/codeintel/debug/protocol.py +259 -0
- package/src/devcouncil/codeintel/debug/python_trace_runner.py +81 -0
- package/src/devcouncil/codeintel/debug/session.py +238 -0
- package/src/devcouncil/codeintel/debug/tracing.py +201 -0
- package/src/devcouncil/codeintel/languages/__init__.py +17 -0
- package/src/devcouncil/codeintel/languages/generic_extractor.py +236 -0
- package/src/devcouncil/codeintel/languages/registry.py +149 -0
- package/src/devcouncil/codeintel/languages/workers.py +245 -0
- package/src/devcouncil/codeintel/query/__init__.py +5 -0
- package/src/devcouncil/codeintel/query/engine.py +289 -0
- package/src/devcouncil/codeintel/resolution/__init__.py +6 -0
- package/src/devcouncil/codeintel/resolution/abstract_state.py +301 -0
- package/src/devcouncil/codeintel/resolution/frameworks/__init__.py +33 -0
- package/src/devcouncil/codeintel/resolution/frameworks/base.py +46 -0
- package/src/devcouncil/codeintel/resolution/frameworks/di.py +56 -0
- package/src/devcouncil/codeintel/resolution/frameworks/events.py +45 -0
- package/src/devcouncil/codeintel/resolution/frameworks/routes.py +88 -0
- package/src/devcouncil/codeintel/resolution/semantic.py +887 -0
- package/src/devcouncil/codeintel/service.py +104 -0
- package/src/devcouncil/codeintel/store/__init__.py +15 -0
- package/src/devcouncil/codeintel/store/sqlite.py +1565 -0
- package/src/devcouncil/codeintel/sync/__init__.py +19 -0
- package/src/devcouncil/codeintel/sync/coordinator.py +430 -0
- package/src/devcouncil/codeintel/sync/incremental.py +484 -0
- package/src/devcouncil/codeintel/sync/lease.py +96 -0
- package/src/devcouncil/codeintel/sync/scope.py +98 -0
- package/src/devcouncil/council/__init__.py +4 -0
- package/src/devcouncil/council/prompts/__init__.py +4 -0
- package/src/devcouncil/domain/checkpoint_refs.py +17 -0
- package/src/devcouncil/domain/evidence.py +1 -0
- package/src/devcouncil/domain/gap.py +10 -0
- package/src/devcouncil/domain/requirement.py +5 -1
- package/src/devcouncil/domain/task.py +43 -2
- package/src/devcouncil/execution/checkpoints.py +25 -31
- package/src/devcouncil/execution/context_builder.py +15 -44
- package/src/devcouncil/execution/fs_watcher.py +64 -0
- package/src/devcouncil/execution/gated_write.py +203 -0
- package/src/devcouncil/execution/handoff.py +2 -1
- package/src/devcouncil/execution/hook_policy.py +19 -5
- package/src/devcouncil/execution/lease_ops.py +177 -0
- package/src/devcouncil/execution/lease_validation.py +71 -0
- package/src/devcouncil/execution/patch.py +3 -0
- package/src/devcouncil/execution/permissions.py +1 -0
- package/src/devcouncil/execution/policy_engine.py +205 -10
- package/src/devcouncil/execution/prompt_builder.py +278 -33
- package/src/devcouncil/execution/run_trace.py +356 -0
- package/src/devcouncil/execution/shell_session.py +46 -5
- package/src/devcouncil/execution/stop_gate.py +746 -0
- package/src/devcouncil/execution/stop_gate_history.py +113 -0
- package/src/devcouncil/execution/stop_gate_state.py +54 -0
- package/src/devcouncil/execution/stop_gate_verify_cache.py +69 -0
- package/src/devcouncil/execution/task_gate_ops.py +590 -0
- package/src/devcouncil/execution/task_runner.py +19 -0
- package/src/devcouncil/executors/advisor_tool.py +315 -0
- package/src/devcouncil/executors/agent_registry.py +125 -17
- package/src/devcouncil/executors/claude_sdk.py +376 -0
- package/src/devcouncil/executors/coding_cli.py +724 -25
- package/src/devcouncil/executors/mini_swe.py +50 -8
- package/src/devcouncil/executors/native/agent.py +224 -19
- package/src/devcouncil/executors/openhands.py +50 -8
- package/src/devcouncil/executors/transient_retry.py +99 -0
- package/src/devcouncil/gating/checks/clean_git.py +5 -2
- package/src/devcouncil/gating/checks/planned_files_check.py +38 -11
- package/src/devcouncil/gating/checks/secret_scan_check.py +2 -2
- package/src/devcouncil/gating/policy.py +46 -2
- package/src/devcouncil/indexing/ast_matcher.py +41 -4
- package/src/devcouncil/indexing/graph/__init__.py +78 -0
- package/src/devcouncil/indexing/graph/api_routes.py +522 -0
- package/src/devcouncil/indexing/graph/build.py +862 -0
- package/src/devcouncil/indexing/graph/cache.py +329 -0
- package/src/devcouncil/indexing/graph/communities.py +28 -0
- package/src/devcouncil/indexing/graph/cypher.py +107 -0
- package/src/devcouncil/indexing/graph/embeddings.py +194 -0
- package/src/devcouncil/indexing/graph/export.py +381 -0
- package/src/devcouncil/indexing/graph/export_links.py +81 -0
- package/src/devcouncil/indexing/graph/extract_python.py +307 -0
- package/src/devcouncil/indexing/graph/extract_ts.py +1205 -0
- package/src/devcouncil/indexing/graph/intel.py +668 -0
- package/src/devcouncil/indexing/graph/liveness.py +992 -0
- package/src/devcouncil/indexing/graph/okf_export.py +65 -0
- package/src/devcouncil/indexing/graph/pdg/__init__.py +67 -0
- package/src/devcouncil/indexing/graph/pdg/build.py +11 -0
- package/src/devcouncil/indexing/graph/pdg/cdg.py +41 -0
- package/src/devcouncil/indexing/graph/pdg/cfg.py +199 -0
- package/src/devcouncil/indexing/graph/pdg/query.py +21 -0
- package/src/devcouncil/indexing/graph/pdg/reaching_def.py +126 -0
- package/src/devcouncil/indexing/graph/pdg/schema.py +253 -0
- package/src/devcouncil/indexing/graph/pdg/taint.py +154 -0
- package/src/devcouncil/indexing/graph/query.py +302 -0
- package/src/devcouncil/indexing/graph/resolve.py +1020 -0
- package/src/devcouncil/indexing/graph/schema.py +103 -0
- package/src/devcouncil/indexing/graph_index.py +20 -29
- package/src/devcouncil/indexing/lsp.py +57 -25
- package/src/devcouncil/indexing/lsp_client.py +577 -0
- package/src/devcouncil/indexing/map_artifacts.py +355 -0
- package/src/devcouncil/indexing/map_refresh.py +141 -0
- package/src/devcouncil/indexing/repo_mapper.py +1509 -138
- package/src/devcouncil/indexing/semantic_index.py +12 -6
- package/src/devcouncil/indexing/subsystem_map.py +163 -0
- package/src/devcouncil/indexing/ts_imports.py +343 -0
- package/src/devcouncil/indexing/viz.py +960 -0
- package/src/devcouncil/indexing/walk.py +52 -0
- package/src/devcouncil/indexing/wiring.py +1776 -0
- package/src/devcouncil/integrations/actions.py +27 -4
- package/src/devcouncil/integrations/check.py +211 -16
- package/src/devcouncil/integrations/claude_assets.py +209 -12
- package/src/devcouncil/integrations/clients/__init__.py +1 -0
- package/src/devcouncil/integrations/clients/aider.py +52 -0
- package/src/devcouncil/integrations/clients/antigravity.py +87 -0
- package/src/devcouncil/integrations/clients/claude.py +339 -0
- package/src/devcouncil/integrations/clients/codex.py +39 -0
- package/src/devcouncil/integrations/clients/common.py +332 -0
- package/src/devcouncil/integrations/clients/cursor.py +164 -0
- package/src/devcouncil/integrations/clients/gemini.py +49 -0
- package/src/devcouncil/integrations/clients/grok.py +105 -0
- package/src/devcouncil/integrations/clients/hooks.py +500 -0
- package/src/devcouncil/integrations/clients/opencode.py +96 -0
- package/src/devcouncil/integrations/clients/warp.py +75 -0
- package/src/devcouncil/integrations/code_review_graph.py +2 -2
- package/src/devcouncil/integrations/github.py +73 -7
- package/src/devcouncil/integrations/integration_cli.py +197 -0
- package/src/devcouncil/integrations/mcp/handlers/__init__.py +1 -0
- package/src/devcouncil/integrations/mcp/handlers/ast_lsp.py +77 -0
- package/src/devcouncil/integrations/mcp/handlers/checkout.py +50 -0
- package/src/devcouncil/integrations/mcp/handlers/cli_gate.py +43 -0
- package/src/devcouncil/integrations/mcp/handlers/codeintel.py +182 -0
- package/src/devcouncil/integrations/mcp/handlers/debug.py +236 -0
- package/src/devcouncil/integrations/mcp/handlers/evidence.py +70 -0
- package/src/devcouncil/integrations/mcp/handlers/git.py +99 -0
- package/src/devcouncil/integrations/mcp/handlers/graph.py +36 -0
- package/src/devcouncil/integrations/mcp/handlers/handoff.py +53 -0
- package/src/devcouncil/integrations/mcp/handlers/knowledge.py +30 -0
- package/src/devcouncil/integrations/mcp/handlers/lease.py +70 -0
- package/src/devcouncil/integrations/mcp/handlers/live.py +108 -0
- package/src/devcouncil/integrations/mcp/handlers/map.py +676 -0
- package/src/devcouncil/integrations/mcp/handlers/next_task.py +35 -0
- package/src/devcouncil/integrations/mcp/handlers/policy.py +80 -0
- package/src/devcouncil/integrations/mcp/handlers/prompts.py +168 -0
- package/src/devcouncil/integrations/mcp/handlers/provenance.py +101 -0
- package/src/devcouncil/integrations/mcp/handlers/read.py +74 -0
- package/src/devcouncil/integrations/mcp/handlers/router_cache.py +53 -0
- package/src/devcouncil/integrations/mcp/handlers/run.py +53 -0
- package/src/devcouncil/integrations/mcp/handlers/runs.py +84 -0
- package/src/devcouncil/integrations/mcp/handlers/scope.py +56 -0
- package/src/devcouncil/integrations/mcp/handlers/status.py +114 -0
- package/src/devcouncil/integrations/mcp/handlers/task.py +100 -0
- package/src/devcouncil/integrations/mcp/handlers/tool_specs.py +904 -0
- package/src/devcouncil/integrations/mcp/handlers/trace.py +65 -0
- package/src/devcouncil/integrations/mcp/handlers/verify.py +45 -0
- package/src/devcouncil/integrations/mcp/handlers/wiki.py +60 -0
- package/src/devcouncil/integrations/mcp/handlers/write.py +69 -0
- package/src/devcouncil/integrations/mcp/server.py +265 -2391
- package/src/devcouncil/integrations/mcp/util.py +303 -0
- package/src/devcouncil/integrations/setup.py +152 -0
- package/src/devcouncil/knowledge/fetch.py +4 -0
- package/src/devcouncil/knowledge/knowledge_select.py +38 -0
- package/src/devcouncil/knowledge/okf.py +2 -1
- package/src/devcouncil/knowledge/resource_discovery.py +40 -0
- package/src/devcouncil/knowledge/wiki.py +643 -0
- package/src/devcouncil/knowledge/wiki_read.py +87 -0
- package/src/devcouncil/live/cards.py +7 -7
- package/src/devcouncil/live/models.py +4 -1
- package/src/devcouncil/live/reviewer.py +90 -11
- package/src/devcouncil/live/signals.py +4 -2
- package/src/devcouncil/live/tasks.py +12 -3
- package/src/devcouncil/live/transcripts.py +69 -2
- package/src/devcouncil/llm/cache.py +5 -6
- package/src/devcouncil/llm/model_defaults.yaml +10 -10
- package/src/devcouncil/llm/provider.py +647 -73
- package/src/devcouncil/llm/router.py +271 -46
- package/src/devcouncil/llm/semantic_bridge.py +614 -0
- package/src/devcouncil/optimization/gepa_agent.py +6 -4
- package/src/devcouncil/optimization/skillopt.py +9 -5
- package/src/devcouncil/planning/arbiter_service.py +12 -3
- package/src/devcouncil/planning/correction_manifest.py +107 -10
- package/src/devcouncil/planning/plan_difficulty.py +69 -0
- package/src/devcouncil/planning/plan_service.py +5 -2
- package/src/devcouncil/planning/planned_files_reconcile.py +191 -0
- package/src/devcouncil/planning/prompt_enhancer_service.py +6 -5
- package/src/devcouncil/planning/question_conversion.py +56 -0
- package/src/devcouncil/planning/spec_service.py +9 -3
- package/src/devcouncil/repo/ci_scaffold.py +197 -1
- package/src/devcouncil/repo/gitignore.py +1 -2
- package/src/devcouncil/reporting/evidence_export.py +124 -0
- package/src/devcouncil/reporting/evidence_html.py +210 -0
- package/src/devcouncil/reporting/json_report.py +16 -12
- package/src/devcouncil/reporting/markdown_report.py +38 -9
- package/src/devcouncil/reporting/mcp_resources.py +142 -0
- package/src/devcouncil/reporting/report_builder.py +40 -4
- package/src/devcouncil/reporting/task_provenance.py +42 -0
- package/src/devcouncil/reporting/verdict.py +75 -0
- package/src/devcouncil/skills/library/README.md +1 -0
- package/src/devcouncil/skills/library/devcouncil-hero-loop.md +109 -0
- package/src/devcouncil/skills/library/devcouncil-verification.md +109 -0
- package/src/devcouncil/skills/library/devcouncil.md +93 -0
- package/src/devcouncil/skills/registry.py +43 -12
- package/src/devcouncil/storage/db.py +57 -11
- package/src/devcouncil/storage/models.py +6 -0
- package/src/devcouncil/storage/native.py +5 -3
- package/src/devcouncil/storage/repositories.py +50 -18
- package/src/devcouncil/telemetry/context.py +28 -0
- package/src/devcouncil/telemetry/cost.py +4 -5
- package/src/devcouncil/telemetry/logging_setup.py +78 -11
- package/src/devcouncil/telemetry/model_pricing.yaml +7 -0
- package/src/devcouncil/telemetry/stages.py +27 -2
- package/src/devcouncil/telemetry/tracker.py +50 -13
- package/src/devcouncil/ui/dashboard.py +120 -8
- package/src/devcouncil/utils/fsio.py +58 -0
- package/src/devcouncil/utils/git_snapshot.py +112 -0
- package/src/devcouncil/utils/json_persist.py +53 -0
- package/src/devcouncil/utils/proc.py +89 -0
- package/src/devcouncil/verification/acceptance_compiler.py +36 -13
- package/src/devcouncil/verification/ad_hoc_check.py +95 -3
- package/src/devcouncil/verification/checks/__init__.py +41 -0
- package/src/devcouncil/verification/checks/acceptance.py +39 -0
- package/src/devcouncil/verification/checks/acceptance_corpus.py +194 -0
- package/src/devcouncil/verification/checks/acceptance_evidence.py +239 -0
- package/src/devcouncil/verification/checks/command_evidence.py +148 -0
- package/src/devcouncil/verification/checks/compiled_acceptance.py +179 -0
- package/src/devcouncil/verification/checks/corpus_stale.py +124 -0
- package/src/devcouncil/verification/checks/corpus_verification.py +9 -0
- package/src/devcouncil/verification/checks/dead_symbols.py +360 -0
- package/src/devcouncil/verification/checks/diff_coverage_gate.py +101 -0
- package/src/devcouncil/verification/checks/doc_code_ref.py +79 -0
- package/src/devcouncil/verification/checks/liveness_ratchet.py +336 -0
- package/src/devcouncil/verification/checks/orphan_diff.py +104 -0
- package/src/devcouncil/verification/checks/planned_files.py +98 -0
- package/src/devcouncil/verification/checks/semantic_diff.py +241 -0
- package/src/devcouncil/verification/checks/stale_map.py +80 -0
- package/src/devcouncil/verification/checks/stub_scan.py +71 -0
- package/src/devcouncil/verification/checks/subsystem_boundary.py +103 -0
- package/src/devcouncil/verification/checks/wiring.py +216 -0
- package/src/devcouncil/verification/claims/__init__.py +23 -0
- package/src/devcouncil/verification/claims/checks.py +395 -0
- package/src/devcouncil/verification/claims/mapper.py +168 -0
- package/src/devcouncil/verification/claims/models.py +39 -0
- package/src/devcouncil/verification/claims/transcript.py +92 -0
- package/src/devcouncil/verification/claims/verdict.py +88 -0
- package/src/devcouncil/verification/command_evidence.py +170 -0
- package/src/devcouncil/verification/command_malformation.py +147 -0
- package/src/devcouncil/verification/command_runner.py +164 -0
- package/src/devcouncil/verification/coverage_measurement.py +292 -0
- package/src/devcouncil/verification/diff_coverage.py +151 -0
- package/src/devcouncil/verification/difficulty.py +296 -0
- package/src/devcouncil/verification/effort_heuristics.py +178 -0
- package/src/devcouncil/verification/gap_ids.py +63 -0
- package/src/devcouncil/verification/gate_cache.py +194 -0
- package/src/devcouncil/verification/gate_selector.py +344 -0
- package/src/devcouncil/verification/git_diff_fallback.py +272 -0
- package/src/devcouncil/verification/implementation_reviewer.py +13 -0
- package/src/devcouncil/verification/incremental_check.py +241 -0
- package/src/devcouncil/verification/next_actions.py +60 -1
- package/src/devcouncil/verification/rigor_analytics.py +130 -0
- package/src/devcouncil/verification/sandbox.py +38 -11
- package/src/devcouncil/verification/stub_detector.py +369 -0
- package/src/devcouncil/verification/test_resolver.py +67 -1
- package/src/devcouncil/verification/verifier.py +137 -1666
- package/src/devcouncil/verification/verify_orchestration.py +610 -0
- package/src/devcouncil/verification/verify_setup.py +176 -0
- package/src/devcouncil/verification/wiki_refresh.py +208 -0
- package/src/semantic_layer/__init__.py +58 -0
- package/src/semantic_layer/benchmark.py +75 -0
- package/src/semantic_layer/cache.py +290 -0
- package/src/semantic_layer/compressor.py +137 -0
- package/src/semantic_layer/config.py +75 -0
- package/src/semantic_layer/embeddings.py +69 -0
- package/src/semantic_layer/llm_backends.py +99 -0
- package/src/semantic_layer/pipeline.py +111 -0
- package/src/semantic_layer/router.py +128 -0
- package/src/semantic_layer/tuner.py +72 -0
- package/uv.lock +973 -9
- package/src/devcouncil/artifacts/migrations.py +0 -20
- package/src/devcouncil/artifacts/schemas.py +0 -23
- package/src/devcouncil/artifacts/serializer.py +0 -21
- package/src/devcouncil/integrations/gitnexus.py +0 -70
- package/src/devcouncil/integrations/graphify.py +0 -34
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import typer
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
from rich.console import Console
|
|
4
5
|
|
|
5
6
|
from devcouncil.execution.checkpoints import CheckpointService
|
|
7
|
+
from devcouncil.telemetry.stages import log_stage, log_step
|
|
6
8
|
|
|
7
9
|
app = typer.Typer()
|
|
8
10
|
console = Console()
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
9
12
|
|
|
10
13
|
@app.callback(invoke_without_command=True)
|
|
11
14
|
def rollback(
|
|
@@ -20,40 +23,48 @@ def rollback(
|
|
|
20
23
|
return
|
|
21
24
|
|
|
22
25
|
root = project_root.expanduser().resolve()
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
26
|
+
from devcouncil.telemetry.logging_setup import set_log_dir
|
|
27
|
+
set_log_dir(root)
|
|
28
|
+
logger.info("dev rollback: task=%s", task_id)
|
|
29
|
+
|
|
30
|
+
with log_stage("rollback", project_root=root, task_id=task_id):
|
|
31
|
+
log_step("rollback/1: locating checkpoint", project_root=root, task_id=task_id, trace=True)
|
|
32
|
+
checkpoint_dir = root / ".devcouncil" / "checkpoints"
|
|
33
|
+
checkpoint_file = checkpoint_dir / f"{task_id}-before.patch"
|
|
34
|
+
after_patch = checkpoint_dir / f"{task_id}-after.patch"
|
|
35
|
+
service = CheckpointService(root)
|
|
36
|
+
|
|
37
|
+
if not checkpoint_file.exists() and not after_patch.exists():
|
|
38
|
+
before_ref = CheckpointService.REF_BEFORE.format(task_id=task_id)
|
|
39
|
+
after_ref = CheckpointService.REF_AFTER.format(task_id=task_id)
|
|
40
|
+
if not service._ref_exists(before_ref) and not service._ref_exists(after_ref):
|
|
41
|
+
console.print(
|
|
42
|
+
f"[red]No checkpoint found for task {task_id}. Expected {after_patch} "
|
|
43
|
+
f"or {checkpoint_file}.[/red]"
|
|
44
|
+
)
|
|
45
|
+
raise typer.Exit(code=1)
|
|
46
|
+
|
|
47
|
+
console.print(f"Rolling back task [bold]{task_id}[/bold]...")
|
|
48
|
+
log_step("rollback/2: reverting checkpoint", project_root=root, task_id=task_id)
|
|
49
|
+
result = service.rollback(task_id)
|
|
50
|
+
if "failed" in result.message.lower() or result.message.startswith("No checkpoint"):
|
|
51
|
+
console.print(f"[yellow]{result.message}[/yellow]")
|
|
52
|
+
if checkpoint_file.exists():
|
|
53
|
+
console.print(
|
|
54
|
+
f"The before-patch at {checkpoint_file} captured the state before the task ran.\n"
|
|
55
|
+
f"To manually reset:\n"
|
|
56
|
+
f" 1. [bold]git stash[/bold] (if you want to keep current changes)\n"
|
|
57
|
+
f" 2. [bold]git checkout -- .[/bold] (discard working tree changes)\n"
|
|
58
|
+
f" 3. [bold]git apply {checkpoint_file}[/bold] (restore pre-task state)"
|
|
59
|
+
)
|
|
60
|
+
elif after_patch.exists():
|
|
61
|
+
console.print(
|
|
62
|
+
f"Only the after-patch at {after_patch} exists (it captured the task's changes).\n"
|
|
63
|
+
f"To manually revert those changes from the working tree:\n"
|
|
64
|
+
f" 1. [bold]git apply --stat {after_patch}[/bold] (inspect what the task changed)\n"
|
|
65
|
+
f" 2. [bold]git apply -R {after_patch}[/bold] (reverse-apply the task's changes)"
|
|
66
|
+
)
|
|
36
67
|
raise typer.Exit(code=1)
|
|
37
68
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if "failed" in result.message.lower() or result.message.startswith("No checkpoint"):
|
|
41
|
-
console.print(f"[yellow]{result.message}[/yellow]")
|
|
42
|
-
if checkpoint_file.exists():
|
|
43
|
-
console.print(
|
|
44
|
-
f"The before-patch at {checkpoint_file} captured the state before the task ran.\n"
|
|
45
|
-
f"To manually reset:\n"
|
|
46
|
-
f" 1. [bold]git stash[/bold] (if you want to keep current changes)\n"
|
|
47
|
-
f" 2. [bold]git checkout -- .[/bold] (discard working tree changes)\n"
|
|
48
|
-
f" 3. [bold]git apply {checkpoint_file}[/bold] (restore pre-task state)"
|
|
49
|
-
)
|
|
50
|
-
elif after_patch.exists():
|
|
51
|
-
console.print(
|
|
52
|
-
f"Only the after-patch at {after_patch} exists (it captured the task's changes).\n"
|
|
53
|
-
f"To manually revert those changes from the working tree:\n"
|
|
54
|
-
f" 1. [bold]git apply --stat {after_patch}[/bold] (inspect what the task changed)\n"
|
|
55
|
-
f" 2. [bold]git apply -R {after_patch}[/bold] (reverse-apply the task's changes)"
|
|
56
|
-
)
|
|
57
|
-
raise typer.Exit(code=1)
|
|
58
|
-
|
|
59
|
-
console.print(f"[green]Successfully rolled back task {task_id}.[/green] {result.message}")
|
|
69
|
+
console.print(f"[green]Successfully rolled back task {task_id}.[/green] {result.message}")
|
|
70
|
+
log_step("rollback/complete", project_root=root, task_id=task_id, trace=True)
|
|
@@ -10,6 +10,7 @@ from devcouncil.executors.coding_cli import CodingCliExecutor
|
|
|
10
10
|
from devcouncil.executors.agent_registry import (
|
|
11
11
|
AGENT_ALIASES,
|
|
12
12
|
BUILTIN_CODING_EXECUTOR_NAMES,
|
|
13
|
+
list_run_executor_names,
|
|
13
14
|
load_cli_agent_specs,
|
|
14
15
|
)
|
|
15
16
|
from devcouncil.executors.native.agent import NativeAgent
|
|
@@ -17,11 +18,14 @@ from devcouncil.llm.provider import create_provider, validate_model_provider
|
|
|
17
18
|
from devcouncil.llm.router import ModelRouter
|
|
18
19
|
from devcouncil.app.config import load_config, get_api_key
|
|
19
20
|
from devcouncil.domain.evidence import CommandResult, DiffEvidence, TestEvidence
|
|
21
|
+
from devcouncil.domain.task import Task
|
|
22
|
+
from devcouncil.domain.requirement import Requirement
|
|
20
23
|
from devcouncil.storage.repositories import GapRepository, EvidenceRepository, StateRepository
|
|
21
24
|
from devcouncil.verification.verifier import Verifier
|
|
22
25
|
from devcouncil.app.state_machine import ProjectPhase
|
|
23
26
|
from devcouncil.cli.commands.init import initialize_project
|
|
24
27
|
from devcouncil.telemetry.traces import TraceLogger
|
|
28
|
+
from devcouncil.telemetry.stages import log_stage, log_step
|
|
25
29
|
|
|
26
30
|
console = Console()
|
|
27
31
|
logger = logging.getLogger(__name__)
|
|
@@ -39,14 +43,59 @@ def _current_changed_files(project_root: Path = Path(".")) -> list[str]:
|
|
|
39
43
|
|
|
40
44
|
return Verifier(project_root).get_changed_files()
|
|
41
45
|
|
|
46
|
+
|
|
47
|
+
def _verify_executor_output_if_present(
|
|
48
|
+
session,
|
|
49
|
+
task,
|
|
50
|
+
reqs,
|
|
51
|
+
*,
|
|
52
|
+
root: Path,
|
|
53
|
+
executor_label: str,
|
|
54
|
+
cli_client: str | None = None,
|
|
55
|
+
cli_executor=None,
|
|
56
|
+
) -> bool:
|
|
57
|
+
"""Run verification when the executor failed but left implementable changes."""
|
|
58
|
+
if not _current_changed_files(root):
|
|
59
|
+
return False
|
|
60
|
+
console.print(
|
|
61
|
+
f"[yellow]{executor_label} failed, but the workspace has changes — "
|
|
62
|
+
f"verifying {task.id} against them anyway.[/yellow]"
|
|
63
|
+
)
|
|
64
|
+
verified = _verify_after_execution(
|
|
65
|
+
session, task, reqs, router=_build_verification_router(root), project_root=root
|
|
66
|
+
)
|
|
67
|
+
_record_project_phase(
|
|
68
|
+
session,
|
|
69
|
+
ProjectPhase.TASK_VERIFIED if verified else ProjectPhase.TASK_BLOCKED,
|
|
70
|
+
)
|
|
71
|
+
TaskRepository(session).save(task)
|
|
72
|
+
if cli_client:
|
|
73
|
+
_record_agent_verification(
|
|
74
|
+
root,
|
|
75
|
+
task.id,
|
|
76
|
+
cli_client,
|
|
77
|
+
getattr(cli_executor, "last_run_id", None) if cli_executor else None,
|
|
78
|
+
verified,
|
|
79
|
+
)
|
|
80
|
+
_run_live_review_after_execution(root, cli_client, task.id)
|
|
81
|
+
_log_exec_outcome(executor_label, task.id, verified=verified)
|
|
82
|
+
if verified:
|
|
83
|
+
console.print(f"\n[green]{executor_label} left verifiable work; {task.id} verified.[/green]")
|
|
84
|
+
else:
|
|
85
|
+
console.print(
|
|
86
|
+
f"\n[yellow]{executor_label} left changes, but {task.id} is blocked by verification gaps.[/yellow]"
|
|
87
|
+
)
|
|
88
|
+
return True
|
|
89
|
+
|
|
42
90
|
def _capture_after_patch(task_id: str, project_root: Path = Path(".")):
|
|
43
91
|
"""Capture the diff after task execution for use by rollback."""
|
|
44
92
|
try:
|
|
45
93
|
from devcouncil.execution.checkpoints import CheckpointService
|
|
46
94
|
|
|
47
95
|
CheckpointService(project_root).create_after(task_id)
|
|
48
|
-
except Exception:
|
|
49
|
-
|
|
96
|
+
except Exception as e:
|
|
97
|
+
# Non-critical — don't block execution, but a missing after checkpoint breaks rollback.
|
|
98
|
+
logger.warning("Failed to capture after checkpoint for %s: %s", task_id, e)
|
|
50
99
|
|
|
51
100
|
def _capture_before_snapshot(task_id: str, project_root: Path = Path(".")):
|
|
52
101
|
from devcouncil.execution.checkpoints import CheckpointService
|
|
@@ -56,11 +105,22 @@ def _capture_before_snapshot(task_id: str, project_root: Path = Path(".")):
|
|
|
56
105
|
def _record_project_phase(session, phase: ProjectPhase):
|
|
57
106
|
StateRepository(session).record_phase(phase.value)
|
|
58
107
|
|
|
59
|
-
def _verify_after_execution(
|
|
108
|
+
def _verify_after_execution(
|
|
109
|
+
session,
|
|
110
|
+
task: Task,
|
|
111
|
+
reqs: list[Requirement],
|
|
112
|
+
router=None,
|
|
113
|
+
project_root: Path = Path("."),
|
|
114
|
+
) -> bool:
|
|
60
115
|
"""Run deterministic verification after an automated executor finishes."""
|
|
61
116
|
import asyncio
|
|
62
117
|
|
|
63
118
|
logger.info("Verifying task %s (router=%s)", task.id, "yes" if router else "no")
|
|
119
|
+
log_step(
|
|
120
|
+
"run/verify: verifying executor output",
|
|
121
|
+
project_root=project_root,
|
|
122
|
+
task_id=task.id,
|
|
123
|
+
)
|
|
64
124
|
verifier = Verifier(project_root, router=router)
|
|
65
125
|
gaps, evidence = asyncio.run(verifier.verify_task(task, reqs))
|
|
66
126
|
blocking = [g for g in gaps if g.blocking]
|
|
@@ -148,13 +208,14 @@ def _run_live_review_after_execution(project_root: Path, client: str, task_id: s
|
|
|
148
208
|
)
|
|
149
209
|
from devcouncil.live.transcripts import latest_assistant_turn
|
|
150
210
|
|
|
151
|
-
transcript = _resolve_transcript(project_root, client, latest=True)
|
|
211
|
+
transcript = _resolve_transcript(project_root, client, latest=True, task_id=task_id)
|
|
152
212
|
if transcript is None or not transcript.exists():
|
|
153
213
|
return
|
|
154
214
|
turn = latest_assistant_turn(transcript, client=client)
|
|
155
215
|
if turn is None:
|
|
156
216
|
return
|
|
157
217
|
card = asyncio.run(_review_turn(turn, project_root, client, use_llm=True, task_id=task_id))
|
|
218
|
+
card = card.model_copy(update={"task_id": task_id, "blocks_gate": False})
|
|
158
219
|
saved_path, duplicate = _save_card_once(project_root, card, persist=True, force=False)
|
|
159
220
|
if saved_path:
|
|
160
221
|
_log_card_reviewed(project_root, card, saved_path, duplicate=duplicate, source="e2e")
|
|
@@ -188,8 +249,8 @@ def run(
|
|
|
188
249
|
"--executor",
|
|
189
250
|
"-e",
|
|
190
251
|
help=(
|
|
191
|
-
"Executor to use (manual, mini, openhands, native-preview, "
|
|
192
|
-
"codex, gemini, claude, opencode, antigravity, warp, cursor, aider, "
|
|
252
|
+
"Executor to use (manual, mini, openhands, native-preview, claude-sdk, "
|
|
253
|
+
"codex, gemini, claude, opencode, antigravity, warp, cursor, grok, aider, "
|
|
193
254
|
"copilot, goose, amp, qwen, crush, or a configured agent)"
|
|
194
255
|
),
|
|
195
256
|
),
|
|
@@ -214,6 +275,11 @@ def run(
|
|
|
214
275
|
console.print("[red]DevCouncil state is unavailable in this directory.[/red]")
|
|
215
276
|
return
|
|
216
277
|
|
|
278
|
+
with log_stage("run", project_root=root, task_id=task_id, executor=executor):
|
|
279
|
+
_run_task_body(root, task_id, executor, profile, stream, db)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _run_task_body(root, task_id, executor, profile, stream, db):
|
|
217
283
|
with db.get_session() as session:
|
|
218
284
|
task_repo = TaskRepository(session)
|
|
219
285
|
task = task_repo.get_by_id(task_id)
|
|
@@ -237,6 +303,7 @@ def run(
|
|
|
237
303
|
|
|
238
304
|
console.print(f"Running task [bold]{task_id}[/bold] using [bold]{executor}[/bold] executor...")
|
|
239
305
|
|
|
306
|
+
log_step("run/1: creating git checkpoint", project_root=root, task_id=task_id)
|
|
240
307
|
# 1. Create Git checkpoint
|
|
241
308
|
try:
|
|
242
309
|
from devcouncil.execution.checkpoints import CheckpointService
|
|
@@ -250,6 +317,38 @@ def run(
|
|
|
250
317
|
console.print(f"[yellow]Warning: Failed to create git checkpoint: {e}[/yellow]")
|
|
251
318
|
|
|
252
319
|
executor = executor.strip().lower().replace("_", "-")
|
|
320
|
+
if executor == "claude-sdk":
|
|
321
|
+
# Preflight the optional SDK BEFORE mutating any state: previously a
|
|
322
|
+
# missing claude-agent-sdk was only discovered inside run_task, after
|
|
323
|
+
# planning had already spent its budget — every such run failed at the
|
|
324
|
+
# finish line with "SDK is not installed" (observed repeatedly in logs).
|
|
325
|
+
# Degrade to the Claude Code CLI executor when it is available (same
|
|
326
|
+
# agent, hook-based gating instead of in-process gating); otherwise
|
|
327
|
+
# fail fast with the actionable install hint.
|
|
328
|
+
import importlib.util
|
|
329
|
+
import shutil as _shutil
|
|
330
|
+
|
|
331
|
+
if importlib.util.find_spec("claude_agent_sdk") is None:
|
|
332
|
+
if _shutil.which("claude"):
|
|
333
|
+
logger.warning(
|
|
334
|
+
"claude-agent-sdk is not installed; falling back to the "
|
|
335
|
+
"'claude' CLI executor for %s (install claude-agent-sdk "
|
|
336
|
+
"to restore in-process tool gating).", task_id,
|
|
337
|
+
)
|
|
338
|
+
console.print(
|
|
339
|
+
"[yellow]claude-agent-sdk is not installed — falling back to the "
|
|
340
|
+
"'claude' CLI executor. Install it with "
|
|
341
|
+
"`pip install claude-agent-sdk` to use --executor claude-sdk.[/yellow]"
|
|
342
|
+
)
|
|
343
|
+
executor = "claude"
|
|
344
|
+
else:
|
|
345
|
+
logger.error("claude-sdk executor unavailable for %s: claude-agent-sdk not installed", task_id)
|
|
346
|
+
console.print(
|
|
347
|
+
"[red]The Claude Agent SDK is not installed and no `claude` CLI was found. "
|
|
348
|
+
"Install the SDK with `pip install claude-agent-sdk`, or use another "
|
|
349
|
+
"executor (e.g. --executor claude).[/red]"
|
|
350
|
+
)
|
|
351
|
+
return
|
|
253
352
|
custom_agents = _custom_cli_agents(root)
|
|
254
353
|
if executor not in CODING_EXECUTORS and executor not in custom_agents:
|
|
255
354
|
ignored = [flag for flag, value in (("--profile", profile), ("--stream", stream)) if value]
|
|
@@ -266,6 +365,12 @@ def run(
|
|
|
266
365
|
console.print("Use 'dev prompt TASK-ID' to get the prompt for this task.")
|
|
267
366
|
console.print("When finished, use 'dev verify TASK-ID' to check the results.")
|
|
268
367
|
elif executor in CODING_EXECUTORS or executor in custom_agents:
|
|
368
|
+
log_step(
|
|
369
|
+
f"run/2: executing with {executor}",
|
|
370
|
+
project_root=root,
|
|
371
|
+
task_id=task_id,
|
|
372
|
+
executor=executor,
|
|
373
|
+
)
|
|
269
374
|
_record_project_phase(session, ProjectPhase.TASK_EXECUTING)
|
|
270
375
|
req_repo = RequirementRepository(session)
|
|
271
376
|
reqs = req_repo.get_all()
|
|
@@ -304,7 +409,18 @@ def run(
|
|
|
304
409
|
else:
|
|
305
410
|
logger.error("%s failed to start or execute for %s: %s", executor, task_id, exec_result.message)
|
|
306
411
|
console.print(f"\n[red]{executor.upper()} failed to start or execute: {exec_result.message}[/red]")
|
|
412
|
+
if not _verify_executor_output_if_present(
|
|
413
|
+
session,
|
|
414
|
+
task,
|
|
415
|
+
reqs,
|
|
416
|
+
root=root,
|
|
417
|
+
executor_label=executor.upper(),
|
|
418
|
+
cli_client=cli_client,
|
|
419
|
+
cli_executor=cli_executor,
|
|
420
|
+
):
|
|
421
|
+
task_repo.save(task)
|
|
307
422
|
elif executor == "mini":
|
|
423
|
+
log_step("run/2: executing with mini-SWE-agent", project_root=root, task_id=task_id)
|
|
308
424
|
_record_project_phase(session, ProjectPhase.TASK_EXECUTING)
|
|
309
425
|
req_repo = RequirementRepository(session)
|
|
310
426
|
reqs = req_repo.get_all()
|
|
@@ -330,6 +446,7 @@ def run(
|
|
|
330
446
|
logger.error("mini-SWE-agent failed to start or execute for %s", task_id)
|
|
331
447
|
console.print("\n[red]mini-SWE-agent failed to start or execute.[/red]")
|
|
332
448
|
elif executor == "openhands":
|
|
449
|
+
log_step("run/2: executing with OpenHands", project_root=root, task_id=task_id)
|
|
333
450
|
_record_project_phase(session, ProjectPhase.TASK_EXECUTING)
|
|
334
451
|
req_repo = RequirementRepository(session)
|
|
335
452
|
reqs = req_repo.get_all()
|
|
@@ -354,7 +471,52 @@ def run(
|
|
|
354
471
|
else:
|
|
355
472
|
logger.error("OpenHands failed to start or execute for %s", task_id)
|
|
356
473
|
console.print("\n[red]OpenHands failed to start or execute.[/red]")
|
|
474
|
+
elif executor == "claude-sdk":
|
|
475
|
+
log_step("run/2: executing with claude-sdk", project_root=root, task_id=task_id)
|
|
476
|
+
# In-process Claude Agent SDK executor: every tool call is gated live against
|
|
477
|
+
# this task's scope, so out-of-scope writes/commands are denied before they land.
|
|
478
|
+
from devcouncil.executors.claude_sdk import ClaudeSdkExecutor
|
|
479
|
+
from devcouncil.executors.agent_registry import load_agent_profiles
|
|
480
|
+
|
|
481
|
+
_record_project_phase(session, ProjectPhase.TASK_EXECUTING)
|
|
482
|
+
req_repo = RequirementRepository(session)
|
|
483
|
+
reqs = req_repo.get_all()
|
|
484
|
+
# Honor --profile for model and env overrides (e.g. ANTHROPIC_BASE_URL to
|
|
485
|
+
# target an alternative Anthropic-compatible endpoint). permission_mode is
|
|
486
|
+
# deliberately NOT taken from the profile: the SDK executor's containment
|
|
487
|
+
# relies on "default" routing every tool call through can_use_tool; a
|
|
488
|
+
# profile's acceptEdits/auto would silently bypass the live scope gate.
|
|
489
|
+
sdk_profile = load_agent_profiles(root).get(profile or "default")
|
|
490
|
+
sdk_executor = ClaudeSdkExecutor(
|
|
491
|
+
root,
|
|
492
|
+
active_task=task,
|
|
493
|
+
model=(sdk_profile.model if sdk_profile else None),
|
|
494
|
+
advisor_model=(sdk_profile.advisor_model if sdk_profile else None),
|
|
495
|
+
env=(dict(sdk_profile.env) if sdk_profile and sdk_profile.env else None),
|
|
496
|
+
)
|
|
497
|
+
exec_result = sdk_executor.run_task(task, reqs)
|
|
498
|
+
_capture_after_patch(task_id, root)
|
|
499
|
+
if exec_result.success:
|
|
500
|
+
_record_project_phase(session, ProjectPhase.TASK_VERIFYING)
|
|
501
|
+
verified = _verify_after_execution(
|
|
502
|
+
session, task, reqs, router=_build_verification_router(root), project_root=root
|
|
503
|
+
)
|
|
504
|
+
_record_project_phase(
|
|
505
|
+
session,
|
|
506
|
+
ProjectPhase.TASK_VERIFIED if verified else ProjectPhase.TASK_BLOCKED,
|
|
507
|
+
)
|
|
508
|
+
task_repo.save(task)
|
|
509
|
+
_run_live_review_after_execution(root, "claude", task.id)
|
|
510
|
+
_log_exec_outcome("claude-sdk", task_id, verified=verified)
|
|
511
|
+
if verified:
|
|
512
|
+
console.print(f"\n[green]claude-sdk finished and task {task_id} verified.[/green]")
|
|
513
|
+
else:
|
|
514
|
+
console.print(f"\n[yellow]claude-sdk finished, but task {task_id} is blocked by verification gaps.[/yellow]")
|
|
515
|
+
else:
|
|
516
|
+
logger.error("claude-sdk failed to start or execute for %s: %s", task_id, exec_result.message)
|
|
517
|
+
console.print(f"\n[red]claude-sdk failed to start or execute: {exec_result.message}[/red]")
|
|
357
518
|
elif executor in {"native", "native-preview"}:
|
|
519
|
+
log_step("run/2: executing with native agent", project_root=root, task_id=task_id)
|
|
358
520
|
# Load config for model routing and permissions
|
|
359
521
|
try:
|
|
360
522
|
config = load_config(root)
|
|
@@ -406,5 +568,8 @@ def run(
|
|
|
406
568
|
logger.error("Native agent failed during execution for %s", task_id)
|
|
407
569
|
console.print("\n[red]Native agent failed during execution.[/red]")
|
|
408
570
|
else:
|
|
409
|
-
|
|
410
|
-
|
|
571
|
+
available = ", ".join(list_run_executor_names(root))
|
|
572
|
+
logger.error("Executor %r not recognized; available: %s", executor, available)
|
|
573
|
+
console.print(f"[red]Unknown executor {executor!r}.[/red]")
|
|
574
|
+
console.print(f"[dim]Available executors: {available}[/dim]")
|
|
575
|
+
log_step("run/complete", project_root=root, task_id=task_id, executor=executor, trace=True)
|