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.
- praisonai_code/__init__.py +17 -0
- praisonai_code/cli/__init__.py +12 -0
- praisonai_code/cli/_forward_shim.py +10 -0
- praisonai_code/cli/_paths.py +88 -0
- praisonai_code/cli/_warnings.py +58 -0
- praisonai_code/cli/app.py +757 -0
- praisonai_code/cli/approval_backend.py +272 -0
- praisonai_code/cli/branding.py +94 -0
- praisonai_code/cli/commands/__init__.py +114 -0
- praisonai_code/cli/commands/acp.py +80 -0
- praisonai_code/cli/commands/agent.py +116 -0
- praisonai_code/cli/commands/agents.py +80 -0
- praisonai_code/cli/commands/app.py +139 -0
- praisonai_code/cli/commands/attach.py +95 -0
- praisonai_code/cli/commands/audit.py +102 -0
- praisonai_code/cli/commands/auth.py +508 -0
- praisonai_code/cli/commands/batch.py +848 -0
- praisonai_code/cli/commands/benchmark.py +286 -0
- praisonai_code/cli/commands/browser.py +299 -0
- praisonai_code/cli/commands/call.py +45 -0
- praisonai_code/cli/commands/chat.py +332 -0
- praisonai_code/cli/commands/checkpoint.py +170 -0
- praisonai_code/cli/commands/code.py +276 -0
- praisonai_code/cli/commands/command.py +114 -0
- praisonai_code/cli/commands/commit.py +47 -0
- praisonai_code/cli/commands/completion.py +333 -0
- praisonai_code/cli/commands/config.py +681 -0
- praisonai_code/cli/commands/context.py +414 -0
- praisonai_code/cli/commands/daemon.py +203 -0
- praisonai_code/cli/commands/debug.py +142 -0
- praisonai_code/cli/commands/deploy.py +71 -0
- praisonai_code/cli/commands/diag.py +55 -0
- praisonai_code/cli/commands/docs.py +1575 -0
- praisonai_code/cli/commands/doctor.py +332 -0
- praisonai_code/cli/commands/endpoints.py +51 -0
- praisonai_code/cli/commands/environment.py +179 -0
- praisonai_code/cli/commands/eval.py +131 -0
- praisonai_code/cli/commands/examples.py +953 -0
- praisonai_code/cli/commands/flow.py +436 -0
- praisonai_code/cli/commands/github.py +752 -0
- praisonai_code/cli/commands/hooks.py +74 -0
- praisonai_code/cli/commands/init.py +174 -0
- praisonai_code/cli/commands/knowledge.py +440 -0
- praisonai_code/cli/commands/langextract.py +120 -0
- praisonai_code/cli/commands/langfuse.py +984 -0
- praisonai_code/cli/commands/loop.py +211 -0
- praisonai_code/cli/commands/lsp.py +112 -0
- praisonai_code/cli/commands/managed.py +659 -0
- praisonai_code/cli/commands/mcp.py +763 -0
- praisonai_code/cli/commands/memory.py +298 -0
- praisonai_code/cli/commands/models.py +264 -0
- praisonai_code/cli/commands/n8n.py +326 -0
- praisonai_code/cli/commands/obs.py +19 -0
- praisonai_code/cli/commands/package.py +76 -0
- praisonai_code/cli/commands/paths.py +106 -0
- praisonai_code/cli/commands/permissions.py +272 -0
- praisonai_code/cli/commands/plugins.py +609 -0
- praisonai_code/cli/commands/port.py +530 -0
- praisonai_code/cli/commands/profile.py +466 -0
- praisonai_code/cli/commands/publish.py +193 -0
- praisonai_code/cli/commands/rag.py +913 -0
- praisonai_code/cli/commands/realtime.py +52 -0
- praisonai_code/cli/commands/recipe.py +684 -0
- praisonai_code/cli/commands/registry.py +59 -0
- praisonai_code/cli/commands/replay.py +830 -0
- praisonai_code/cli/commands/research.py +49 -0
- praisonai_code/cli/commands/retrieval.py +377 -0
- praisonai_code/cli/commands/rules.py +71 -0
- praisonai_code/cli/commands/run.py +1573 -0
- praisonai_code/cli/commands/sandbox.py +371 -0
- praisonai_code/cli/commands/schedule.py +529 -0
- praisonai_code/cli/commands/serve.py +690 -0
- praisonai_code/cli/commands/session.py +450 -0
- praisonai_code/cli/commands/setup.py +174 -0
- praisonai_code/cli/commands/skills.py +545 -0
- praisonai_code/cli/commands/standardise.py +711 -0
- praisonai_code/cli/commands/templates.py +54 -0
- praisonai_code/cli/commands/test.py +558 -0
- praisonai_code/cli/commands/todo.py +74 -0
- praisonai_code/cli/commands/tools.py +205 -0
- praisonai_code/cli/commands/traces.py +145 -0
- praisonai_code/cli/commands/tracker.py +852 -0
- praisonai_code/cli/commands/train.py +613 -0
- praisonai_code/cli/commands/ui.py +172 -0
- praisonai_code/cli/commands/up.py +354 -0
- praisonai_code/cli/commands/validate.py +291 -0
- praisonai_code/cli/commands/version.py +101 -0
- praisonai_code/cli/commands/workflow.py +97 -0
- praisonai_code/cli/config_loader.py +437 -0
- praisonai_code/cli/configuration/__init__.py +27 -0
- praisonai_code/cli/configuration/config.schema.json +57 -0
- praisonai_code/cli/configuration/credentials.py +446 -0
- praisonai_code/cli/configuration/loader.py +364 -0
- praisonai_code/cli/configuration/model_resolver.py +161 -0
- praisonai_code/cli/configuration/oauth.py +389 -0
- praisonai_code/cli/configuration/paths.py +224 -0
- praisonai_code/cli/configuration/resolver.py +687 -0
- praisonai_code/cli/configuration/schema.py +317 -0
- praisonai_code/cli/execution/__init__.py +99 -0
- praisonai_code/cli/execution/core.py +208 -0
- praisonai_code/cli/execution/profiler.py +898 -0
- praisonai_code/cli/execution/request.py +85 -0
- praisonai_code/cli/execution/result.py +74 -0
- praisonai_code/cli/fallback_schema.py +416 -0
- praisonai_code/cli/features/__init__.py +278 -0
- praisonai_code/cli/features/_endpoint_registry.py +64 -0
- praisonai_code/cli/features/_search_registry.py +43 -0
- praisonai_code/cli/features/acp.py +236 -0
- praisonai_code/cli/features/action_orchestrator.py +576 -0
- praisonai_code/cli/features/agent_scheduler.py +773 -0
- praisonai_code/cli/features/agent_tools.py +603 -0
- praisonai_code/cli/features/agents.py +397 -0
- praisonai_code/cli/features/at_mentions.py +471 -0
- praisonai_code/cli/features/audit_cli.py +270 -0
- praisonai_code/cli/features/auto_memory.py +182 -0
- praisonai_code/cli/features/auto_mode.py +552 -0
- praisonai_code/cli/features/autonomy_mode.py +546 -0
- praisonai_code/cli/features/background.py +356 -0
- praisonai_code/cli/features/base.py +168 -0
- praisonai_code/cli/features/benchmark.py +1462 -0
- praisonai_code/cli/features/capabilities.py +1326 -0
- praisonai_code/cli/features/checkpoints.py +345 -0
- praisonai_code/cli/features/cli_profiler.py +335 -0
- praisonai_code/cli/features/code_intelligence.py +666 -0
- praisonai_code/cli/features/compaction.py +294 -0
- praisonai_code/cli/features/compare.py +534 -0
- praisonai_code/cli/features/config_hierarchy.py +366 -0
- praisonai_code/cli/features/context_manager.py +597 -0
- praisonai_code/cli/features/cost_tracker.py +514 -0
- praisonai_code/cli/features/csv_test_runner.py +736 -0
- praisonai_code/cli/features/custom_definitions.py +790 -0
- praisonai_code/cli/features/debug.py +810 -0
- praisonai_code/cli/features/deploy.py +605 -0
- praisonai_code/cli/features/diag.py +289 -0
- praisonai_code/cli/features/display_jsonl.py +173 -0
- praisonai_code/cli/features/doctor/__init__.py +63 -0
- praisonai_code/cli/features/doctor/checks/__init__.py +29 -0
- praisonai_code/cli/features/doctor/checks/acp_checks.py +220 -0
- praisonai_code/cli/features/doctor/checks/bot_checks.py +340 -0
- praisonai_code/cli/features/doctor/checks/config_checks.py +373 -0
- praisonai_code/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai_code/cli/features/doctor/checks/env_checks.py +637 -0
- praisonai_code/cli/features/doctor/checks/gateway_checks.py +387 -0
- praisonai_code/cli/features/doctor/checks/lsp_checks.py +231 -0
- praisonai_code/cli/features/doctor/checks/mcp_checks.py +367 -0
- praisonai_code/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai_code/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai_code/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai_code/cli/features/doctor/checks/packaging_checks.py +422 -0
- praisonai_code/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai_code/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai_code/cli/features/doctor/checks/runtime_checks.py +650 -0
- praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +220 -0
- praisonai_code/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai_code/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai_code/cli/features/doctor/checks/skills_checks.py +327 -0
- praisonai_code/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai_code/cli/features/doctor/engine.py +266 -0
- praisonai_code/cli/features/doctor/formatters.py +377 -0
- praisonai_code/cli/features/doctor/handler.py +564 -0
- praisonai_code/cli/features/doctor/models.py +276 -0
- praisonai_code/cli/features/doctor/registry.py +239 -0
- praisonai_code/cli/features/endpoints.py +1016 -0
- praisonai_code/cli/features/eval.py +559 -0
- praisonai_code/cli/features/examples.py +707 -0
- praisonai_code/cli/features/external_agents.py +231 -0
- praisonai_code/cli/features/fast_context.py +410 -0
- praisonai_code/cli/features/file_history.py +320 -0
- praisonai_code/cli/features/flow_display.py +566 -0
- praisonai_code/cli/features/git_attribution.py +159 -0
- praisonai_code/cli/features/git_integration.py +651 -0
- praisonai_code/cli/features/guardrail.py +171 -0
- praisonai_code/cli/features/handoff.py +252 -0
- praisonai_code/cli/features/hooks.py +583 -0
- praisonai_code/cli/features/hybrid_workflow.py +391 -0
- praisonai_code/cli/features/image.py +384 -0
- praisonai_code/cli/features/interactive_core_headless.py +450 -0
- praisonai_code/cli/features/interactive_runtime.py +600 -0
- praisonai_code/cli/features/interactive_test_harness.py +537 -0
- praisonai_code/cli/features/interactive_tools.py +428 -0
- praisonai_code/cli/features/interactive_tui.py +603 -0
- praisonai_code/cli/features/job_workflow.py +906 -0
- praisonai_code/cli/features/jobs.py +632 -0
- praisonai_code/cli/features/knowledge.py +531 -0
- praisonai_code/cli/features/knowledge_cli.py +438 -0
- praisonai_code/cli/features/lite.py +244 -0
- praisonai_code/cli/features/logs.py +200 -0
- praisonai_code/cli/features/lsp_cli.py +225 -0
- praisonai_code/cli/features/lsp_diagnostics.py +185 -0
- praisonai_code/cli/features/mcp.py +344 -0
- praisonai_code/cli/features/message_queue.py +587 -0
- praisonai_code/cli/features/metrics.py +210 -0
- praisonai_code/cli/features/migrate.py +1329 -0
- praisonai_code/cli/features/migration_flow.py +463 -0
- praisonai_code/cli/features/migration_spec.py +276 -0
- praisonai_code/cli/features/n8n.py +703 -0
- praisonai_code/cli/features/observability.py +293 -0
- praisonai_code/cli/features/ollama.py +361 -0
- praisonai_code/cli/features/output_modes.py +155 -0
- praisonai_code/cli/features/output_style.py +273 -0
- praisonai_code/cli/features/package.py +631 -0
- praisonai_code/cli/features/performance.py +308 -0
- praisonai_code/cli/features/persistence.py +636 -0
- praisonai_code/cli/features/profiler/__init__.py +81 -0
- praisonai_code/cli/features/profiler/core.py +558 -0
- praisonai_code/cli/features/profiler/optimizations.py +652 -0
- praisonai_code/cli/features/profiler/suite.py +386 -0
- praisonai_code/cli/features/queue/__init__.py +73 -0
- praisonai_code/cli/features/queue/manager.py +435 -0
- praisonai_code/cli/features/queue/models.py +289 -0
- praisonai_code/cli/features/queue/persistence.py +564 -0
- praisonai_code/cli/features/queue/scheduler.py +529 -0
- praisonai_code/cli/features/queue/worker.py +400 -0
- praisonai_code/cli/features/recipe.py +2187 -0
- praisonai_code/cli/features/recipe_creator.py +996 -0
- praisonai_code/cli/features/recipe_optimizer.py +1364 -0
- praisonai_code/cli/features/recipe_prompts.py +226 -0
- praisonai_code/cli/features/registry.py +229 -0
- praisonai_code/cli/features/repo_map.py +860 -0
- praisonai_code/cli/features/router.py +466 -0
- praisonai_code/cli/features/safe_shell.py +427 -0
- praisonai_code/cli/features/sandbox_cli.py +283 -0
- praisonai_code/cli/features/sandbox_executor.py +536 -0
- praisonai_code/cli/features/sdk_knowledge.py +500 -0
- praisonai_code/cli/features/session.py +222 -0
- praisonai_code/cli/features/session_checkpoints.py +208 -0
- praisonai_code/cli/features/setup/__init__.py +9 -0
- praisonai_code/cli/features/setup/handler.py +355 -0
- praisonai_code/cli/features/setup/templates.py +62 -0
- praisonai_code/cli/features/skills.py +940 -0
- praisonai_code/cli/features/slash_commands.py +692 -0
- praisonai_code/cli/features/telemetry.py +179 -0
- praisonai_code/cli/features/templates.py +1390 -0
- praisonai_code/cli/features/thinking.py +343 -0
- praisonai_code/cli/features/todo.py +334 -0
- praisonai_code/cli/features/tools.py +680 -0
- praisonai_code/cli/features/tui/__init__.py +83 -0
- praisonai_code/cli/features/tui/app.py +871 -0
- praisonai_code/cli/features/tui/cli.py +580 -0
- praisonai_code/cli/features/tui/config.py +150 -0
- praisonai_code/cli/features/tui/debug.py +526 -0
- praisonai_code/cli/features/tui/events.py +99 -0
- praisonai_code/cli/features/tui/mock_provider.py +328 -0
- praisonai_code/cli/features/tui/orchestrator.py +652 -0
- praisonai_code/cli/features/tui/screens/__init__.py +50 -0
- praisonai_code/cli/features/tui/screens/help.py +157 -0
- praisonai_code/cli/features/tui/screens/main.py +568 -0
- praisonai_code/cli/features/tui/screens/queue.py +174 -0
- praisonai_code/cli/features/tui/screens/session.py +124 -0
- praisonai_code/cli/features/tui/screens/settings.py +148 -0
- praisonai_code/cli/features/tui/session_store.py +198 -0
- praisonai_code/cli/features/tui/widgets/__init__.py +56 -0
- praisonai_code/cli/features/tui/widgets/chat.py +263 -0
- praisonai_code/cli/features/tui/widgets/command_popup.py +258 -0
- praisonai_code/cli/features/tui/widgets/composer.py +292 -0
- praisonai_code/cli/features/tui/widgets/file_popup.py +207 -0
- praisonai_code/cli/features/tui/widgets/queue_panel.py +223 -0
- praisonai_code/cli/features/tui/widgets/status.py +181 -0
- praisonai_code/cli/features/tui/widgets/tool_panel.py +307 -0
- praisonai_code/cli/features/wizard.py +289 -0
- praisonai_code/cli/features/workflow.py +802 -0
- praisonai_code/cli/features/yaml_utils.py +321 -0
- praisonai_code/cli/interactive/__init__.py +48 -0
- praisonai_code/cli/interactive/async_tui.py +1218 -0
- praisonai_code/cli/interactive/config.py +139 -0
- praisonai_code/cli/interactive/core.py +618 -0
- praisonai_code/cli/interactive/events.py +131 -0
- praisonai_code/cli/interactive/frontends/__init__.py +31 -0
- praisonai_code/cli/interactive/frontends/rich_frontend.py +462 -0
- praisonai_code/cli/interactive/frontends/textual_frontend.py +157 -0
- praisonai_code/cli/interactive/praison_io.py +502 -0
- praisonai_code/cli/interactive/repl.py +297 -0
- praisonai_code/cli/interactive/split_tui.py +456 -0
- praisonai_code/cli/interactive/tui_app.py +457 -0
- praisonai_code/cli/langfuse_client.py +360 -0
- praisonai_code/cli/main.py +7421 -0
- praisonai_code/cli/output/__init__.py +25 -0
- praisonai_code/cli/output/console.py +456 -0
- praisonai_code/cli/output/event_bridge.py +191 -0
- praisonai_code/cli/schedule_cli.py +54 -0
- praisonai_code/cli/schema_provider.py +23 -0
- praisonai_code/cli/session/__init__.py +16 -0
- praisonai_code/cli/session/resume.py +148 -0
- praisonai_code/cli/session/unified.py +548 -0
- praisonai_code/cli/state/__init__.py +31 -0
- praisonai_code/cli/state/identifiers.py +161 -0
- praisonai_code/cli/state/project_sessions.py +383 -0
- praisonai_code/cli/state/sessions.py +390 -0
- praisonai_code/cli/ui/__init__.py +160 -0
- praisonai_code/cli/ui/config.py +46 -0
- praisonai_code/cli/ui/events.py +61 -0
- praisonai_code/cli/ui/mg_backend.py +342 -0
- praisonai_code/cli/ui/plain.py +133 -0
- praisonai_code/cli/ui/rich_backend.py +162 -0
- praisonai_code/cli/unified_schema.py +655 -0
- praisonai_code/cli/utils/env_utils.py +126 -0
- praisonai_code/cli/utils/project.py +131 -0
- praisonai_code/cli_backends/__init__.py +73 -0
- praisonai_code/cli_backends/claude.py +373 -0
- praisonai_code/cli_backends/registry.py +113 -0
- praisonai_code/runtime/__init__.py +36 -0
- praisonai_code/runtime/__main__.py +81 -0
- praisonai_code/runtime/client.py +131 -0
- praisonai_code/runtime/descriptor.py +209 -0
- praisonai_code/runtime/server.py +356 -0
- praisonai_code-0.0.1.dist-info/METADATA +80 -0
- praisonai_code-0.0.1.dist-info/RECORD +309 -0
- praisonai_code-0.0.1.dist-info/WHEEL +5 -0
- praisonai_code-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Gateway-specific doctor checks for PraisonAI.
|
|
3
|
+
|
|
4
|
+
Validates gateway/bot configuration, performs migrations, and checks security.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import time
|
|
11
|
+
from typing import List, Optional
|
|
12
|
+
|
|
13
|
+
from ..models import CheckResult, CheckStatus, CheckCategory, CheckSeverity, DoctorConfig
|
|
14
|
+
from ..registry import register_check
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@register_check(
|
|
18
|
+
id="gateway_config_validation",
|
|
19
|
+
title="Gateway Config Validation",
|
|
20
|
+
description="Validate gateway/bot configuration files",
|
|
21
|
+
category=CheckCategory.BOTS,
|
|
22
|
+
severity=CheckSeverity.HIGH,
|
|
23
|
+
)
|
|
24
|
+
def check_gateway_config_validation(config: DoctorConfig) -> CheckResult:
|
|
25
|
+
"""Validate gateway/bot configuration using canonical schema."""
|
|
26
|
+
start = time.time()
|
|
27
|
+
|
|
28
|
+
# Check multiple possible config locations
|
|
29
|
+
config_paths = []
|
|
30
|
+
if hasattr(config, 'config_file') and config.config_file:
|
|
31
|
+
config_paths.append(config.config_file)
|
|
32
|
+
|
|
33
|
+
# Check common locations
|
|
34
|
+
from praisonai.cli._paths import resolve_bot_config_path
|
|
35
|
+
config_paths.extend([
|
|
36
|
+
resolve_bot_config_path("gateway.yaml"),
|
|
37
|
+
resolve_bot_config_path("bot.yaml"),
|
|
38
|
+
"gateway.yaml",
|
|
39
|
+
"bot.yaml",
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
# Find first existing config
|
|
43
|
+
config_path = None
|
|
44
|
+
for path in config_paths:
|
|
45
|
+
if os.path.exists(path):
|
|
46
|
+
config_path = path
|
|
47
|
+
break
|
|
48
|
+
|
|
49
|
+
if not config_path:
|
|
50
|
+
return CheckResult(
|
|
51
|
+
id="gateway_config_validation",
|
|
52
|
+
title="Gateway Config Validation",
|
|
53
|
+
category=CheckCategory.BOTS,
|
|
54
|
+
status=CheckStatus.WARN,
|
|
55
|
+
message="No gateway/bot config found",
|
|
56
|
+
remediation="Run 'praisonai onboard' to create bot.yaml",
|
|
57
|
+
duration_ms=(time.time() - start) * 1000,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
from praisonai.bots._config_schema import load_and_validate_gateway_yaml
|
|
62
|
+
validated_config = load_and_validate_gateway_yaml(config_path)
|
|
63
|
+
|
|
64
|
+
channel_count = len(validated_config.channels)
|
|
65
|
+
agent_count = 1 if validated_config.agent else 0
|
|
66
|
+
if validated_config.agents:
|
|
67
|
+
agent_count = len(validated_config.agents)
|
|
68
|
+
|
|
69
|
+
return CheckResult(
|
|
70
|
+
id="gateway_config_validation",
|
|
71
|
+
title="Gateway Config Validation",
|
|
72
|
+
category=CheckCategory.BOTS,
|
|
73
|
+
status=CheckStatus.PASS,
|
|
74
|
+
message=f"{config_path} valid ({channel_count} channels, {agent_count} agents)",
|
|
75
|
+
duration_ms=(time.time() - start) * 1000,
|
|
76
|
+
)
|
|
77
|
+
except ValueError as e:
|
|
78
|
+
return CheckResult(
|
|
79
|
+
id="gateway_config_validation",
|
|
80
|
+
title="Gateway Config Validation",
|
|
81
|
+
category=CheckCategory.BOTS,
|
|
82
|
+
status=CheckStatus.FAIL,
|
|
83
|
+
message=f"Invalid config: {str(e)[:100]}",
|
|
84
|
+
details=str(e),
|
|
85
|
+
remediation="Fix validation errors in your config file",
|
|
86
|
+
duration_ms=(time.time() - start) * 1000,
|
|
87
|
+
)
|
|
88
|
+
except Exception as e:
|
|
89
|
+
return CheckResult(
|
|
90
|
+
id="gateway_config_validation",
|
|
91
|
+
title="Gateway Config Validation",
|
|
92
|
+
category=CheckCategory.BOTS,
|
|
93
|
+
status=CheckStatus.ERROR,
|
|
94
|
+
message=f"Error validating config: {str(e)[:100]}",
|
|
95
|
+
remediation="Check config file syntax",
|
|
96
|
+
duration_ms=(time.time() - start) * 1000,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@register_check(
|
|
101
|
+
id="gateway_security",
|
|
102
|
+
title="Gateway Security Settings",
|
|
103
|
+
description="Check gateway security configuration",
|
|
104
|
+
category=CheckCategory.BOTS,
|
|
105
|
+
severity=CheckSeverity.HIGH,
|
|
106
|
+
)
|
|
107
|
+
def check_gateway_security(config: DoctorConfig) -> CheckResult:
|
|
108
|
+
"""Check gateway security settings for safe defaults."""
|
|
109
|
+
start = time.time()
|
|
110
|
+
|
|
111
|
+
# Find config file
|
|
112
|
+
from praisonai.cli._paths import resolve_bot_config_path
|
|
113
|
+
config_path = None
|
|
114
|
+
for path in [resolve_bot_config_path("gateway.yaml"), resolve_bot_config_path("bot.yaml"), "gateway.yaml", "bot.yaml"]:
|
|
115
|
+
if os.path.exists(path):
|
|
116
|
+
config_path = path
|
|
117
|
+
break
|
|
118
|
+
|
|
119
|
+
if not config_path:
|
|
120
|
+
return CheckResult(
|
|
121
|
+
id="gateway_security",
|
|
122
|
+
title="Gateway Security Settings",
|
|
123
|
+
category=CheckCategory.BOTS,
|
|
124
|
+
status=CheckStatus.SKIP,
|
|
125
|
+
message="No config found - security check skipped",
|
|
126
|
+
duration_ms=(time.time() - start) * 1000,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
from praisonai.bots._config_schema import load_and_validate_gateway_yaml
|
|
131
|
+
validated_config = load_and_validate_gateway_yaml(config_path)
|
|
132
|
+
|
|
133
|
+
security_issues = []
|
|
134
|
+
warnings = []
|
|
135
|
+
|
|
136
|
+
for channel_name, channel in validated_config.channels.items():
|
|
137
|
+
# Check for open allowlists (CRITICAL)
|
|
138
|
+
if not channel.allowed_users and not channel.allowlist and not channel.blocklist:
|
|
139
|
+
security_issues.append(
|
|
140
|
+
f"{channel_name}: No user restrictions - bot responds to EVERYONE!"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Check for overly permissive group policies (WARNING)
|
|
144
|
+
if channel.group_policy == "respond_all":
|
|
145
|
+
warnings.append(
|
|
146
|
+
f"{channel_name}: Using 'respond_all' - consider 'mention_only'"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Check for missing tokens
|
|
150
|
+
if not channel.token:
|
|
151
|
+
security_issues.append(
|
|
152
|
+
f"{channel_name}: No token configured"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
# Check gateway auth token
|
|
156
|
+
if not os.environ.get("GATEWAY_AUTH_TOKEN"):
|
|
157
|
+
warnings.append("GATEWAY_AUTH_TOKEN not set - gateway has no authentication")
|
|
158
|
+
|
|
159
|
+
if security_issues:
|
|
160
|
+
return CheckResult(
|
|
161
|
+
id="gateway_security",
|
|
162
|
+
title="Gateway Security Settings",
|
|
163
|
+
category=CheckCategory.BOTS,
|
|
164
|
+
status=CheckStatus.FAIL,
|
|
165
|
+
message=f"Critical security issues: {len(security_issues)} problem(s)",
|
|
166
|
+
details="\n".join(security_issues + warnings),
|
|
167
|
+
remediation="Add allowed_users to restrict bot access. Use 'mention_only' for groups.",
|
|
168
|
+
duration_ms=(time.time() - start) * 1000,
|
|
169
|
+
)
|
|
170
|
+
elif warnings:
|
|
171
|
+
return CheckResult(
|
|
172
|
+
id="gateway_security",
|
|
173
|
+
title="Gateway Security Settings",
|
|
174
|
+
category=CheckCategory.BOTS,
|
|
175
|
+
status=CheckStatus.WARN,
|
|
176
|
+
message=f"Security recommendations: {len(warnings)} improvement(s)",
|
|
177
|
+
details="\n".join(warnings),
|
|
178
|
+
remediation="Consider stricter security settings",
|
|
179
|
+
duration_ms=(time.time() - start) * 1000,
|
|
180
|
+
)
|
|
181
|
+
else:
|
|
182
|
+
return CheckResult(
|
|
183
|
+
id="gateway_security",
|
|
184
|
+
title="Gateway Security Settings",
|
|
185
|
+
category=CheckCategory.BOTS,
|
|
186
|
+
status=CheckStatus.PASS,
|
|
187
|
+
message="Security configuration looks good",
|
|
188
|
+
duration_ms=(time.time() - start) * 1000,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
except Exception as e:
|
|
192
|
+
return CheckResult(
|
|
193
|
+
id="gateway_security",
|
|
194
|
+
title="Gateway Security Settings",
|
|
195
|
+
category=CheckCategory.BOTS,
|
|
196
|
+
status=CheckStatus.ERROR,
|
|
197
|
+
message=f"Error checking security: {str(e)[:100]}",
|
|
198
|
+
remediation="Fix config errors first",
|
|
199
|
+
duration_ms=(time.time() - start) * 1000,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@register_check(
|
|
204
|
+
id="gateway_config_migration",
|
|
205
|
+
title="Gateway Config Migration",
|
|
206
|
+
description="Check if config needs migration to canonical format",
|
|
207
|
+
category=CheckCategory.BOTS,
|
|
208
|
+
severity=CheckSeverity.MEDIUM,
|
|
209
|
+
)
|
|
210
|
+
def check_gateway_config_migration(config: DoctorConfig) -> CheckResult:
|
|
211
|
+
"""Check if configuration needs migration to canonical format."""
|
|
212
|
+
start = time.time()
|
|
213
|
+
|
|
214
|
+
# Find config file
|
|
215
|
+
from praisonai.cli._paths import resolve_bot_config_path
|
|
216
|
+
config_path = None
|
|
217
|
+
for path in [resolve_bot_config_path("gateway.yaml"), resolve_bot_config_path("bot.yaml"), "gateway.yaml", "bot.yaml"]:
|
|
218
|
+
if os.path.exists(path):
|
|
219
|
+
config_path = path
|
|
220
|
+
break
|
|
221
|
+
|
|
222
|
+
if not config_path:
|
|
223
|
+
return CheckResult(
|
|
224
|
+
id="gateway_config_migration",
|
|
225
|
+
title="Gateway Config Migration",
|
|
226
|
+
category=CheckCategory.BOTS,
|
|
227
|
+
status=CheckStatus.SKIP,
|
|
228
|
+
message="No config found - migration check skipped",
|
|
229
|
+
duration_ms=(time.time() - start) * 1000,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
try:
|
|
233
|
+
import yaml
|
|
234
|
+
import copy
|
|
235
|
+
with open(config_path) as f:
|
|
236
|
+
raw = yaml.safe_load(f) or {}
|
|
237
|
+
|
|
238
|
+
# Deep copy to preserve original for comparison
|
|
239
|
+
original = copy.deepcopy(raw)
|
|
240
|
+
|
|
241
|
+
from praisonai.bots._config_schema import migrate_legacy_config
|
|
242
|
+
migrated = migrate_legacy_config(copy.deepcopy(original))
|
|
243
|
+
|
|
244
|
+
# Check if migration changed anything
|
|
245
|
+
if migrated != original:
|
|
246
|
+
changes = []
|
|
247
|
+
|
|
248
|
+
# Detect specific migrations
|
|
249
|
+
if "platform" in raw and "token" in raw and "channels" not in raw:
|
|
250
|
+
changes.append("Single-bot format can be migrated to multi-channel format")
|
|
251
|
+
|
|
252
|
+
if "platforms" in raw and "channels" not in raw:
|
|
253
|
+
changes.append("BotOS platforms format can be migrated to channels format")
|
|
254
|
+
|
|
255
|
+
# Check for string allowed_users
|
|
256
|
+
if "channels" in raw:
|
|
257
|
+
for channel_name, channel in raw["channels"].items():
|
|
258
|
+
if isinstance(channel.get("allowed_users"), str):
|
|
259
|
+
changes.append(f"{channel_name}: allowed_users string → list migration available")
|
|
260
|
+
|
|
261
|
+
return CheckResult(
|
|
262
|
+
id="gateway_config_migration",
|
|
263
|
+
title="Gateway Config Migration",
|
|
264
|
+
category=CheckCategory.BOTS,
|
|
265
|
+
status=CheckStatus.WARN,
|
|
266
|
+
message=f"Config can be migrated: {len(changes)} change(s)",
|
|
267
|
+
details="\n".join(changes),
|
|
268
|
+
remediation="Run 'praisonai gateway migrate' to update config to latest format",
|
|
269
|
+
duration_ms=(time.time() - start) * 1000,
|
|
270
|
+
)
|
|
271
|
+
else:
|
|
272
|
+
return CheckResult(
|
|
273
|
+
id="gateway_config_migration",
|
|
274
|
+
title="Gateway Config Migration",
|
|
275
|
+
category=CheckCategory.BOTS,
|
|
276
|
+
status=CheckStatus.PASS,
|
|
277
|
+
message="Config uses current format",
|
|
278
|
+
duration_ms=(time.time() - start) * 1000,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
except Exception as e:
|
|
282
|
+
return CheckResult(
|
|
283
|
+
id="gateway_config_migration",
|
|
284
|
+
title="Gateway Config Migration",
|
|
285
|
+
category=CheckCategory.BOTS,
|
|
286
|
+
status=CheckStatus.ERROR,
|
|
287
|
+
message=f"Error checking migration: {str(e)[:100]}",
|
|
288
|
+
remediation="Fix config syntax errors first",
|
|
289
|
+
duration_ms=(time.time() - start) * 1000,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
@register_check(
|
|
294
|
+
id="gateway_env_substitution",
|
|
295
|
+
title="Gateway Environment Variables",
|
|
296
|
+
description="Check environment variable substitution in config",
|
|
297
|
+
category=CheckCategory.BOTS,
|
|
298
|
+
severity=CheckSeverity.MEDIUM,
|
|
299
|
+
)
|
|
300
|
+
def check_gateway_env_substitution(config: DoctorConfig) -> CheckResult:
|
|
301
|
+
"""Check that environment variables referenced in config are set."""
|
|
302
|
+
start = time.time()
|
|
303
|
+
|
|
304
|
+
# Find config file
|
|
305
|
+
from praisonai.cli._paths import resolve_bot_config_path
|
|
306
|
+
config_path = None
|
|
307
|
+
for path in [resolve_bot_config_path("gateway.yaml"), resolve_bot_config_path("bot.yaml"), "gateway.yaml", "bot.yaml"]:
|
|
308
|
+
if os.path.exists(path):
|
|
309
|
+
config_path = path
|
|
310
|
+
break
|
|
311
|
+
|
|
312
|
+
if not config_path:
|
|
313
|
+
return CheckResult(
|
|
314
|
+
id="gateway_env_substitution",
|
|
315
|
+
title="Gateway Environment Variables",
|
|
316
|
+
category=CheckCategory.BOTS,
|
|
317
|
+
status=CheckStatus.SKIP,
|
|
318
|
+
message="No config found - env check skipped",
|
|
319
|
+
duration_ms=(time.time() - start) * 1000,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
try:
|
|
323
|
+
import re
|
|
324
|
+
from praisonai.cli.utils.env_utils import load_env_file
|
|
325
|
+
|
|
326
|
+
# Load .env file first to ensure all env vars are available
|
|
327
|
+
try:
|
|
328
|
+
load_env_file()
|
|
329
|
+
except:
|
|
330
|
+
pass # .env file might not exist, continue anyway
|
|
331
|
+
|
|
332
|
+
with open(config_path) as f:
|
|
333
|
+
content = f.read()
|
|
334
|
+
|
|
335
|
+
# Find all ${VAR} references
|
|
336
|
+
env_refs = re.findall(r'\$\{([^}]+)\}', content)
|
|
337
|
+
|
|
338
|
+
if not env_refs:
|
|
339
|
+
return CheckResult(
|
|
340
|
+
id="gateway_env_substitution",
|
|
341
|
+
title="Gateway Environment Variables",
|
|
342
|
+
category=CheckCategory.BOTS,
|
|
343
|
+
status=CheckStatus.PASS,
|
|
344
|
+
message="No environment variables referenced",
|
|
345
|
+
duration_ms=(time.time() - start) * 1000,
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
# Check which are set
|
|
349
|
+
missing = []
|
|
350
|
+
found = []
|
|
351
|
+
for env_var in sorted(set(env_refs)):
|
|
352
|
+
if env_var in os.environ:
|
|
353
|
+
found.append(env_var)
|
|
354
|
+
else:
|
|
355
|
+
missing.append(env_var)
|
|
356
|
+
|
|
357
|
+
if missing:
|
|
358
|
+
return CheckResult(
|
|
359
|
+
id="gateway_env_substitution",
|
|
360
|
+
title="Gateway Environment Variables",
|
|
361
|
+
category=CheckCategory.BOTS,
|
|
362
|
+
status=CheckStatus.FAIL,
|
|
363
|
+
message=f"Missing environment variables: {len(missing)}",
|
|
364
|
+
details=f"Not set: {', '.join(missing)}",
|
|
365
|
+
remediation=f"Set missing variables: {' '.join(f'export {v}=...' for v in missing)}",
|
|
366
|
+
duration_ms=(time.time() - start) * 1000,
|
|
367
|
+
)
|
|
368
|
+
else:
|
|
369
|
+
return CheckResult(
|
|
370
|
+
id="gateway_env_substitution",
|
|
371
|
+
title="Gateway Environment Variables",
|
|
372
|
+
category=CheckCategory.BOTS,
|
|
373
|
+
status=CheckStatus.PASS,
|
|
374
|
+
message=f"All {len(found)} environment variables are set",
|
|
375
|
+
duration_ms=(time.time() - start) * 1000,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
except Exception as e:
|
|
379
|
+
return CheckResult(
|
|
380
|
+
id="gateway_env_substitution",
|
|
381
|
+
title="Gateway Environment Variables",
|
|
382
|
+
category=CheckCategory.BOTS,
|
|
383
|
+
status=CheckStatus.ERROR,
|
|
384
|
+
message=f"Error checking env vars: {str(e)[:100]}",
|
|
385
|
+
remediation="Check config file access",
|
|
386
|
+
duration_ms=(time.time() - start) * 1000,
|
|
387
|
+
)
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LSP health checks for PraisonAI Doctor.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
import shutil
|
|
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="lsp_module",
|
|
17
|
+
title="LSP Module Available",
|
|
18
|
+
category=CheckCategory.TOOLS,
|
|
19
|
+
description="Check if LSP module is installed"
|
|
20
|
+
)
|
|
21
|
+
def check_lsp_module(config=None) -> CheckResult:
|
|
22
|
+
"""Check if LSP module is available."""
|
|
23
|
+
try:
|
|
24
|
+
import importlib.util
|
|
25
|
+
spec = importlib.util.find_spec("praisonaiagents.lsp")
|
|
26
|
+
|
|
27
|
+
if spec is not None:
|
|
28
|
+
return CheckResult(
|
|
29
|
+
id="lsp_module",
|
|
30
|
+
title="LSP Module Available",
|
|
31
|
+
category=CheckCategory.TOOLS,
|
|
32
|
+
status=CheckStatus.PASS,
|
|
33
|
+
message="LSP module is available",
|
|
34
|
+
metadata={"module": "praisonaiagents.lsp"}
|
|
35
|
+
)
|
|
36
|
+
else:
|
|
37
|
+
return CheckResult(
|
|
38
|
+
id="lsp_module",
|
|
39
|
+
title="LSP Module Available",
|
|
40
|
+
category=CheckCategory.TOOLS,
|
|
41
|
+
status=CheckStatus.WARN,
|
|
42
|
+
message="LSP module not found",
|
|
43
|
+
remediation="Install praisonaiagents with LSP support"
|
|
44
|
+
)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
return CheckResult(
|
|
47
|
+
id="lsp_module",
|
|
48
|
+
title="LSP Module Available",
|
|
49
|
+
category=CheckCategory.TOOLS,
|
|
50
|
+
status=CheckStatus.FAIL,
|
|
51
|
+
message=f"Error checking LSP module: {e}",
|
|
52
|
+
metadata={"error": str(e)}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@register_check(
|
|
57
|
+
id="lsp_client",
|
|
58
|
+
title="LSP Client Import",
|
|
59
|
+
category=CheckCategory.TOOLS,
|
|
60
|
+
description="Check if LSP client can be imported"
|
|
61
|
+
)
|
|
62
|
+
def check_lsp_client(config=None) -> CheckResult:
|
|
63
|
+
"""Check if LSP client can be imported."""
|
|
64
|
+
try:
|
|
65
|
+
from praisonaiagents.lsp import LSPClient # noqa: F401
|
|
66
|
+
|
|
67
|
+
return CheckResult(
|
|
68
|
+
id="lsp_client",
|
|
69
|
+
title="LSP Client Import",
|
|
70
|
+
category=CheckCategory.TOOLS,
|
|
71
|
+
status=CheckStatus.PASS,
|
|
72
|
+
message="LSP client can be imported",
|
|
73
|
+
metadata={"class": "LSPClient"}
|
|
74
|
+
)
|
|
75
|
+
except ImportError as e:
|
|
76
|
+
return CheckResult(
|
|
77
|
+
id="lsp_client",
|
|
78
|
+
title="LSP Client Import",
|
|
79
|
+
category=CheckCategory.TOOLS,
|
|
80
|
+
status=CheckStatus.WARN,
|
|
81
|
+
message=f"LSP client import failed: {e}",
|
|
82
|
+
metadata={"error": str(e)}
|
|
83
|
+
)
|
|
84
|
+
except Exception as e:
|
|
85
|
+
return CheckResult(
|
|
86
|
+
id="lsp_client",
|
|
87
|
+
title="LSP Client Import",
|
|
88
|
+
category=CheckCategory.TOOLS,
|
|
89
|
+
status=CheckStatus.FAIL,
|
|
90
|
+
message=f"Error importing LSP client: {e}",
|
|
91
|
+
metadata={"error": str(e)}
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@register_check(
|
|
96
|
+
id="lsp_server_python",
|
|
97
|
+
title="Python LSP Server",
|
|
98
|
+
category=CheckCategory.TOOLS,
|
|
99
|
+
description="Check if Python language server is available"
|
|
100
|
+
)
|
|
101
|
+
def check_lsp_server_python(config=None) -> CheckResult:
|
|
102
|
+
"""Check if Python language server is available."""
|
|
103
|
+
servers = [
|
|
104
|
+
("pyright-langserver", "pyright"),
|
|
105
|
+
("pylsp", "python-lsp-server"),
|
|
106
|
+
("pyls", "python-language-server"),
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
found = []
|
|
110
|
+
for cmd, package in servers:
|
|
111
|
+
if shutil.which(cmd):
|
|
112
|
+
found.append({"command": cmd, "package": package})
|
|
113
|
+
|
|
114
|
+
if found:
|
|
115
|
+
return CheckResult(
|
|
116
|
+
id="lsp_server_python",
|
|
117
|
+
title="Python LSP Server",
|
|
118
|
+
category=CheckCategory.TOOLS,
|
|
119
|
+
status=CheckStatus.PASS,
|
|
120
|
+
message=f"Python LSP server available: {found[0]['command']}",
|
|
121
|
+
metadata={"servers": found}
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
return CheckResult(
|
|
125
|
+
id="lsp_server_python",
|
|
126
|
+
title="Python LSP Server",
|
|
127
|
+
category=CheckCategory.TOOLS,
|
|
128
|
+
status=CheckStatus.WARN,
|
|
129
|
+
message="No Python LSP server found",
|
|
130
|
+
remediation="Install with: npm install -g pyright OR pip install python-lsp-server"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@register_check(
|
|
135
|
+
id="lsp_server_typescript",
|
|
136
|
+
title="TypeScript LSP Server",
|
|
137
|
+
category=CheckCategory.TOOLS,
|
|
138
|
+
description="Check if TypeScript language server is available"
|
|
139
|
+
)
|
|
140
|
+
def check_lsp_server_typescript(config=None) -> CheckResult:
|
|
141
|
+
"""Check if TypeScript language server is available."""
|
|
142
|
+
if shutil.which("typescript-language-server"):
|
|
143
|
+
return CheckResult(
|
|
144
|
+
id="lsp_server_typescript",
|
|
145
|
+
title="TypeScript LSP Server",
|
|
146
|
+
category=CheckCategory.TOOLS,
|
|
147
|
+
status=CheckStatus.PASS,
|
|
148
|
+
message="TypeScript LSP server available",
|
|
149
|
+
metadata={"command": "typescript-language-server"}
|
|
150
|
+
)
|
|
151
|
+
elif shutil.which("tsserver"):
|
|
152
|
+
return CheckResult(
|
|
153
|
+
id="lsp_server_typescript",
|
|
154
|
+
title="TypeScript LSP Server",
|
|
155
|
+
category=CheckCategory.TOOLS,
|
|
156
|
+
status=CheckStatus.PASS,
|
|
157
|
+
message="TypeScript server available (tsserver)",
|
|
158
|
+
metadata={"command": "tsserver"}
|
|
159
|
+
)
|
|
160
|
+
else:
|
|
161
|
+
return CheckResult(
|
|
162
|
+
id="lsp_server_typescript",
|
|
163
|
+
title="TypeScript LSP Server",
|
|
164
|
+
category=CheckCategory.TOOLS,
|
|
165
|
+
status=CheckStatus.SKIP,
|
|
166
|
+
message="TypeScript LSP server not found (optional)",
|
|
167
|
+
remediation="Install with: npm install -g typescript-language-server typescript"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@register_check(
|
|
172
|
+
id="lsp_runtime",
|
|
173
|
+
title="LSP Runtime Check",
|
|
174
|
+
category=CheckCategory.TOOLS,
|
|
175
|
+
description="Check if LSP runtime can start",
|
|
176
|
+
requires_deep=True
|
|
177
|
+
)
|
|
178
|
+
def check_lsp_runtime(config=None) -> CheckResult:
|
|
179
|
+
"""Check if LSP runtime can start."""
|
|
180
|
+
try:
|
|
181
|
+
from praisonai.cli.features.interactive_runtime import create_runtime
|
|
182
|
+
|
|
183
|
+
async def _check():
|
|
184
|
+
runtime = create_runtime(
|
|
185
|
+
workspace=".",
|
|
186
|
+
lsp=True,
|
|
187
|
+
acp=False
|
|
188
|
+
)
|
|
189
|
+
try:
|
|
190
|
+
await runtime.start()
|
|
191
|
+
ready = runtime.lsp_ready
|
|
192
|
+
error = runtime._lsp_state.error
|
|
193
|
+
return ready, error
|
|
194
|
+
finally:
|
|
195
|
+
await runtime.stop()
|
|
196
|
+
|
|
197
|
+
ready, error = asyncio.run(_check())
|
|
198
|
+
|
|
199
|
+
if ready:
|
|
200
|
+
return CheckResult(
|
|
201
|
+
id="lsp_runtime",
|
|
202
|
+
title="LSP Runtime Check",
|
|
203
|
+
category=CheckCategory.TOOLS,
|
|
204
|
+
status=CheckStatus.PASS,
|
|
205
|
+
message="LSP runtime started successfully",
|
|
206
|
+
metadata={"ready": True}
|
|
207
|
+
)
|
|
208
|
+
else:
|
|
209
|
+
return CheckResult(
|
|
210
|
+
id="lsp_runtime",
|
|
211
|
+
title="LSP Runtime Check",
|
|
212
|
+
category=CheckCategory.TOOLS,
|
|
213
|
+
status=CheckStatus.WARN,
|
|
214
|
+
message=f"LSP runtime failed to start: {error}",
|
|
215
|
+
metadata={"ready": False, "error": str(error)}
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
except Exception as e:
|
|
219
|
+
return CheckResult(
|
|
220
|
+
id="lsp_runtime",
|
|
221
|
+
title="LSP Runtime Check",
|
|
222
|
+
category=CheckCategory.TOOLS,
|
|
223
|
+
status=CheckStatus.FAIL,
|
|
224
|
+
message=f"LSP runtime check failed: {e}",
|
|
225
|
+
metadata={"error": str(e)}
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def register_lsp_checks():
|
|
230
|
+
"""Register all LSP checks."""
|
|
231
|
+
pass
|