devcouncil 0.1.0 → 0.2.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.
Files changed (190) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +197 -494
  3. package/package.json +9 -2
  4. package/pyproject.toml +62 -27
  5. package/src/devcouncil/__main__.py +4 -4
  6. package/src/devcouncil/app/__init__.py +28 -28
  7. package/src/devcouncil/app/config.py +297 -108
  8. package/src/devcouncil/app/errors.py +23 -23
  9. package/src/devcouncil/app/events.py +44 -44
  10. package/src/devcouncil/app/orchestrator.py +67 -67
  11. package/src/devcouncil/app/project_status.py +29 -0
  12. package/src/devcouncil/app/run_context.py +39 -39
  13. package/src/devcouncil/app/state_machine.py +108 -108
  14. package/src/devcouncil/artifacts/__init__.py +1 -1
  15. package/src/devcouncil/artifacts/coverage.py +96 -96
  16. package/src/devcouncil/artifacts/graph.py +163 -143
  17. package/src/devcouncil/artifacts/migrations.py +20 -20
  18. package/src/devcouncil/artifacts/schemas.py +23 -23
  19. package/src/devcouncil/artifacts/serializer.py +21 -21
  20. package/src/devcouncil/artifacts/validators.py +27 -27
  21. package/src/devcouncil/assets/__init__.py +1 -0
  22. package/src/devcouncil/assets/devcouncil-logo.svg +60 -0
  23. package/src/devcouncil/assets/devcouncil_logo_premium.png +0 -0
  24. package/src/devcouncil/cli/commands/agents.py +292 -0
  25. package/src/devcouncil/cli/commands/artifacts.py +54 -48
  26. package/src/devcouncil/cli/commands/ast.py +22 -0
  27. package/src/devcouncil/cli/commands/baseline.py +35 -32
  28. package/src/devcouncil/cli/commands/check.py +209 -0
  29. package/src/devcouncil/cli/commands/config.py +115 -54
  30. package/src/devcouncil/cli/commands/cost.py +57 -0
  31. package/src/devcouncil/cli/commands/dashboard.py +31 -0
  32. package/src/devcouncil/cli/commands/doctor.py +291 -47
  33. package/src/devcouncil/cli/commands/evidence.py +48 -0
  34. package/src/devcouncil/cli/commands/go.py +656 -0
  35. package/src/devcouncil/cli/commands/handoff.py +69 -0
  36. package/src/devcouncil/cli/commands/hook.py +209 -33
  37. package/src/devcouncil/cli/commands/init.py +204 -57
  38. package/src/devcouncil/cli/commands/integrate.py +1171 -76
  39. package/src/devcouncil/cli/commands/lsp.py +20 -0
  40. package/src/devcouncil/cli/commands/map.py +96 -22
  41. package/src/devcouncil/cli/commands/plan.py +422 -210
  42. package/src/devcouncil/cli/commands/prompt.py +48 -34
  43. package/src/devcouncil/cli/commands/repair.py +89 -69
  44. package/src/devcouncil/cli/commands/report.py +120 -54
  45. package/src/devcouncil/cli/commands/reset_demo_state.py +33 -28
  46. package/src/devcouncil/cli/commands/rollback.py +55 -54
  47. package/src/devcouncil/cli/commands/run.py +285 -220
  48. package/src/devcouncil/cli/commands/runs.py +223 -0
  49. package/src/devcouncil/cli/commands/scaffold.py +32 -0
  50. package/src/devcouncil/cli/commands/semantic.py +47 -0
  51. package/src/devcouncil/cli/commands/setup.py +300 -20
  52. package/src/devcouncil/cli/commands/shell.py +73 -0
  53. package/src/devcouncil/cli/commands/show.py +76 -57
  54. package/src/devcouncil/cli/commands/skills.py +88 -0
  55. package/src/devcouncil/cli/commands/status.py +141 -105
  56. package/src/devcouncil/cli/commands/tasks.py +55 -41
  57. package/src/devcouncil/cli/commands/trace.py +49 -4
  58. package/src/devcouncil/cli/commands/verify.py +293 -128
  59. package/src/devcouncil/cli/commands/version.py +20 -20
  60. package/src/devcouncil/cli/commands/watch.py +574 -0
  61. package/src/devcouncil/cli/commands/watch_fs.py +40 -0
  62. package/src/devcouncil/cli/main.py +92 -25
  63. package/src/devcouncil/council/prompts/arbiter.md +19 -19
  64. package/src/devcouncil/council/prompts/critic_a.md +10 -10
  65. package/src/devcouncil/council/prompts/critic_b.md +10 -10
  66. package/src/devcouncil/council/prompts/implementation_reviewer.md +16 -16
  67. package/src/devcouncil/council/prompts/planner_a.md +16 -16
  68. package/src/devcouncil/council/prompts/planner_b.md +16 -16
  69. package/src/devcouncil/council/prompts/rebuttal.md +10 -10
  70. package/src/devcouncil/council/prompts/spec_writer.md +12 -12
  71. package/src/devcouncil/domain/assumption.py +17 -17
  72. package/src/devcouncil/domain/critique.py +32 -32
  73. package/src/devcouncil/domain/evidence.py +47 -27
  74. package/src/devcouncil/domain/gap.py +52 -26
  75. package/src/devcouncil/domain/requirement.py +22 -22
  76. package/src/devcouncil/domain/task.py +55 -26
  77. package/src/devcouncil/execution/__init__.py +1 -1
  78. package/src/devcouncil/execution/checkpoints.py +246 -0
  79. package/src/devcouncil/execution/context_builder.py +54 -54
  80. package/src/devcouncil/execution/executor.py +15 -15
  81. package/src/devcouncil/execution/fs_watcher.py +180 -0
  82. package/src/devcouncil/execution/handoff.py +102 -0
  83. package/src/devcouncil/execution/hook_policy.py +186 -77
  84. package/src/devcouncil/execution/patch.py +77 -28
  85. package/src/devcouncil/execution/permissions.py +52 -59
  86. package/src/devcouncil/execution/policy_engine.py +343 -0
  87. package/src/devcouncil/execution/prompt_builder.py +650 -38
  88. package/src/devcouncil/execution/shell_session.py +225 -0
  89. package/src/devcouncil/execution/task_runner.py +68 -64
  90. package/src/devcouncil/executors/__init__.py +1 -1
  91. package/src/devcouncil/executors/agent_registry.py +575 -0
  92. package/src/devcouncil/executors/coding_cli.py +736 -0
  93. package/src/devcouncil/executors/mini_swe.py +63 -63
  94. package/src/devcouncil/executors/native/agent.py +186 -85
  95. package/src/devcouncil/executors/openhands.py +56 -56
  96. package/src/devcouncil/gating/__init__.py +1 -1
  97. package/src/devcouncil/gating/checks/clean_git.py +52 -45
  98. package/src/devcouncil/gating/checks/planned_files_check.py +32 -32
  99. package/src/devcouncil/gating/checks/requirement_coverage.py +26 -26
  100. package/src/devcouncil/gating/checks/secret_scan_check.py +53 -34
  101. package/src/devcouncil/gating/policy.py +315 -167
  102. package/src/devcouncil/hardware.py +184 -0
  103. package/src/devcouncil/indexing/__init__.py +1 -1
  104. package/src/devcouncil/indexing/ast_matcher.py +168 -0
  105. package/src/devcouncil/indexing/graph_index.py +48 -48
  106. package/src/devcouncil/indexing/lsp.py +161 -0
  107. package/src/devcouncil/indexing/repo_mapper.py +1455 -204
  108. package/src/devcouncil/indexing/semantic_index.py +205 -0
  109. package/src/devcouncil/integrations/actions.py +146 -0
  110. package/src/devcouncil/integrations/check.py +423 -0
  111. package/src/devcouncil/integrations/github.py +35 -35
  112. package/src/devcouncil/integrations/github_intent.py +142 -0
  113. package/src/devcouncil/integrations/gitnexus.py +62 -27
  114. package/src/devcouncil/integrations/graphify.py +34 -34
  115. package/src/devcouncil/integrations/mcp/server.py +2072 -96
  116. package/src/devcouncil/integrations/opencode_devcouncil_plugin.mjs +24 -0
  117. package/src/devcouncil/integrations/pr_comments.py +62 -0
  118. package/src/devcouncil/live/__init__.py +2 -0
  119. package/src/devcouncil/live/cards.py +349 -0
  120. package/src/devcouncil/live/models.py +63 -0
  121. package/src/devcouncil/live/repair_prompt.py +83 -0
  122. package/src/devcouncil/live/reviewer.py +70 -0
  123. package/src/devcouncil/live/signals.py +135 -0
  124. package/src/devcouncil/live/summary.py +34 -0
  125. package/src/devcouncil/live/tasks.py +18 -0
  126. package/src/devcouncil/live/transcripts.py +141 -0
  127. package/src/devcouncil/llm/__init__.py +1 -1
  128. package/src/devcouncil/llm/cache.py +42 -38
  129. package/src/devcouncil/llm/model_defaults.yaml +44 -0
  130. package/src/devcouncil/llm/provider.py +627 -125
  131. package/src/devcouncil/llm/router.py +303 -118
  132. package/src/devcouncil/optimization/__init__.py +1 -0
  133. package/src/devcouncil/optimization/gepa_agent.py +318 -0
  134. package/src/devcouncil/planning/__init__.py +1 -1
  135. package/src/devcouncil/planning/arbiter_service.py +57 -57
  136. package/src/devcouncil/planning/correction_manifest.py +303 -0
  137. package/src/devcouncil/planning/critique_service.py +71 -66
  138. package/src/devcouncil/planning/plan_service.py +60 -46
  139. package/src/devcouncil/planning/prompt_enhancer_service.py +167 -0
  140. package/src/devcouncil/planning/repair_service.py +39 -39
  141. package/src/devcouncil/planning/spec_service.py +70 -44
  142. package/src/devcouncil/repo/ci_scaffold.py +157 -0
  143. package/src/devcouncil/repo/gitignore.py +123 -0
  144. package/src/devcouncil/repo/sca.py +374 -0
  145. package/src/devcouncil/reporting/github_check.py +32 -32
  146. package/src/devcouncil/reporting/json_report.py +30 -17
  147. package/src/devcouncil/reporting/markdown_report.py +83 -46
  148. package/src/devcouncil/reporting/report_builder.py +14 -14
  149. package/src/devcouncil/skills/__init__.py +19 -0
  150. package/src/devcouncil/skills/library/README.md +46 -0
  151. package/src/devcouncil/skills/library/ai-training.md +50 -0
  152. package/src/devcouncil/skills/library/android.md +50 -0
  153. package/src/devcouncil/skills/library/backend.md +52 -0
  154. package/src/devcouncil/skills/library/core-engineering.md +95 -0
  155. package/src/devcouncil/skills/library/data-engineering.md +47 -0
  156. package/src/devcouncil/skills/library/desktop.md +46 -0
  157. package/src/devcouncil/skills/library/devops.md +48 -0
  158. package/src/devcouncil/skills/library/game-dev.md +46 -0
  159. package/src/devcouncil/skills/library/ios.md +48 -0
  160. package/src/devcouncil/skills/library/mobile-cross-platform.md +46 -0
  161. package/src/devcouncil/skills/library/security.md +48 -0
  162. package/src/devcouncil/skills/library/systems.md +48 -0
  163. package/src/devcouncil/skills/library/web.md +47 -0
  164. package/src/devcouncil/skills/library/windows.md +47 -0
  165. package/src/devcouncil/skills/registry.py +330 -0
  166. package/src/devcouncil/storage/db.py +147 -66
  167. package/src/devcouncil/storage/models.py +204 -83
  168. package/src/devcouncil/storage/native.py +557 -0
  169. package/src/devcouncil/storage/repositories.py +388 -249
  170. package/src/devcouncil/telemetry/cost.py +140 -34
  171. package/src/devcouncil/telemetry/model_pricing.yaml +48 -0
  172. package/src/devcouncil/telemetry/pricing.py +28 -0
  173. package/src/devcouncil/telemetry/traces.py +62 -7
  174. package/src/devcouncil/telemetry/tracker.py +52 -49
  175. package/src/devcouncil/ui/__init__.py +1 -0
  176. package/src/devcouncil/ui/dashboard.py +423 -0
  177. package/src/devcouncil/utils/__init__.py +1 -1
  178. package/src/devcouncil/utils/redaction.py +147 -141
  179. package/src/devcouncil/utils/subprocess_env.py +69 -0
  180. package/src/devcouncil/verification/__init__.py +1 -1
  181. package/src/devcouncil/verification/acceptance_compiler.py +125 -0
  182. package/src/devcouncil/verification/ad_hoc_check.py +129 -0
  183. package/src/devcouncil/verification/diff_coverage.py +353 -0
  184. package/src/devcouncil/verification/implementation_reviewer.py +55 -55
  185. package/src/devcouncil/verification/next_actions.py +189 -0
  186. package/src/devcouncil/verification/sandbox.py +178 -0
  187. package/src/devcouncil/verification/test_resolver.py +91 -0
  188. package/src/devcouncil/verification/verifier.py +1342 -307
  189. package/uv.lock +205 -64
  190. package/src/devcouncil/indexing/symbol_index.py +0 -0
@@ -0,0 +1,20 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+ import typer
5
+
6
+ from devcouncil.indexing.lsp import LspInspector
7
+
8
+ app = typer.Typer(help="Inspect optional LSP integration readiness.")
9
+
10
+
11
+ @app.command("inspect")
12
+ def inspect(
13
+ project_root: Path = typer.Option(Path("."), "--project-root", help="Repository root."),
14
+ ):
15
+ """Print detected language servers and initialize payloads."""
16
+ root = project_root.expanduser().resolve()
17
+ if not root.exists():
18
+ typer.echo(json.dumps({"languages": [], "servers": [], "initialize_requests": {}, "error": f"{root} does not exist"}, indent=2))
19
+ raise typer.Exit(code=1)
20
+ typer.echo(LspInspector(root).summary_json())
@@ -2,37 +2,111 @@ import json
2
2
  from pathlib import Path
3
3
 
4
4
  import typer
5
- from rich.console import Console
6
-
7
- from devcouncil.indexing.repo_mapper import RepoMapper
5
+ from rich.console import Console
6
+
7
+ from devcouncil.cli.commands.init import initialize_project
8
+ from devcouncil.indexing.repo_mapper import RepoMap, RepoMapper
8
9
  from devcouncil.integrations.code_review_graph import CodeReviewGraphAdapter
9
10
  from devcouncil.storage.db import get_db
10
-
11
+
11
12
  console = Console()
12
13
  status_console = Console(stderr=True)
13
-
14
-
15
- def map_repo(
16
- goal: str = typer.Argument("", help="Goal text used for candidate-file ranking."),
17
- output: Path = typer.Option(
18
- Path(".devcouncil/repo_map.json"),
19
- "--output",
20
- "-o",
21
- help="Path to write repo_map.json.",
22
- ),
23
- ):
24
- """Build the deterministic repository map without calling an LLM."""
25
- if not get_db():
26
- console.print("[red]DevCouncil not initialized. Run 'dev init' first.[/red]")
27
- raise typer.Exit(code=1)
28
-
29
- repo_map = RepoMapper(Path(".")).map_repo(goal)
30
- graph_context = CodeReviewGraphAdapter(Path(".")).get_context()
14
+
15
+ AGENT_GUIDE_MARKER = "<!-- Managed by dev map: keep this file in sync with .devcouncil/repo_map.json. -->"
16
+
17
+
18
+ def _important_surfaces(repo_map: RepoMap) -> list[str]:
19
+ """Derive the 'important surfaces' list from the computed map, so the guide points
20
+ at THIS repo's real subsystems instead of hardcoded DevCouncil paths."""
21
+ lines: list[str] = []
22
+ for index, subsystem in enumerate(repo_map.subsystems[:6], start=1):
23
+ lines.append(f"{index}. `{subsystem.area}/` — {subsystem.summary}")
24
+ if not lines:
25
+ for index, path in enumerate(repo_map.important_files[:6], start=1):
26
+ lines.append(f"{index}. `{path}`")
27
+ return lines or ["1. See `.devcouncil/repo_map.json` for the file index."]
28
+
29
+
30
+ def _agent_guide_text(repo_map_path: Path, repo_root: Path, repo_map: RepoMap) -> str:
31
+ return "\n".join(
32
+ [
33
+ AGENT_GUIDE_MARKER,
34
+ "",
35
+ "# Agent Workspace Guide",
36
+ "",
37
+ "Use `.devcouncil/repo_map.json` as the primary file index for this workspace.",
38
+ f"Repo map: `{repo_map_path.relative_to(repo_root).as_posix() if repo_map_path.is_relative_to(repo_root) else repo_map_path}`",
39
+ "",
40
+ "Workflow for agents:",
41
+ "1. Open `.devcouncil/repo_map.json` before guessing at file locations.",
42
+ "2. Use the `files` list to resolve module ownership and nearby siblings.",
43
+ "3. Use `subsystems` for subsystem-level navigation.",
44
+ "4. In `subsystems`, use `entry_points` + `critical_files` for entry points and starting context.",
45
+ "5. Use `role_files` in `subsystems` for subsystem role buckets (entry, runtime, policy, adapters, etc.).",
46
+ "6. Use `neighbors` and `handoff_paths` in `subsystems` to follow cross-subsystem flow.",
47
+ "7. Run `dev map` again after large refactors to refresh the map.",
48
+ "",
49
+ "Important surfaces:",
50
+ *_important_surfaces(repo_map),
51
+ "",
52
+ "If the map and source disagree, trust the source and regenerate the map.",
53
+ ]
54
+ )
55
+
56
+
57
+ def _write_agent_guides(repo_root: Path, repo_map_path: Path, repo_map: RepoMap) -> None:
58
+ for filename in ("AGENTS.md", "CLAUDE.md"):
59
+ path = repo_root / filename
60
+ if path.exists():
61
+ existing = path.read_text(encoding="utf-8")
62
+ if AGENT_GUIDE_MARKER not in existing:
63
+ continue
64
+ path.write_text(_agent_guide_text(repo_map_path, repo_root, repo_map) + "\n", encoding="utf-8")
65
+
66
+
67
+ def generate_map_artifacts(root: Path, output: Path, goal: str = "", *, scan_dependencies: bool = False) -> RepoMap:
68
+ """Build the repo map and write repo_map.json + agent guides (no LLM, no re-init).
69
+
70
+ Assumes ``.devcouncil/`` already exists. Shared by the ``dev map`` command and
71
+ by project initialization so a freshly set-up repo is immediately navigable.
72
+ ``scan_dependencies`` is opt-in (off for init and default mapping) because it can
73
+ shell out to dependency auditors.
74
+ """
75
+ repo_map = RepoMapper(root).map_repo(goal, scan_dependencies=scan_dependencies)
76
+ graph_context = CodeReviewGraphAdapter(root).get_context()
77
+ output = output if output.is_absolute() else root / output
31
78
  output.parent.mkdir(parents=True, exist_ok=True)
32
79
  output.write_text(repo_map.model_dump_json(indent=2), encoding="utf-8")
80
+ _write_agent_guides(root, output, repo_map)
33
81
  if graph_context.available:
34
82
  graph_output = output.with_name("code_review_graph_context.json")
35
83
  graph_output.write_text(graph_context.model_dump_json(indent=2), encoding="utf-8")
36
84
  status_console.print(f"[green]Wrote code-review-graph context to {graph_output}[/green]")
85
+ return repo_map
86
+
87
+
88
+ def map_repo(
89
+ goal: str = typer.Argument("", help="Goal text used for candidate-file ranking."),
90
+ output: Path = typer.Option(
91
+ Path(".devcouncil/repo_map.json"),
92
+ "--output",
93
+ "-o",
94
+ help="Path to write repo_map.json.",
95
+ ),
96
+ project_root: Path = typer.Option(Path("."), "--project-root", help="Repository root containing .devcouncil/."),
97
+ scan_deps: bool = typer.Option(
98
+ False,
99
+ "--scan-deps",
100
+ help="Run available dependency auditors (pip-audit/npm audit/osv-scanner) and record dependency_risks in the map. Off by default.",
101
+ ),
102
+ ):
103
+ """Build the deterministic repository map without calling an LLM."""
104
+ root = project_root.expanduser().resolve()
105
+ initialize_project(root, quiet=True, with_map=False)
106
+ if not get_db(root):
107
+ raise typer.Exit(code=1)
108
+
109
+ output = output if output.is_absolute() else root / output
110
+ repo_map = generate_map_artifacts(root, output, goal, scan_dependencies=scan_deps)
37
111
  typer.echo(json.dumps(repo_map.model_dump(), indent=2))
38
112
  status_console.print(f"[green]Wrote repository map to {output}[/green]")