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,220 @@
1
+ """
2
+ ACP health checks for PraisonAI Doctor.
3
+ """
4
+
5
+ import asyncio
6
+ import logging
7
+ import os
8
+
9
+ from ..models import CheckCategory, CheckResult, CheckStatus
10
+ from ..registry import register_check
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ @register_check(
16
+ id="acp_module",
17
+ title="ACP Module Available",
18
+ category=CheckCategory.TOOLS,
19
+ description="Check if ACP module is installed"
20
+ )
21
+ def check_acp_module(config=None) -> CheckResult:
22
+ """Check if ACP module is available."""
23
+ try:
24
+ import importlib.util
25
+ spec = importlib.util.find_spec("praisonai.acp")
26
+
27
+ if spec is not None:
28
+ return CheckResult(
29
+ id="acp_module",
30
+ title="ACP Module Available",
31
+ category=CheckCategory.TOOLS,
32
+ status=CheckStatus.PASS,
33
+ message="ACP module is available",
34
+ metadata={"module": "praisonai.acp"}
35
+ )
36
+ else:
37
+ return CheckResult(
38
+ id="acp_module",
39
+ title="ACP Module Available",
40
+ category=CheckCategory.TOOLS,
41
+ status=CheckStatus.WARN,
42
+ message="ACP module not found",
43
+ remediation="ACP module should be part of praisonai package"
44
+ )
45
+ except Exception as e:
46
+ return CheckResult(
47
+ id="acp_module",
48
+ title="ACP Module Available",
49
+ category=CheckCategory.TOOLS,
50
+ status=CheckStatus.FAIL,
51
+ message=f"Error checking ACP module: {e}",
52
+ metadata={"error": str(e)}
53
+ )
54
+
55
+
56
+ @register_check(
57
+ id="acp_sdk",
58
+ title="ACP SDK Available",
59
+ category=CheckCategory.TOOLS,
60
+ description="Check if agent-client-protocol SDK is installed"
61
+ )
62
+ def check_acp_sdk(config=None) -> CheckResult:
63
+ """Check if ACP SDK is available."""
64
+ try:
65
+ import importlib.util
66
+ spec = importlib.util.find_spec("acp")
67
+
68
+ if spec is not None:
69
+ return CheckResult(
70
+ id="acp_sdk",
71
+ title="ACP SDK Available",
72
+ category=CheckCategory.TOOLS,
73
+ status=CheckStatus.PASS,
74
+ message="ACP SDK (agent-client-protocol) is installed",
75
+ metadata={"package": "agent-client-protocol"}
76
+ )
77
+ else:
78
+ return CheckResult(
79
+ id="acp_sdk",
80
+ title="ACP SDK Available",
81
+ category=CheckCategory.TOOLS,
82
+ status=CheckStatus.SKIP,
83
+ message="ACP SDK not installed (optional)",
84
+ remediation="Install with: pip install agent-client-protocol"
85
+ )
86
+ except Exception as e:
87
+ return CheckResult(
88
+ id="acp_sdk",
89
+ title="ACP SDK Available",
90
+ category=CheckCategory.TOOLS,
91
+ status=CheckStatus.FAIL,
92
+ message=f"Error checking ACP SDK: {e}",
93
+ metadata={"error": str(e)}
94
+ )
95
+
96
+
97
+ @register_check(
98
+ id="acp_server",
99
+ title="ACP Server Import",
100
+ category=CheckCategory.TOOLS,
101
+ description="Check if ACP server can be imported"
102
+ )
103
+ def check_acp_server(config=None) -> CheckResult:
104
+ """Check if ACP server can be imported."""
105
+ try:
106
+ from praisonai.acp import ACPServer # noqa: F401
107
+
108
+ return CheckResult(
109
+ id="acp_server",
110
+ title="ACP Server Import",
111
+ category=CheckCategory.TOOLS,
112
+ status=CheckStatus.PASS,
113
+ message="ACP server can be imported",
114
+ metadata={"class": "ACPServer"}
115
+ )
116
+ except ImportError as e:
117
+ return CheckResult(
118
+ id="acp_server",
119
+ title="ACP Server Import",
120
+ category=CheckCategory.TOOLS,
121
+ status=CheckStatus.WARN,
122
+ message=f"ACP server import failed: {e}",
123
+ metadata={"error": str(e)}
124
+ )
125
+ except Exception as e:
126
+ return CheckResult(
127
+ id="acp_server",
128
+ title="ACP Server Import",
129
+ category=CheckCategory.TOOLS,
130
+ status=CheckStatus.FAIL,
131
+ message=f"Error importing ACP server: {e}",
132
+ metadata={"error": str(e)}
133
+ )
134
+
135
+
136
+ @register_check(
137
+ id="acp_config",
138
+ title="ACP Configuration",
139
+ category=CheckCategory.CONFIG,
140
+ description="Check ACP configuration"
141
+ )
142
+ def check_acp_config(config=None) -> CheckResult:
143
+ """Check ACP configuration."""
144
+ acp_conf = {
145
+ "approval_mode": os.environ.get("PRAISONAI_APPROVAL_MODE", "manual"),
146
+ "allow_write": os.environ.get("PRAISONAI_ALLOW_WRITE", "false"),
147
+ "allow_shell": os.environ.get("PRAISONAI_ALLOW_SHELL", "false"),
148
+ }
149
+
150
+ return CheckResult(
151
+ id="acp_config",
152
+ title="ACP Configuration",
153
+ category=CheckCategory.CONFIG,
154
+ status=CheckStatus.PASS,
155
+ message=f"ACP configured with approval_mode={acp_conf['approval_mode']}",
156
+ metadata=acp_conf
157
+ )
158
+
159
+
160
+ @register_check(
161
+ id="acp_runtime",
162
+ title="ACP Runtime Check",
163
+ category=CheckCategory.TOOLS,
164
+ description="Check if ACP runtime can start",
165
+ requires_deep=True
166
+ )
167
+ def check_acp_runtime(config=None) -> CheckResult:
168
+ """Check if ACP runtime can start."""
169
+ try:
170
+ from praisonai.cli.features.interactive_runtime import create_runtime
171
+
172
+ async def _check():
173
+ runtime = create_runtime(
174
+ workspace=".",
175
+ lsp=False,
176
+ acp=True
177
+ )
178
+ try:
179
+ await runtime.start()
180
+ ready = runtime.acp_ready
181
+ error = runtime._acp_state.error
182
+ return ready, error
183
+ finally:
184
+ await runtime.stop()
185
+
186
+ ready, error = asyncio.run(_check())
187
+
188
+ if ready:
189
+ return CheckResult(
190
+ id="acp_runtime",
191
+ title="ACP Runtime Check",
192
+ category=CheckCategory.TOOLS,
193
+ status=CheckStatus.PASS,
194
+ message="ACP runtime started successfully",
195
+ metadata={"ready": True}
196
+ )
197
+ else:
198
+ return CheckResult(
199
+ id="acp_runtime",
200
+ title="ACP Runtime Check",
201
+ category=CheckCategory.TOOLS,
202
+ status=CheckStatus.WARN,
203
+ message=f"ACP runtime failed to start: {error}",
204
+ metadata={"ready": False, "error": str(error)}
205
+ )
206
+
207
+ except Exception as e:
208
+ return CheckResult(
209
+ id="acp_runtime",
210
+ title="ACP Runtime Check",
211
+ category=CheckCategory.TOOLS,
212
+ status=CheckStatus.FAIL,
213
+ message=f"ACP runtime check failed: {e}",
214
+ metadata={"error": str(e)}
215
+ )
216
+
217
+
218
+ def register_acp_checks():
219
+ """Register all ACP checks."""
220
+ pass
@@ -0,0 +1,340 @@
1
+ """
2
+ Bot-specific doctor checks for PraisonAI.
3
+
4
+ Registers checks for bot tokens, config validation, and channel probes.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import time
11
+ from typing import List
12
+
13
+ from ..models import CheckResult, CheckStatus, CheckCategory, CheckSeverity, DoctorConfig
14
+ from ..registry import register_check
15
+
16
+
17
+ @register_check(
18
+ id="bot_tokens",
19
+ title="Bot Tokens",
20
+ description="Check bot token environment variables",
21
+ category=CheckCategory.BOTS,
22
+ severity=CheckSeverity.MEDIUM,
23
+ )
24
+ def check_bot_tokens(config: DoctorConfig) -> CheckResult:
25
+ """Check bot token environment variables."""
26
+ from praisonai.cli._paths import resolve_bot_config_path
27
+ config_path = getattr(config, 'config_file', None) or resolve_bot_config_path("bot.yaml")
28
+ token_vars = {
29
+ "TELEGRAM_BOT_TOKEN": "Telegram",
30
+ "DISCORD_BOT_TOKEN": "Discord",
31
+ "SLACK_BOT_TOKEN": "Slack",
32
+ "WHATSAPP_ACCESS_TOKEN": "WhatsApp",
33
+ }
34
+ found = []
35
+ for var, name in token_vars.items():
36
+ if os.environ.get(var):
37
+ found.append(name)
38
+
39
+ if found:
40
+ return CheckResult(
41
+ id="bot_tokens",
42
+ title="Bot Tokens",
43
+ category=CheckCategory.BOTS,
44
+ status=CheckStatus.PASS,
45
+ message=f"Found: {', '.join(found)}",
46
+ )
47
+ return CheckResult(
48
+ id="bot_tokens",
49
+ title="Bot Tokens",
50
+ category=CheckCategory.BOTS,
51
+ status=CheckStatus.WARN,
52
+ message="No bot tokens found in environment",
53
+ remediation="Set at least one: export TELEGRAM_BOT_TOKEN=your_token",
54
+ )
55
+
56
+
57
+ @register_check(
58
+ id="bot_config",
59
+ title="Bot Config",
60
+ description="Check bot.yaml exists and is valid",
61
+ category=CheckCategory.BOTS,
62
+ severity=CheckSeverity.MEDIUM,
63
+ )
64
+ def check_bot_config(config: DoctorConfig) -> CheckResult:
65
+ """Check bot.yaml exists and is valid."""
66
+ start = time.time()
67
+ from praisonai.cli._paths import resolve_bot_config_path
68
+ config_path = getattr(config, 'config_file', None) or resolve_bot_config_path("bot.yaml")
69
+ if not os.path.exists(config_path):
70
+ return CheckResult(
71
+ id="bot_config",
72
+ title="Bot Config",
73
+ category=CheckCategory.BOTS,
74
+ status=CheckStatus.WARN,
75
+ message=f"{config_path} not found",
76
+ remediation="Run 'praisonai onboard' to create one",
77
+ duration_ms=(time.time() - start) * 1000,
78
+ )
79
+ try:
80
+ from praisonai.bots._config_schema import load_and_validate_bot_yaml
81
+ load_and_validate_bot_yaml(config_path)
82
+ return CheckResult(
83
+ id="bot_config",
84
+ title="Bot Config",
85
+ category=CheckCategory.BOTS,
86
+ status=CheckStatus.PASS,
87
+ message=f"{config_path} valid",
88
+ duration_ms=(time.time() - start) * 1000,
89
+ )
90
+ except Exception as e:
91
+ return CheckResult(
92
+ id="bot_config",
93
+ title="Bot Config",
94
+ category=CheckCategory.BOTS,
95
+ status=CheckStatus.FAIL,
96
+ message=f"Invalid: {str(e)[:200]}",
97
+ remediation="Fix errors in bot.yaml or run 'praisonai onboard'",
98
+ duration_ms=(time.time() - start) * 1000,
99
+ )
100
+
101
+
102
+ @register_check(
103
+ id="bot_security",
104
+ title="Bot Security Config",
105
+ description="Check bot security configuration for safe defaults",
106
+ category=CheckCategory.BOTS,
107
+ severity=CheckSeverity.HIGH,
108
+ )
109
+ def check_bot_security(config: DoctorConfig) -> CheckResult:
110
+ """Check bot security configuration for safe defaults."""
111
+ start = time.time()
112
+ from praisonai.cli._paths import resolve_bot_config_path
113
+ config_path = getattr(config, 'config_file', None) or resolve_bot_config_path("bot.yaml")
114
+ channel_warnings = []
115
+ global_warnings = []
116
+
117
+ # Check if bot.yaml exists
118
+ if not os.path.exists(config_path):
119
+ return CheckResult(
120
+ id="bot_security",
121
+ title="Bot Security Config",
122
+ category=CheckCategory.BOTS,
123
+ status=CheckStatus.SKIP,
124
+ message=f"{config_path} not found - security check skipped",
125
+ duration_ms=(time.time() - start) * 1000,
126
+ )
127
+
128
+ try:
129
+ from praisonai.bots._config_schema import load_and_validate_bot_yaml
130
+ config = load_and_validate_bot_yaml(config_path)
131
+
132
+ # Check for risky configurations across channels
133
+ for channel_name, channel_config in config.channels.items():
134
+ # Check for missing allowlists in production-like setups
135
+ if not channel_config.allowlist and not channel_config.blocklist:
136
+ channel_warnings.append(f"{channel_name}: No allowlist/blocklist configured")
137
+
138
+ # Check for overly permissive group policies
139
+ if channel_config.group_policy == "respond_all":
140
+ channel_warnings.append(f"{channel_name}: group_policy='respond_all' - consider 'mention_only' for security")
141
+
142
+ # Check for missing gateway pairing settings
143
+ gateway_secret = os.environ.get("PRAISONAI_GATEWAY_SECRET")
144
+ if not gateway_secret:
145
+ global_warnings.append("PRAISONAI_GATEWAY_SECRET not set - pairing codes will not persist across restarts")
146
+
147
+ # Determine status
148
+ all_warnings = channel_warnings + global_warnings
149
+ if all_warnings:
150
+ channel_count = len(channel_warnings)
151
+ global_count = len(global_warnings)
152
+
153
+ if channel_count > 0 and global_count > 0:
154
+ message = f"Security recommendations: {channel_count} channel(s) and {global_count} global setting(s) could be improved"
155
+ elif channel_count > 0:
156
+ message = f"Security recommendations: {channel_count} channel(s) could use stricter defaults"
157
+ else:
158
+ message = f"Security recommendations: {global_count} global setting(s) could be improved"
159
+
160
+ return CheckResult(
161
+ id="bot_security",
162
+ title="Bot Security Config",
163
+ category=CheckCategory.BOTS,
164
+ status=CheckStatus.WARN,
165
+ message=message,
166
+ details='\n'.join(all_warnings),
167
+ remediation="Consider allowlists for DM security and 'mention_only' group policy. See security docs for safe defaults.",
168
+ duration_ms=(time.time() - start) * 1000,
169
+ )
170
+ else:
171
+ return CheckResult(
172
+ id="bot_security",
173
+ title="Bot Security Config",
174
+ category=CheckCategory.BOTS,
175
+ status=CheckStatus.PASS,
176
+ message="Security configuration looks good",
177
+ duration_ms=(time.time() - start) * 1000,
178
+ )
179
+
180
+ except ValueError as e:
181
+ return CheckResult(
182
+ id="bot_security",
183
+ title="Bot Security Config",
184
+ category=CheckCategory.BOTS,
185
+ status=CheckStatus.FAIL,
186
+ message=f"Invalid bot security config: {str(e)[:100]}",
187
+ details=str(e)[:200],
188
+ remediation="Fix bot.yaml security settings and re-run doctor",
189
+ duration_ms=(time.time() - start) * 1000,
190
+ )
191
+ except Exception as e:
192
+ return CheckResult(
193
+ id="bot_security",
194
+ title="Bot Security Config",
195
+ category=CheckCategory.BOTS,
196
+ status=CheckStatus.ERROR,
197
+ message=f"Error checking security: {str(e)[:100]}",
198
+ remediation="Fix bot.yaml syntax errors first",
199
+ duration_ms=(time.time() - start) * 1000,
200
+ )
201
+
202
+
203
+ @register_check(
204
+ id="multi_channel_tokens",
205
+ title="Multi-Channel Token Configuration",
206
+ description="Check for duplicate tokens across channels and validate multi-channel setup",
207
+ category=CheckCategory.BOTS,
208
+ severity=CheckSeverity.MEDIUM,
209
+ )
210
+ def check_multi_channel_tokens(config: DoctorConfig) -> CheckResult:
211
+ """Check multi-channel token configuration for duplicates and naming conventions."""
212
+ start = time.time()
213
+ from praisonai.cli._paths import resolve_bot_config_path
214
+ config_path = getattr(config, 'config_file', None) or resolve_bot_config_path("bot.yaml")
215
+
216
+ # Check if bot.yaml exists
217
+ if not os.path.exists(config_path):
218
+ return CheckResult(
219
+ id="multi_channel_tokens",
220
+ title="Multi-Channel Token Configuration",
221
+ category=CheckCategory.BOTS,
222
+ status=CheckStatus.SKIP,
223
+ message=f"{config_path} not found - multi-channel check skipped",
224
+ duration_ms=(time.time() - start) * 1000,
225
+ )
226
+
227
+ try:
228
+ from praisonai.bots._config_schema import load_and_validate_bot_yaml
229
+ config_data = load_and_validate_bot_yaml(config_path)
230
+
231
+ warnings = []
232
+ errors = []
233
+
234
+ # Extract token environment variables from channels
235
+ channel_tokens = {} # env_var -> [channel_keys_using_it]
236
+ channel_platforms = {} # platform -> [channel_keys]
237
+
238
+ for channel_name, channel_config in config_data.channels.items():
239
+ platform = channel_config.platform
240
+ token_ref = channel_config.token
241
+
242
+ # Track platforms
243
+ if platform not in channel_platforms:
244
+ channel_platforms[platform] = []
245
+ channel_platforms[platform].append(channel_name)
246
+
247
+ # Extract environment variable from token reference like ${TELEGRAM_BOT_TOKEN}
248
+ if token_ref and token_ref.startswith("${") and token_ref.endswith("}"):
249
+ env_var = token_ref[2:-1] # Remove ${ and }
250
+ if env_var not in channel_tokens:
251
+ channel_tokens[env_var] = []
252
+ channel_tokens[env_var].append(channel_name)
253
+
254
+ # Check for duplicate token usage by env var reference
255
+ for env_var, channels in channel_tokens.items():
256
+ if len(channels) > 1:
257
+ errors.append(f"Token {env_var} is used by multiple channels: {', '.join(channels)}")
258
+
259
+ # Also check duplicate token usage by resolved token value
260
+ token_value_to_channels = {} # token_value -> [channel_keys]
261
+ for env_var, channels in channel_tokens.items():
262
+ token_value = os.environ.get(env_var)
263
+ if token_value:
264
+ token_value_to_channels.setdefault(token_value, []).extend(channels)
265
+
266
+ for _, channels in token_value_to_channels.items():
267
+ unique_channels = sorted(set(channels))
268
+ if len(unique_channels) > 1:
269
+ errors.append(
270
+ f"Same bot token value is used by multiple channels: {', '.join(unique_channels)}"
271
+ )
272
+
273
+ # Check for multi-platform channels with good naming conventions
274
+ for platform, channels in channel_platforms.items():
275
+ if len(channels) > 1:
276
+ # Multiple channels on same platform - check naming convention
277
+ for channel_name in channels:
278
+ channel_config = config_data.channels[channel_name]
279
+ token_ref = channel_config.token
280
+ if token_ref and token_ref.startswith("${") and token_ref.endswith("}"):
281
+ env_var = token_ref[2:-1]
282
+
283
+ # Check if follows naming convention: PLATFORM_ROLE_BOT_TOKEN
284
+ expected_pattern = f"{platform.upper()}_"
285
+ if not env_var.startswith(expected_pattern) or not env_var.endswith("_BOT_TOKEN"):
286
+ warnings.append(f"Channel '{channel_name}' token '{env_var}' doesn't follow naming convention '{platform.upper()}_<ROLE>_BOT_TOKEN'")
287
+
288
+ # Check for missing tokens
289
+ missing_tokens = []
290
+ for env_var in channel_tokens.keys():
291
+ if not os.environ.get(env_var):
292
+ missing_tokens.append(env_var)
293
+
294
+ # Determine status
295
+ if errors:
296
+ return CheckResult(
297
+ id="multi_channel_tokens",
298
+ title="Multi-Channel Token Configuration",
299
+ category=CheckCategory.BOTS,
300
+ status=CheckStatus.FAIL,
301
+ message=f"Token configuration errors: {len(errors)} duplicate(s) found",
302
+ details='\n'.join(errors + warnings),
303
+ remediation="Each channel must have a unique bot token. Create separate bots in @BotFather and use unique environment variables.",
304
+ duration_ms=(time.time() - start) * 1000,
305
+ )
306
+ elif warnings or missing_tokens:
307
+ all_issues = warnings + [f"Missing token: {token}" for token in missing_tokens]
308
+ return CheckResult(
309
+ id="multi_channel_tokens",
310
+ title="Multi-Channel Token Configuration",
311
+ category=CheckCategory.BOTS,
312
+ status=CheckStatus.WARN,
313
+ message=f"Multi-channel setup with {len(all_issues)} recommendation(s)",
314
+ details='\n'.join(all_issues),
315
+ remediation="Consider following the naming convention PLATFORM_ROLE_BOT_TOKEN for clarity.",
316
+ duration_ms=(time.time() - start) * 1000,
317
+ )
318
+ else:
319
+ channel_count = sum(len(channels) for channels in channel_platforms.values())
320
+ return CheckResult(
321
+ id="multi_channel_tokens",
322
+ title="Multi-Channel Token Configuration",
323
+ category=CheckCategory.BOTS,
324
+ status=CheckStatus.PASS,
325
+ message=f"Multi-channel configuration looks good ({channel_count} channels)",
326
+ duration_ms=(time.time() - start) * 1000,
327
+ )
328
+
329
+ except Exception as e:
330
+ return CheckResult(
331
+ id="multi_channel_tokens",
332
+ title="Multi-Channel Token Configuration",
333
+ category=CheckCategory.BOTS,
334
+ status=CheckStatus.ERROR,
335
+ message=f"Error checking multi-channel config: {str(e)[:100]}",
336
+ remediation="Fix bot.yaml syntax errors first",
337
+ duration_ms=(time.time() - start) * 1000,
338
+ )
339
+
340
+