devcouncil 0.2.0 → 0.2.2

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 (205) hide show
  1. package/README.md +144 -308
  2. package/bin/devcouncil.js +130 -32
  3. package/package.json +22 -19
  4. package/pyproject.toml +0 -66
  5. package/src/devcouncil/__init__.py +0 -0
  6. package/src/devcouncil/__main__.py +0 -4
  7. package/src/devcouncil/app/__init__.py +0 -28
  8. package/src/devcouncil/app/config.py +0 -320
  9. package/src/devcouncil/app/errors.py +0 -23
  10. package/src/devcouncil/app/events.py +0 -44
  11. package/src/devcouncil/app/orchestrator.py +0 -92
  12. package/src/devcouncil/app/project_status.py +0 -29
  13. package/src/devcouncil/app/run_context.py +0 -39
  14. package/src/devcouncil/app/state_machine.py +0 -108
  15. package/src/devcouncil/artifacts/__init__.py +0 -1
  16. package/src/devcouncil/artifacts/coverage.py +0 -96
  17. package/src/devcouncil/artifacts/graph.py +0 -163
  18. package/src/devcouncil/artifacts/migrations.py +0 -20
  19. package/src/devcouncil/artifacts/schemas.py +0 -23
  20. package/src/devcouncil/artifacts/serializer.py +0 -21
  21. package/src/devcouncil/artifacts/validators.py +0 -27
  22. package/src/devcouncil/assets/__init__.py +0 -1
  23. package/src/devcouncil/assets/devcouncil-logo.svg +0 -60
  24. package/src/devcouncil/assets/devcouncil_logo_premium.png +0 -0
  25. package/src/devcouncil/cli/__init__.py +0 -0
  26. package/src/devcouncil/cli/commands/__init__.py +0 -0
  27. package/src/devcouncil/cli/commands/agents.py +0 -292
  28. package/src/devcouncil/cli/commands/artifacts.py +0 -54
  29. package/src/devcouncil/cli/commands/ast.py +0 -22
  30. package/src/devcouncil/cli/commands/baseline.py +0 -35
  31. package/src/devcouncil/cli/commands/check.py +0 -209
  32. package/src/devcouncil/cli/commands/config.py +0 -115
  33. package/src/devcouncil/cli/commands/cost.py +0 -57
  34. package/src/devcouncil/cli/commands/dashboard.py +0 -31
  35. package/src/devcouncil/cli/commands/doctor.py +0 -340
  36. package/src/devcouncil/cli/commands/evidence.py +0 -48
  37. package/src/devcouncil/cli/commands/go.py +0 -656
  38. package/src/devcouncil/cli/commands/handoff.py +0 -69
  39. package/src/devcouncil/cli/commands/hook.py +0 -237
  40. package/src/devcouncil/cli/commands/init.py +0 -289
  41. package/src/devcouncil/cli/commands/integrate.py +0 -1515
  42. package/src/devcouncil/cli/commands/lsp.py +0 -20
  43. package/src/devcouncil/cli/commands/map.py +0 -112
  44. package/src/devcouncil/cli/commands/mcp_server.py +0 -18
  45. package/src/devcouncil/cli/commands/plan.py +0 -488
  46. package/src/devcouncil/cli/commands/prompt.py +0 -61
  47. package/src/devcouncil/cli/commands/repair.py +0 -89
  48. package/src/devcouncil/cli/commands/report.py +0 -137
  49. package/src/devcouncil/cli/commands/reset_demo_state.py +0 -33
  50. package/src/devcouncil/cli/commands/rollback.py +0 -59
  51. package/src/devcouncil/cli/commands/run.py +0 -289
  52. package/src/devcouncil/cli/commands/runs.py +0 -223
  53. package/src/devcouncil/cli/commands/scaffold.py +0 -32
  54. package/src/devcouncil/cli/commands/semantic.py +0 -47
  55. package/src/devcouncil/cli/commands/setup.py +0 -362
  56. package/src/devcouncil/cli/commands/shell.py +0 -73
  57. package/src/devcouncil/cli/commands/show.py +0 -76
  58. package/src/devcouncil/cli/commands/skills.py +0 -88
  59. package/src/devcouncil/cli/commands/status.py +0 -141
  60. package/src/devcouncil/cli/commands/tasks.py +0 -55
  61. package/src/devcouncil/cli/commands/trace.py +0 -88
  62. package/src/devcouncil/cli/commands/verify.py +0 -328
  63. package/src/devcouncil/cli/commands/version.py +0 -20
  64. package/src/devcouncil/cli/commands/watch.py +0 -574
  65. package/src/devcouncil/cli/commands/watch_fs.py +0 -40
  66. package/src/devcouncil/cli/main.py +0 -137
  67. package/src/devcouncil/council/__init__.py +0 -0
  68. package/src/devcouncil/council/prompts/__init__.py +0 -0
  69. package/src/devcouncil/council/prompts/arbiter.md +0 -19
  70. package/src/devcouncil/council/prompts/critic_a.md +0 -10
  71. package/src/devcouncil/council/prompts/critic_b.md +0 -10
  72. package/src/devcouncil/council/prompts/implementation_reviewer.md +0 -16
  73. package/src/devcouncil/council/prompts/planner_a.md +0 -16
  74. package/src/devcouncil/council/prompts/planner_b.md +0 -16
  75. package/src/devcouncil/council/prompts/rebuttal.md +0 -10
  76. package/src/devcouncil/council/prompts/spec_writer.md +0 -12
  77. package/src/devcouncil/domain/__init__.py +0 -0
  78. package/src/devcouncil/domain/assumption.py +0 -17
  79. package/src/devcouncil/domain/critique.py +0 -32
  80. package/src/devcouncil/domain/evidence.py +0 -47
  81. package/src/devcouncil/domain/gap.py +0 -52
  82. package/src/devcouncil/domain/requirement.py +0 -22
  83. package/src/devcouncil/domain/task.py +0 -55
  84. package/src/devcouncil/execution/__init__.py +0 -1
  85. package/src/devcouncil/execution/checkpoints.py +0 -246
  86. package/src/devcouncil/execution/context_builder.py +0 -60
  87. package/src/devcouncil/execution/executor.py +0 -15
  88. package/src/devcouncil/execution/fs_watcher.py +0 -180
  89. package/src/devcouncil/execution/handoff.py +0 -102
  90. package/src/devcouncil/execution/hook_policy.py +0 -253
  91. package/src/devcouncil/execution/patch.py +0 -77
  92. package/src/devcouncil/execution/paths.py +0 -14
  93. package/src/devcouncil/execution/permissions.py +0 -85
  94. package/src/devcouncil/execution/policy_engine.py +0 -343
  95. package/src/devcouncil/execution/prompt_builder.py +0 -671
  96. package/src/devcouncil/execution/shell_session.py +0 -225
  97. package/src/devcouncil/execution/task_runner.py +0 -170
  98. package/src/devcouncil/executors/__init__.py +0 -1
  99. package/src/devcouncil/executors/agent_registry.py +0 -575
  100. package/src/devcouncil/executors/coding_cli.py +0 -736
  101. package/src/devcouncil/executors/mini_swe.py +0 -73
  102. package/src/devcouncil/executors/native/__init__.py +0 -0
  103. package/src/devcouncil/executors/native/agent.py +0 -208
  104. package/src/devcouncil/executors/openhands.py +0 -71
  105. package/src/devcouncil/gating/__init__.py +0 -1
  106. package/src/devcouncil/gating/checks/__init__.py +0 -0
  107. package/src/devcouncil/gating/checks/clean_git.py +0 -52
  108. package/src/devcouncil/gating/checks/planned_files_check.py +0 -32
  109. package/src/devcouncil/gating/checks/requirement_coverage.py +0 -26
  110. package/src/devcouncil/gating/checks/secret_scan_check.py +0 -53
  111. package/src/devcouncil/gating/policy.py +0 -338
  112. package/src/devcouncil/hardware.py +0 -184
  113. package/src/devcouncil/indexing/__init__.py +0 -1
  114. package/src/devcouncil/indexing/ast_matcher.py +0 -168
  115. package/src/devcouncil/indexing/graph_index.py +0 -48
  116. package/src/devcouncil/indexing/lsp.py +0 -161
  117. package/src/devcouncil/indexing/repo_mapper.py +0 -1455
  118. package/src/devcouncil/indexing/semantic_index.py +0 -205
  119. package/src/devcouncil/integrations/actions.py +0 -146
  120. package/src/devcouncil/integrations/check.py +0 -423
  121. package/src/devcouncil/integrations/code_review_graph.py +0 -163
  122. package/src/devcouncil/integrations/github.py +0 -39
  123. package/src/devcouncil/integrations/github_intent.py +0 -142
  124. package/src/devcouncil/integrations/gitnexus.py +0 -62
  125. package/src/devcouncil/integrations/graphify.py +0 -34
  126. package/src/devcouncil/integrations/mcp/__init__.py +0 -0
  127. package/src/devcouncil/integrations/mcp/server.py +0 -2122
  128. package/src/devcouncil/integrations/opencode_devcouncil_plugin.mjs +0 -24
  129. package/src/devcouncil/integrations/pr_comments.py +0 -62
  130. package/src/devcouncil/live/__init__.py +0 -2
  131. package/src/devcouncil/live/cards.py +0 -349
  132. package/src/devcouncil/live/models.py +0 -63
  133. package/src/devcouncil/live/repair_prompt.py +0 -83
  134. package/src/devcouncil/live/reviewer.py +0 -70
  135. package/src/devcouncil/live/signals.py +0 -135
  136. package/src/devcouncil/live/summary.py +0 -34
  137. package/src/devcouncil/live/tasks.py +0 -18
  138. package/src/devcouncil/live/transcripts.py +0 -141
  139. package/src/devcouncil/llm/__init__.py +0 -1
  140. package/src/devcouncil/llm/cache.py +0 -42
  141. package/src/devcouncil/llm/model_defaults.yaml +0 -44
  142. package/src/devcouncil/llm/provider.py +0 -627
  143. package/src/devcouncil/llm/router.py +0 -310
  144. package/src/devcouncil/optimization/__init__.py +0 -1
  145. package/src/devcouncil/optimization/gepa_agent.py +0 -318
  146. package/src/devcouncil/planning/__init__.py +0 -1
  147. package/src/devcouncil/planning/arbiter_service.py +0 -57
  148. package/src/devcouncil/planning/correction_manifest.py +0 -303
  149. package/src/devcouncil/planning/critique_service.py +0 -71
  150. package/src/devcouncil/planning/plan_service.py +0 -60
  151. package/src/devcouncil/planning/prompt_enhancer_service.py +0 -167
  152. package/src/devcouncil/planning/repair_service.py +0 -39
  153. package/src/devcouncil/planning/spec_service.py +0 -70
  154. package/src/devcouncil/repo/__init__.py +0 -0
  155. package/src/devcouncil/repo/ci_scaffold.py +0 -157
  156. package/src/devcouncil/repo/gitignore.py +0 -123
  157. package/src/devcouncil/repo/sca.py +0 -374
  158. package/src/devcouncil/reporting/__init__.py +0 -0
  159. package/src/devcouncil/reporting/github_check.py +0 -32
  160. package/src/devcouncil/reporting/json_report.py +0 -30
  161. package/src/devcouncil/reporting/markdown_report.py +0 -83
  162. package/src/devcouncil/reporting/report_builder.py +0 -14
  163. package/src/devcouncil/skills/__init__.py +0 -19
  164. package/src/devcouncil/skills/library/README.md +0 -46
  165. package/src/devcouncil/skills/library/ai-training.md +0 -50
  166. package/src/devcouncil/skills/library/android.md +0 -50
  167. package/src/devcouncil/skills/library/backend.md +0 -52
  168. package/src/devcouncil/skills/library/core-engineering.md +0 -95
  169. package/src/devcouncil/skills/library/data-engineering.md +0 -47
  170. package/src/devcouncil/skills/library/desktop.md +0 -46
  171. package/src/devcouncil/skills/library/devops.md +0 -48
  172. package/src/devcouncil/skills/library/game-dev.md +0 -46
  173. package/src/devcouncil/skills/library/ios.md +0 -48
  174. package/src/devcouncil/skills/library/mobile-cross-platform.md +0 -46
  175. package/src/devcouncil/skills/library/security.md +0 -48
  176. package/src/devcouncil/skills/library/systems.md +0 -48
  177. package/src/devcouncil/skills/library/web.md +0 -47
  178. package/src/devcouncil/skills/library/windows.md +0 -47
  179. package/src/devcouncil/skills/registry.py +0 -330
  180. package/src/devcouncil/storage/__init__.py +0 -0
  181. package/src/devcouncil/storage/db.py +0 -147
  182. package/src/devcouncil/storage/models.py +0 -204
  183. package/src/devcouncil/storage/native.py +0 -557
  184. package/src/devcouncil/storage/repositories.py +0 -485
  185. package/src/devcouncil/telemetry/__init__.py +0 -0
  186. package/src/devcouncil/telemetry/cost.py +0 -140
  187. package/src/devcouncil/telemetry/model_pricing.yaml +0 -48
  188. package/src/devcouncil/telemetry/pricing.py +0 -28
  189. package/src/devcouncil/telemetry/traces.py +0 -146
  190. package/src/devcouncil/telemetry/tracker.py +0 -52
  191. package/src/devcouncil/ui/__init__.py +0 -1
  192. package/src/devcouncil/ui/dashboard.py +0 -423
  193. package/src/devcouncil/utils/__init__.py +0 -1
  194. package/src/devcouncil/utils/redaction.py +0 -147
  195. package/src/devcouncil/utils/subprocess_env.py +0 -69
  196. package/src/devcouncil/verification/__init__.py +0 -1
  197. package/src/devcouncil/verification/acceptance_compiler.py +0 -125
  198. package/src/devcouncil/verification/ad_hoc_check.py +0 -129
  199. package/src/devcouncil/verification/diff_coverage.py +0 -353
  200. package/src/devcouncil/verification/implementation_reviewer.py +0 -55
  201. package/src/devcouncil/verification/next_actions.py +0 -189
  202. package/src/devcouncil/verification/sandbox.py +0 -178
  203. package/src/devcouncil/verification/test_resolver.py +0 -91
  204. package/src/devcouncil/verification/verifier.py +0 -1548
  205. package/uv.lock +0 -1226
@@ -1,575 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import shutil
4
- from dataclasses import dataclass, field
5
- from pathlib import Path
6
- from typing import Any
7
-
8
- from devcouncil.app.config import CliAgentProfileConfig, load_config
9
-
10
-
11
- AGENT_ALIASES = {
12
- "agy": "antigravity",
13
- "agy-cli": "antigravity",
14
- "antigravity-cli": "antigravity",
15
- "google-antigravity": "antigravity",
16
- "codex-cli": "codex",
17
- "gemini-cli": "gemini",
18
- "claude-cli": "claude",
19
- "claude-code": "claude",
20
- "opencode-cli": "opencode",
21
- "open-code": "opencode",
22
- "warp-cli": "warp",
23
- "oz": "warp",
24
- "oz-cli": "warp",
25
- "cursor-agent": "cursor",
26
- "cursor-cli": "cursor",
27
- "copilot-cli": "copilot",
28
- "github-copilot": "copilot",
29
- "gh-copilot": "copilot",
30
- "goose-cli": "goose",
31
- "block-goose": "goose",
32
- "amp-cli": "amp",
33
- "sourcegraph-amp": "amp",
34
- "qwen-code": "qwen",
35
- "qwen-cli": "qwen",
36
- "crush-cli": "crush",
37
- "charm-crush": "crush",
38
- }
39
-
40
- BUILTIN_AGENT_NAMES = {
41
- "aider",
42
- "amp",
43
- "antigravity",
44
- "claude",
45
- "codex",
46
- "copilot",
47
- "crush",
48
- "cursor",
49
- "gemini",
50
- "goose",
51
- "opencode",
52
- "qwen",
53
- "warp",
54
- }
55
-
56
- BUILTIN_CODING_EXECUTOR_NAMES = tuple(sorted(BUILTIN_AGENT_NAMES))
57
- VALID_INPUT_MODES = {"stdin", "argument", "prompt-file"}
58
-
59
-
60
- @dataclass(frozen=True)
61
- class CliAgentSpec:
62
- name: str
63
- command: str
64
- args: list[str] = field(default_factory=list)
65
- input_mode: str = "stdin"
66
- prompt_arg: str | None = None
67
- timeout_seconds: int | None = None
68
- env: dict[str, str] = field(default_factory=dict)
69
- display_name: str | None = None
70
- kind: str = "custom"
71
- supports_mcp: bool = False
72
- supports_diff_review: bool = False
73
- default_profile: str = "default"
74
- help_command: list[str] = field(default_factory=list)
75
- built_in: bool = False
76
- capabilities: list[str] = field(default_factory=list)
77
- supports_handoff: bool = False
78
- preferred_artifact_format: str = "json"
79
-
80
- @property
81
- def label(self) -> str:
82
- return self.display_name or self.name
83
-
84
- @property
85
- def executable(self) -> str:
86
- return self.command
87
-
88
- def base_command(self) -> list[str]:
89
- return [self.command, *self.args]
90
-
91
-
92
- def normalize_agent_name(name: str) -> str:
93
- normalized = (name or "").strip().lower().replace("_", "-")
94
- return AGENT_ALIASES.get(normalized, normalized)
95
-
96
-
97
- def resolve_cursor_agent_executable() -> str | None:
98
- for candidate in ("cursor-agent", "agent"):
99
- if shutil.which(candidate):
100
- return candidate
101
- return None
102
-
103
-
104
- CODING_CLI_PROBE_ORDER: tuple[str, ...] = (
105
- "codex",
106
- "gemini",
107
- "claude",
108
- "cursor",
109
- "opencode",
110
- "antigravity",
111
- "warp",
112
- "aider",
113
- "copilot",
114
- "goose",
115
- "amp",
116
- "qwen",
117
- "crush",
118
- )
119
-
120
- @dataclass(frozen=True)
121
- class CodingCliIntegrationInfo:
122
- name: str
123
- label: str
124
- tier: int
125
- headless: bool
126
- mcp: bool
127
- hooks: bool
128
- launcher_shim: bool
129
- notes: str
130
-
131
- @property
132
- def enforcement(self) -> str:
133
- """Honest containment posture: ``pre-action`` when a native hook blocks
134
- unauthorized writes/commands before they happen, else ``verify-only`` — for
135
- which "forbidden changes" are caught only post-hoc by verification, not blocked
136
- up front. Surfaced so users aren't misled into assuming hard containment."""
137
- return "pre-action" if self.hooks else "verify-only"
138
-
139
-
140
- # Tier 1 = headless executor + verify; tier 2 = MCP companion; hooks = native pre-tool policy.
141
- CODING_CLI_INTEGRATION_INFO: dict[str, CodingCliIntegrationInfo] = {
142
- "codex": CodingCliIntegrationInfo(
143
- "codex", "Codex CLI", 1, True, True, True, True, "dev integrate codex --apply"
144
- ),
145
- "gemini": CodingCliIntegrationInfo(
146
- "gemini", "Gemini CLI", 1, True, True, True, True, "dev integrate gemini --apply"
147
- ),
148
- "claude": CodingCliIntegrationInfo(
149
- "claude", "Claude Code", 1, True, True, True, True, "dev integrate claude --apply"
150
- ),
151
- "cursor": CodingCliIntegrationInfo(
152
- "cursor",
153
- "Cursor",
154
- 1,
155
- True,
156
- True,
157
- True,
158
- True,
159
- "dev integrate cursor --apply; cursor-agent for headless",
160
- ),
161
- "opencode": CodingCliIntegrationInfo(
162
- "opencode", "OpenCode", 1, True, True, True, True, "dev integrate opencode --apply"
163
- ),
164
- "antigravity": CodingCliIntegrationInfo(
165
- "antigravity",
166
- "Google Antigravity CLI",
167
- 1,
168
- True,
169
- True,
170
- False,
171
- True,
172
- "dev integrate antigravity --apply",
173
- ),
174
- "warp": CodingCliIntegrationInfo(
175
- "warp", "Warp / Oz", 1, True, True, False, True, "dev integrate warp --apply"
176
- ),
177
- "aider": CodingCliIntegrationInfo(
178
- "aider", "Aider", 1, True, False, False, True, "dev integrate aider --apply"
179
- ),
180
- "copilot": CodingCliIntegrationInfo(
181
- "copilot", "GitHub Copilot CLI", 1, True, True, False, True, "dev run TASK-ID --executor copilot"
182
- ),
183
- "goose": CodingCliIntegrationInfo(
184
- "goose", "Goose", 1, True, True, False, True, "dev run TASK-ID --executor goose"
185
- ),
186
- "amp": CodingCliIntegrationInfo(
187
- "amp", "Amp (Sourcegraph)", 1, True, True, False, True, "dev run TASK-ID --executor amp"
188
- ),
189
- "qwen": CodingCliIntegrationInfo(
190
- "qwen", "Qwen Code", 1, True, True, False, True, "dev run TASK-ID --executor qwen"
191
- ),
192
- "crush": CodingCliIntegrationInfo(
193
- "crush", "Crush (Charm)", 1, True, True, False, True, "dev run TASK-ID --executor crush"
194
- ),
195
- }
196
-
197
- # First successful probe wins (cursor tries cursor-agent then cursor).
198
- CODING_CLI_VERSION_COMMANDS: dict[str, tuple[tuple[str, ...], ...]] = {
199
- "codex": (("codex", "--version"),),
200
- "gemini": (("gemini", "--version"),),
201
- "claude": (("claude", "--version"),),
202
- "cursor": (("cursor-agent", "--version"), ("cursor", "--version")),
203
- "opencode": (("opencode", "--version"),),
204
- "antigravity": (("agy", "--version"),),
205
- "warp": (("oz", "--version"),),
206
- "aider": (("aider", "--version"),),
207
- "copilot": (("copilot", "--version"),),
208
- "goose": (("goose", "--version"),),
209
- "amp": (("amp", "--version"),),
210
- "qwen": (("qwen", "--version"),),
211
- "crush": (("crush", "--version"),),
212
- }
213
-
214
-
215
- def integration_tier_label(client: str) -> str:
216
- info = CODING_CLI_INTEGRATION_INFO.get(normalize_agent_name(client))
217
- tier = info.tier if info is not None else 3
218
- if tier == 1:
219
- return "Tier 1 (headless executor)"
220
- if tier == 2:
221
- return "Tier 2 (MCP companion)"
222
- return "Tier 3 (sidecar)"
223
-
224
-
225
- def resolve_coding_cli_executable(project_root: Path, client: str) -> str | None:
226
- normalized = normalize_agent_name(client)
227
- if normalized == "cursor":
228
- return resolve_cursor_agent_executable()
229
- spec = get_cli_agent_spec(project_root, normalized)
230
- if not spec:
231
- return None
232
- return spec.executable if shutil.which(spec.executable) else None
233
-
234
-
235
- def resolve_coding_cli_probe_order(project_root: Path) -> tuple[str, ...]:
236
- try:
237
- configured = load_config(project_root).execution.coding_cli_probe_order
238
- if configured:
239
- return tuple(normalize_agent_name(name) for name in configured)
240
- except Exception:
241
- pass
242
- return CODING_CLI_PROBE_ORDER
243
-
244
-
245
- def detect_available_coding_cli(
246
- project_root: Path,
247
- probe_order: tuple[str, ...] | None = None,
248
- ) -> str | None:
249
- for client in probe_order or resolve_coding_cli_probe_order(project_root):
250
- if resolve_coding_cli_executable(project_root, client):
251
- return client
252
- return None
253
-
254
-
255
- def resolve_automated_executor(
256
- project_root: Path,
257
- explicit: str | None = None,
258
- *,
259
- probe_order: tuple[str, ...] | None = None,
260
- ) -> str:
261
- if explicit:
262
- return normalize_agent_name(explicit)
263
- try:
264
- config = load_config(project_root).execution
265
- configured = normalize_agent_name(config.default_executor)
266
- if probe_order is None:
267
- probe_order = resolve_coding_cli_probe_order(project_root)
268
- except Exception:
269
- configured = "manual"
270
- if probe_order is None:
271
- probe_order = CODING_CLI_PROBE_ORDER
272
- if configured != "manual":
273
- return configured
274
- detected = detect_available_coding_cli(project_root, probe_order=probe_order)
275
- return detected or configured
276
-
277
-
278
- def is_reserved_agent_name(name: str) -> bool:
279
- return normalize_agent_name(name) in BUILTIN_AGENT_NAMES
280
-
281
-
282
- def builtin_agent_specs(project_root: Path) -> dict[str, CliAgentSpec]:
283
- warp_mcp_path = project_root / ".devcouncil" / "integrations" / "warp-mcp.json"
284
- return {
285
- "codex": CliAgentSpec(
286
- name="codex",
287
- command="codex",
288
- args=["exec", "-"],
289
- display_name="Codex CLI",
290
- kind="coding-cli",
291
- supports_mcp=True,
292
- supports_diff_review=True,
293
- supports_handoff=True,
294
- built_in=True,
295
- ),
296
- "gemini": CliAgentSpec(
297
- name="gemini",
298
- command="gemini",
299
- display_name="Gemini CLI",
300
- kind="coding-cli",
301
- supports_mcp=True,
302
- built_in=True,
303
- ),
304
- "claude": CliAgentSpec(
305
- name="claude",
306
- # `-p` runs headless; `--permission-mode acceptEdits` lets Claude Code
307
- # actually apply file edits without an interactive approval prompt
308
- # (otherwise it only describes the change and the diff stays empty).
309
- command="claude",
310
- args=["-p", "--permission-mode", "acceptEdits"],
311
- display_name="Claude Code",
312
- kind="coding-cli",
313
- supports_mcp=True,
314
- supports_diff_review=True,
315
- supports_handoff=True,
316
- built_in=True,
317
- ),
318
- "opencode": CliAgentSpec(
319
- name="opencode",
320
- command="opencode",
321
- args=[
322
- "run",
323
- "--file",
324
- "{prompt_file}",
325
- "Execute the DevCouncil task described in the attached prompt file.",
326
- ],
327
- input_mode="prompt-file",
328
- display_name="OpenCode",
329
- kind="coding-cli",
330
- supports_mcp=True,
331
- supports_diff_review=True,
332
- supports_handoff=True,
333
- built_in=True,
334
- ),
335
- "antigravity": CliAgentSpec(
336
- name="antigravity",
337
- command="agy",
338
- args=[
339
- "--print",
340
- "--print-timeout",
341
- "30m",
342
- "Read and execute the DevCouncil task prompt at {prompt_file}.",
343
- ],
344
- input_mode="prompt-file",
345
- display_name="Google Antigravity CLI",
346
- kind="coding-cli",
347
- supports_mcp=True,
348
- supports_diff_review=True,
349
- supports_handoff=True,
350
- built_in=True,
351
- ),
352
- "warp": CliAgentSpec(
353
- name="warp",
354
- command="oz",
355
- args=["agent", "run", "--cwd", str(project_root), "--mcp", str(warp_mcp_path), "--prompt"],
356
- input_mode="argument",
357
- display_name="Warp / Oz",
358
- kind="agent-platform",
359
- supports_mcp=True,
360
- supports_diff_review=True,
361
- supports_handoff=True,
362
- built_in=True,
363
- ),
364
- "cursor": CliAgentSpec(
365
- name="cursor",
366
- command=resolve_cursor_agent_executable() or "cursor-agent",
367
- args=[
368
- "--print",
369
- "--trust",
370
- "--workspace",
371
- str(project_root),
372
- "Read and execute the DevCouncil task prompt at {prompt_file}.",
373
- ],
374
- input_mode="prompt-file",
375
- display_name="Cursor Agent",
376
- kind="coding-cli",
377
- supports_mcp=True,
378
- supports_diff_review=True,
379
- supports_handoff=True,
380
- built_in=True,
381
- ),
382
- "aider": CliAgentSpec(
383
- name="aider",
384
- command="aider",
385
- args=["--yes", "--no-show-model-warnings", "--message"],
386
- input_mode="argument",
387
- display_name="Aider",
388
- kind="coding-cli",
389
- supports_mcp=False,
390
- supports_diff_review=True,
391
- supports_handoff=True,
392
- built_in=True,
393
- ),
394
- "copilot": CliAgentSpec(
395
- name="copilot",
396
- command="copilot",
397
- args=["--allow-all-tools", "-p"],
398
- input_mode="argument",
399
- display_name="GitHub Copilot CLI",
400
- kind="coding-cli",
401
- supports_mcp=True,
402
- supports_diff_review=True,
403
- supports_handoff=True,
404
- built_in=True,
405
- ),
406
- "goose": CliAgentSpec(
407
- name="goose",
408
- command="goose",
409
- args=["run", "-i", "{prompt_file}"],
410
- input_mode="prompt-file",
411
- display_name="Goose",
412
- kind="coding-cli",
413
- supports_mcp=True,
414
- supports_diff_review=True,
415
- supports_handoff=True,
416
- built_in=True,
417
- ),
418
- "amp": CliAgentSpec(
419
- name="amp",
420
- command="amp",
421
- args=["-x"],
422
- input_mode="argument",
423
- display_name="Amp (Sourcegraph)",
424
- kind="coding-cli",
425
- supports_mcp=True,
426
- supports_diff_review=True,
427
- supports_handoff=True,
428
- built_in=True,
429
- ),
430
- "qwen": CliAgentSpec(
431
- name="qwen",
432
- command="qwen",
433
- display_name="Qwen Code",
434
- kind="coding-cli",
435
- supports_mcp=True,
436
- supports_diff_review=True,
437
- supports_handoff=True,
438
- built_in=True,
439
- ),
440
- "crush": CliAgentSpec(
441
- name="crush",
442
- command="crush",
443
- args=["run"],
444
- input_mode="argument",
445
- display_name="Crush (Charm)",
446
- kind="coding-cli",
447
- supports_mcp=True,
448
- supports_diff_review=True,
449
- supports_handoff=True,
450
- built_in=True,
451
- ),
452
- }
453
-
454
-
455
- def load_cli_agent_specs(project_root: Path) -> dict[str, CliAgentSpec]:
456
- specs = builtin_agent_specs(project_root)
457
- try:
458
- configured = load_config(project_root).integrations.cli_agents.agents
459
- except Exception:
460
- configured = {}
461
-
462
- for raw_name, agent in configured.items():
463
- name = normalize_agent_name(raw_name)
464
- if name in BUILTIN_AGENT_NAMES:
465
- continue
466
- data = agent.model_dump()
467
- specs[name] = CliAgentSpec(
468
- name=name,
469
- command=data["command"],
470
- args=list(data.get("args") or []),
471
- input_mode=data.get("input_mode") or "stdin",
472
- prompt_arg=data.get("prompt_arg"),
473
- timeout_seconds=data.get("timeout_seconds"),
474
- env=dict(data.get("env") or {}),
475
- display_name=data.get("display_name"),
476
- kind=data.get("kind") or "custom",
477
- supports_mcp=bool(data.get("supports_mcp")),
478
- supports_diff_review=bool(data.get("supports_diff_review")),
479
- default_profile=data.get("default_profile") or "default",
480
- help_command=list(data.get("help_command") or []),
481
- built_in=False,
482
- )
483
- return specs
484
-
485
-
486
- def get_cli_agent_spec(project_root: Path, name: str) -> CliAgentSpec | None:
487
- return load_cli_agent_specs(project_root).get(normalize_agent_name(name))
488
-
489
-
490
- def default_agent_profiles() -> dict[str, dict[str, Any]]:
491
- return {
492
- "default": {
493
- "description": "Balanced local execution with DevCouncil verification.",
494
- "timeout_seconds": None,
495
- "prompt_preamble": "",
496
- "require_explicit_confirmation": False,
497
- },
498
- "yolo": {
499
- "description": "Faster local execution; DevCouncil still verifies the final diff.",
500
- "timeout_seconds": 3600,
501
- "prompt_preamble": (
502
- "Profile: yolo. Move efficiently within the task scope, but keep all changes "
503
- "inside the planned files and run the expected verification commands."
504
- ),
505
- "require_explicit_confirmation": False,
506
- # yolo leans on the CLI's most permissive auto-apply mode so the agent
507
- # never stalls on an approval prompt.
508
- "permission_mode": "auto",
509
- },
510
- "prod": {
511
- "description": "Restrictive execution for high-risk repositories.",
512
- "timeout_seconds": 1800,
513
- "prompt_preamble": (
514
- "Profile: prod. Treat this as high-risk work. Do not broaden scope, do not "
515
- "change dependencies or schemas unless the task explicitly allows it, and "
516
- "prefer minimal, easily reviewed edits."
517
- ),
518
- "require_explicit_confirmation": True,
519
- # prod drops blanket auto-approval: edits are gated rather than blindly
520
- # applied, so the subprocess invocation is materially more contained than
521
- # yolo's instead of being byte-for-byte identical.
522
- "permission_mode": "gated",
523
- },
524
- }
525
-
526
-
527
- def load_agent_profiles(project_root: Path) -> dict[str, CliAgentProfileConfig]:
528
- raw_profiles = default_agent_profiles()
529
- try:
530
- configured = load_config(project_root).integrations.cli_agents.profiles
531
- except Exception:
532
- configured = {}
533
- profiles = {
534
- name: CliAgentProfileConfig.model_validate(data)
535
- for name, data in raw_profiles.items()
536
- }
537
- profiles.update(configured)
538
- return profiles
539
-
540
-
541
- def agent_config_entry(
542
- *,
543
- command: str,
544
- args: list[str] | None = None,
545
- input_mode: str = "stdin",
546
- prompt_arg: str | None = None,
547
- timeout_seconds: int | None = None,
548
- env: dict[str, str] | None = None,
549
- display_name: str | None = None,
550
- kind: str = "custom",
551
- supports_mcp: bool = False,
552
- supports_diff_review: bool = False,
553
- default_profile: str = "default",
554
- help_command: list[str] | None = None,
555
- ) -> dict[str, Any]:
556
- entry: dict[str, Any] = {
557
- "command": command,
558
- "args": args or [],
559
- "input_mode": input_mode,
560
- "kind": kind,
561
- "supports_mcp": supports_mcp,
562
- "supports_diff_review": supports_diff_review,
563
- "default_profile": default_profile,
564
- }
565
- if prompt_arg:
566
- entry["prompt_arg"] = prompt_arg
567
- if timeout_seconds is not None:
568
- entry["timeout_seconds"] = timeout_seconds
569
- if env:
570
- entry["env"] = env
571
- if display_name:
572
- entry["display_name"] = display_name
573
- if help_command:
574
- entry["help_command"] = help_command
575
- return entry