devcouncil 0.1.1 → 0.3.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 (159) hide show
  1. package/README.md +201 -6
  2. package/package.json +9 -2
  3. package/pyproject.toml +34 -2
  4. package/src/devcouncil/app/config.py +348 -12
  5. package/src/devcouncil/app/orchestrator.py +10 -6
  6. package/src/devcouncil/app/state_machine.py +4 -0
  7. package/src/devcouncil/artifacts/graph.py +32 -5
  8. package/src/devcouncil/assets/__init__.py +1 -0
  9. package/src/devcouncil/assets/devcouncil-logo.svg +60 -0
  10. package/src/devcouncil/assets/devcouncil_logo_premium.png +0 -0
  11. package/src/devcouncil/cli/commands/agents.py +292 -0
  12. package/src/devcouncil/cli/commands/artifacts.py +6 -3
  13. package/src/devcouncil/cli/commands/check.py +220 -0
  14. package/src/devcouncil/cli/commands/config.py +43 -4
  15. package/src/devcouncil/cli/commands/cost.py +57 -0
  16. package/src/devcouncil/cli/commands/dashboard.py +6 -1
  17. package/src/devcouncil/cli/commands/design.py +186 -0
  18. package/src/devcouncil/cli/commands/doctor.py +379 -22
  19. package/src/devcouncil/cli/commands/evidence.py +48 -0
  20. package/src/devcouncil/cli/commands/go.py +532 -33
  21. package/src/devcouncil/cli/commands/handoff.py +69 -0
  22. package/src/devcouncil/cli/commands/hook.py +296 -15
  23. package/src/devcouncil/cli/commands/init.py +161 -20
  24. package/src/devcouncil/cli/commands/integrate.py +1371 -124
  25. package/src/devcouncil/cli/commands/logs.py +106 -0
  26. package/src/devcouncil/cli/commands/map.py +80 -10
  27. package/src/devcouncil/cli/commands/okf.py +245 -0
  28. package/src/devcouncil/cli/commands/plan.py +256 -55
  29. package/src/devcouncil/cli/commands/prompt.py +18 -7
  30. package/src/devcouncil/cli/commands/repair.py +50 -24
  31. package/src/devcouncil/cli/commands/report.py +8 -0
  32. package/src/devcouncil/cli/commands/reset_demo_state.py +4 -2
  33. package/src/devcouncil/cli/commands/rollback.py +27 -28
  34. package/src/devcouncil/cli/commands/run.py +195 -54
  35. package/src/devcouncil/cli/commands/runs.py +223 -0
  36. package/src/devcouncil/cli/commands/scaffold.py +32 -0
  37. package/src/devcouncil/cli/commands/semantic.py +47 -0
  38. package/src/devcouncil/cli/commands/setup.py +145 -6
  39. package/src/devcouncil/cli/commands/shell.py +73 -0
  40. package/src/devcouncil/cli/commands/skills.py +267 -0
  41. package/src/devcouncil/cli/commands/status.py +30 -15
  42. package/src/devcouncil/cli/commands/trace.py +47 -3
  43. package/src/devcouncil/cli/commands/verify.py +144 -3
  44. package/src/devcouncil/cli/commands/watch.py +32 -12
  45. package/src/devcouncil/cli/commands/watch_fs.py +40 -0
  46. package/src/devcouncil/cli/main.py +91 -7
  47. package/src/devcouncil/domain/evidence.py +29 -2
  48. package/src/devcouncil/domain/gap.py +27 -1
  49. package/src/devcouncil/domain/task.py +31 -2
  50. package/src/devcouncil/execution/checkpoints.py +256 -0
  51. package/src/devcouncil/execution/context_builder.py +1 -1
  52. package/src/devcouncil/execution/fs_watcher.py +205 -0
  53. package/src/devcouncil/execution/handoff.py +102 -0
  54. package/src/devcouncil/execution/hook_policy.py +162 -74
  55. package/src/devcouncil/execution/patch.py +65 -10
  56. package/src/devcouncil/execution/permissions.py +24 -24
  57. package/src/devcouncil/execution/policy_engine.py +350 -0
  58. package/src/devcouncil/execution/prompt_builder.py +751 -23
  59. package/src/devcouncil/execution/shell_session.py +231 -0
  60. package/src/devcouncil/execution/task_runner.py +24 -9
  61. package/src/devcouncil/executors/agent_registry.py +596 -0
  62. package/src/devcouncil/executors/coding_cli.py +791 -39
  63. package/src/devcouncil/executors/mini_swe.py +6 -0
  64. package/src/devcouncil/executors/native/agent.py +135 -19
  65. package/src/devcouncil/executors/openhands.py +6 -0
  66. package/src/devcouncil/gating/checks/clean_git.py +3 -1
  67. package/src/devcouncil/gating/checks/secret_scan_check.py +47 -21
  68. package/src/devcouncil/gating/policy.py +190 -11
  69. package/src/devcouncil/hardware.py +184 -0
  70. package/src/devcouncil/indexing/ast_matcher.py +17 -7
  71. package/src/devcouncil/indexing/lsp.py +45 -4
  72. package/src/devcouncil/indexing/repo_mapper.py +1284 -15
  73. package/src/devcouncil/indexing/semantic_index.py +221 -0
  74. package/src/devcouncil/integrations/actions.py +166 -0
  75. package/src/devcouncil/integrations/check.py +426 -0
  76. package/src/devcouncil/integrations/claude_assets.py +444 -0
  77. package/src/devcouncil/integrations/code_review_graph.py +13 -2
  78. package/src/devcouncil/integrations/github_intent.py +149 -0
  79. package/src/devcouncil/integrations/gitnexus.py +45 -2
  80. package/src/devcouncil/integrations/mcp/server.py +1944 -32
  81. package/src/devcouncil/integrations/opencode_devcouncil_plugin.mjs +24 -0
  82. package/src/devcouncil/integrations/pr_comments.py +9 -0
  83. package/src/devcouncil/knowledge/__init__.py +23 -0
  84. package/src/devcouncil/knowledge/design.py +374 -0
  85. package/src/devcouncil/knowledge/design_conformance.py +317 -0
  86. package/src/devcouncil/knowledge/fetch.py +223 -0
  87. package/src/devcouncil/knowledge/frontmatter.py +51 -0
  88. package/src/devcouncil/knowledge/okf.py +202 -0
  89. package/src/devcouncil/knowledge/skill_bridge.py +96 -0
  90. package/src/devcouncil/knowledge/sources.py +239 -0
  91. package/src/devcouncil/live/cards.py +181 -25
  92. package/src/devcouncil/live/repair_prompt.py +29 -6
  93. package/src/devcouncil/live/reviewer.py +72 -13
  94. package/src/devcouncil/live/signals.py +2 -2
  95. package/src/devcouncil/live/summary.py +18 -8
  96. package/src/devcouncil/live/transcripts.py +47 -11
  97. package/src/devcouncil/llm/cache.py +20 -8
  98. package/src/devcouncil/llm/model_defaults.yaml +44 -0
  99. package/src/devcouncil/llm/provider.py +617 -49
  100. package/src/devcouncil/llm/router.py +337 -53
  101. package/src/devcouncil/optimization/__init__.py +1 -0
  102. package/src/devcouncil/optimization/gepa_agent.py +318 -0
  103. package/src/devcouncil/optimization/skillopt.py +673 -0
  104. package/src/devcouncil/planning/arbiter_service.py +10 -2
  105. package/src/devcouncil/planning/correction_manifest.py +346 -0
  106. package/src/devcouncil/planning/critique_service.py +16 -4
  107. package/src/devcouncil/planning/plan_service.py +86 -6
  108. package/src/devcouncil/planning/prompt_enhancer_service.py +206 -1
  109. package/src/devcouncil/planning/repair_service.py +8 -2
  110. package/src/devcouncil/planning/spec_service.py +37 -3
  111. package/src/devcouncil/repo/ci_scaffold.py +165 -0
  112. package/src/devcouncil/repo/gitignore.py +123 -0
  113. package/src/devcouncil/repo/sca.py +384 -0
  114. package/src/devcouncil/reporting/json_report.py +22 -1
  115. package/src/devcouncil/reporting/markdown_report.py +29 -1
  116. package/src/devcouncil/reporting/okf_bundle_writer.py +364 -0
  117. package/src/devcouncil/reporting/okf_html.py +323 -0
  118. package/src/devcouncil/reporting/report_builder.py +18 -1
  119. package/src/devcouncil/skills/__init__.py +19 -0
  120. package/src/devcouncil/skills/library/README.md +46 -0
  121. package/src/devcouncil/skills/library/ai-training.md +50 -0
  122. package/src/devcouncil/skills/library/android.md +50 -0
  123. package/src/devcouncil/skills/library/backend.md +52 -0
  124. package/src/devcouncil/skills/library/core-engineering.md +95 -0
  125. package/src/devcouncil/skills/library/data-engineering.md +47 -0
  126. package/src/devcouncil/skills/library/desktop.md +46 -0
  127. package/src/devcouncil/skills/library/devops.md +48 -0
  128. package/src/devcouncil/skills/library/game-dev.md +46 -0
  129. package/src/devcouncil/skills/library/ios.md +48 -0
  130. package/src/devcouncil/skills/library/mobile-cross-platform.md +46 -0
  131. package/src/devcouncil/skills/library/security.md +48 -0
  132. package/src/devcouncil/skills/library/systems.md +48 -0
  133. package/src/devcouncil/skills/library/web.md +47 -0
  134. package/src/devcouncil/skills/library/windows.md +47 -0
  135. package/src/devcouncil/skills/registry.py +408 -0
  136. package/src/devcouncil/storage/db.py +140 -3
  137. package/src/devcouncil/storage/models.py +125 -0
  138. package/src/devcouncil/storage/native.py +559 -0
  139. package/src/devcouncil/storage/repositories.py +157 -78
  140. package/src/devcouncil/telemetry/cost.py +123 -17
  141. package/src/devcouncil/telemetry/logging_setup.py +244 -0
  142. package/src/devcouncil/telemetry/model_pricing.yaml +48 -0
  143. package/src/devcouncil/telemetry/pricing.py +28 -0
  144. package/src/devcouncil/telemetry/stages.py +141 -0
  145. package/src/devcouncil/telemetry/traces.py +62 -7
  146. package/src/devcouncil/telemetry/tracker.py +24 -10
  147. package/src/devcouncil/ui/dashboard.py +393 -28
  148. package/src/devcouncil/utils/redaction.py +9 -3
  149. package/src/devcouncil/utils/subprocess_env.py +69 -0
  150. package/src/devcouncil/verification/acceptance_compiler.py +253 -0
  151. package/src/devcouncil/verification/ad_hoc_check.py +135 -0
  152. package/src/devcouncil/verification/diff_coverage.py +353 -0
  153. package/src/devcouncil/verification/implementation_reviewer.py +11 -2
  154. package/src/devcouncil/verification/next_actions.py +189 -0
  155. package/src/devcouncil/verification/sandbox.py +181 -0
  156. package/src/devcouncil/verification/test_resolver.py +91 -0
  157. package/src/devcouncil/verification/verifier.py +1549 -143
  158. package/uv.lock +205 -64
  159. package/src/devcouncil/indexing/symbol_index.py +0 -0
@@ -1,38 +1,50 @@
1
1
  import json
2
2
  import hashlib
3
+ import logging
3
4
  from pathlib import Path
4
5
  from typing import Optional
5
6
  from devcouncil.llm.provider import LLMResponse
6
7
 
8
+ logger = logging.getLogger(__name__)
9
+
7
10
  class LLMCache:
8
11
  def __init__(self, project_root: Path):
9
12
  self.cache_dir = project_root / ".devcouncil" / "cache" / "llm"
10
13
  self.cache_dir.mkdir(parents=True, exist_ok=True)
11
14
 
12
- def _get_key(self, model: str, messages: list, temp: float, json_mode: bool) -> str:
15
+ def _get_key(self, model: str, messages: list, temp: float, json_mode: bool, provider_fingerprint: str = "") -> str:
13
16
  data = {
14
17
  "model": model,
15
18
  "messages": messages,
16
19
  "temp": temp,
17
- "json_mode": json_mode
20
+ "json_mode": json_mode,
21
+ # Provider-specific knobs that change the output for an identical prompt
22
+ # (e.g. Ollama's num_ctx / base_url). Empty for providers without such knobs,
23
+ # so their cache keys are unchanged.
24
+ "provider": provider_fingerprint,
18
25
  }
19
26
  s = json.dumps(data, sort_keys=True)
20
27
  return hashlib.sha256(s.encode("utf-8")).hexdigest()
21
28
 
22
- def get(self, model: str, messages: list, temp: float, json_mode: bool) -> Optional[LLMResponse]:
23
- key = self._get_key(model, messages, temp, json_mode)
29
+ def get(self, model: str, messages: list, temp: float, json_mode: bool, provider_fingerprint: str = "", cache_key: Optional[str] = None) -> Optional[LLMResponse]:
30
+ # Hashing the JSON payload is non-trivial; let callers compute the key once
31
+ # (via ``_get_key``) and pass it to both get() and set() to avoid recomputing.
32
+ key = cache_key if cache_key is not None else self._get_key(model, messages, temp, json_mode, provider_fingerprint)
24
33
  cache_file = self.cache_dir / f"{key}.json"
25
34
  if cache_file.exists():
26
35
  try:
27
36
  with open(cache_file, "r") as f:
28
37
  data = json.load(f)
38
+ logger.debug("LLM cache HIT model=%s key=%s", model, key[:12])
29
39
  return LLMResponse(**data)
30
- except Exception:
31
- pass
40
+ except Exception as e:
41
+ logger.warning("LLM cache read failed for key=%s: %s", key[:12], e)
42
+ logger.debug("LLM cache MISS model=%s key=%s", model, key[:12])
32
43
  return None
33
44
 
34
- def set(self, model: str, messages: list, temp: float, json_mode: bool, response: LLMResponse):
35
- key = self._get_key(model, messages, temp, json_mode)
45
+ def set(self, model: str, messages: list, temp: float, json_mode: bool, response: LLMResponse, provider_fingerprint: str = "", cache_key: Optional[str] = None):
46
+ key = cache_key if cache_key is not None else self._get_key(model, messages, temp, json_mode, provider_fingerprint)
36
47
  cache_file = self.cache_dir / f"{key}.json"
37
48
  with open(cache_file, "w") as f:
38
49
  json.dump(response.model_dump(), f)
50
+ logger.debug("LLM cache STORE model=%s key=%s", model, key[:12])
@@ -0,0 +1,44 @@
1
+ openrouter:
2
+ spec_writer: anthropic/claude-sonnet-4.6
3
+ prompt_enhancer: anthropic/claude-sonnet-4.6
4
+ planner_a: anthropic/claude-sonnet-4.6
5
+ planner_b: google/gemini-2.5-pro
6
+ critic_a: openai/gpt-5.5
7
+ critic_b: anthropic/claude-opus-4.8
8
+ arbiter: openai/gpt-5.5
9
+ native_agent: anthropic/claude-sonnet-4.6
10
+ implementation_reviewer: openai/gpt-5.5
11
+ live_reviewer: openai/gpt-5.5
12
+ vertexai:
13
+ spec_writer: google/gemini-2.5-flash
14
+ prompt_enhancer: google/gemini-2.5-flash
15
+ planner_a: google/gemini-2.5-flash
16
+ planner_b: google/gemini-2.5-flash
17
+ critic_a: google/gemini-2.5-flash
18
+ critic_b: google/gemini-2.5-flash
19
+ arbiter: google/gemini-2.5-flash
20
+ native_agent: google/gemini-2.5-flash
21
+ implementation_reviewer: google/gemini-2.5-flash
22
+ live_reviewer: google/gemini-2.5-flash
23
+ doubleword:
24
+ spec_writer: deepseek/deepseek-v4
25
+ prompt_enhancer: deepseek/deepseek-v4
26
+ planner_a: deepseek/deepseek-v4
27
+ planner_b: deepseek/deepseek-v4
28
+ critic_a: deepseek/deepseek-v4
29
+ critic_b: deepseek/deepseek-v4
30
+ arbiter: deepseek/deepseek-v4
31
+ native_agent: deepseek/deepseek-v4
32
+ implementation_reviewer: deepseek/deepseek-v4
33
+ live_reviewer: deepseek/deepseek-v4
34
+ ollama:
35
+ spec_writer: qwen2.5-coder:7b
36
+ prompt_enhancer: qwen2.5-coder:7b
37
+ planner_a: qwen2.5-coder:7b
38
+ planner_b: qwen2.5-coder:7b
39
+ critic_a: qwen2.5-coder:7b
40
+ critic_b: qwen2.5-coder:7b
41
+ arbiter: qwen2.5-coder:7b
42
+ native_agent: qwen2.5-coder:7b
43
+ implementation_reviewer: qwen2.5-coder:7b
44
+ live_reviewer: qwen2.5-coder:7b