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,564 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Doctor CLI handler for PraisonAI.
|
|
3
|
+
|
|
4
|
+
Provides the main DoctorHandler class that integrates with the CLI.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import sys
|
|
9
|
+
from typing import List, Optional
|
|
10
|
+
|
|
11
|
+
from ..base import CommandHandler
|
|
12
|
+
from .models import CheckCategory, DoctorConfig, DoctorReport
|
|
13
|
+
from .engine import DoctorEngine
|
|
14
|
+
from .registry import get_registry
|
|
15
|
+
from .formatters import get_formatter
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DoctorHandler(CommandHandler):
|
|
19
|
+
"""
|
|
20
|
+
Handler for the 'praisonai doctor' command.
|
|
21
|
+
|
|
22
|
+
Provides comprehensive health checks and diagnostics.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def feature_name(self) -> str:
|
|
27
|
+
return "doctor"
|
|
28
|
+
|
|
29
|
+
def get_actions(self) -> List[str]:
|
|
30
|
+
return [
|
|
31
|
+
"env",
|
|
32
|
+
"config",
|
|
33
|
+
"tools",
|
|
34
|
+
"bots",
|
|
35
|
+
"db",
|
|
36
|
+
"mcp",
|
|
37
|
+
"obs",
|
|
38
|
+
"skills",
|
|
39
|
+
"memory",
|
|
40
|
+
"permissions",
|
|
41
|
+
"network",
|
|
42
|
+
"performance",
|
|
43
|
+
"packaging",
|
|
44
|
+
"runtime",
|
|
45
|
+
"ci",
|
|
46
|
+
"selftest",
|
|
47
|
+
"fix",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
def _register_checks(self) -> None:
|
|
51
|
+
"""Register all doctor checks."""
|
|
52
|
+
from .checks import register_all_checks
|
|
53
|
+
register_all_checks()
|
|
54
|
+
|
|
55
|
+
def _parse_args(self, args: List[str]) -> argparse.Namespace:
|
|
56
|
+
"""Parse doctor command arguments."""
|
|
57
|
+
parser = argparse.ArgumentParser(
|
|
58
|
+
prog="praisonai doctor",
|
|
59
|
+
description="PraisonAI health checks and diagnostics",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Subcommand
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"subcommand",
|
|
65
|
+
nargs="?",
|
|
66
|
+
choices=self.get_actions() + [None],
|
|
67
|
+
help="Subcommand to run (default: run all fast checks)",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Global flags
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--json",
|
|
73
|
+
action="store_true",
|
|
74
|
+
help="Output in JSON format",
|
|
75
|
+
)
|
|
76
|
+
parser.add_argument(
|
|
77
|
+
"--format",
|
|
78
|
+
choices=["text", "json"],
|
|
79
|
+
default="text",
|
|
80
|
+
help="Output format (default: text)",
|
|
81
|
+
)
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"--output", "-o",
|
|
84
|
+
type=str,
|
|
85
|
+
help="Write report to file",
|
|
86
|
+
)
|
|
87
|
+
parser.add_argument(
|
|
88
|
+
"--deep",
|
|
89
|
+
action="store_true",
|
|
90
|
+
help="Enable deeper probes (DB connects, network checks)",
|
|
91
|
+
)
|
|
92
|
+
parser.add_argument(
|
|
93
|
+
"--timeout",
|
|
94
|
+
type=float,
|
|
95
|
+
default=10.0,
|
|
96
|
+
help="Per-check timeout in seconds (default: 10)",
|
|
97
|
+
)
|
|
98
|
+
parser.add_argument(
|
|
99
|
+
"--strict",
|
|
100
|
+
action="store_true",
|
|
101
|
+
help="Treat warnings as failures",
|
|
102
|
+
)
|
|
103
|
+
parser.add_argument(
|
|
104
|
+
"--quiet", "-q",
|
|
105
|
+
action="store_true",
|
|
106
|
+
help="Minimal output",
|
|
107
|
+
)
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"--no-color",
|
|
110
|
+
action="store_true",
|
|
111
|
+
help="Disable ANSI colors",
|
|
112
|
+
)
|
|
113
|
+
parser.add_argument(
|
|
114
|
+
"--only",
|
|
115
|
+
type=str,
|
|
116
|
+
help="Only run these check IDs (comma-separated)",
|
|
117
|
+
)
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"--skip",
|
|
120
|
+
type=str,
|
|
121
|
+
help="Skip these check IDs (comma-separated)",
|
|
122
|
+
)
|
|
123
|
+
parser.add_argument(
|
|
124
|
+
"--list-checks",
|
|
125
|
+
action="store_true",
|
|
126
|
+
help="List available check IDs",
|
|
127
|
+
)
|
|
128
|
+
parser.add_argument(
|
|
129
|
+
"--version",
|
|
130
|
+
action="store_true",
|
|
131
|
+
help="Show doctor module version",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Subcommand-specific flags
|
|
135
|
+
parser.add_argument(
|
|
136
|
+
"--show-keys",
|
|
137
|
+
action="store_true",
|
|
138
|
+
help="Show masked API key values (env subcommand)",
|
|
139
|
+
)
|
|
140
|
+
parser.add_argument(
|
|
141
|
+
"--require",
|
|
142
|
+
type=str,
|
|
143
|
+
help="Require these env vars (comma-separated)",
|
|
144
|
+
)
|
|
145
|
+
parser.add_argument(
|
|
146
|
+
"--file", "-f",
|
|
147
|
+
type=str,
|
|
148
|
+
help="Config file to validate (config subcommand)",
|
|
149
|
+
)
|
|
150
|
+
parser.add_argument(
|
|
151
|
+
"--schema",
|
|
152
|
+
action="store_true",
|
|
153
|
+
help="Print expected schema (config subcommand)",
|
|
154
|
+
)
|
|
155
|
+
parser.add_argument(
|
|
156
|
+
"--dsn",
|
|
157
|
+
type=str,
|
|
158
|
+
help="Database DSN (db subcommand)",
|
|
159
|
+
)
|
|
160
|
+
parser.add_argument(
|
|
161
|
+
"--provider",
|
|
162
|
+
type=str,
|
|
163
|
+
help="Provider name (db/obs subcommand)",
|
|
164
|
+
)
|
|
165
|
+
parser.add_argument(
|
|
166
|
+
"--read-only",
|
|
167
|
+
action="store_true",
|
|
168
|
+
default=True,
|
|
169
|
+
help="Read-only mode for DB checks (default: true)",
|
|
170
|
+
)
|
|
171
|
+
parser.add_argument(
|
|
172
|
+
"--name",
|
|
173
|
+
type=str,
|
|
174
|
+
help="Name filter (mcp/tools subcommand)",
|
|
175
|
+
)
|
|
176
|
+
parser.add_argument(
|
|
177
|
+
"--category",
|
|
178
|
+
type=str,
|
|
179
|
+
help="Category filter (tools subcommand)",
|
|
180
|
+
)
|
|
181
|
+
parser.add_argument(
|
|
182
|
+
"--all",
|
|
183
|
+
action="store_true",
|
|
184
|
+
dest="all_checks",
|
|
185
|
+
help="Show all items (tools subcommand)",
|
|
186
|
+
)
|
|
187
|
+
parser.add_argument(
|
|
188
|
+
"--missing-only",
|
|
189
|
+
action="store_true",
|
|
190
|
+
help="Show only missing items (tools subcommand)",
|
|
191
|
+
)
|
|
192
|
+
parser.add_argument(
|
|
193
|
+
"--list-tools",
|
|
194
|
+
action="store_true",
|
|
195
|
+
help="List MCP tools (mcp subcommand)",
|
|
196
|
+
)
|
|
197
|
+
parser.add_argument(
|
|
198
|
+
"--path",
|
|
199
|
+
type=str,
|
|
200
|
+
help="Path to check (skills subcommand)",
|
|
201
|
+
)
|
|
202
|
+
parser.add_argument(
|
|
203
|
+
"--all-installed",
|
|
204
|
+
action="store_true",
|
|
205
|
+
help="Check all installed skills",
|
|
206
|
+
)
|
|
207
|
+
parser.add_argument(
|
|
208
|
+
"--budget-ms",
|
|
209
|
+
type=int,
|
|
210
|
+
help="Import time budget in ms (performance subcommand)",
|
|
211
|
+
)
|
|
212
|
+
parser.add_argument(
|
|
213
|
+
"--top",
|
|
214
|
+
type=int,
|
|
215
|
+
default=10,
|
|
216
|
+
dest="top_n",
|
|
217
|
+
help="Number of top items to show (default: 10)",
|
|
218
|
+
)
|
|
219
|
+
parser.add_argument(
|
|
220
|
+
"--fail-fast",
|
|
221
|
+
action="store_true",
|
|
222
|
+
help="Stop on first failure (ci subcommand)",
|
|
223
|
+
)
|
|
224
|
+
parser.add_argument(
|
|
225
|
+
"--mock",
|
|
226
|
+
action="store_true",
|
|
227
|
+
default=True,
|
|
228
|
+
help="Use mock mode (selftest, default: true)",
|
|
229
|
+
)
|
|
230
|
+
parser.add_argument(
|
|
231
|
+
"--live",
|
|
232
|
+
action="store_true",
|
|
233
|
+
help="Use live API calls (selftest)",
|
|
234
|
+
)
|
|
235
|
+
parser.add_argument(
|
|
236
|
+
"--model",
|
|
237
|
+
type=str,
|
|
238
|
+
help="Model to use for selftest",
|
|
239
|
+
)
|
|
240
|
+
parser.add_argument(
|
|
241
|
+
"--save-report",
|
|
242
|
+
action="store_true",
|
|
243
|
+
help="Save selftest report",
|
|
244
|
+
)
|
|
245
|
+
parser.add_argument(
|
|
246
|
+
"--team",
|
|
247
|
+
type=str,
|
|
248
|
+
help="Team YAML file to validate (runtime subcommand)",
|
|
249
|
+
)
|
|
250
|
+
parser.add_argument(
|
|
251
|
+
"--workflow",
|
|
252
|
+
type=str,
|
|
253
|
+
help="Workflow YAML file to validate (runtime subcommand)",
|
|
254
|
+
)
|
|
255
|
+
parser.add_argument(
|
|
256
|
+
"--execute",
|
|
257
|
+
action="store_true",
|
|
258
|
+
help="Execute fixes instead of dry-run (fix/runtime subcommand)",
|
|
259
|
+
)
|
|
260
|
+
parser.add_argument(
|
|
261
|
+
"--no-backup",
|
|
262
|
+
action="store_true",
|
|
263
|
+
help="Skip creating backup files (fix subcommand)",
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
# Runtime migration options
|
|
267
|
+
parser.add_argument(
|
|
268
|
+
"--fix",
|
|
269
|
+
action="store_true",
|
|
270
|
+
help="Apply migration fixes automatically (runtime subcommand)",
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
return parser.parse_args(args)
|
|
274
|
+
|
|
275
|
+
def _build_config(self, args: argparse.Namespace) -> DoctorConfig:
|
|
276
|
+
"""Build DoctorConfig from parsed arguments."""
|
|
277
|
+
return DoctorConfig(
|
|
278
|
+
deep=args.deep,
|
|
279
|
+
timeout=args.timeout if args.deep else min(args.timeout, 10.0),
|
|
280
|
+
strict=args.strict,
|
|
281
|
+
quiet=args.quiet,
|
|
282
|
+
no_color=args.no_color,
|
|
283
|
+
format="json" if args.json else args.format,
|
|
284
|
+
output_path=args.output,
|
|
285
|
+
only=args.only.split(",") if args.only else [],
|
|
286
|
+
skip=args.skip.split(",") if args.skip else [],
|
|
287
|
+
show_keys=args.show_keys,
|
|
288
|
+
require_keys=args.require.split(",") if args.require else [],
|
|
289
|
+
config_file=args.file,
|
|
290
|
+
dsn=args.dsn,
|
|
291
|
+
provider=args.provider,
|
|
292
|
+
read_only=args.read_only,
|
|
293
|
+
mock=args.mock and not args.live,
|
|
294
|
+
live=args.live,
|
|
295
|
+
model=args.model,
|
|
296
|
+
budget_ms=args.budget_ms,
|
|
297
|
+
top_n=args.top_n,
|
|
298
|
+
fail_fast=args.fail_fast,
|
|
299
|
+
list_tools=args.list_tools,
|
|
300
|
+
all_checks=args.all_checks,
|
|
301
|
+
missing_only=args.missing_only,
|
|
302
|
+
name=args.name,
|
|
303
|
+
category=args.category,
|
|
304
|
+
path=args.path,
|
|
305
|
+
save_report=args.save_report,
|
|
306
|
+
team_file=args.team,
|
|
307
|
+
workflow_file=args.workflow,
|
|
308
|
+
fix=getattr(args, 'fix', False),
|
|
309
|
+
execute=getattr(args, 'execute', False),
|
|
310
|
+
no_backup=getattr(args, 'no_backup', False),
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
def _get_categories_for_subcommand(self, subcommand: Optional[str]) -> Optional[List[CheckCategory]]:
|
|
314
|
+
"""Get check categories for a subcommand."""
|
|
315
|
+
category_map = {
|
|
316
|
+
"env": [CheckCategory.ENVIRONMENT],
|
|
317
|
+
"config": [CheckCategory.CONFIG],
|
|
318
|
+
"tools": [CheckCategory.TOOLS],
|
|
319
|
+
"bots": [CheckCategory.BOTS],
|
|
320
|
+
"db": [CheckCategory.DATABASE],
|
|
321
|
+
"mcp": [CheckCategory.MCP],
|
|
322
|
+
"obs": [CheckCategory.OBSERVABILITY],
|
|
323
|
+
"skills": [CheckCategory.SKILLS],
|
|
324
|
+
"memory": [CheckCategory.MEMORY],
|
|
325
|
+
"permissions": [CheckCategory.PERMISSIONS],
|
|
326
|
+
"network": [CheckCategory.NETWORK],
|
|
327
|
+
"performance": [CheckCategory.PERFORMANCE],
|
|
328
|
+
"packaging": [CheckCategory.PACKAGING],
|
|
329
|
+
"runtime": [CheckCategory.RUNTIME],
|
|
330
|
+
"selftest": [CheckCategory.SELFTEST],
|
|
331
|
+
"ci": None, # CI runs all checks
|
|
332
|
+
}
|
|
333
|
+
return category_map.get(subcommand)
|
|
334
|
+
|
|
335
|
+
def _run_fix_mode(self, config: DoctorConfig) -> int:
|
|
336
|
+
"""Run fix mode to migrate deprecated cli_backend configurations."""
|
|
337
|
+
import os
|
|
338
|
+
import yaml
|
|
339
|
+
import glob
|
|
340
|
+
|
|
341
|
+
if not config.quiet:
|
|
342
|
+
print("🔧 PraisonAI Configuration Migration Tool")
|
|
343
|
+
print(" Checking for deprecated cli_backend usage...")
|
|
344
|
+
|
|
345
|
+
# Find YAML files to check
|
|
346
|
+
yaml_files = []
|
|
347
|
+
if config.config_file:
|
|
348
|
+
yaml_files = [config.config_file]
|
|
349
|
+
else:
|
|
350
|
+
# Look for common YAML files in current directory
|
|
351
|
+
patterns = ["*.yaml", "*.yml", "agents.yaml", "config.yaml"]
|
|
352
|
+
for pattern in patterns:
|
|
353
|
+
yaml_files.extend(glob.glob(pattern))
|
|
354
|
+
yaml_files = list(dict.fromkeys(yaml_files)) # Remove duplicates while preserving order
|
|
355
|
+
|
|
356
|
+
if not yaml_files:
|
|
357
|
+
if not config.quiet:
|
|
358
|
+
print("ℹ️ No YAML files found to migrate.")
|
|
359
|
+
return 0
|
|
360
|
+
|
|
361
|
+
issues_found = 0
|
|
362
|
+
files_modified = 0
|
|
363
|
+
files_failed = 0
|
|
364
|
+
|
|
365
|
+
for yaml_file in yaml_files:
|
|
366
|
+
if not os.path.exists(yaml_file):
|
|
367
|
+
continue
|
|
368
|
+
|
|
369
|
+
try:
|
|
370
|
+
with open(yaml_file, 'r') as f:
|
|
371
|
+
data = yaml.safe_load(f)
|
|
372
|
+
|
|
373
|
+
# Check for deprecated cli_backend usage
|
|
374
|
+
if self._has_deprecated_cli_backend(data):
|
|
375
|
+
issues_found += 1
|
|
376
|
+
if not config.quiet:
|
|
377
|
+
print(f"⚠️ Found deprecated cli_backend in: {yaml_file}")
|
|
378
|
+
|
|
379
|
+
if config.execute:
|
|
380
|
+
# Create backup if needed
|
|
381
|
+
if not config.no_backup:
|
|
382
|
+
backup_file = f"{yaml_file}.bak"
|
|
383
|
+
import shutil
|
|
384
|
+
shutil.copy2(yaml_file, backup_file)
|
|
385
|
+
if not config.quiet:
|
|
386
|
+
print(f"💾 Backup created: {backup_file}")
|
|
387
|
+
|
|
388
|
+
# Apply migration (simplified)
|
|
389
|
+
migrated_data = self._migrate_cli_backend_config(data)
|
|
390
|
+
|
|
391
|
+
# Write back the file
|
|
392
|
+
with open(yaml_file, 'w') as f:
|
|
393
|
+
yaml.dump(migrated_data, f, default_flow_style=False)
|
|
394
|
+
|
|
395
|
+
files_modified += 1
|
|
396
|
+
if not config.quiet:
|
|
397
|
+
print(f"✅ Migrated: {yaml_file}")
|
|
398
|
+
else:
|
|
399
|
+
if not config.quiet:
|
|
400
|
+
print(" Run with --execute to apply migration")
|
|
401
|
+
|
|
402
|
+
except Exception as e:
|
|
403
|
+
files_failed += 1
|
|
404
|
+
if not config.quiet:
|
|
405
|
+
print(f"❌ Error processing {yaml_file}: {e}")
|
|
406
|
+
|
|
407
|
+
if not config.quiet:
|
|
408
|
+
if issues_found == 0:
|
|
409
|
+
print("✅ No deprecated cli_backend configurations found.")
|
|
410
|
+
else:
|
|
411
|
+
action = "would be" if not config.execute else "were"
|
|
412
|
+
print(f"📊 Summary: {issues_found} files with deprecated configs, {files_modified} {action} migrated.")
|
|
413
|
+
|
|
414
|
+
if not config.execute and issues_found > 0:
|
|
415
|
+
print("\n💡 To apply migrations, run: praisonai doctor fix --execute")
|
|
416
|
+
|
|
417
|
+
return 1 if files_failed > 0 else 0
|
|
418
|
+
|
|
419
|
+
def _has_deprecated_cli_backend(self, data: dict) -> bool:
|
|
420
|
+
"""Check if YAML config has deprecated cli_backend usage."""
|
|
421
|
+
if not isinstance(data, dict):
|
|
422
|
+
return False
|
|
423
|
+
|
|
424
|
+
# Check roles and agents sections for cli_backend
|
|
425
|
+
for section in ['roles', 'agents']:
|
|
426
|
+
section_data = data.get(section, {})
|
|
427
|
+
if isinstance(section_data, dict):
|
|
428
|
+
for agent_config in section_data.values():
|
|
429
|
+
if isinstance(agent_config, dict) and 'cli_backend' in agent_config:
|
|
430
|
+
# Check if there's also model configuration
|
|
431
|
+
if 'llm' in agent_config or 'model' in agent_config:
|
|
432
|
+
return True
|
|
433
|
+
return False
|
|
434
|
+
|
|
435
|
+
def _migrate_cli_backend_config(self, data: dict) -> dict:
|
|
436
|
+
"""Migrate cli_backend configuration (simplified migration)."""
|
|
437
|
+
migrated = data.copy()
|
|
438
|
+
|
|
439
|
+
# Add migration comment at top level
|
|
440
|
+
if 'migration_info' not in migrated:
|
|
441
|
+
migrated['migration_info'] = {
|
|
442
|
+
'cli_backend_migration': 'Agent-level cli_backend deprecated. Consider model-scoped runtime configuration.',
|
|
443
|
+
'migrated_by': 'praisonai doctor fix',
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
# For now, just add comments rather than removing cli_backend
|
|
447
|
+
# since full migration requires understanding the intended model-scoped runtime pattern
|
|
448
|
+
for section in ['roles', 'agents']:
|
|
449
|
+
section_data = migrated.get(section, {})
|
|
450
|
+
if isinstance(section_data, dict):
|
|
451
|
+
for agent_name, agent_config in section_data.items():
|
|
452
|
+
if isinstance(agent_config, dict) and 'cli_backend' in agent_config:
|
|
453
|
+
if 'llm' in agent_config or 'model' in agent_config:
|
|
454
|
+
# Add migration note
|
|
455
|
+
agent_config['_migration_note'] = f"cli_backend is deprecated when model is specified. Consider model-scoped runtime."
|
|
456
|
+
|
|
457
|
+
return migrated
|
|
458
|
+
|
|
459
|
+
def execute(self, action: str, action_args: List[str], **kwargs) -> int:
|
|
460
|
+
"""
|
|
461
|
+
Execute the doctor command.
|
|
462
|
+
|
|
463
|
+
Args:
|
|
464
|
+
action: The subcommand or empty string
|
|
465
|
+
action_args: Additional arguments
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
Exit code (0=pass, 1=fail, 2=error)
|
|
469
|
+
"""
|
|
470
|
+
# Combine action and action_args for parsing
|
|
471
|
+
all_args = [action] + action_args if action and action != "help" else action_args
|
|
472
|
+
|
|
473
|
+
try:
|
|
474
|
+
args = self._parse_args(all_args)
|
|
475
|
+
except SystemExit:
|
|
476
|
+
return 0 # Help was shown
|
|
477
|
+
|
|
478
|
+
# Handle special flags
|
|
479
|
+
if args.version:
|
|
480
|
+
from . import __version__
|
|
481
|
+
print(f"PraisonAI Doctor v{__version__}")
|
|
482
|
+
return 0
|
|
483
|
+
|
|
484
|
+
# Register all checks
|
|
485
|
+
self._register_checks()
|
|
486
|
+
|
|
487
|
+
if args.list_checks:
|
|
488
|
+
registry = get_registry()
|
|
489
|
+
print(registry.list_checks_text())
|
|
490
|
+
return 0
|
|
491
|
+
|
|
492
|
+
# Build config
|
|
493
|
+
config = self._build_config(args)
|
|
494
|
+
|
|
495
|
+
# Handle CI mode
|
|
496
|
+
if args.subcommand == "ci":
|
|
497
|
+
config.format = "json"
|
|
498
|
+
config.no_color = True
|
|
499
|
+
config.quiet = True
|
|
500
|
+
|
|
501
|
+
# Handle fix mode
|
|
502
|
+
if args.subcommand == "fix":
|
|
503
|
+
return self._run_fix_mode(config)
|
|
504
|
+
|
|
505
|
+
# Get categories for subcommand
|
|
506
|
+
categories = self._get_categories_for_subcommand(args.subcommand)
|
|
507
|
+
|
|
508
|
+
# Run doctor
|
|
509
|
+
engine = DoctorEngine(config)
|
|
510
|
+
report = engine.run(categories=categories)
|
|
511
|
+
|
|
512
|
+
# Format output
|
|
513
|
+
formatter = get_formatter(
|
|
514
|
+
format_type=config.format,
|
|
515
|
+
no_color=config.no_color,
|
|
516
|
+
quiet=config.quiet,
|
|
517
|
+
show_prefix_suffix=config.show_keys,
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# Write output
|
|
521
|
+
if config.output_path:
|
|
522
|
+
with open(config.output_path, "w", encoding="utf-8") as f:
|
|
523
|
+
formatter.write(report, f)
|
|
524
|
+
if not config.quiet:
|
|
525
|
+
print(f"Report written to: {config.output_path}")
|
|
526
|
+
else:
|
|
527
|
+
formatter.write(report, sys.stdout)
|
|
528
|
+
|
|
529
|
+
return report.exit_code
|
|
530
|
+
|
|
531
|
+
def run(self, args: List[str]) -> int:
|
|
532
|
+
"""
|
|
533
|
+
Run the doctor command from CLI.
|
|
534
|
+
|
|
535
|
+
Args:
|
|
536
|
+
args: Command line arguments after 'doctor'
|
|
537
|
+
|
|
538
|
+
Returns:
|
|
539
|
+
Exit code
|
|
540
|
+
"""
|
|
541
|
+
if not args:
|
|
542
|
+
return self.execute("", [])
|
|
543
|
+
|
|
544
|
+
action = args[0] if args else ""
|
|
545
|
+
action_args = args[1:] if len(args) > 1 else []
|
|
546
|
+
|
|
547
|
+
return self.execute(action, action_args)
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
def run_doctor(args: Optional[List[str]] = None) -> int:
|
|
551
|
+
"""
|
|
552
|
+
Convenience function to run doctor from CLI.
|
|
553
|
+
|
|
554
|
+
Args:
|
|
555
|
+
args: Command line arguments (default: sys.argv[1:])
|
|
556
|
+
|
|
557
|
+
Returns:
|
|
558
|
+
Exit code
|
|
559
|
+
"""
|
|
560
|
+
if args is None:
|
|
561
|
+
args = sys.argv[1:]
|
|
562
|
+
|
|
563
|
+
handler = DoctorHandler()
|
|
564
|
+
return handler.run(args)
|