devcouncil 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (366) hide show
  1. package/README.md +92 -33
  2. package/package.json +6 -2
  3. package/packages/codeintel-grammars/hatch_build.py +43 -0
  4. package/packages/codeintel-grammars/pyproject.toml +16 -0
  5. package/packages/codeintel-grammars/src/devcouncil_codeintel_grammars/__init__.py +93 -0
  6. package/pyproject.toml +99 -4
  7. package/src/devcouncil/app/config.py +512 -20
  8. package/src/devcouncil/app/events.py +4 -23
  9. package/src/devcouncil/app/orchestrator.py +5 -0
  10. package/src/devcouncil/app/run_context.py +3 -3
  11. package/src/devcouncil/assets/__init__.py +4 -1
  12. package/src/devcouncil/assets/vendor/force-graph.min.js +5 -0
  13. package/src/devcouncil/campaign/__init__.py +71 -0
  14. package/src/devcouncil/campaign/bloom.py +137 -0
  15. package/src/devcouncil/campaign/dashboard.py +123 -0
  16. package/src/devcouncil/campaign/mailbox.py +305 -0
  17. package/src/devcouncil/campaign/notify.py +91 -0
  18. package/src/devcouncil/campaign/orchestrator.py +592 -0
  19. package/src/devcouncil/campaign/prompts/coordinator.md +29 -0
  20. package/src/devcouncil/campaign/prompts/director.md +21 -0
  21. package/src/devcouncil/campaign/prompts/protocol.md +46 -0
  22. package/src/devcouncil/campaign/prompts/reviewer.md +24 -0
  23. package/src/devcouncil/campaign/prompts/worker.md +24 -0
  24. package/src/devcouncil/campaign/roles.py +202 -0
  25. package/src/devcouncil/campaign/watcher.py +153 -0
  26. package/src/devcouncil/cli/commands/agents.py +24 -17
  27. package/src/devcouncil/cli/commands/artifacts.py +36 -27
  28. package/src/devcouncil/cli/commands/ast.py +12 -3
  29. package/src/devcouncil/cli/commands/baseline.py +21 -12
  30. package/src/devcouncil/cli/commands/boot.py +218 -0
  31. package/src/devcouncil/cli/commands/campaign.py +302 -0
  32. package/src/devcouncil/cli/commands/check.py +225 -12
  33. package/src/devcouncil/cli/commands/config.py +221 -74
  34. package/src/devcouncil/cli/commands/cost.py +137 -28
  35. package/src/devcouncil/cli/commands/dashboard.py +12 -4
  36. package/src/devcouncil/cli/commands/debug_cmd.py +249 -0
  37. package/src/devcouncil/cli/commands/design.py +27 -17
  38. package/src/devcouncil/cli/commands/doctor.py +790 -8
  39. package/src/devcouncil/cli/commands/evidence.py +41 -20
  40. package/src/devcouncil/cli/commands/export.py +73 -0
  41. package/src/devcouncil/cli/commands/gaps.py +175 -0
  42. package/src/devcouncil/cli/commands/gated_write.py +76 -0
  43. package/src/devcouncil/cli/commands/go.py +220 -68
  44. package/src/devcouncil/cli/commands/graph_cmd.py +1192 -0
  45. package/src/devcouncil/cli/commands/handoff.py +45 -34
  46. package/src/devcouncil/cli/commands/hook.py +630 -85
  47. package/src/devcouncil/cli/commands/init.py +89 -30
  48. package/src/devcouncil/cli/commands/integrate.py +296 -1385
  49. package/src/devcouncil/cli/commands/lease.py +120 -0
  50. package/src/devcouncil/cli/commands/logs.py +12 -5
  51. package/src/devcouncil/cli/commands/lsp.py +40 -5
  52. package/src/devcouncil/cli/commands/map.py +317 -74
  53. package/src/devcouncil/cli/commands/mcp_server.py +12 -2
  54. package/src/devcouncil/cli/commands/okf.py +44 -6
  55. package/src/devcouncil/cli/commands/plan.py +184 -69
  56. package/src/devcouncil/cli/commands/prompt.py +26 -17
  57. package/src/devcouncil/cli/commands/provenance.py +79 -0
  58. package/src/devcouncil/cli/commands/repair.py +60 -49
  59. package/src/devcouncil/cli/commands/report.py +148 -40
  60. package/src/devcouncil/cli/commands/requirements.py +104 -0
  61. package/src/devcouncil/cli/commands/reset_demo_state.py +13 -4
  62. package/src/devcouncil/cli/commands/rollback.py +46 -35
  63. package/src/devcouncil/cli/commands/run.py +173 -8
  64. package/src/devcouncil/cli/commands/runs.py +298 -68
  65. package/src/devcouncil/cli/commands/scaffold.py +33 -12
  66. package/src/devcouncil/cli/commands/semantic.py +29 -14
  67. package/src/devcouncil/cli/commands/setup.py +103 -93
  68. package/src/devcouncil/cli/commands/shell.py +51 -42
  69. package/src/devcouncil/cli/commands/show.py +56 -42
  70. package/src/devcouncil/cli/commands/skills.py +29 -20
  71. package/src/devcouncil/cli/commands/status.py +80 -67
  72. package/src/devcouncil/cli/commands/task_gate.py +295 -0
  73. package/src/devcouncil/cli/commands/tasks.py +248 -19
  74. package/src/devcouncil/cli/commands/trace.py +14 -8
  75. package/src/devcouncil/cli/commands/verify.py +33 -8
  76. package/src/devcouncil/cli/commands/version.py +14 -6
  77. package/src/devcouncil/cli/commands/watch.py +56 -40
  78. package/src/devcouncil/cli/commands/watch_fs.py +30 -19
  79. package/src/devcouncil/cli/commands/wiki.py +278 -0
  80. package/src/devcouncil/cli/main.py +58 -1
  81. package/src/devcouncil/codeintel/__init__.py +16 -0
  82. package/src/devcouncil/codeintel/build_control.py +429 -0
  83. package/src/devcouncil/codeintel/build_worker.py +78 -0
  84. package/src/devcouncil/codeintel/debug/__init__.py +17 -0
  85. package/src/devcouncil/codeintel/debug/broker.py +114 -0
  86. package/src/devcouncil/codeintel/debug/broker_client.py +61 -0
  87. package/src/devcouncil/codeintel/debug/consent.py +36 -0
  88. package/src/devcouncil/codeintel/debug/discovery.py +132 -0
  89. package/src/devcouncil/codeintel/debug/fingerprint.py +85 -0
  90. package/src/devcouncil/codeintel/debug/protocol.py +259 -0
  91. package/src/devcouncil/codeintel/debug/python_trace_runner.py +81 -0
  92. package/src/devcouncil/codeintel/debug/session.py +238 -0
  93. package/src/devcouncil/codeintel/debug/tracing.py +201 -0
  94. package/src/devcouncil/codeintel/languages/__init__.py +17 -0
  95. package/src/devcouncil/codeintel/languages/generic_extractor.py +236 -0
  96. package/src/devcouncil/codeintel/languages/registry.py +149 -0
  97. package/src/devcouncil/codeintel/languages/workers.py +245 -0
  98. package/src/devcouncil/codeintel/query/__init__.py +5 -0
  99. package/src/devcouncil/codeintel/query/engine.py +289 -0
  100. package/src/devcouncil/codeintel/resolution/__init__.py +6 -0
  101. package/src/devcouncil/codeintel/resolution/abstract_state.py +301 -0
  102. package/src/devcouncil/codeintel/resolution/frameworks/__init__.py +33 -0
  103. package/src/devcouncil/codeintel/resolution/frameworks/base.py +46 -0
  104. package/src/devcouncil/codeintel/resolution/frameworks/di.py +56 -0
  105. package/src/devcouncil/codeintel/resolution/frameworks/events.py +45 -0
  106. package/src/devcouncil/codeintel/resolution/frameworks/routes.py +88 -0
  107. package/src/devcouncil/codeintel/resolution/semantic.py +887 -0
  108. package/src/devcouncil/codeintel/service.py +104 -0
  109. package/src/devcouncil/codeintel/store/__init__.py +15 -0
  110. package/src/devcouncil/codeintel/store/sqlite.py +1565 -0
  111. package/src/devcouncil/codeintel/sync/__init__.py +19 -0
  112. package/src/devcouncil/codeintel/sync/coordinator.py +430 -0
  113. package/src/devcouncil/codeintel/sync/incremental.py +484 -0
  114. package/src/devcouncil/codeintel/sync/lease.py +96 -0
  115. package/src/devcouncil/codeintel/sync/scope.py +98 -0
  116. package/src/devcouncil/council/__init__.py +4 -0
  117. package/src/devcouncil/council/prompts/__init__.py +4 -0
  118. package/src/devcouncil/domain/checkpoint_refs.py +17 -0
  119. package/src/devcouncil/domain/evidence.py +1 -0
  120. package/src/devcouncil/domain/gap.py +10 -0
  121. package/src/devcouncil/domain/requirement.py +5 -1
  122. package/src/devcouncil/domain/task.py +43 -2
  123. package/src/devcouncil/execution/checkpoints.py +25 -31
  124. package/src/devcouncil/execution/context_builder.py +15 -44
  125. package/src/devcouncil/execution/fs_watcher.py +64 -0
  126. package/src/devcouncil/execution/gated_write.py +203 -0
  127. package/src/devcouncil/execution/handoff.py +2 -1
  128. package/src/devcouncil/execution/hook_policy.py +19 -5
  129. package/src/devcouncil/execution/lease_ops.py +177 -0
  130. package/src/devcouncil/execution/lease_validation.py +71 -0
  131. package/src/devcouncil/execution/patch.py +3 -0
  132. package/src/devcouncil/execution/permissions.py +1 -0
  133. package/src/devcouncil/execution/policy_engine.py +205 -10
  134. package/src/devcouncil/execution/prompt_builder.py +278 -33
  135. package/src/devcouncil/execution/run_trace.py +356 -0
  136. package/src/devcouncil/execution/shell_session.py +46 -5
  137. package/src/devcouncil/execution/stop_gate.py +746 -0
  138. package/src/devcouncil/execution/stop_gate_history.py +113 -0
  139. package/src/devcouncil/execution/stop_gate_state.py +54 -0
  140. package/src/devcouncil/execution/stop_gate_verify_cache.py +69 -0
  141. package/src/devcouncil/execution/task_gate_ops.py +590 -0
  142. package/src/devcouncil/execution/task_runner.py +19 -0
  143. package/src/devcouncil/executors/advisor_tool.py +315 -0
  144. package/src/devcouncil/executors/agent_registry.py +125 -17
  145. package/src/devcouncil/executors/claude_sdk.py +376 -0
  146. package/src/devcouncil/executors/coding_cli.py +724 -25
  147. package/src/devcouncil/executors/mini_swe.py +50 -8
  148. package/src/devcouncil/executors/native/agent.py +224 -19
  149. package/src/devcouncil/executors/openhands.py +50 -8
  150. package/src/devcouncil/executors/transient_retry.py +99 -0
  151. package/src/devcouncil/gating/checks/clean_git.py +5 -2
  152. package/src/devcouncil/gating/checks/planned_files_check.py +38 -11
  153. package/src/devcouncil/gating/checks/secret_scan_check.py +2 -2
  154. package/src/devcouncil/gating/policy.py +46 -2
  155. package/src/devcouncil/indexing/ast_matcher.py +41 -4
  156. package/src/devcouncil/indexing/graph/__init__.py +78 -0
  157. package/src/devcouncil/indexing/graph/api_routes.py +522 -0
  158. package/src/devcouncil/indexing/graph/build.py +862 -0
  159. package/src/devcouncil/indexing/graph/cache.py +329 -0
  160. package/src/devcouncil/indexing/graph/communities.py +28 -0
  161. package/src/devcouncil/indexing/graph/cypher.py +107 -0
  162. package/src/devcouncil/indexing/graph/embeddings.py +194 -0
  163. package/src/devcouncil/indexing/graph/export.py +381 -0
  164. package/src/devcouncil/indexing/graph/export_links.py +81 -0
  165. package/src/devcouncil/indexing/graph/extract_python.py +307 -0
  166. package/src/devcouncil/indexing/graph/extract_ts.py +1205 -0
  167. package/src/devcouncil/indexing/graph/intel.py +668 -0
  168. package/src/devcouncil/indexing/graph/liveness.py +992 -0
  169. package/src/devcouncil/indexing/graph/okf_export.py +65 -0
  170. package/src/devcouncil/indexing/graph/pdg/__init__.py +67 -0
  171. package/src/devcouncil/indexing/graph/pdg/build.py +11 -0
  172. package/src/devcouncil/indexing/graph/pdg/cdg.py +41 -0
  173. package/src/devcouncil/indexing/graph/pdg/cfg.py +199 -0
  174. package/src/devcouncil/indexing/graph/pdg/query.py +21 -0
  175. package/src/devcouncil/indexing/graph/pdg/reaching_def.py +126 -0
  176. package/src/devcouncil/indexing/graph/pdg/schema.py +253 -0
  177. package/src/devcouncil/indexing/graph/pdg/taint.py +154 -0
  178. package/src/devcouncil/indexing/graph/query.py +302 -0
  179. package/src/devcouncil/indexing/graph/resolve.py +1020 -0
  180. package/src/devcouncil/indexing/graph/schema.py +103 -0
  181. package/src/devcouncil/indexing/graph_index.py +20 -29
  182. package/src/devcouncil/indexing/lsp.py +57 -25
  183. package/src/devcouncil/indexing/lsp_client.py +577 -0
  184. package/src/devcouncil/indexing/map_artifacts.py +355 -0
  185. package/src/devcouncil/indexing/map_refresh.py +141 -0
  186. package/src/devcouncil/indexing/repo_mapper.py +1509 -138
  187. package/src/devcouncil/indexing/semantic_index.py +12 -6
  188. package/src/devcouncil/indexing/subsystem_map.py +163 -0
  189. package/src/devcouncil/indexing/ts_imports.py +343 -0
  190. package/src/devcouncil/indexing/viz.py +964 -0
  191. package/src/devcouncil/indexing/walk.py +52 -0
  192. package/src/devcouncil/indexing/wiring.py +1776 -0
  193. package/src/devcouncil/integrations/actions.py +27 -4
  194. package/src/devcouncil/integrations/check.py +211 -16
  195. package/src/devcouncil/integrations/claude_assets.py +209 -12
  196. package/src/devcouncil/integrations/clients/__init__.py +1 -0
  197. package/src/devcouncil/integrations/clients/aider.py +52 -0
  198. package/src/devcouncil/integrations/clients/antigravity.py +87 -0
  199. package/src/devcouncil/integrations/clients/claude.py +339 -0
  200. package/src/devcouncil/integrations/clients/codex.py +39 -0
  201. package/src/devcouncil/integrations/clients/common.py +332 -0
  202. package/src/devcouncil/integrations/clients/cursor.py +164 -0
  203. package/src/devcouncil/integrations/clients/gemini.py +49 -0
  204. package/src/devcouncil/integrations/clients/grok.py +105 -0
  205. package/src/devcouncil/integrations/clients/hooks.py +500 -0
  206. package/src/devcouncil/integrations/clients/opencode.py +96 -0
  207. package/src/devcouncil/integrations/clients/warp.py +75 -0
  208. package/src/devcouncil/integrations/code_review_graph.py +2 -2
  209. package/src/devcouncil/integrations/github.py +73 -7
  210. package/src/devcouncil/integrations/integration_cli.py +197 -0
  211. package/src/devcouncil/integrations/mcp/handlers/__init__.py +1 -0
  212. package/src/devcouncil/integrations/mcp/handlers/ast_lsp.py +77 -0
  213. package/src/devcouncil/integrations/mcp/handlers/checkout.py +50 -0
  214. package/src/devcouncil/integrations/mcp/handlers/cli_gate.py +43 -0
  215. package/src/devcouncil/integrations/mcp/handlers/codeintel.py +182 -0
  216. package/src/devcouncil/integrations/mcp/handlers/debug.py +236 -0
  217. package/src/devcouncil/integrations/mcp/handlers/evidence.py +70 -0
  218. package/src/devcouncil/integrations/mcp/handlers/git.py +281 -0
  219. package/src/devcouncil/integrations/mcp/handlers/graph.py +34 -0
  220. package/src/devcouncil/integrations/mcp/handlers/handoff.py +53 -0
  221. package/src/devcouncil/integrations/mcp/handlers/knowledge.py +28 -0
  222. package/src/devcouncil/integrations/mcp/handlers/lease.py +70 -0
  223. package/src/devcouncil/integrations/mcp/handlers/live.py +108 -0
  224. package/src/devcouncil/integrations/mcp/handlers/map.py +676 -0
  225. package/src/devcouncil/integrations/mcp/handlers/next_task.py +35 -0
  226. package/src/devcouncil/integrations/mcp/handlers/policy.py +80 -0
  227. package/src/devcouncil/integrations/mcp/handlers/prompts.py +168 -0
  228. package/src/devcouncil/integrations/mcp/handlers/provenance.py +87 -0
  229. package/src/devcouncil/integrations/mcp/handlers/read.py +103 -0
  230. package/src/devcouncil/integrations/mcp/handlers/router_cache.py +53 -0
  231. package/src/devcouncil/integrations/mcp/handlers/run.py +53 -0
  232. package/src/devcouncil/integrations/mcp/handlers/runs.py +69 -0
  233. package/src/devcouncil/integrations/mcp/handlers/scope.py +56 -0
  234. package/src/devcouncil/integrations/mcp/handlers/status.py +199 -0
  235. package/src/devcouncil/integrations/mcp/handlers/task.py +88 -0
  236. package/src/devcouncil/integrations/mcp/handlers/tool_specs.py +922 -0
  237. package/src/devcouncil/integrations/mcp/handlers/trace.py +65 -0
  238. package/src/devcouncil/integrations/mcp/handlers/verify.py +45 -0
  239. package/src/devcouncil/integrations/mcp/handlers/wiki.py +53 -0
  240. package/src/devcouncil/integrations/mcp/handlers/write.py +69 -0
  241. package/src/devcouncil/integrations/mcp/server.py +265 -2391
  242. package/src/devcouncil/integrations/mcp/util.py +325 -0
  243. package/src/devcouncil/integrations/setup.py +152 -0
  244. package/src/devcouncil/knowledge/fetch.py +4 -0
  245. package/src/devcouncil/knowledge/knowledge_select.py +38 -0
  246. package/src/devcouncil/knowledge/okf.py +2 -1
  247. package/src/devcouncil/knowledge/resource_discovery.py +40 -0
  248. package/src/devcouncil/knowledge/wiki.py +643 -0
  249. package/src/devcouncil/knowledge/wiki_read.py +87 -0
  250. package/src/devcouncil/live/cards.py +7 -7
  251. package/src/devcouncil/live/models.py +4 -1
  252. package/src/devcouncil/live/reviewer.py +90 -11
  253. package/src/devcouncil/live/signals.py +4 -2
  254. package/src/devcouncil/live/summary.py +21 -3
  255. package/src/devcouncil/live/tasks.py +12 -3
  256. package/src/devcouncil/live/transcripts.py +69 -2
  257. package/src/devcouncil/llm/cache.py +5 -6
  258. package/src/devcouncil/llm/model_defaults.yaml +10 -10
  259. package/src/devcouncil/llm/provider.py +647 -73
  260. package/src/devcouncil/llm/router.py +271 -46
  261. package/src/devcouncil/llm/semantic_bridge.py +614 -0
  262. package/src/devcouncil/optimization/gepa_agent.py +6 -4
  263. package/src/devcouncil/optimization/skillopt.py +9 -5
  264. package/src/devcouncil/planning/arbiter_service.py +12 -3
  265. package/src/devcouncil/planning/correction_manifest.py +107 -10
  266. package/src/devcouncil/planning/plan_difficulty.py +69 -0
  267. package/src/devcouncil/planning/plan_service.py +5 -2
  268. package/src/devcouncil/planning/planned_files_reconcile.py +191 -0
  269. package/src/devcouncil/planning/prompt_enhancer_service.py +6 -5
  270. package/src/devcouncil/planning/question_conversion.py +56 -0
  271. package/src/devcouncil/planning/spec_service.py +9 -3
  272. package/src/devcouncil/repo/ci_scaffold.py +197 -1
  273. package/src/devcouncil/repo/gitignore.py +1 -2
  274. package/src/devcouncil/reporting/evidence_export.py +124 -0
  275. package/src/devcouncil/reporting/evidence_html.py +210 -0
  276. package/src/devcouncil/reporting/json_report.py +16 -12
  277. package/src/devcouncil/reporting/markdown_report.py +38 -9
  278. package/src/devcouncil/reporting/mcp_resources.py +142 -0
  279. package/src/devcouncil/reporting/report_builder.py +40 -4
  280. package/src/devcouncil/reporting/task_provenance.py +42 -0
  281. package/src/devcouncil/reporting/verdict.py +75 -0
  282. package/src/devcouncil/skills/library/README.md +1 -0
  283. package/src/devcouncil/skills/library/devcouncil-hero-loop.md +109 -0
  284. package/src/devcouncil/skills/library/devcouncil-verification.md +109 -0
  285. package/src/devcouncil/skills/library/devcouncil.md +93 -0
  286. package/src/devcouncil/skills/registry.py +43 -12
  287. package/src/devcouncil/storage/db.py +57 -11
  288. package/src/devcouncil/storage/models.py +6 -0
  289. package/src/devcouncil/storage/native.py +5 -3
  290. package/src/devcouncil/storage/repositories.py +50 -18
  291. package/src/devcouncil/telemetry/context.py +28 -0
  292. package/src/devcouncil/telemetry/cost.py +4 -5
  293. package/src/devcouncil/telemetry/logging_setup.py +78 -11
  294. package/src/devcouncil/telemetry/model_pricing.yaml +7 -0
  295. package/src/devcouncil/telemetry/stages.py +27 -2
  296. package/src/devcouncil/telemetry/tracker.py +50 -13
  297. package/src/devcouncil/ui/dashboard.py +120 -8
  298. package/src/devcouncil/utils/fsio.py +58 -0
  299. package/src/devcouncil/utils/git_snapshot.py +112 -0
  300. package/src/devcouncil/utils/json_persist.py +53 -0
  301. package/src/devcouncil/utils/proc.py +89 -0
  302. package/src/devcouncil/verification/acceptance_compiler.py +36 -13
  303. package/src/devcouncil/verification/ad_hoc_check.py +95 -3
  304. package/src/devcouncil/verification/checks/__init__.py +41 -0
  305. package/src/devcouncil/verification/checks/acceptance.py +39 -0
  306. package/src/devcouncil/verification/checks/acceptance_corpus.py +194 -0
  307. package/src/devcouncil/verification/checks/acceptance_evidence.py +239 -0
  308. package/src/devcouncil/verification/checks/command_evidence.py +148 -0
  309. package/src/devcouncil/verification/checks/compiled_acceptance.py +179 -0
  310. package/src/devcouncil/verification/checks/corpus_stale.py +124 -0
  311. package/src/devcouncil/verification/checks/corpus_verification.py +9 -0
  312. package/src/devcouncil/verification/checks/dead_symbols.py +360 -0
  313. package/src/devcouncil/verification/checks/diff_coverage_gate.py +101 -0
  314. package/src/devcouncil/verification/checks/doc_code_ref.py +79 -0
  315. package/src/devcouncil/verification/checks/liveness_ratchet.py +336 -0
  316. package/src/devcouncil/verification/checks/orphan_diff.py +104 -0
  317. package/src/devcouncil/verification/checks/planned_files.py +98 -0
  318. package/src/devcouncil/verification/checks/semantic_diff.py +241 -0
  319. package/src/devcouncil/verification/checks/stale_map.py +80 -0
  320. package/src/devcouncil/verification/checks/stub_scan.py +71 -0
  321. package/src/devcouncil/verification/checks/subsystem_boundary.py +103 -0
  322. package/src/devcouncil/verification/checks/wiring.py +216 -0
  323. package/src/devcouncil/verification/claims/__init__.py +23 -0
  324. package/src/devcouncil/verification/claims/checks.py +395 -0
  325. package/src/devcouncil/verification/claims/mapper.py +168 -0
  326. package/src/devcouncil/verification/claims/models.py +39 -0
  327. package/src/devcouncil/verification/claims/transcript.py +92 -0
  328. package/src/devcouncil/verification/claims/verdict.py +88 -0
  329. package/src/devcouncil/verification/command_evidence.py +170 -0
  330. package/src/devcouncil/verification/command_malformation.py +147 -0
  331. package/src/devcouncil/verification/command_runner.py +164 -0
  332. package/src/devcouncil/verification/coverage_measurement.py +292 -0
  333. package/src/devcouncil/verification/diff_coverage.py +151 -0
  334. package/src/devcouncil/verification/difficulty.py +296 -0
  335. package/src/devcouncil/verification/effort_heuristics.py +178 -0
  336. package/src/devcouncil/verification/gap_ids.py +63 -0
  337. package/src/devcouncil/verification/gate_cache.py +194 -0
  338. package/src/devcouncil/verification/gate_selector.py +344 -0
  339. package/src/devcouncil/verification/git_diff_fallback.py +272 -0
  340. package/src/devcouncil/verification/implementation_reviewer.py +13 -0
  341. package/src/devcouncil/verification/incremental_check.py +241 -0
  342. package/src/devcouncil/verification/next_actions.py +60 -1
  343. package/src/devcouncil/verification/rigor_analytics.py +130 -0
  344. package/src/devcouncil/verification/sandbox.py +38 -11
  345. package/src/devcouncil/verification/stub_detector.py +369 -0
  346. package/src/devcouncil/verification/test_resolver.py +67 -1
  347. package/src/devcouncil/verification/verifier.py +137 -1666
  348. package/src/devcouncil/verification/verify_orchestration.py +610 -0
  349. package/src/devcouncil/verification/verify_setup.py +176 -0
  350. package/src/devcouncil/verification/wiki_refresh.py +208 -0
  351. package/src/semantic_layer/__init__.py +58 -0
  352. package/src/semantic_layer/benchmark.py +75 -0
  353. package/src/semantic_layer/cache.py +290 -0
  354. package/src/semantic_layer/compressor.py +137 -0
  355. package/src/semantic_layer/config.py +75 -0
  356. package/src/semantic_layer/embeddings.py +69 -0
  357. package/src/semantic_layer/llm_backends.py +99 -0
  358. package/src/semantic_layer/pipeline.py +111 -0
  359. package/src/semantic_layer/router.py +128 -0
  360. package/src/semantic_layer/tuner.py +72 -0
  361. package/uv.lock +973 -9
  362. package/src/devcouncil/artifacts/migrations.py +0 -20
  363. package/src/devcouncil/artifacts/schemas.py +0 -23
  364. package/src/devcouncil/artifacts/serializer.py +0 -21
  365. package/src/devcouncil/integrations/gitnexus.py +0 -70
  366. package/src/devcouncil/integrations/graphify.py +0 -34
@@ -22,16 +22,19 @@ from devcouncil.cli.commands.integrate import (
22
22
  _codex_command,
23
23
  _configure_antigravity,
24
24
  _configure_cursor,
25
+ _configure_grok,
25
26
  _configure_native_hooks,
26
27
  _configure_opencode,
27
28
  _configure_warp,
28
29
  _configure,
29
- _gemini_command,
30
30
  )
31
31
  from devcouncil.llm.provider import apply_provider_default_role_models, build_role_model_config, validate_model_provider
32
+ from devcouncil.telemetry.stages import log_stage, log_step
33
+ import logging
32
34
 
33
35
  app = typer.Typer()
34
36
  console = Console()
37
+ logger = logging.getLogger(__name__)
35
38
 
36
39
 
37
40
  def _set_model_provider(project_root: Path, provider: str) -> None:
@@ -180,7 +183,6 @@ def _configure_coding_cli_integrations(project_root: Path, apply: bool, gemini_s
180
183
  console.print("[bold]Coding CLI integration[/bold]")
181
184
  commands = [
182
185
  ("Codex CLI", _codex_command(project_root)),
183
- ("Gemini CLI", _gemini_command(project_root, gemini_scope)),
184
186
  ("Claude Code", _claude_command(project_root, "local")),
185
187
  ]
186
188
  results = []
@@ -190,6 +192,7 @@ def _configure_coding_cli_integrations(project_root: Path, apply: bool, gemini_s
190
192
  continue
191
193
  results.append(_configure(tool, command, apply))
192
194
  results.append(_configure_cursor(project_root, apply))
195
+ results.append(_configure_grok(project_root, apply))
193
196
  results.append(_configure_opencode(project_root, apply))
194
197
  results.append(_configure_antigravity(project_root, apply))
195
198
  results.append(_configure_warp(project_root, apply))
@@ -261,6 +264,9 @@ def setup(
261
264
  raise typer.Exit(code=2)
262
265
 
263
266
  root = project_root.expanduser().resolve()
267
+ from devcouncil.telemetry.logging_setup import set_log_dir
268
+ set_log_dir(root)
269
+ logger.info("dev setup: integrate=%s apply=%s", integrate, apply)
264
270
  try:
265
271
  role_models = parse_role_model_overrides(role_model)
266
272
  initial_provider = validate_model_provider(provider) if provider else "openrouter"
@@ -268,95 +274,99 @@ def setup(
268
274
  console.print(f"[red]{e}[/red]")
269
275
  raise typer.Exit(code=2) from e
270
276
 
271
- # Size the default local model to the host's memory ceiling (unified RAM on Apple
272
- # Silicon, VRAM on a discrete GPU, system RAM otherwise) instead of the static 7b,
273
- # so users on any OS get a capable council out of the box. Only when the user chose
274
- # Ollama and did not pin a model.
275
- if initial_provider == "ollama" and model is None:
276
- from devcouncil import hardware
277
-
278
- host = hardware.describe_host()
279
- model = host.recommended_ollama_model
280
- console.print(
281
- f"[green]Detected {host.chip_label} ({host.memory_label}); "
282
- f"defaulting Ollama model to {model}.[/green] "
283
- "Override with --model, and pull it first: "
284
- f"[bold]ollama pull {model}[/bold]."
285
- )
286
- elif initial_provider == "ollama" and model is not None:
287
- # Model pinned explicitly — still remind the user it must be pulled locally.
288
- console.print(
289
- f"[green]Using Ollama model {model}.[/green] "
290
- f"Pull it first if needed: [bold]ollama pull {model}[/bold]."
277
+ with log_stage("setup", project_root=root, integrate=integrate):
278
+ log_step("setup/1: initializing project", project_root=root, trace=True)
279
+
280
+ # Size the default local model to the host's memory ceiling (unified RAM on Apple
281
+ # Silicon, VRAM on a discrete GPU, system RAM otherwise) instead of the static 7b,
282
+ # so users on any OS get a capable council out of the box. Only when the user chose
283
+ # Ollama and did not pin a model.
284
+ if initial_provider == "ollama" and model is None:
285
+ from devcouncil import hardware
286
+
287
+ host = hardware.describe_host()
288
+ model = host.recommended_ollama_model
289
+ console.print(
290
+ f"[green]Detected {host.chip_label} ({host.memory_label}); "
291
+ f"defaulting Ollama model to {model}.[/green] "
292
+ "Override with --model, and pull it first: "
293
+ f"[bold]ollama pull {model}[/bold]."
294
+ )
295
+ elif initial_provider == "ollama" and model is not None:
296
+ # Model pinned explicitly still remind the user it must be pulled locally.
297
+ console.print(
298
+ f"[green]Using Ollama model {model}.[/green] "
299
+ f"Pull it first if needed: [bold]ollama pull {model}[/bold]."
300
+ )
301
+
302
+ created = initialize_project(
303
+ root,
304
+ project_name=name,
305
+ model_provider=initial_provider,
306
+ model=model,
307
+ role_models=role_models,
308
+ with_map=not skip_map,
309
+ with_skills=not skip_skills,
291
310
  )
292
-
293
- created = initialize_project(
294
- root,
295
- project_name=name,
296
- model_provider=initial_provider,
297
- model=model,
298
- role_models=role_models,
299
- with_map=not skip_map,
300
- with_skills=not skip_skills,
301
- )
302
- if not created:
303
- console.print(f"[yellow]DevCouncil is already initialized at {root / '.devcouncil'}.[/yellow]")
304
-
305
- if provider:
306
- try:
307
- _set_model_provider(root, provider)
308
- except ValueError as e:
309
- console.print(f"[red]{e}[/red]")
310
- raise typer.Exit(code=2) from e
311
-
312
- _set_model_roles(root, model=model, role_models=role_models)
313
-
314
- configured_provider = load_config(root).models.provider
315
- _configure_vertexai_settings(root, configured_provider, vertex_project, vertex_location)
316
- _configure_api_key(root, api_key, skip_api_key)
317
-
318
- console.print()
319
- render_doctor_check(root)
320
-
321
- if scaffold_ci:
322
- from devcouncil.repo.ci_scaffold import WORKFLOW_RELPATH, scaffold_ci as scaffold_ci_workflow
323
-
324
- written = scaffold_ci_workflow(root)
325
- if written is None:
326
- console.print(f"[yellow]{WORKFLOW_RELPATH.as_posix()} already exists; left unchanged.[/yellow]")
327
- else:
328
- console.print(f"[green]Wrote starter CI workflow {written.relative_to(root).as_posix()}.[/green]")
329
-
330
- if integrate:
331
- _configure_coding_cli_integrations(root, apply=apply, gemini_scope=gemini_scope)
332
- elif created and not skip_integrations:
333
- _prompt_for_first_run_integrations(root, apply=True, gemini_scope=gemini_scope)
334
-
335
- console.print()
336
- console.print(Panel.fit(
337
- "\n".join([
338
- "[bold]Next commands[/bold]",
339
- f"Keep running DevCouncil commands in this terminal at: {root}",
340
- "One-command agent path:",
341
- "dev e2e \"Describe the implementation goal\"",
342
- "",
343
- "Manual sidecar path:",
344
- "dev plan \"Describe the implementation goal\"",
345
- "dev tasks",
346
- "dev run TASK-001 --executor manual",
347
- "dev prompt TASK-001",
348
- "Paste only the dev prompt output into your coding CLI.",
349
- "Paste only the dev prompt output into your coding CLI, or run directly:",
350
- "dev run TASK-001 --executor codex",
351
- "dev run TASK-001 --executor gemini",
352
- "dev run TASK-001 --executor claude",
353
- "dev run TASK-001 --executor opencode",
354
- "dev run TASK-001 --executor antigravity",
355
- "dev verify TASK-001",
356
- "",
357
- "Use [bold]dev setup --integrate[/bold] to preview coding CLI MCP and native hook setup.",
358
- "Use [bold]dev setup --integrate --apply[/bold] to configure detected clients.",
359
- ]),
360
- title="DevCouncil is ready",
361
- border_style="green",
362
- ))
311
+ if not created:
312
+ console.print(f"[yellow]DevCouncil is already initialized at {root / '.devcouncil'}.[/yellow]")
313
+
314
+ if provider:
315
+ try:
316
+ _set_model_provider(root, provider)
317
+ except ValueError as e:
318
+ console.print(f"[red]{e}[/red]")
319
+ raise typer.Exit(code=2) from e
320
+
321
+ _set_model_roles(root, model=model, role_models=role_models)
322
+
323
+ configured_provider = load_config(root).models.provider
324
+ _configure_vertexai_settings(root, configured_provider, vertex_project, vertex_location)
325
+ _configure_api_key(root, api_key, skip_api_key)
326
+
327
+ console.print()
328
+ render_doctor_check(root)
329
+
330
+ if scaffold_ci:
331
+ from devcouncil.repo.ci_scaffold import WORKFLOW_RELPATH, scaffold_ci as scaffold_ci_workflow
332
+
333
+ written = scaffold_ci_workflow(root)
334
+ if written is None:
335
+ console.print(f"[yellow]{WORKFLOW_RELPATH.as_posix()} already exists; left unchanged.[/yellow]")
336
+ else:
337
+ console.print(f"[green]Wrote starter CI workflow {written.relative_to(root).as_posix()}.[/green]")
338
+
339
+ if integrate:
340
+ _configure_coding_cli_integrations(root, apply=apply, gemini_scope=gemini_scope)
341
+ elif created and not skip_integrations:
342
+ _prompt_for_first_run_integrations(root, apply=True, gemini_scope=gemini_scope)
343
+
344
+ console.print()
345
+ console.print(Panel.fit(
346
+ "\n".join([
347
+ "[bold]Next commands[/bold]",
348
+ f"Keep running DevCouncil commands in this terminal at: {root}",
349
+ "One-command agent path:",
350
+ "dev e2e \"Describe the implementation goal\"",
351
+ "",
352
+ "Manual sidecar path:",
353
+ "dev plan \"Describe the implementation goal\"",
354
+ "dev tasks",
355
+ "dev run TASK-001 --executor manual",
356
+ "dev prompt TASK-001",
357
+ "Paste only the dev prompt output into your coding CLI.",
358
+ "Paste only the dev prompt output into your coding CLI, or run directly:",
359
+ "dev run TASK-001 --executor codex",
360
+ "dev run TASK-001 --executor gemini",
361
+ "dev run TASK-001 --executor claude",
362
+ "dev run TASK-001 --executor opencode",
363
+ "dev run TASK-001 --executor antigravity",
364
+ "dev verify TASK-001",
365
+ "",
366
+ "Use [bold]dev setup --integrate[/bold] to preview coding CLI MCP and native hook setup.",
367
+ "Use [bold]dev setup --integrate --apply[/bold] to configure detected clients.",
368
+ ]),
369
+ title="DevCouncil is ready",
370
+ border_style="green",
371
+ ))
372
+ log_step("setup/complete", project_root=root, trace=True)
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  import typer
2
3
  from pathlib import Path
3
4
  from rich.console import Console
@@ -6,8 +7,10 @@ from devcouncil.cli.commands.init import initialize_project
6
7
  from devcouncil.execution.shell_session import GuardedShellSession
7
8
  from devcouncil.storage.db import get_db
8
9
  from devcouncil.storage.repositories import TaskRepository
10
+ from devcouncil.telemetry.stages import log_stage, log_step
9
11
 
10
12
  console = Console()
13
+ logger = logging.getLogger(__name__)
11
14
 
12
15
 
13
16
  def shell(
@@ -21,53 +24,59 @@ def shell(
21
24
  Run guarded shell commands for a task.
22
25
  """
23
26
  root = project_root.expanduser().resolve()
27
+ from devcouncil.telemetry.logging_setup import set_log_dir
28
+ set_log_dir(root)
29
+ logger.info("dev shell: task=%s command=%s", task_id, "set" if command else "interactive")
24
30
  initialize_project(root, quiet=True)
25
31
  db = get_db(root)
26
32
  if not db:
27
33
  console.print("[red]DevCouncil not initialized.[/red]")
28
34
  raise typer.Exit(code=1)
29
35
 
30
- with db.get_session() as session:
31
- task = TaskRepository(session).get_by_id(task_id)
32
- if not task:
33
- console.print(f"[red]Task {task_id} not found.[/red]")
34
- raise typer.Exit(code=1)
36
+ with log_stage("shell", project_root=root, task_id=task_id):
37
+ log_step("shell/1: loading task and starting session", project_root=root, task_id=task_id, trace=True)
38
+ with db.get_session() as session:
39
+ task = TaskRepository(session).get_by_id(task_id)
40
+ if not task:
41
+ console.print(f"[red]Task {task_id} not found.[/red]")
42
+ raise typer.Exit(code=1)
35
43
 
36
- try:
37
- session_runner = GuardedShellSession(root, task, shell=shell_name)
38
- except ValueError as exc:
39
- console.print(f"[red]{exc}[/red]")
40
- raise typer.Exit(code=2)
41
- try:
42
- session_runner.start(force=force)
43
- except ValueError as exc:
44
- # A live or stale lease from a prior session blocks a new one. Don't dump
45
- # a traceback — tell the user how to recover.
46
- console.print(f"[red]{exc}[/red]")
47
- console.print(
48
- "[yellow]Another shell session may be active for this task. If it is "
49
- "stale (a previous session crashed), re-run with [bold]--force[/bold] to "
50
- "reclaim it.[/yellow]"
51
- )
52
- raise typer.Exit(code=2)
53
- try:
54
- if command:
55
- code = session_runner.run_one(command)
56
- raise typer.Exit(code=code)
44
+ try:
45
+ session_runner = GuardedShellSession(root, task, shell=shell_name)
46
+ except ValueError as exc:
47
+ console.print(f"[red]{exc}[/red]")
48
+ raise typer.Exit(code=2)
49
+ try:
50
+ session_runner.start(force=force)
51
+ except ValueError as exc:
52
+ console.print(f"[red]{exc}[/red]")
53
+ console.print(
54
+ "[yellow]Another shell session may be active for this task. If it is "
55
+ "stale (a previous session crashed), re-run with [bold]--force[/bold] to "
56
+ "reclaim it.[/yellow]"
57
+ )
58
+ raise typer.Exit(code=2)
59
+ try:
60
+ if command:
61
+ log_step("shell/2: running guarded command", project_root=root, task_id=task_id)
62
+ code = session_runner.run_one(command)
63
+ log_step("shell/complete", project_root=root, task_id=task_id, trace=True)
64
+ raise typer.Exit(code=code)
57
65
 
58
- console.print(f"[cyan]Guarded shell for {task_id}. Type exit or quit to end.[/cyan]")
59
- while True:
60
- try:
61
- line = input(f"devcouncil:{task_id}> ")
62
- except (EOFError, KeyboardInterrupt):
63
- break
64
- normalized = line.strip()
65
- if normalized.lower() in {"exit", "quit"}:
66
- break
67
- if not normalized:
68
- continue
69
- code = session_runner.run_one(normalized)
70
- if code != 0:
71
- console.print(f"[yellow]Command exited with {code}[/yellow]")
72
- finally:
73
- session_runner.finish()
66
+ console.print(f"[cyan]Guarded shell for {task_id}. Type exit or quit to end.[/cyan]")
67
+ while True:
68
+ try:
69
+ line = input(f"devcouncil:{task_id}> ")
70
+ except (EOFError, KeyboardInterrupt):
71
+ break
72
+ normalized = line.strip()
73
+ if normalized.lower() in {"exit", "quit"}:
74
+ break
75
+ if not normalized:
76
+ continue
77
+ code = session_runner.run_one(normalized)
78
+ if code != 0:
79
+ console.print(f"[yellow]Command exited with {code}[/yellow]")
80
+ finally:
81
+ session_runner.finish()
82
+ log_step("shell/complete", project_root=root, task_id=task_id, trace=True)
@@ -1,4 +1,5 @@
1
- import json
1
+ from devcouncil.utils.json_persist import dump_json
2
+ import logging
2
3
  from pathlib import Path
3
4
 
4
5
  import typer
@@ -7,9 +8,11 @@ from rich.panel import Panel
7
8
  from devcouncil.cli.commands.init import initialize_project
8
9
  from devcouncil.storage.db import get_db
9
10
  from devcouncil.storage.repositories import TaskRepository, RequirementRepository
11
+ from devcouncil.telemetry.stages import log_stage, log_step
10
12
 
11
13
  app = typer.Typer()
12
14
  console = Console()
15
+ logger = logging.getLogger(__name__)
13
16
 
14
17
  @app.callback(invoke_without_command=True)
15
18
  def show(
@@ -25,52 +28,63 @@ def show(
25
28
  return
26
29
 
27
30
  root = project_root.expanduser().resolve()
31
+ from devcouncil.telemetry.logging_setup import set_log_dir
32
+ set_log_dir(root)
33
+ logger.info("dev show: task=%s json=%s", task_id, json_format)
28
34
  initialize_project(root, quiet=True)
29
35
  db = get_db(root)
30
36
  if not db:
31
37
  raise typer.Exit(code=1)
32
38
 
33
- with db.get_session() as session:
34
- task_repo = TaskRepository(session)
35
- req_repo = RequirementRepository(session)
36
-
37
- task = task_repo.get_by_id(task_id)
38
- if not task:
39
- console.print(f"[red]Task {task_id} not found.[/red]")
40
- raise typer.Exit(code=1)
41
-
42
- reqs = req_repo.get_all()
43
- req_map = {r.id: r for r in reqs}
39
+ with log_stage("show", project_root=root, task_id=task_id):
40
+ log_step("show/1: loading task details", project_root=root, task_id=task_id, trace=True)
41
+ with db.get_session() as session:
42
+ task_repo = TaskRepository(session)
43
+ req_repo = RequirementRepository(session)
44
44
 
45
- if json_format:
46
- linked_requirements = [
47
- req_map[req_id].model_dump()
48
- for req_id in task.requirement_ids
49
- if req_id in req_map
50
- ]
51
- typer.echo(json.dumps({
52
- "task": task.model_dump(),
53
- "linked_requirements": linked_requirements,
54
- }, indent=2))
55
- return
45
+ task = task_repo.get_by_id(task_id)
46
+ if not task:
47
+ message = f"Task {task_id} not found."
48
+ if json_format:
49
+ typer.echo(dump_json({"ok": False, "error": message, "task_id": task_id}, indent=2))
50
+ else:
51
+ console.print(f"[red]{message}[/red]")
52
+ raise typer.Exit(code=1)
56
53
 
57
- output = f"[bold]Status:[/bold] {task.status}\n\n"
58
- output += f"[bold]Description:[/bold]\n{task.description}\n\n"
59
-
60
- output += "[bold]Linked Requirements:[/bold]\n"
61
- for req_id in task.requirement_ids:
62
- req = req_map.get(req_id)
63
- if req:
64
- output += f" - [cyan]{req.id}[/cyan]: {req.title}\n"
65
- else:
66
- output += f" - [cyan]{req_id}[/cyan]: (Requirement not found)\n"
67
-
68
- output += "\n[bold]Planned Files:[/bold]\n"
69
- for pf in task.planned_files:
70
- output += f" - {pf.path} ({pf.allowed_change}): {pf.reason}\n"
71
-
72
- output += "\n[bold]Expected Tests:[/bold]\n"
73
- for et in task.expected_tests:
74
- output += f" - {et}\n"
54
+ reqs = req_repo.get_all()
55
+ req_map = {r.id: r for r in reqs}
75
56
 
76
- console.print(Panel(output, title=f"Task {task.id}: {task.title}", expand=False))
57
+ if json_format:
58
+ linked_requirements = [
59
+ req_map[req_id].model_dump()
60
+ for req_id in task.requirement_ids
61
+ if req_id in req_map
62
+ ]
63
+ typer.echo(dump_json({
64
+ "task": task.model_dump(),
65
+ "linked_requirements": linked_requirements,
66
+ }, indent=2))
67
+ log_step("show/complete", project_root=root, task_id=task_id, trace=True)
68
+ return
69
+
70
+ output = f"[bold]Status:[/bold] {task.status}\n\n"
71
+ output += f"[bold]Description:[/bold]\n{task.description}\n\n"
72
+
73
+ output += "[bold]Linked Requirements:[/bold]\n"
74
+ for req_id in task.requirement_ids:
75
+ req = req_map.get(req_id)
76
+ if req:
77
+ output += f" - [cyan]{req.id}[/cyan]: {req.title}\n"
78
+ else:
79
+ output += f" - [cyan]{req_id}[/cyan]: (Requirement not found)\n"
80
+
81
+ output += "\n[bold]Planned Files:[/bold]\n"
82
+ for pf in task.planned_files:
83
+ output += f" - {pf.path} ({pf.allowed_change}): {pf.reason}\n"
84
+
85
+ output += "\n[bold]Expected Tests:[/bold]\n"
86
+ for et in task.expected_tests:
87
+ output += f" - {et}\n"
88
+
89
+ console.print(Panel(output, title=f"Task {task.id}: {task.title}", expand=False))
90
+ log_step("show/complete", project_root=root, task_id=task_id, trace=True)
@@ -7,9 +7,12 @@ from rich.table import Table
7
7
 
8
8
  from devcouncil.knowledge.frontmatter import build_frontmatter_markdown
9
9
  from devcouncil.skills.registry import Skill, get_skill, load_skills, scaffold_skills, select_skills
10
+ from devcouncil.telemetry.stages import log_stage, log_step
11
+ import logging
10
12
 
11
13
  app = typer.Typer(help="Inspect and scaffold DevCouncil engineering skills for coding agents.")
12
14
  console = Console()
15
+ logger = logging.getLogger(__name__)
13
16
 
14
17
 
15
18
  def _is_repo_skill(skill, project_root: Path) -> bool:
@@ -33,27 +36,33 @@ def skills(
33
36
  return
34
37
 
35
38
  root = project_root.expanduser().resolve()
36
- all_skills = load_skills(project_root=root)
37
- if not all_skills:
38
- console.print("[yellow]No skills found in the DevCouncil skills library.[/yellow]")
39
- raise typer.Exit()
39
+ from devcouncil.telemetry.logging_setup import set_log_dir
40
+ set_log_dir(root)
41
+ logger.info("dev skills list: goal=%r", goal)
42
+ with log_stage("skills", project_root=root):
43
+ log_step("skills/1: loading skill registry", project_root=root, trace=True)
44
+ all_skills = load_skills(project_root=root)
45
+ if not all_skills:
46
+ console.print("[yellow]No skills found in the DevCouncil skills library.[/yellow]")
47
+ raise typer.Exit()
40
48
 
41
- selected = {skill.name for skill in select_skills(goal, root)}
42
- table = Table(title="DevCouncil Skills")
43
- table.add_column("Skill", style="cyan")
44
- table.add_column("Source", justify="center")
45
- table.add_column("Applies", justify="center")
46
- table.add_column("Description")
47
- for skill in all_skills:
48
- applies = "always" if skill.always else ("yes" if skill.name in selected else "-")
49
- style = "green" if skill.name in selected else "dim"
50
- source = "repo" if _is_repo_skill(skill, root) else "library"
51
- table.add_row(skill.name, source, f"[{style}]{applies}[/{style}]", skill.description)
52
- console.print(table)
53
- console.print(
54
- "\nScaffold the applicable skills into this repo with: "
55
- "[bold]dev skills scaffold[/bold] (add a goal to widen selection, or --all)."
56
- )
49
+ selected = {skill.name for skill in select_skills(goal, root)}
50
+ table = Table(title="DevCouncil Skills")
51
+ table.add_column("Skill", style="cyan")
52
+ table.add_column("Source", justify="center")
53
+ table.add_column("Applies", justify="center")
54
+ table.add_column("Description")
55
+ for skill in all_skills:
56
+ applies = "always" if skill.always else ("yes" if skill.name in selected else "-")
57
+ style = "green" if skill.name in selected else "dim"
58
+ source = "repo" if _is_repo_skill(skill, root) else "library"
59
+ table.add_row(skill.name, source, f"[{style}]{applies}[/{style}]", skill.description)
60
+ console.print(table)
61
+ console.print(
62
+ "\nScaffold the applicable skills into this repo with: "
63
+ "[bold]dev skills scaffold[/bold] (add a goal to widen selection, or --all)."
64
+ )
65
+ log_step("skills/complete", project_root=root, count=len(all_skills), trace=True)
57
66
 
58
67
 
59
68
  @app.command("show")