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,276 @@
1
+ """
2
+ Data models for the Doctor CLI module.
3
+
4
+ Defines the core data structures for check results, reports, and configuration.
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from enum import Enum
9
+ from typing import Any, Dict, List, Optional
10
+ import time
11
+
12
+
13
+ class CheckStatus(Enum):
14
+ """Status of a doctor check."""
15
+ PASS = "pass"
16
+ WARN = "warn"
17
+ FAIL = "fail"
18
+ SKIP = "skip"
19
+ ERROR = "error"
20
+
21
+
22
+ class CheckCategory(Enum):
23
+ """Category of a doctor check."""
24
+ ENVIRONMENT = "environment"
25
+ CONFIG = "config"
26
+ TOOLS = "tools"
27
+ DATABASE = "database"
28
+ MCP = "mcp"
29
+ OBSERVABILITY = "observability"
30
+ SKILLS = "skills"
31
+ MEMORY = "memory"
32
+ PERMISSIONS = "permissions"
33
+ NETWORK = "network"
34
+ PERFORMANCE = "performance"
35
+ PACKAGING = "packaging"
36
+ RUNTIME = "runtime"
37
+ SELFTEST = "selftest"
38
+ BOTS = "bots"
39
+
40
+
41
+ class CheckSeverity(Enum):
42
+ """Severity level of a check."""
43
+ CRITICAL = "critical"
44
+ HIGH = "high"
45
+ MEDIUM = "medium"
46
+ LOW = "low"
47
+ INFO = "info"
48
+
49
+
50
+ @dataclass
51
+ class CheckResult:
52
+ """Result of a single doctor check."""
53
+ id: str
54
+ title: str
55
+ category: CheckCategory
56
+ status: CheckStatus
57
+ message: str
58
+ details: Optional[str] = None
59
+ remediation: Optional[str] = None
60
+ duration_ms: float = 0.0
61
+ severity: CheckSeverity = CheckSeverity.MEDIUM
62
+ metadata: Dict[str, Any] = field(default_factory=dict)
63
+
64
+ def to_dict(self) -> Dict[str, Any]:
65
+ """Convert to dictionary for JSON serialization."""
66
+ return {
67
+ "id": self.id,
68
+ "title": self.title,
69
+ "category": self.category.value,
70
+ "status": self.status.value,
71
+ "message": self.message,
72
+ "details": self.details,
73
+ "remediation": self.remediation,
74
+ "duration_ms": round(self.duration_ms, 2),
75
+ "severity": self.severity.value,
76
+ "metadata": self.metadata,
77
+ }
78
+
79
+ @property
80
+ def passed(self) -> bool:
81
+ """Check if this result is considered passing."""
82
+ return self.status in (CheckStatus.PASS, CheckStatus.SKIP)
83
+
84
+ @property
85
+ def is_warning(self) -> bool:
86
+ """Check if this result is a warning."""
87
+ return self.status == CheckStatus.WARN
88
+
89
+ @property
90
+ def is_failure(self) -> bool:
91
+ """Check if this result is a failure."""
92
+ return self.status in (CheckStatus.FAIL, CheckStatus.ERROR)
93
+
94
+
95
+ @dataclass
96
+ class CheckDefinition:
97
+ """Definition of a doctor check."""
98
+ id: str
99
+ title: str
100
+ description: str
101
+ category: CheckCategory
102
+ severity: CheckSeverity = CheckSeverity.MEDIUM
103
+ requires_deep: bool = False
104
+ dependencies: List[str] = field(default_factory=list)
105
+ tags: List[str] = field(default_factory=list)
106
+
107
+ def to_dict(self) -> Dict[str, Any]:
108
+ """Convert to dictionary."""
109
+ return {
110
+ "id": self.id,
111
+ "title": self.title,
112
+ "description": self.description,
113
+ "category": self.category.value,
114
+ "severity": self.severity.value,
115
+ "requires_deep": self.requires_deep,
116
+ "dependencies": self.dependencies,
117
+ "tags": self.tags,
118
+ }
119
+
120
+
121
+ @dataclass
122
+ class EnvironmentSummary:
123
+ """Summary of the runtime environment."""
124
+ python_version: str = ""
125
+ python_executable: str = ""
126
+ os_name: str = ""
127
+ os_version: str = ""
128
+ architecture: str = ""
129
+ praisonai_version: str = ""
130
+ praisonaiagents_version: str = ""
131
+ working_directory: str = ""
132
+ virtual_env: Optional[str] = None
133
+
134
+ def to_dict(self) -> Dict[str, Any]:
135
+ """Convert to dictionary."""
136
+ return {
137
+ "python_version": self.python_version,
138
+ "python_executable": self.python_executable,
139
+ "os_name": self.os_name,
140
+ "os_version": self.os_version,
141
+ "architecture": self.architecture,
142
+ "praisonai_version": self.praisonai_version,
143
+ "praisonaiagents_version": self.praisonaiagents_version,
144
+ "working_directory": self.working_directory,
145
+ "virtual_env": self.virtual_env,
146
+ }
147
+
148
+
149
+ @dataclass
150
+ class ReportSummary:
151
+ """Summary statistics for a doctor report."""
152
+ total: int = 0
153
+ passed: int = 0
154
+ warnings: int = 0
155
+ failed: int = 0
156
+ skipped: int = 0
157
+ errors: int = 0
158
+
159
+ def to_dict(self) -> Dict[str, Any]:
160
+ """Convert to dictionary."""
161
+ return {
162
+ "total": self.total,
163
+ "passed": self.passed,
164
+ "warnings": self.warnings,
165
+ "failed": self.failed,
166
+ "skipped": self.skipped,
167
+ "errors": self.errors,
168
+ }
169
+
170
+
171
+ @dataclass
172
+ class DoctorReport:
173
+ """Complete doctor report."""
174
+ version: str = "1.0.0"
175
+ timestamp: str = ""
176
+ duration_ms: float = 0.0
177
+ environment: EnvironmentSummary = field(default_factory=EnvironmentSummary)
178
+ results: List[CheckResult] = field(default_factory=list)
179
+ summary: ReportSummary = field(default_factory=ReportSummary)
180
+ exit_code: int = 0
181
+ mode: str = "fast"
182
+ filters: Dict[str, Any] = field(default_factory=dict)
183
+
184
+ def __post_init__(self):
185
+ if not self.timestamp:
186
+ from datetime import datetime, timezone
187
+ self.timestamp = datetime.now(timezone.utc).isoformat()
188
+
189
+ def calculate_summary(self) -> None:
190
+ """Calculate summary statistics from results."""
191
+ self.summary = ReportSummary(
192
+ total=len(self.results),
193
+ passed=sum(1 for r in self.results if r.status == CheckStatus.PASS),
194
+ warnings=sum(1 for r in self.results if r.status == CheckStatus.WARN),
195
+ failed=sum(1 for r in self.results if r.status == CheckStatus.FAIL),
196
+ skipped=sum(1 for r in self.results if r.status == CheckStatus.SKIP),
197
+ errors=sum(1 for r in self.results if r.status == CheckStatus.ERROR),
198
+ )
199
+
200
+ def calculate_exit_code(self, strict: bool = False) -> int:
201
+ """
202
+ Calculate exit code based on results.
203
+
204
+ Args:
205
+ strict: If True, treat warnings as failures
206
+
207
+ Returns:
208
+ 0: All passed (warnings allowed unless strict)
209
+ 1: Failures present
210
+ 2: Internal errors
211
+ """
212
+ if self.summary.errors > 0:
213
+ return 2
214
+ if self.summary.failed > 0:
215
+ return 1
216
+ if strict and self.summary.warnings > 0:
217
+ return 1
218
+ return 0
219
+
220
+ def to_dict(self) -> Dict[str, Any]:
221
+ """Convert to dictionary for JSON serialization."""
222
+ return {
223
+ "version": self.version,
224
+ "timestamp": self.timestamp,
225
+ "duration_ms": round(self.duration_ms, 2),
226
+ "environment": self.environment.to_dict(),
227
+ "results": [r.to_dict() for r in self.results],
228
+ "summary": self.summary.to_dict(),
229
+ "exit_code": self.exit_code,
230
+ "mode": self.mode,
231
+ "filters": self.filters,
232
+ }
233
+
234
+
235
+ @dataclass
236
+ class DoctorConfig:
237
+ """Configuration for doctor execution."""
238
+ deep: bool = False
239
+ timeout: float = 10.0
240
+ strict: bool = False
241
+ quiet: bool = False
242
+ no_color: bool = False
243
+ format: str = "text"
244
+ output_path: Optional[str] = None
245
+ only: List[str] = field(default_factory=list)
246
+ skip: List[str] = field(default_factory=list)
247
+
248
+ # Subcommand-specific options
249
+ show_keys: bool = False
250
+ require_keys: List[str] = field(default_factory=list)
251
+ config_file: Optional[str] = None
252
+ dsn: Optional[str] = None
253
+ provider: Optional[str] = None
254
+ read_only: bool = True
255
+ mock: bool = True
256
+ live: bool = False
257
+ model: Optional[str] = None
258
+ budget_ms: Optional[int] = None
259
+ top_n: int = 10
260
+ fail_fast: bool = False
261
+ list_tools: bool = False
262
+ all_checks: bool = False
263
+ missing_only: bool = False
264
+ name: Optional[str] = None
265
+ category: Optional[str] = None
266
+ path: Optional[str] = None
267
+ save_report: bool = False
268
+
269
+ # Runtime-specific options
270
+ team_file: Optional[str] = None
271
+ workflow_file: Optional[str] = None
272
+
273
+ # Fix subcommand options
274
+ fix: bool = False
275
+ execute: bool = False
276
+ no_backup: bool = False
@@ -0,0 +1,239 @@
1
+ """
2
+ Check registry for the Doctor CLI module.
3
+
4
+ Manages registration and discovery of doctor checks.
5
+ """
6
+
7
+ from typing import Callable, Dict, List, Optional, Set
8
+ from .models import CheckDefinition, CheckCategory, CheckSeverity, CheckResult
9
+
10
+
11
+ class CheckRegistry:
12
+ """
13
+ Registry for doctor checks.
14
+
15
+ Manages check definitions and their implementations.
16
+ """
17
+
18
+ _instance: Optional["CheckRegistry"] = None
19
+
20
+ def __new__(cls) -> "CheckRegistry":
21
+ """Singleton pattern for global registry."""
22
+ if cls._instance is None:
23
+ cls._instance = super().__new__(cls)
24
+ cls._instance._checks: Dict[str, CheckDefinition] = {}
25
+ cls._instance._implementations: Dict[str, Callable] = {}
26
+ cls._instance._initialized = False
27
+ return cls._instance
28
+
29
+ @classmethod
30
+ def get_instance(cls) -> "CheckRegistry":
31
+ """Get the singleton instance."""
32
+ return cls()
33
+
34
+ @classmethod
35
+ def reset(cls) -> None:
36
+ """Reset the registry (for testing)."""
37
+ cls._instance = None
38
+
39
+ def register(
40
+ self,
41
+ id: str,
42
+ title: str,
43
+ description: str,
44
+ category: CheckCategory,
45
+ implementation: Callable,
46
+ severity: CheckSeverity = CheckSeverity.MEDIUM,
47
+ requires_deep: bool = False,
48
+ dependencies: Optional[List[str]] = None,
49
+ tags: Optional[List[str]] = None,
50
+ ) -> None:
51
+ """
52
+ Register a doctor check.
53
+
54
+ Args:
55
+ id: Unique identifier (snake_case)
56
+ title: Human-readable title
57
+ description: Short description of what the check does
58
+ category: Check category
59
+ implementation: Callable that performs the check
60
+ severity: Severity level
61
+ requires_deep: Whether this check requires --deep mode
62
+ dependencies: List of check IDs this check depends on
63
+ tags: Optional tags for filtering
64
+ """
65
+ definition = CheckDefinition(
66
+ id=id,
67
+ title=title,
68
+ description=description,
69
+ category=category,
70
+ severity=severity,
71
+ requires_deep=requires_deep,
72
+ dependencies=dependencies or [],
73
+ tags=tags or [],
74
+ )
75
+ self._checks[id] = definition
76
+ self._implementations[id] = implementation
77
+
78
+ def get_check(self, id: str) -> Optional[CheckDefinition]:
79
+ """Get a check definition by ID."""
80
+ return self._checks.get(id)
81
+
82
+ def get_implementation(self, id: str) -> Optional[Callable]:
83
+ """Get a check implementation by ID."""
84
+ return self._implementations.get(id)
85
+
86
+ def get_all_checks(self) -> List[CheckDefinition]:
87
+ """Get all registered checks."""
88
+ return list(self._checks.values())
89
+
90
+ def get_check_ids(self) -> List[str]:
91
+ """Get all registered check IDs."""
92
+ return list(self._checks.keys())
93
+
94
+ def get_checks_by_category(self, category: CheckCategory) -> List[CheckDefinition]:
95
+ """Get all checks in a category."""
96
+ return [c for c in self._checks.values() if c.category == category]
97
+
98
+ def get_checks_by_tag(self, tag: str) -> List[CheckDefinition]:
99
+ """Get all checks with a specific tag."""
100
+ return [c for c in self._checks.values() if tag in c.tags]
101
+
102
+ def filter_checks(
103
+ self,
104
+ only: Optional[List[str]] = None,
105
+ skip: Optional[List[str]] = None,
106
+ categories: Optional[List[CheckCategory]] = None,
107
+ deep_mode: bool = False,
108
+ ) -> List[CheckDefinition]:
109
+ """
110
+ Filter checks based on criteria.
111
+
112
+ Args:
113
+ only: Only include these check IDs
114
+ skip: Skip these check IDs
115
+ categories: Only include checks in these categories
116
+ deep_mode: Include checks that require deep mode
117
+
118
+ Returns:
119
+ Filtered list of check definitions
120
+ """
121
+ checks = list(self._checks.values())
122
+
123
+ # Filter by only
124
+ if only:
125
+ only_set = set(only)
126
+ checks = [c for c in checks if c.id in only_set]
127
+
128
+ # Filter by skip
129
+ if skip:
130
+ skip_set = set(skip)
131
+ checks = [c for c in checks if c.id not in skip_set]
132
+
133
+ # Filter by categories
134
+ if categories:
135
+ checks = [c for c in checks if c.category in categories]
136
+
137
+ # Filter by deep mode
138
+ if not deep_mode:
139
+ checks = [c for c in checks if not c.requires_deep]
140
+
141
+ return checks
142
+
143
+ def resolve_dependencies(self, check_ids: List[str]) -> List[str]:
144
+ """
145
+ Resolve check dependencies and return ordered list.
146
+
147
+ Args:
148
+ check_ids: List of check IDs to resolve
149
+
150
+ Returns:
151
+ Ordered list of check IDs with dependencies first
152
+ """
153
+ resolved: List[str] = []
154
+ seen: Set[str] = set()
155
+
156
+ def resolve(id: str) -> None:
157
+ if id in seen:
158
+ return
159
+ seen.add(id)
160
+
161
+ check = self._checks.get(id)
162
+ if check:
163
+ for dep in check.dependencies:
164
+ resolve(dep)
165
+ resolved.append(id)
166
+
167
+ for id in check_ids:
168
+ resolve(id)
169
+
170
+ return resolved
171
+
172
+ def list_checks_text(self) -> str:
173
+ """Generate text listing of all checks."""
174
+ lines = ["Available Doctor Checks:", ""]
175
+
176
+ # Group by category
177
+ by_category: Dict[CheckCategory, List[CheckDefinition]] = {}
178
+ for check in self._checks.values():
179
+ if check.category not in by_category:
180
+ by_category[check.category] = []
181
+ by_category[check.category].append(check)
182
+
183
+ for category in CheckCategory:
184
+ if category in by_category:
185
+ lines.append(f" {category.value.upper()}:")
186
+ for check in sorted(by_category[category], key=lambda c: c.id):
187
+ deep_marker = " [deep]" if check.requires_deep else ""
188
+ lines.append(f" {check.id:<30} {check.description}{deep_marker}")
189
+ lines.append("")
190
+
191
+ return "\n".join(lines)
192
+
193
+
194
+ # Global registry instance
195
+ _registry = CheckRegistry()
196
+
197
+
198
+ def register_check(
199
+ id: str,
200
+ title: str,
201
+ description: str,
202
+ category: CheckCategory,
203
+ severity: CheckSeverity = CheckSeverity.MEDIUM,
204
+ requires_deep: bool = False,
205
+ dependencies: Optional[List[str]] = None,
206
+ tags: Optional[List[str]] = None,
207
+ ):
208
+ """
209
+ Decorator to register a doctor check.
210
+
211
+ Usage:
212
+ @register_check(
213
+ id="python_version",
214
+ title="Python Version",
215
+ description="Check Python version is 3.9+",
216
+ category=CheckCategory.ENVIRONMENT,
217
+ )
218
+ def check_python_version(config: DoctorConfig) -> CheckResult:
219
+ ...
220
+ """
221
+ def decorator(func: Callable) -> Callable:
222
+ _registry.register(
223
+ id=id,
224
+ title=title,
225
+ description=description,
226
+ category=category,
227
+ implementation=func,
228
+ severity=severity,
229
+ requires_deep=requires_deep,
230
+ dependencies=dependencies,
231
+ tags=tags,
232
+ )
233
+ return func
234
+ return decorator
235
+
236
+
237
+ def get_registry() -> CheckRegistry:
238
+ """Get the global check registry."""
239
+ return _registry