praisonai-code 0.0.1__py3-none-any.whl

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 (309) hide show
  1. praisonai_code/__init__.py +17 -0
  2. praisonai_code/cli/__init__.py +12 -0
  3. praisonai_code/cli/_forward_shim.py +10 -0
  4. praisonai_code/cli/_paths.py +88 -0
  5. praisonai_code/cli/_warnings.py +58 -0
  6. praisonai_code/cli/app.py +757 -0
  7. praisonai_code/cli/approval_backend.py +272 -0
  8. praisonai_code/cli/branding.py +94 -0
  9. praisonai_code/cli/commands/__init__.py +114 -0
  10. praisonai_code/cli/commands/acp.py +80 -0
  11. praisonai_code/cli/commands/agent.py +116 -0
  12. praisonai_code/cli/commands/agents.py +80 -0
  13. praisonai_code/cli/commands/app.py +139 -0
  14. praisonai_code/cli/commands/attach.py +95 -0
  15. praisonai_code/cli/commands/audit.py +102 -0
  16. praisonai_code/cli/commands/auth.py +508 -0
  17. praisonai_code/cli/commands/batch.py +848 -0
  18. praisonai_code/cli/commands/benchmark.py +286 -0
  19. praisonai_code/cli/commands/browser.py +299 -0
  20. praisonai_code/cli/commands/call.py +45 -0
  21. praisonai_code/cli/commands/chat.py +332 -0
  22. praisonai_code/cli/commands/checkpoint.py +170 -0
  23. praisonai_code/cli/commands/code.py +276 -0
  24. praisonai_code/cli/commands/command.py +114 -0
  25. praisonai_code/cli/commands/commit.py +47 -0
  26. praisonai_code/cli/commands/completion.py +333 -0
  27. praisonai_code/cli/commands/config.py +681 -0
  28. praisonai_code/cli/commands/context.py +414 -0
  29. praisonai_code/cli/commands/daemon.py +203 -0
  30. praisonai_code/cli/commands/debug.py +142 -0
  31. praisonai_code/cli/commands/deploy.py +71 -0
  32. praisonai_code/cli/commands/diag.py +55 -0
  33. praisonai_code/cli/commands/docs.py +1575 -0
  34. praisonai_code/cli/commands/doctor.py +332 -0
  35. praisonai_code/cli/commands/endpoints.py +51 -0
  36. praisonai_code/cli/commands/environment.py +179 -0
  37. praisonai_code/cli/commands/eval.py +131 -0
  38. praisonai_code/cli/commands/examples.py +953 -0
  39. praisonai_code/cli/commands/flow.py +436 -0
  40. praisonai_code/cli/commands/github.py +752 -0
  41. praisonai_code/cli/commands/hooks.py +74 -0
  42. praisonai_code/cli/commands/init.py +174 -0
  43. praisonai_code/cli/commands/knowledge.py +440 -0
  44. praisonai_code/cli/commands/langextract.py +120 -0
  45. praisonai_code/cli/commands/langfuse.py +984 -0
  46. praisonai_code/cli/commands/loop.py +211 -0
  47. praisonai_code/cli/commands/lsp.py +112 -0
  48. praisonai_code/cli/commands/managed.py +659 -0
  49. praisonai_code/cli/commands/mcp.py +763 -0
  50. praisonai_code/cli/commands/memory.py +298 -0
  51. praisonai_code/cli/commands/models.py +264 -0
  52. praisonai_code/cli/commands/n8n.py +326 -0
  53. praisonai_code/cli/commands/obs.py +19 -0
  54. praisonai_code/cli/commands/package.py +76 -0
  55. praisonai_code/cli/commands/paths.py +106 -0
  56. praisonai_code/cli/commands/permissions.py +272 -0
  57. praisonai_code/cli/commands/plugins.py +609 -0
  58. praisonai_code/cli/commands/port.py +530 -0
  59. praisonai_code/cli/commands/profile.py +466 -0
  60. praisonai_code/cli/commands/publish.py +193 -0
  61. praisonai_code/cli/commands/rag.py +913 -0
  62. praisonai_code/cli/commands/realtime.py +52 -0
  63. praisonai_code/cli/commands/recipe.py +684 -0
  64. praisonai_code/cli/commands/registry.py +59 -0
  65. praisonai_code/cli/commands/replay.py +830 -0
  66. praisonai_code/cli/commands/research.py +49 -0
  67. praisonai_code/cli/commands/retrieval.py +377 -0
  68. praisonai_code/cli/commands/rules.py +71 -0
  69. praisonai_code/cli/commands/run.py +1573 -0
  70. praisonai_code/cli/commands/sandbox.py +371 -0
  71. praisonai_code/cli/commands/schedule.py +529 -0
  72. praisonai_code/cli/commands/serve.py +690 -0
  73. praisonai_code/cli/commands/session.py +450 -0
  74. praisonai_code/cli/commands/setup.py +174 -0
  75. praisonai_code/cli/commands/skills.py +545 -0
  76. praisonai_code/cli/commands/standardise.py +711 -0
  77. praisonai_code/cli/commands/templates.py +54 -0
  78. praisonai_code/cli/commands/test.py +558 -0
  79. praisonai_code/cli/commands/todo.py +74 -0
  80. praisonai_code/cli/commands/tools.py +205 -0
  81. praisonai_code/cli/commands/traces.py +145 -0
  82. praisonai_code/cli/commands/tracker.py +852 -0
  83. praisonai_code/cli/commands/train.py +613 -0
  84. praisonai_code/cli/commands/ui.py +172 -0
  85. praisonai_code/cli/commands/up.py +354 -0
  86. praisonai_code/cli/commands/validate.py +291 -0
  87. praisonai_code/cli/commands/version.py +101 -0
  88. praisonai_code/cli/commands/workflow.py +97 -0
  89. praisonai_code/cli/config_loader.py +437 -0
  90. praisonai_code/cli/configuration/__init__.py +27 -0
  91. praisonai_code/cli/configuration/config.schema.json +57 -0
  92. praisonai_code/cli/configuration/credentials.py +446 -0
  93. praisonai_code/cli/configuration/loader.py +364 -0
  94. praisonai_code/cli/configuration/model_resolver.py +161 -0
  95. praisonai_code/cli/configuration/oauth.py +389 -0
  96. praisonai_code/cli/configuration/paths.py +224 -0
  97. praisonai_code/cli/configuration/resolver.py +687 -0
  98. praisonai_code/cli/configuration/schema.py +317 -0
  99. praisonai_code/cli/execution/__init__.py +99 -0
  100. praisonai_code/cli/execution/core.py +208 -0
  101. praisonai_code/cli/execution/profiler.py +898 -0
  102. praisonai_code/cli/execution/request.py +85 -0
  103. praisonai_code/cli/execution/result.py +74 -0
  104. praisonai_code/cli/fallback_schema.py +416 -0
  105. praisonai_code/cli/features/__init__.py +278 -0
  106. praisonai_code/cli/features/_endpoint_registry.py +64 -0
  107. praisonai_code/cli/features/_search_registry.py +43 -0
  108. praisonai_code/cli/features/acp.py +236 -0
  109. praisonai_code/cli/features/action_orchestrator.py +576 -0
  110. praisonai_code/cli/features/agent_scheduler.py +773 -0
  111. praisonai_code/cli/features/agent_tools.py +603 -0
  112. praisonai_code/cli/features/agents.py +397 -0
  113. praisonai_code/cli/features/at_mentions.py +471 -0
  114. praisonai_code/cli/features/audit_cli.py +270 -0
  115. praisonai_code/cli/features/auto_memory.py +182 -0
  116. praisonai_code/cli/features/auto_mode.py +552 -0
  117. praisonai_code/cli/features/autonomy_mode.py +546 -0
  118. praisonai_code/cli/features/background.py +356 -0
  119. praisonai_code/cli/features/base.py +168 -0
  120. praisonai_code/cli/features/benchmark.py +1462 -0
  121. praisonai_code/cli/features/capabilities.py +1326 -0
  122. praisonai_code/cli/features/checkpoints.py +345 -0
  123. praisonai_code/cli/features/cli_profiler.py +335 -0
  124. praisonai_code/cli/features/code_intelligence.py +666 -0
  125. praisonai_code/cli/features/compaction.py +294 -0
  126. praisonai_code/cli/features/compare.py +534 -0
  127. praisonai_code/cli/features/config_hierarchy.py +366 -0
  128. praisonai_code/cli/features/context_manager.py +597 -0
  129. praisonai_code/cli/features/cost_tracker.py +514 -0
  130. praisonai_code/cli/features/csv_test_runner.py +736 -0
  131. praisonai_code/cli/features/custom_definitions.py +790 -0
  132. praisonai_code/cli/features/debug.py +810 -0
  133. praisonai_code/cli/features/deploy.py +605 -0
  134. praisonai_code/cli/features/diag.py +289 -0
  135. praisonai_code/cli/features/display_jsonl.py +173 -0
  136. praisonai_code/cli/features/doctor/__init__.py +63 -0
  137. praisonai_code/cli/features/doctor/checks/__init__.py +29 -0
  138. praisonai_code/cli/features/doctor/checks/acp_checks.py +220 -0
  139. praisonai_code/cli/features/doctor/checks/bot_checks.py +340 -0
  140. praisonai_code/cli/features/doctor/checks/config_checks.py +373 -0
  141. praisonai_code/cli/features/doctor/checks/db_checks.py +366 -0
  142. praisonai_code/cli/features/doctor/checks/env_checks.py +637 -0
  143. praisonai_code/cli/features/doctor/checks/gateway_checks.py +387 -0
  144. praisonai_code/cli/features/doctor/checks/lsp_checks.py +231 -0
  145. praisonai_code/cli/features/doctor/checks/mcp_checks.py +367 -0
  146. praisonai_code/cli/features/doctor/checks/memory_checks.py +268 -0
  147. praisonai_code/cli/features/doctor/checks/network_checks.py +251 -0
  148. praisonai_code/cli/features/doctor/checks/obs_checks.py +328 -0
  149. praisonai_code/cli/features/doctor/checks/packaging_checks.py +422 -0
  150. praisonai_code/cli/features/doctor/checks/performance_checks.py +235 -0
  151. praisonai_code/cli/features/doctor/checks/permissions_checks.py +259 -0
  152. praisonai_code/cli/features/doctor/checks/runtime_checks.py +650 -0
  153. praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +220 -0
  154. praisonai_code/cli/features/doctor/checks/selftest_checks.py +322 -0
  155. praisonai_code/cli/features/doctor/checks/serve_checks.py +426 -0
  156. praisonai_code/cli/features/doctor/checks/skills_checks.py +327 -0
  157. praisonai_code/cli/features/doctor/checks/tools_checks.py +371 -0
  158. praisonai_code/cli/features/doctor/engine.py +266 -0
  159. praisonai_code/cli/features/doctor/formatters.py +377 -0
  160. praisonai_code/cli/features/doctor/handler.py +564 -0
  161. praisonai_code/cli/features/doctor/models.py +276 -0
  162. praisonai_code/cli/features/doctor/registry.py +239 -0
  163. praisonai_code/cli/features/endpoints.py +1016 -0
  164. praisonai_code/cli/features/eval.py +559 -0
  165. praisonai_code/cli/features/examples.py +707 -0
  166. praisonai_code/cli/features/external_agents.py +231 -0
  167. praisonai_code/cli/features/fast_context.py +410 -0
  168. praisonai_code/cli/features/file_history.py +320 -0
  169. praisonai_code/cli/features/flow_display.py +566 -0
  170. praisonai_code/cli/features/git_attribution.py +159 -0
  171. praisonai_code/cli/features/git_integration.py +651 -0
  172. praisonai_code/cli/features/guardrail.py +171 -0
  173. praisonai_code/cli/features/handoff.py +252 -0
  174. praisonai_code/cli/features/hooks.py +583 -0
  175. praisonai_code/cli/features/hybrid_workflow.py +391 -0
  176. praisonai_code/cli/features/image.py +384 -0
  177. praisonai_code/cli/features/interactive_core_headless.py +450 -0
  178. praisonai_code/cli/features/interactive_runtime.py +600 -0
  179. praisonai_code/cli/features/interactive_test_harness.py +537 -0
  180. praisonai_code/cli/features/interactive_tools.py +428 -0
  181. praisonai_code/cli/features/interactive_tui.py +603 -0
  182. praisonai_code/cli/features/job_workflow.py +906 -0
  183. praisonai_code/cli/features/jobs.py +632 -0
  184. praisonai_code/cli/features/knowledge.py +531 -0
  185. praisonai_code/cli/features/knowledge_cli.py +438 -0
  186. praisonai_code/cli/features/lite.py +244 -0
  187. praisonai_code/cli/features/logs.py +200 -0
  188. praisonai_code/cli/features/lsp_cli.py +225 -0
  189. praisonai_code/cli/features/lsp_diagnostics.py +185 -0
  190. praisonai_code/cli/features/mcp.py +344 -0
  191. praisonai_code/cli/features/message_queue.py +587 -0
  192. praisonai_code/cli/features/metrics.py +210 -0
  193. praisonai_code/cli/features/migrate.py +1329 -0
  194. praisonai_code/cli/features/migration_flow.py +463 -0
  195. praisonai_code/cli/features/migration_spec.py +276 -0
  196. praisonai_code/cli/features/n8n.py +703 -0
  197. praisonai_code/cli/features/observability.py +293 -0
  198. praisonai_code/cli/features/ollama.py +361 -0
  199. praisonai_code/cli/features/output_modes.py +155 -0
  200. praisonai_code/cli/features/output_style.py +273 -0
  201. praisonai_code/cli/features/package.py +631 -0
  202. praisonai_code/cli/features/performance.py +308 -0
  203. praisonai_code/cli/features/persistence.py +636 -0
  204. praisonai_code/cli/features/profiler/__init__.py +81 -0
  205. praisonai_code/cli/features/profiler/core.py +558 -0
  206. praisonai_code/cli/features/profiler/optimizations.py +652 -0
  207. praisonai_code/cli/features/profiler/suite.py +386 -0
  208. praisonai_code/cli/features/queue/__init__.py +73 -0
  209. praisonai_code/cli/features/queue/manager.py +435 -0
  210. praisonai_code/cli/features/queue/models.py +289 -0
  211. praisonai_code/cli/features/queue/persistence.py +564 -0
  212. praisonai_code/cli/features/queue/scheduler.py +529 -0
  213. praisonai_code/cli/features/queue/worker.py +400 -0
  214. praisonai_code/cli/features/recipe.py +2187 -0
  215. praisonai_code/cli/features/recipe_creator.py +996 -0
  216. praisonai_code/cli/features/recipe_optimizer.py +1364 -0
  217. praisonai_code/cli/features/recipe_prompts.py +226 -0
  218. praisonai_code/cli/features/registry.py +229 -0
  219. praisonai_code/cli/features/repo_map.py +860 -0
  220. praisonai_code/cli/features/router.py +466 -0
  221. praisonai_code/cli/features/safe_shell.py +427 -0
  222. praisonai_code/cli/features/sandbox_cli.py +283 -0
  223. praisonai_code/cli/features/sandbox_executor.py +536 -0
  224. praisonai_code/cli/features/sdk_knowledge.py +500 -0
  225. praisonai_code/cli/features/session.py +222 -0
  226. praisonai_code/cli/features/session_checkpoints.py +208 -0
  227. praisonai_code/cli/features/setup/__init__.py +9 -0
  228. praisonai_code/cli/features/setup/handler.py +355 -0
  229. praisonai_code/cli/features/setup/templates.py +62 -0
  230. praisonai_code/cli/features/skills.py +940 -0
  231. praisonai_code/cli/features/slash_commands.py +692 -0
  232. praisonai_code/cli/features/telemetry.py +179 -0
  233. praisonai_code/cli/features/templates.py +1390 -0
  234. praisonai_code/cli/features/thinking.py +343 -0
  235. praisonai_code/cli/features/todo.py +334 -0
  236. praisonai_code/cli/features/tools.py +680 -0
  237. praisonai_code/cli/features/tui/__init__.py +83 -0
  238. praisonai_code/cli/features/tui/app.py +871 -0
  239. praisonai_code/cli/features/tui/cli.py +580 -0
  240. praisonai_code/cli/features/tui/config.py +150 -0
  241. praisonai_code/cli/features/tui/debug.py +526 -0
  242. praisonai_code/cli/features/tui/events.py +99 -0
  243. praisonai_code/cli/features/tui/mock_provider.py +328 -0
  244. praisonai_code/cli/features/tui/orchestrator.py +652 -0
  245. praisonai_code/cli/features/tui/screens/__init__.py +50 -0
  246. praisonai_code/cli/features/tui/screens/help.py +157 -0
  247. praisonai_code/cli/features/tui/screens/main.py +568 -0
  248. praisonai_code/cli/features/tui/screens/queue.py +174 -0
  249. praisonai_code/cli/features/tui/screens/session.py +124 -0
  250. praisonai_code/cli/features/tui/screens/settings.py +148 -0
  251. praisonai_code/cli/features/tui/session_store.py +198 -0
  252. praisonai_code/cli/features/tui/widgets/__init__.py +56 -0
  253. praisonai_code/cli/features/tui/widgets/chat.py +263 -0
  254. praisonai_code/cli/features/tui/widgets/command_popup.py +258 -0
  255. praisonai_code/cli/features/tui/widgets/composer.py +292 -0
  256. praisonai_code/cli/features/tui/widgets/file_popup.py +207 -0
  257. praisonai_code/cli/features/tui/widgets/queue_panel.py +223 -0
  258. praisonai_code/cli/features/tui/widgets/status.py +181 -0
  259. praisonai_code/cli/features/tui/widgets/tool_panel.py +307 -0
  260. praisonai_code/cli/features/wizard.py +289 -0
  261. praisonai_code/cli/features/workflow.py +802 -0
  262. praisonai_code/cli/features/yaml_utils.py +321 -0
  263. praisonai_code/cli/interactive/__init__.py +48 -0
  264. praisonai_code/cli/interactive/async_tui.py +1218 -0
  265. praisonai_code/cli/interactive/config.py +139 -0
  266. praisonai_code/cli/interactive/core.py +618 -0
  267. praisonai_code/cli/interactive/events.py +131 -0
  268. praisonai_code/cli/interactive/frontends/__init__.py +31 -0
  269. praisonai_code/cli/interactive/frontends/rich_frontend.py +462 -0
  270. praisonai_code/cli/interactive/frontends/textual_frontend.py +157 -0
  271. praisonai_code/cli/interactive/praison_io.py +502 -0
  272. praisonai_code/cli/interactive/repl.py +297 -0
  273. praisonai_code/cli/interactive/split_tui.py +456 -0
  274. praisonai_code/cli/interactive/tui_app.py +457 -0
  275. praisonai_code/cli/langfuse_client.py +360 -0
  276. praisonai_code/cli/main.py +7421 -0
  277. praisonai_code/cli/output/__init__.py +25 -0
  278. praisonai_code/cli/output/console.py +456 -0
  279. praisonai_code/cli/output/event_bridge.py +191 -0
  280. praisonai_code/cli/schedule_cli.py +54 -0
  281. praisonai_code/cli/schema_provider.py +23 -0
  282. praisonai_code/cli/session/__init__.py +16 -0
  283. praisonai_code/cli/session/resume.py +148 -0
  284. praisonai_code/cli/session/unified.py +548 -0
  285. praisonai_code/cli/state/__init__.py +31 -0
  286. praisonai_code/cli/state/identifiers.py +161 -0
  287. praisonai_code/cli/state/project_sessions.py +383 -0
  288. praisonai_code/cli/state/sessions.py +390 -0
  289. praisonai_code/cli/ui/__init__.py +160 -0
  290. praisonai_code/cli/ui/config.py +46 -0
  291. praisonai_code/cli/ui/events.py +61 -0
  292. praisonai_code/cli/ui/mg_backend.py +342 -0
  293. praisonai_code/cli/ui/plain.py +133 -0
  294. praisonai_code/cli/ui/rich_backend.py +162 -0
  295. praisonai_code/cli/unified_schema.py +655 -0
  296. praisonai_code/cli/utils/env_utils.py +126 -0
  297. praisonai_code/cli/utils/project.py +131 -0
  298. praisonai_code/cli_backends/__init__.py +73 -0
  299. praisonai_code/cli_backends/claude.py +373 -0
  300. praisonai_code/cli_backends/registry.py +113 -0
  301. praisonai_code/runtime/__init__.py +36 -0
  302. praisonai_code/runtime/__main__.py +81 -0
  303. praisonai_code/runtime/client.py +131 -0
  304. praisonai_code/runtime/descriptor.py +209 -0
  305. praisonai_code/runtime/server.py +356 -0
  306. praisonai_code-0.0.1.dist-info/METADATA +80 -0
  307. praisonai_code-0.0.1.dist-info/RECORD +309 -0
  308. praisonai_code-0.0.1.dist-info/WHEEL +5 -0
  309. praisonai_code-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,564 @@
1
+ """
2
+ Doctor CLI handler for PraisonAI.
3
+
4
+ Provides the main DoctorHandler class that integrates with the CLI.
5
+ """
6
+
7
+ import argparse
8
+ import sys
9
+ from typing import List, Optional
10
+
11
+ from ..base import CommandHandler
12
+ from .models import CheckCategory, DoctorConfig, DoctorReport
13
+ from .engine import DoctorEngine
14
+ from .registry import get_registry
15
+ from .formatters import get_formatter
16
+
17
+
18
+ class DoctorHandler(CommandHandler):
19
+ """
20
+ Handler for the 'praisonai doctor' command.
21
+
22
+ Provides comprehensive health checks and diagnostics.
23
+ """
24
+
25
+ @property
26
+ def feature_name(self) -> str:
27
+ return "doctor"
28
+
29
+ def get_actions(self) -> List[str]:
30
+ return [
31
+ "env",
32
+ "config",
33
+ "tools",
34
+ "bots",
35
+ "db",
36
+ "mcp",
37
+ "obs",
38
+ "skills",
39
+ "memory",
40
+ "permissions",
41
+ "network",
42
+ "performance",
43
+ "packaging",
44
+ "runtime",
45
+ "ci",
46
+ "selftest",
47
+ "fix",
48
+ ]
49
+
50
+ def _register_checks(self) -> None:
51
+ """Register all doctor checks."""
52
+ from .checks import register_all_checks
53
+ register_all_checks()
54
+
55
+ def _parse_args(self, args: List[str]) -> argparse.Namespace:
56
+ """Parse doctor command arguments."""
57
+ parser = argparse.ArgumentParser(
58
+ prog="praisonai doctor",
59
+ description="PraisonAI health checks and diagnostics",
60
+ )
61
+
62
+ # Subcommand
63
+ parser.add_argument(
64
+ "subcommand",
65
+ nargs="?",
66
+ choices=self.get_actions() + [None],
67
+ help="Subcommand to run (default: run all fast checks)",
68
+ )
69
+
70
+ # Global flags
71
+ parser.add_argument(
72
+ "--json",
73
+ action="store_true",
74
+ help="Output in JSON format",
75
+ )
76
+ parser.add_argument(
77
+ "--format",
78
+ choices=["text", "json"],
79
+ default="text",
80
+ help="Output format (default: text)",
81
+ )
82
+ parser.add_argument(
83
+ "--output", "-o",
84
+ type=str,
85
+ help="Write report to file",
86
+ )
87
+ parser.add_argument(
88
+ "--deep",
89
+ action="store_true",
90
+ help="Enable deeper probes (DB connects, network checks)",
91
+ )
92
+ parser.add_argument(
93
+ "--timeout",
94
+ type=float,
95
+ default=10.0,
96
+ help="Per-check timeout in seconds (default: 10)",
97
+ )
98
+ parser.add_argument(
99
+ "--strict",
100
+ action="store_true",
101
+ help="Treat warnings as failures",
102
+ )
103
+ parser.add_argument(
104
+ "--quiet", "-q",
105
+ action="store_true",
106
+ help="Minimal output",
107
+ )
108
+ parser.add_argument(
109
+ "--no-color",
110
+ action="store_true",
111
+ help="Disable ANSI colors",
112
+ )
113
+ parser.add_argument(
114
+ "--only",
115
+ type=str,
116
+ help="Only run these check IDs (comma-separated)",
117
+ )
118
+ parser.add_argument(
119
+ "--skip",
120
+ type=str,
121
+ help="Skip these check IDs (comma-separated)",
122
+ )
123
+ parser.add_argument(
124
+ "--list-checks",
125
+ action="store_true",
126
+ help="List available check IDs",
127
+ )
128
+ parser.add_argument(
129
+ "--version",
130
+ action="store_true",
131
+ help="Show doctor module version",
132
+ )
133
+
134
+ # Subcommand-specific flags
135
+ parser.add_argument(
136
+ "--show-keys",
137
+ action="store_true",
138
+ help="Show masked API key values (env subcommand)",
139
+ )
140
+ parser.add_argument(
141
+ "--require",
142
+ type=str,
143
+ help="Require these env vars (comma-separated)",
144
+ )
145
+ parser.add_argument(
146
+ "--file", "-f",
147
+ type=str,
148
+ help="Config file to validate (config subcommand)",
149
+ )
150
+ parser.add_argument(
151
+ "--schema",
152
+ action="store_true",
153
+ help="Print expected schema (config subcommand)",
154
+ )
155
+ parser.add_argument(
156
+ "--dsn",
157
+ type=str,
158
+ help="Database DSN (db subcommand)",
159
+ )
160
+ parser.add_argument(
161
+ "--provider",
162
+ type=str,
163
+ help="Provider name (db/obs subcommand)",
164
+ )
165
+ parser.add_argument(
166
+ "--read-only",
167
+ action="store_true",
168
+ default=True,
169
+ help="Read-only mode for DB checks (default: true)",
170
+ )
171
+ parser.add_argument(
172
+ "--name",
173
+ type=str,
174
+ help="Name filter (mcp/tools subcommand)",
175
+ )
176
+ parser.add_argument(
177
+ "--category",
178
+ type=str,
179
+ help="Category filter (tools subcommand)",
180
+ )
181
+ parser.add_argument(
182
+ "--all",
183
+ action="store_true",
184
+ dest="all_checks",
185
+ help="Show all items (tools subcommand)",
186
+ )
187
+ parser.add_argument(
188
+ "--missing-only",
189
+ action="store_true",
190
+ help="Show only missing items (tools subcommand)",
191
+ )
192
+ parser.add_argument(
193
+ "--list-tools",
194
+ action="store_true",
195
+ help="List MCP tools (mcp subcommand)",
196
+ )
197
+ parser.add_argument(
198
+ "--path",
199
+ type=str,
200
+ help="Path to check (skills subcommand)",
201
+ )
202
+ parser.add_argument(
203
+ "--all-installed",
204
+ action="store_true",
205
+ help="Check all installed skills",
206
+ )
207
+ parser.add_argument(
208
+ "--budget-ms",
209
+ type=int,
210
+ help="Import time budget in ms (performance subcommand)",
211
+ )
212
+ parser.add_argument(
213
+ "--top",
214
+ type=int,
215
+ default=10,
216
+ dest="top_n",
217
+ help="Number of top items to show (default: 10)",
218
+ )
219
+ parser.add_argument(
220
+ "--fail-fast",
221
+ action="store_true",
222
+ help="Stop on first failure (ci subcommand)",
223
+ )
224
+ parser.add_argument(
225
+ "--mock",
226
+ action="store_true",
227
+ default=True,
228
+ help="Use mock mode (selftest, default: true)",
229
+ )
230
+ parser.add_argument(
231
+ "--live",
232
+ action="store_true",
233
+ help="Use live API calls (selftest)",
234
+ )
235
+ parser.add_argument(
236
+ "--model",
237
+ type=str,
238
+ help="Model to use for selftest",
239
+ )
240
+ parser.add_argument(
241
+ "--save-report",
242
+ action="store_true",
243
+ help="Save selftest report",
244
+ )
245
+ parser.add_argument(
246
+ "--team",
247
+ type=str,
248
+ help="Team YAML file to validate (runtime subcommand)",
249
+ )
250
+ parser.add_argument(
251
+ "--workflow",
252
+ type=str,
253
+ help="Workflow YAML file to validate (runtime subcommand)",
254
+ )
255
+ parser.add_argument(
256
+ "--execute",
257
+ action="store_true",
258
+ help="Execute fixes instead of dry-run (fix/runtime subcommand)",
259
+ )
260
+ parser.add_argument(
261
+ "--no-backup",
262
+ action="store_true",
263
+ help="Skip creating backup files (fix subcommand)",
264
+ )
265
+
266
+ # Runtime migration options
267
+ parser.add_argument(
268
+ "--fix",
269
+ action="store_true",
270
+ help="Apply migration fixes automatically (runtime subcommand)",
271
+ )
272
+
273
+ return parser.parse_args(args)
274
+
275
+ def _build_config(self, args: argparse.Namespace) -> DoctorConfig:
276
+ """Build DoctorConfig from parsed arguments."""
277
+ return DoctorConfig(
278
+ deep=args.deep,
279
+ timeout=args.timeout if args.deep else min(args.timeout, 10.0),
280
+ strict=args.strict,
281
+ quiet=args.quiet,
282
+ no_color=args.no_color,
283
+ format="json" if args.json else args.format,
284
+ output_path=args.output,
285
+ only=args.only.split(",") if args.only else [],
286
+ skip=args.skip.split(",") if args.skip else [],
287
+ show_keys=args.show_keys,
288
+ require_keys=args.require.split(",") if args.require else [],
289
+ config_file=args.file,
290
+ dsn=args.dsn,
291
+ provider=args.provider,
292
+ read_only=args.read_only,
293
+ mock=args.mock and not args.live,
294
+ live=args.live,
295
+ model=args.model,
296
+ budget_ms=args.budget_ms,
297
+ top_n=args.top_n,
298
+ fail_fast=args.fail_fast,
299
+ list_tools=args.list_tools,
300
+ all_checks=args.all_checks,
301
+ missing_only=args.missing_only,
302
+ name=args.name,
303
+ category=args.category,
304
+ path=args.path,
305
+ save_report=args.save_report,
306
+ team_file=args.team,
307
+ workflow_file=args.workflow,
308
+ fix=getattr(args, 'fix', False),
309
+ execute=getattr(args, 'execute', False),
310
+ no_backup=getattr(args, 'no_backup', False),
311
+ )
312
+
313
+ def _get_categories_for_subcommand(self, subcommand: Optional[str]) -> Optional[List[CheckCategory]]:
314
+ """Get check categories for a subcommand."""
315
+ category_map = {
316
+ "env": [CheckCategory.ENVIRONMENT],
317
+ "config": [CheckCategory.CONFIG],
318
+ "tools": [CheckCategory.TOOLS],
319
+ "bots": [CheckCategory.BOTS],
320
+ "db": [CheckCategory.DATABASE],
321
+ "mcp": [CheckCategory.MCP],
322
+ "obs": [CheckCategory.OBSERVABILITY],
323
+ "skills": [CheckCategory.SKILLS],
324
+ "memory": [CheckCategory.MEMORY],
325
+ "permissions": [CheckCategory.PERMISSIONS],
326
+ "network": [CheckCategory.NETWORK],
327
+ "performance": [CheckCategory.PERFORMANCE],
328
+ "packaging": [CheckCategory.PACKAGING],
329
+ "runtime": [CheckCategory.RUNTIME],
330
+ "selftest": [CheckCategory.SELFTEST],
331
+ "ci": None, # CI runs all checks
332
+ }
333
+ return category_map.get(subcommand)
334
+
335
+ def _run_fix_mode(self, config: DoctorConfig) -> int:
336
+ """Run fix mode to migrate deprecated cli_backend configurations."""
337
+ import os
338
+ import yaml
339
+ import glob
340
+
341
+ if not config.quiet:
342
+ print("🔧 PraisonAI Configuration Migration Tool")
343
+ print(" Checking for deprecated cli_backend usage...")
344
+
345
+ # Find YAML files to check
346
+ yaml_files = []
347
+ if config.config_file:
348
+ yaml_files = [config.config_file]
349
+ else:
350
+ # Look for common YAML files in current directory
351
+ patterns = ["*.yaml", "*.yml", "agents.yaml", "config.yaml"]
352
+ for pattern in patterns:
353
+ yaml_files.extend(glob.glob(pattern))
354
+ yaml_files = list(dict.fromkeys(yaml_files)) # Remove duplicates while preserving order
355
+
356
+ if not yaml_files:
357
+ if not config.quiet:
358
+ print("ℹ️ No YAML files found to migrate.")
359
+ return 0
360
+
361
+ issues_found = 0
362
+ files_modified = 0
363
+ files_failed = 0
364
+
365
+ for yaml_file in yaml_files:
366
+ if not os.path.exists(yaml_file):
367
+ continue
368
+
369
+ try:
370
+ with open(yaml_file, 'r') as f:
371
+ data = yaml.safe_load(f)
372
+
373
+ # Check for deprecated cli_backend usage
374
+ if self._has_deprecated_cli_backend(data):
375
+ issues_found += 1
376
+ if not config.quiet:
377
+ print(f"⚠️ Found deprecated cli_backend in: {yaml_file}")
378
+
379
+ if config.execute:
380
+ # Create backup if needed
381
+ if not config.no_backup:
382
+ backup_file = f"{yaml_file}.bak"
383
+ import shutil
384
+ shutil.copy2(yaml_file, backup_file)
385
+ if not config.quiet:
386
+ print(f"💾 Backup created: {backup_file}")
387
+
388
+ # Apply migration (simplified)
389
+ migrated_data = self._migrate_cli_backend_config(data)
390
+
391
+ # Write back the file
392
+ with open(yaml_file, 'w') as f:
393
+ yaml.dump(migrated_data, f, default_flow_style=False)
394
+
395
+ files_modified += 1
396
+ if not config.quiet:
397
+ print(f"✅ Migrated: {yaml_file}")
398
+ else:
399
+ if not config.quiet:
400
+ print(" Run with --execute to apply migration")
401
+
402
+ except Exception as e:
403
+ files_failed += 1
404
+ if not config.quiet:
405
+ print(f"❌ Error processing {yaml_file}: {e}")
406
+
407
+ if not config.quiet:
408
+ if issues_found == 0:
409
+ print("✅ No deprecated cli_backend configurations found.")
410
+ else:
411
+ action = "would be" if not config.execute else "were"
412
+ print(f"📊 Summary: {issues_found} files with deprecated configs, {files_modified} {action} migrated.")
413
+
414
+ if not config.execute and issues_found > 0:
415
+ print("\n💡 To apply migrations, run: praisonai doctor fix --execute")
416
+
417
+ return 1 if files_failed > 0 else 0
418
+
419
+ def _has_deprecated_cli_backend(self, data: dict) -> bool:
420
+ """Check if YAML config has deprecated cli_backend usage."""
421
+ if not isinstance(data, dict):
422
+ return False
423
+
424
+ # Check roles and agents sections for cli_backend
425
+ for section in ['roles', 'agents']:
426
+ section_data = data.get(section, {})
427
+ if isinstance(section_data, dict):
428
+ for agent_config in section_data.values():
429
+ if isinstance(agent_config, dict) and 'cli_backend' in agent_config:
430
+ # Check if there's also model configuration
431
+ if 'llm' in agent_config or 'model' in agent_config:
432
+ return True
433
+ return False
434
+
435
+ def _migrate_cli_backend_config(self, data: dict) -> dict:
436
+ """Migrate cli_backend configuration (simplified migration)."""
437
+ migrated = data.copy()
438
+
439
+ # Add migration comment at top level
440
+ if 'migration_info' not in migrated:
441
+ migrated['migration_info'] = {
442
+ 'cli_backend_migration': 'Agent-level cli_backend deprecated. Consider model-scoped runtime configuration.',
443
+ 'migrated_by': 'praisonai doctor fix',
444
+ }
445
+
446
+ # For now, just add comments rather than removing cli_backend
447
+ # since full migration requires understanding the intended model-scoped runtime pattern
448
+ for section in ['roles', 'agents']:
449
+ section_data = migrated.get(section, {})
450
+ if isinstance(section_data, dict):
451
+ for agent_name, agent_config in section_data.items():
452
+ if isinstance(agent_config, dict) and 'cli_backend' in agent_config:
453
+ if 'llm' in agent_config or 'model' in agent_config:
454
+ # Add migration note
455
+ agent_config['_migration_note'] = f"cli_backend is deprecated when model is specified. Consider model-scoped runtime."
456
+
457
+ return migrated
458
+
459
+ def execute(self, action: str, action_args: List[str], **kwargs) -> int:
460
+ """
461
+ Execute the doctor command.
462
+
463
+ Args:
464
+ action: The subcommand or empty string
465
+ action_args: Additional arguments
466
+
467
+ Returns:
468
+ Exit code (0=pass, 1=fail, 2=error)
469
+ """
470
+ # Combine action and action_args for parsing
471
+ all_args = [action] + action_args if action and action != "help" else action_args
472
+
473
+ try:
474
+ args = self._parse_args(all_args)
475
+ except SystemExit:
476
+ return 0 # Help was shown
477
+
478
+ # Handle special flags
479
+ if args.version:
480
+ from . import __version__
481
+ print(f"PraisonAI Doctor v{__version__}")
482
+ return 0
483
+
484
+ # Register all checks
485
+ self._register_checks()
486
+
487
+ if args.list_checks:
488
+ registry = get_registry()
489
+ print(registry.list_checks_text())
490
+ return 0
491
+
492
+ # Build config
493
+ config = self._build_config(args)
494
+
495
+ # Handle CI mode
496
+ if args.subcommand == "ci":
497
+ config.format = "json"
498
+ config.no_color = True
499
+ config.quiet = True
500
+
501
+ # Handle fix mode
502
+ if args.subcommand == "fix":
503
+ return self._run_fix_mode(config)
504
+
505
+ # Get categories for subcommand
506
+ categories = self._get_categories_for_subcommand(args.subcommand)
507
+
508
+ # Run doctor
509
+ engine = DoctorEngine(config)
510
+ report = engine.run(categories=categories)
511
+
512
+ # Format output
513
+ formatter = get_formatter(
514
+ format_type=config.format,
515
+ no_color=config.no_color,
516
+ quiet=config.quiet,
517
+ show_prefix_suffix=config.show_keys,
518
+ )
519
+
520
+ # Write output
521
+ if config.output_path:
522
+ with open(config.output_path, "w", encoding="utf-8") as f:
523
+ formatter.write(report, f)
524
+ if not config.quiet:
525
+ print(f"Report written to: {config.output_path}")
526
+ else:
527
+ formatter.write(report, sys.stdout)
528
+
529
+ return report.exit_code
530
+
531
+ def run(self, args: List[str]) -> int:
532
+ """
533
+ Run the doctor command from CLI.
534
+
535
+ Args:
536
+ args: Command line arguments after 'doctor'
537
+
538
+ Returns:
539
+ Exit code
540
+ """
541
+ if not args:
542
+ return self.execute("", [])
543
+
544
+ action = args[0] if args else ""
545
+ action_args = args[1:] if len(args) > 1 else []
546
+
547
+ return self.execute(action, action_args)
548
+
549
+
550
+ def run_doctor(args: Optional[List[str]] = None) -> int:
551
+ """
552
+ Convenience function to run doctor from CLI.
553
+
554
+ Args:
555
+ args: Command line arguments (default: sys.argv[1:])
556
+
557
+ Returns:
558
+ Exit code
559
+ """
560
+ if args is None:
561
+ args = sys.argv[1:]
562
+
563
+ handler = DoctorHandler()
564
+ return handler.run(args)