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,609 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Plugins command group for PraisonAI CLI.
|
|
3
|
+
|
|
4
|
+
Provides plugin management commands inspired by moltbot's plugins CLI.
|
|
5
|
+
Supports listing, enabling, disabling, and inspecting plugins.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
app = typer.Typer(
|
|
11
|
+
help="Plugin management and inspection",
|
|
12
|
+
no_args_is_help=True,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.command("list")
|
|
17
|
+
def plugins_list(
|
|
18
|
+
enabled_only: bool = typer.Option(False, "--enabled", help="Show only enabled plugins"),
|
|
19
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON"),
|
|
20
|
+
):
|
|
21
|
+
"""List available plugins.
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
praisonai plugins list
|
|
25
|
+
praisonai plugins list --enabled
|
|
26
|
+
praisonai plugins list --json
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
# Try to get plugins from the plugin system
|
|
30
|
+
plugins = _get_available_plugins()
|
|
31
|
+
|
|
32
|
+
if enabled_only:
|
|
33
|
+
plugins = [p for p in plugins if p.get("enabled", False)]
|
|
34
|
+
|
|
35
|
+
if json_output:
|
|
36
|
+
import json
|
|
37
|
+
print(json.dumps(plugins, indent=2))
|
|
38
|
+
else:
|
|
39
|
+
from rich.console import Console
|
|
40
|
+
from rich.table import Table
|
|
41
|
+
|
|
42
|
+
console = Console()
|
|
43
|
+
table = Table(title=f"Plugins ({len(plugins)} available)")
|
|
44
|
+
table.add_column("ID", style="cyan")
|
|
45
|
+
table.add_column("Name")
|
|
46
|
+
table.add_column("Status")
|
|
47
|
+
table.add_column("Description")
|
|
48
|
+
|
|
49
|
+
for plugin in plugins:
|
|
50
|
+
status = "[green]enabled[/green]" if plugin.get("enabled") else "[dim]disabled[/dim]"
|
|
51
|
+
table.add_row(
|
|
52
|
+
plugin.get("id", "-"),
|
|
53
|
+
plugin.get("name", "-"),
|
|
54
|
+
status,
|
|
55
|
+
plugin.get("description", "-")[:40] + "..." if len(plugin.get("description", "")) > 40 else plugin.get("description", "-"),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
console.print(table)
|
|
59
|
+
|
|
60
|
+
except Exception as e:
|
|
61
|
+
typer.echo(f"Error listing plugins: {e}", err=True)
|
|
62
|
+
raise typer.Exit(1)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@app.command("info")
|
|
66
|
+
def plugins_info(
|
|
67
|
+
plugin_id: str = typer.Argument(..., help="Plugin ID"),
|
|
68
|
+
):
|
|
69
|
+
"""Show detailed information about a plugin.
|
|
70
|
+
|
|
71
|
+
Examples:
|
|
72
|
+
praisonai plugins info memory-core
|
|
73
|
+
praisonai plugins info browser-tool
|
|
74
|
+
"""
|
|
75
|
+
try:
|
|
76
|
+
plugins = _get_available_plugins()
|
|
77
|
+
plugin = next((p for p in plugins if p.get("id") == plugin_id), None)
|
|
78
|
+
|
|
79
|
+
if not plugin:
|
|
80
|
+
typer.echo(f"Plugin not found: {plugin_id}", err=True)
|
|
81
|
+
raise typer.Exit(1)
|
|
82
|
+
|
|
83
|
+
from rich.console import Console
|
|
84
|
+
from rich.panel import Panel
|
|
85
|
+
|
|
86
|
+
console = Console()
|
|
87
|
+
|
|
88
|
+
console.print(f"\n[bold cyan]{plugin.get('name', plugin_id)}[/bold cyan]")
|
|
89
|
+
console.print(f"ID: {plugin.get('id', '-')}")
|
|
90
|
+
console.print(f"Status: {'[green]enabled[/green]' if plugin.get('enabled') else '[dim]disabled[/dim]'}")
|
|
91
|
+
console.print(f"Description: {plugin.get('description', '-')}")
|
|
92
|
+
|
|
93
|
+
if plugin.get("version"):
|
|
94
|
+
console.print(f"Version: {plugin.get('version')}")
|
|
95
|
+
if plugin.get("author"):
|
|
96
|
+
console.print(f"Author: {plugin.get('author')}")
|
|
97
|
+
if plugin.get("hooks"):
|
|
98
|
+
console.print(f"Hooks: {', '.join(plugin.get('hooks', []))}")
|
|
99
|
+
if plugin.get("config_schema"):
|
|
100
|
+
console.print("\n[bold]Config Schema:[/bold]")
|
|
101
|
+
import json
|
|
102
|
+
console.print(Panel(json.dumps(plugin.get("config_schema"), indent=2)))
|
|
103
|
+
|
|
104
|
+
except Exception as e:
|
|
105
|
+
typer.echo(f"Error: {e}", err=True)
|
|
106
|
+
raise typer.Exit(1)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@app.command("enable")
|
|
110
|
+
def plugins_enable(
|
|
111
|
+
plugin_id: str = typer.Argument(..., help="Plugin ID to enable"),
|
|
112
|
+
):
|
|
113
|
+
"""Enable a plugin.
|
|
114
|
+
|
|
115
|
+
Examples:
|
|
116
|
+
praisonai plugins enable memory-core
|
|
117
|
+
praisonai plugins enable browser-tool
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
# Update config to enable plugin
|
|
121
|
+
config_path = _get_config_path()
|
|
122
|
+
config = _load_config(config_path)
|
|
123
|
+
|
|
124
|
+
if "plugins" not in config:
|
|
125
|
+
config["plugins"] = {}
|
|
126
|
+
if "enabled" not in config["plugins"]:
|
|
127
|
+
config["plugins"]["enabled"] = []
|
|
128
|
+
|
|
129
|
+
if plugin_id not in config["plugins"]["enabled"]:
|
|
130
|
+
config["plugins"]["enabled"].append(plugin_id)
|
|
131
|
+
_save_config(config_path, config)
|
|
132
|
+
typer.echo(f"[green]✓[/green] Plugin enabled: {plugin_id}")
|
|
133
|
+
else:
|
|
134
|
+
typer.echo(f"Plugin already enabled: {plugin_id}")
|
|
135
|
+
|
|
136
|
+
except Exception as e:
|
|
137
|
+
typer.echo(f"Error enabling plugin: {e}", err=True)
|
|
138
|
+
raise typer.Exit(1)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@app.command("disable")
|
|
142
|
+
def plugins_disable(
|
|
143
|
+
plugin_id: str = typer.Argument(..., help="Plugin ID to disable"),
|
|
144
|
+
):
|
|
145
|
+
"""Disable a plugin.
|
|
146
|
+
|
|
147
|
+
Examples:
|
|
148
|
+
praisonai plugins disable memory-core
|
|
149
|
+
praisonai plugins disable browser-tool
|
|
150
|
+
"""
|
|
151
|
+
try:
|
|
152
|
+
config_path = _get_config_path()
|
|
153
|
+
config = _load_config(config_path)
|
|
154
|
+
|
|
155
|
+
if "plugins" in config and "enabled" in config["plugins"]:
|
|
156
|
+
if plugin_id in config["plugins"]["enabled"]:
|
|
157
|
+
config["plugins"]["enabled"].remove(plugin_id)
|
|
158
|
+
_save_config(config_path, config)
|
|
159
|
+
typer.echo(f"[yellow]![/yellow] Plugin disabled: {plugin_id}")
|
|
160
|
+
else:
|
|
161
|
+
typer.echo(f"Plugin not enabled: {plugin_id}")
|
|
162
|
+
else:
|
|
163
|
+
typer.echo(f"Plugin not enabled: {plugin_id}")
|
|
164
|
+
|
|
165
|
+
except Exception as e:
|
|
166
|
+
typer.echo(f"Error disabling plugin: {e}", err=True)
|
|
167
|
+
raise typer.Exit(1)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@app.command("doctor")
|
|
171
|
+
def plugins_doctor():
|
|
172
|
+
"""Check plugin health and configuration.
|
|
173
|
+
|
|
174
|
+
Verifies that all enabled plugins are properly configured and
|
|
175
|
+
their dependencies are met.
|
|
176
|
+
|
|
177
|
+
Examples:
|
|
178
|
+
praisonai plugins doctor
|
|
179
|
+
"""
|
|
180
|
+
try:
|
|
181
|
+
from rich.console import Console
|
|
182
|
+
from rich.table import Table
|
|
183
|
+
|
|
184
|
+
console = Console()
|
|
185
|
+
plugins = _get_available_plugins()
|
|
186
|
+
enabled_plugins = [p for p in plugins if p.get("enabled")]
|
|
187
|
+
|
|
188
|
+
console.print("[bold]Plugin Health Check[/bold]\n")
|
|
189
|
+
|
|
190
|
+
if not enabled_plugins:
|
|
191
|
+
console.print("[yellow]No plugins enabled[/yellow]")
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
table = Table()
|
|
195
|
+
table.add_column("Plugin", style="cyan")
|
|
196
|
+
table.add_column("Status")
|
|
197
|
+
table.add_column("Issues")
|
|
198
|
+
|
|
199
|
+
issues_found = 0
|
|
200
|
+
|
|
201
|
+
for plugin in enabled_plugins:
|
|
202
|
+
issues = []
|
|
203
|
+
|
|
204
|
+
# Check if plugin module exists
|
|
205
|
+
if plugin.get("module"):
|
|
206
|
+
try:
|
|
207
|
+
__import__(plugin["module"])
|
|
208
|
+
except ImportError:
|
|
209
|
+
issues.append("Module not found")
|
|
210
|
+
|
|
211
|
+
# Check required config
|
|
212
|
+
if plugin.get("required_config"):
|
|
213
|
+
for key in plugin["required_config"]:
|
|
214
|
+
# Check if config key exists
|
|
215
|
+
pass # Would check actual config
|
|
216
|
+
|
|
217
|
+
if issues:
|
|
218
|
+
status = "[red]✗ Issues[/red]"
|
|
219
|
+
issues_found += len(issues)
|
|
220
|
+
else:
|
|
221
|
+
status = "[green]✓ OK[/green]"
|
|
222
|
+
|
|
223
|
+
table.add_row(
|
|
224
|
+
plugin.get("name", plugin.get("id")),
|
|
225
|
+
status,
|
|
226
|
+
", ".join(issues) if issues else "-",
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
console.print(table)
|
|
230
|
+
|
|
231
|
+
if issues_found:
|
|
232
|
+
console.print(f"\n[red]Found {issues_found} issue(s)[/red]")
|
|
233
|
+
else:
|
|
234
|
+
console.print(f"\n[green]All {len(enabled_plugins)} plugins healthy[/green]")
|
|
235
|
+
|
|
236
|
+
except Exception as e:
|
|
237
|
+
typer.echo(f"Error: {e}", err=True)
|
|
238
|
+
raise typer.Exit(1)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# ============ Single-File Plugin Commands ============
|
|
242
|
+
|
|
243
|
+
@app.command("create")
|
|
244
|
+
def plugins_create(
|
|
245
|
+
name: str = typer.Argument(..., help="Plugin name (will be converted to snake_case)"),
|
|
246
|
+
description: str = typer.Option("A PraisonAI plugin", "--description", "-d", help="Plugin description"),
|
|
247
|
+
author: str = typer.Option("", "--author", "-a", help="Plugin author"),
|
|
248
|
+
output_dir: str = typer.Option(None, "--output", "-o", help="Output directory (default: ~/.praison/plugins/)"),
|
|
249
|
+
):
|
|
250
|
+
"""Create a new single-file plugin from template.
|
|
251
|
+
|
|
252
|
+
Creates a new plugin with WordPress-style docstring header in the
|
|
253
|
+
user's plugin directory (~/.praison/plugins/).
|
|
254
|
+
|
|
255
|
+
Examples:
|
|
256
|
+
praisonai plugins create weather
|
|
257
|
+
praisonai plugins create weather --description "Weather API tools"
|
|
258
|
+
praisonai plugins create weather -o ./my_plugins/
|
|
259
|
+
"""
|
|
260
|
+
try:
|
|
261
|
+
from pathlib import Path
|
|
262
|
+
from praisonaiagents.plugins.discovery import get_plugin_template, ensure_plugin_dir
|
|
263
|
+
|
|
264
|
+
# Sanitize plugin name
|
|
265
|
+
safe_name = name.lower().replace("-", "_").replace(" ", "_")
|
|
266
|
+
|
|
267
|
+
# Determine output directory
|
|
268
|
+
if output_dir:
|
|
269
|
+
plugin_dir = Path(output_dir).expanduser().resolve()
|
|
270
|
+
plugin_dir.mkdir(parents=True, exist_ok=True)
|
|
271
|
+
else:
|
|
272
|
+
plugin_dir = ensure_plugin_dir()
|
|
273
|
+
|
|
274
|
+
plugin_path = plugin_dir / f"{safe_name}.py"
|
|
275
|
+
|
|
276
|
+
# Check if file already exists
|
|
277
|
+
if plugin_path.exists():
|
|
278
|
+
overwrite = typer.confirm(f"Plugin {plugin_path} already exists. Overwrite?")
|
|
279
|
+
if not overwrite:
|
|
280
|
+
typer.echo("Cancelled.")
|
|
281
|
+
raise typer.Exit(0)
|
|
282
|
+
|
|
283
|
+
# Generate template
|
|
284
|
+
template = get_plugin_template(name, description, author)
|
|
285
|
+
|
|
286
|
+
# Write file
|
|
287
|
+
plugin_path.write_text(template)
|
|
288
|
+
|
|
289
|
+
typer.echo(f"[green]✓[/green] Created plugin: {plugin_path}")
|
|
290
|
+
typer.echo(f"\nNext steps:")
|
|
291
|
+
typer.echo(f" 1. Edit {plugin_path} to add your tools")
|
|
292
|
+
typer.echo(f" 2. Run 'praisonai plugins discover' to verify")
|
|
293
|
+
typer.echo(f" 3. Use tools with Agent(tools=['example_tool'])")
|
|
294
|
+
|
|
295
|
+
except ImportError as e:
|
|
296
|
+
typer.echo(f"Error: praisonaiagents package not found. Install with: pip install praisonaiagents", err=True)
|
|
297
|
+
raise typer.Exit(1)
|
|
298
|
+
except Exception as e:
|
|
299
|
+
typer.echo(f"Error creating plugin: {e}", err=True)
|
|
300
|
+
raise typer.Exit(1)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
@app.command("install")
|
|
304
|
+
def plugins_install(
|
|
305
|
+
source: str = typer.Argument(..., help="Path to plugin file to install"),
|
|
306
|
+
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing plugin"),
|
|
307
|
+
):
|
|
308
|
+
"""Install a single-file plugin.
|
|
309
|
+
|
|
310
|
+
Copies a plugin file to the user's plugin directory (~/.praison/plugins/).
|
|
311
|
+
|
|
312
|
+
Examples:
|
|
313
|
+
praisonai plugins install ./my_weather_plugin.py
|
|
314
|
+
praisonai plugins install ./my_weather_plugin.py --force
|
|
315
|
+
"""
|
|
316
|
+
try:
|
|
317
|
+
from pathlib import Path
|
|
318
|
+
import shutil
|
|
319
|
+
from praisonaiagents.plugins.discovery import ensure_plugin_dir
|
|
320
|
+
from praisonaiagents.plugins.parser import parse_plugin_header_from_file
|
|
321
|
+
|
|
322
|
+
source_path = Path(source).expanduser().resolve()
|
|
323
|
+
|
|
324
|
+
# Validate source file
|
|
325
|
+
if not source_path.exists():
|
|
326
|
+
typer.echo(f"Error: File not found: {source}", err=True)
|
|
327
|
+
raise typer.Exit(1)
|
|
328
|
+
|
|
329
|
+
if not source_path.suffix == ".py":
|
|
330
|
+
typer.echo(f"Error: Plugin must be a Python file (.py)", err=True)
|
|
331
|
+
raise typer.Exit(1)
|
|
332
|
+
|
|
333
|
+
# Validate plugin header
|
|
334
|
+
try:
|
|
335
|
+
metadata = parse_plugin_header_from_file(str(source_path))
|
|
336
|
+
plugin_name = metadata.get("name", source_path.stem)
|
|
337
|
+
except Exception as e:
|
|
338
|
+
typer.echo(f"Error: Invalid plugin header: {e}", err=True)
|
|
339
|
+
raise typer.Exit(1)
|
|
340
|
+
|
|
341
|
+
# Install to user plugin directory
|
|
342
|
+
plugin_dir = ensure_plugin_dir()
|
|
343
|
+
dest_path = plugin_dir / source_path.name
|
|
344
|
+
|
|
345
|
+
if dest_path.exists() and not force:
|
|
346
|
+
overwrite = typer.confirm(f"Plugin {dest_path.name} already exists. Overwrite?")
|
|
347
|
+
if not overwrite:
|
|
348
|
+
typer.echo("Cancelled.")
|
|
349
|
+
raise typer.Exit(0)
|
|
350
|
+
|
|
351
|
+
shutil.copy2(source_path, dest_path)
|
|
352
|
+
|
|
353
|
+
typer.echo(f"[green]✓[/green] Installed '{plugin_name}' to {dest_path}")
|
|
354
|
+
typer.echo(f"\nTools will be available on next run.")
|
|
355
|
+
|
|
356
|
+
except ImportError:
|
|
357
|
+
typer.echo(f"Error: praisonaiagents package not found.", err=True)
|
|
358
|
+
raise typer.Exit(1)
|
|
359
|
+
except typer.Exit:
|
|
360
|
+
raise
|
|
361
|
+
except Exception as e:
|
|
362
|
+
typer.echo(f"Error installing plugin: {e}", err=True)
|
|
363
|
+
raise typer.Exit(1)
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
@app.command("discover")
|
|
367
|
+
def plugins_discover(
|
|
368
|
+
plugin_dirs: str = typer.Option(None, "--dirs", "-d", help="Additional plugin directories (comma-separated)"),
|
|
369
|
+
load: bool = typer.Option(False, "--load", "-l", help="Actually load the plugins"),
|
|
370
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON"),
|
|
371
|
+
):
|
|
372
|
+
"""Discover single-file plugins from plugin directories.
|
|
373
|
+
|
|
374
|
+
Scans ~/.praison/plugins/ and ./.praison/plugins/ for valid plugins.
|
|
375
|
+
|
|
376
|
+
Examples:
|
|
377
|
+
praisonai plugins discover
|
|
378
|
+
praisonai plugins discover --load
|
|
379
|
+
praisonai plugins discover --json
|
|
380
|
+
"""
|
|
381
|
+
try:
|
|
382
|
+
from praisonaiagents.plugins.discovery import discover_plugins, discover_and_load_plugins
|
|
383
|
+
|
|
384
|
+
extra_dirs = plugin_dirs.split(",") if plugin_dirs else None
|
|
385
|
+
|
|
386
|
+
if load:
|
|
387
|
+
plugins = discover_and_load_plugins(extra_dirs)
|
|
388
|
+
else:
|
|
389
|
+
plugins = discover_plugins(extra_dirs)
|
|
390
|
+
|
|
391
|
+
if json_output:
|
|
392
|
+
import json
|
|
393
|
+
print(json.dumps(plugins, indent=2, default=str))
|
|
394
|
+
else:
|
|
395
|
+
from rich.console import Console
|
|
396
|
+
from rich.table import Table
|
|
397
|
+
|
|
398
|
+
console = Console()
|
|
399
|
+
|
|
400
|
+
if not plugins:
|
|
401
|
+
console.print("[yellow]No single-file plugins found.[/yellow]")
|
|
402
|
+
console.print("\nCreate one with: praisonai plugins init <name>")
|
|
403
|
+
return
|
|
404
|
+
|
|
405
|
+
table = Table(title=f"Single-File Plugins ({len(plugins)} found)")
|
|
406
|
+
table.add_column("Name", style="cyan")
|
|
407
|
+
table.add_column("Version")
|
|
408
|
+
table.add_column("Tools", style="green")
|
|
409
|
+
table.add_column("Path")
|
|
410
|
+
|
|
411
|
+
for plugin in plugins:
|
|
412
|
+
tools = plugin.get("tools", [])
|
|
413
|
+
tools_str = ", ".join(tools[:3])
|
|
414
|
+
if len(tools) > 3:
|
|
415
|
+
tools_str += f" (+{len(tools)-3})"
|
|
416
|
+
|
|
417
|
+
table.add_row(
|
|
418
|
+
plugin.get("name", "-"),
|
|
419
|
+
plugin.get("version", "-"),
|
|
420
|
+
tools_str or "-",
|
|
421
|
+
str(plugin.get("path", "-"))[:40],
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
console.print(table)
|
|
425
|
+
|
|
426
|
+
if load:
|
|
427
|
+
console.print("\n[green]Plugins loaded.[/green] Tools are now available.")
|
|
428
|
+
|
|
429
|
+
except ImportError:
|
|
430
|
+
typer.echo(f"Error: praisonaiagents package not found.", err=True)
|
|
431
|
+
raise typer.Exit(1)
|
|
432
|
+
except Exception as e:
|
|
433
|
+
typer.echo(f"Error discovering plugins: {e}", err=True)
|
|
434
|
+
raise typer.Exit(1)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
@app.command("remove")
|
|
438
|
+
def plugins_remove(
|
|
439
|
+
name: str = typer.Argument(..., help="Plugin name or filename to remove"),
|
|
440
|
+
force: bool = typer.Option(False, "--force", "-f", help="Remove without confirmation"),
|
|
441
|
+
):
|
|
442
|
+
"""Remove a single-file plugin.
|
|
443
|
+
|
|
444
|
+
Removes a plugin from the user's plugin directory.
|
|
445
|
+
|
|
446
|
+
Examples:
|
|
447
|
+
praisonai plugins remove weather
|
|
448
|
+
praisonai plugins remove weather_plugin.py --force
|
|
449
|
+
"""
|
|
450
|
+
try:
|
|
451
|
+
from pathlib import Path
|
|
452
|
+
from praisonaiagents.plugins.discovery import get_default_plugin_dirs
|
|
453
|
+
|
|
454
|
+
# Normalize name
|
|
455
|
+
if not name.endswith(".py"):
|
|
456
|
+
name = f"{name}.py"
|
|
457
|
+
|
|
458
|
+
# Search in plugin directories
|
|
459
|
+
plugin_path = None
|
|
460
|
+
for plugin_dir in get_default_plugin_dirs():
|
|
461
|
+
candidate = plugin_dir / name
|
|
462
|
+
if candidate.exists():
|
|
463
|
+
plugin_path = candidate
|
|
464
|
+
break
|
|
465
|
+
|
|
466
|
+
# Also check user directory explicitly
|
|
467
|
+
if not plugin_path:
|
|
468
|
+
user_dir = Path.home() / ".praison" / "plugins"
|
|
469
|
+
candidate = user_dir / name
|
|
470
|
+
if candidate.exists():
|
|
471
|
+
plugin_path = candidate
|
|
472
|
+
|
|
473
|
+
if not plugin_path:
|
|
474
|
+
typer.echo(f"Plugin not found: {name}", err=True)
|
|
475
|
+
raise typer.Exit(1)
|
|
476
|
+
|
|
477
|
+
if not force:
|
|
478
|
+
confirm = typer.confirm(f"Remove plugin {plugin_path}?")
|
|
479
|
+
if not confirm:
|
|
480
|
+
typer.echo("Cancelled.")
|
|
481
|
+
raise typer.Exit(0)
|
|
482
|
+
|
|
483
|
+
plugin_path.unlink()
|
|
484
|
+
typer.echo(f"[green]✓[/green] Removed: {plugin_path}")
|
|
485
|
+
|
|
486
|
+
except ImportError:
|
|
487
|
+
# Fallback without praisonaiagents
|
|
488
|
+
from pathlib import Path
|
|
489
|
+
user_dir = Path.home() / ".praison" / "plugins"
|
|
490
|
+
if not name.endswith(".py"):
|
|
491
|
+
name = f"{name}.py"
|
|
492
|
+
plugin_path = user_dir / name
|
|
493
|
+
if plugin_path.exists():
|
|
494
|
+
if force or typer.confirm(f"Remove plugin {plugin_path}?"):
|
|
495
|
+
plugin_path.unlink()
|
|
496
|
+
typer.echo(f"[green]✓[/green] Removed: {plugin_path}")
|
|
497
|
+
else:
|
|
498
|
+
typer.echo(f"Plugin not found: {name}", err=True)
|
|
499
|
+
raise typer.Exit(1)
|
|
500
|
+
except typer.Exit:
|
|
501
|
+
raise
|
|
502
|
+
except Exception as e:
|
|
503
|
+
typer.echo(f"Error removing plugin: {e}", err=True)
|
|
504
|
+
raise typer.Exit(1)
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def _get_available_plugins():
|
|
508
|
+
"""Get list of available plugins."""
|
|
509
|
+
# Built-in plugins
|
|
510
|
+
plugins = [
|
|
511
|
+
{
|
|
512
|
+
"id": "memory-core",
|
|
513
|
+
"name": "Memory Core",
|
|
514
|
+
"description": "Semantic memory indexing and search",
|
|
515
|
+
"enabled": True,
|
|
516
|
+
"hooks": ["on_message", "on_session_start"],
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
"id": "browser-tool",
|
|
520
|
+
"name": "Browser Tool",
|
|
521
|
+
"description": "Browser automation and control",
|
|
522
|
+
"enabled": False,
|
|
523
|
+
"hooks": ["on_tool_call"],
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
"id": "knowledge-rag",
|
|
527
|
+
"name": "Knowledge RAG",
|
|
528
|
+
"description": "Retrieval-augmented generation",
|
|
529
|
+
"enabled": False,
|
|
530
|
+
"hooks": ["on_message", "on_context_build"],
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
"id": "telemetry",
|
|
534
|
+
"name": "Telemetry",
|
|
535
|
+
"description": "Usage tracking and analytics",
|
|
536
|
+
"enabled": False,
|
|
537
|
+
"hooks": ["on_request", "on_response"],
|
|
538
|
+
},
|
|
539
|
+
]
|
|
540
|
+
|
|
541
|
+
# Try to load actual plugin registry
|
|
542
|
+
try:
|
|
543
|
+
from praisonaiagents.plugins import get_plugin_registry
|
|
544
|
+
registry = get_plugin_registry()
|
|
545
|
+
if registry:
|
|
546
|
+
# Merge with actual plugins
|
|
547
|
+
pass
|
|
548
|
+
except ImportError:
|
|
549
|
+
pass
|
|
550
|
+
|
|
551
|
+
return plugins
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def _get_config_path():
|
|
555
|
+
"""Get config file path."""
|
|
556
|
+
from pathlib import Path
|
|
557
|
+
|
|
558
|
+
config_dir = Path.home() / ".praisonai"
|
|
559
|
+
config_dir.mkdir(exist_ok=True)
|
|
560
|
+
return config_dir / "config.json"
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def _load_config(path):
|
|
564
|
+
"""Load config from file."""
|
|
565
|
+
import json
|
|
566
|
+
|
|
567
|
+
if path.exists():
|
|
568
|
+
with open(path) as f:
|
|
569
|
+
return json.load(f)
|
|
570
|
+
return {}
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
def _save_config(path, config):
|
|
574
|
+
"""Save config to file."""
|
|
575
|
+
import json
|
|
576
|
+
|
|
577
|
+
with open(path, "w") as f:
|
|
578
|
+
json.dump(config, f, indent=2)
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
@app.callback(invoke_without_command=True)
|
|
582
|
+
def plugins_callback(ctx: typer.Context):
|
|
583
|
+
"""Show plugins help if no subcommand provided."""
|
|
584
|
+
if ctx.invoked_subcommand is None:
|
|
585
|
+
help_text = """
|
|
586
|
+
[bold cyan]PraisonAI Plugins - Plugin Management[/bold cyan]
|
|
587
|
+
|
|
588
|
+
Manage plugins with: praisonai plugins <command>
|
|
589
|
+
|
|
590
|
+
[bold]Commands:[/bold]
|
|
591
|
+
[green]list[/green] List available plugins
|
|
592
|
+
[green]info[/green] Show plugin details
|
|
593
|
+
[green]enable[/green] Enable a plugin
|
|
594
|
+
[green]disable[/green] Disable a plugin
|
|
595
|
+
[green]doctor[/green] Check plugin health
|
|
596
|
+
|
|
597
|
+
[bold]Examples:[/bold]
|
|
598
|
+
praisonai plugins list
|
|
599
|
+
praisonai plugins info memory-core
|
|
600
|
+
praisonai plugins enable browser-tool
|
|
601
|
+
praisonai plugins doctor
|
|
602
|
+
"""
|
|
603
|
+
try:
|
|
604
|
+
from rich import print as rprint
|
|
605
|
+
rprint(help_text)
|
|
606
|
+
except ImportError:
|
|
607
|
+
import re
|
|
608
|
+
plain = re.sub(r'\[/?[^\]]+\]', '', help_text)
|
|
609
|
+
print(plain)
|