PraisonAI 3.0.0__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/__init__.py +54 -0
- praisonai/__main__.py +15 -0
- praisonai/acp/__init__.py +54 -0
- praisonai/acp/config.py +159 -0
- praisonai/acp/server.py +587 -0
- praisonai/acp/session.py +219 -0
- praisonai/adapters/__init__.py +50 -0
- praisonai/adapters/readers.py +395 -0
- praisonai/adapters/rerankers.py +315 -0
- praisonai/adapters/retrievers.py +394 -0
- praisonai/adapters/vector_stores.py +409 -0
- praisonai/agent_scheduler.py +337 -0
- praisonai/agents_generator.py +903 -0
- praisonai/api/call.py +292 -0
- praisonai/auto.py +1197 -0
- praisonai/capabilities/__init__.py +275 -0
- praisonai/capabilities/a2a.py +140 -0
- praisonai/capabilities/assistants.py +283 -0
- praisonai/capabilities/audio.py +320 -0
- praisonai/capabilities/batches.py +469 -0
- praisonai/capabilities/completions.py +336 -0
- praisonai/capabilities/container_files.py +155 -0
- praisonai/capabilities/containers.py +93 -0
- praisonai/capabilities/embeddings.py +158 -0
- praisonai/capabilities/files.py +467 -0
- praisonai/capabilities/fine_tuning.py +293 -0
- praisonai/capabilities/guardrails.py +182 -0
- praisonai/capabilities/images.py +330 -0
- praisonai/capabilities/mcp.py +190 -0
- praisonai/capabilities/messages.py +270 -0
- praisonai/capabilities/moderations.py +154 -0
- praisonai/capabilities/ocr.py +217 -0
- praisonai/capabilities/passthrough.py +204 -0
- praisonai/capabilities/rag.py +207 -0
- praisonai/capabilities/realtime.py +160 -0
- praisonai/capabilities/rerank.py +165 -0
- praisonai/capabilities/responses.py +266 -0
- praisonai/capabilities/search.py +109 -0
- praisonai/capabilities/skills.py +133 -0
- praisonai/capabilities/vector_store_files.py +334 -0
- praisonai/capabilities/vector_stores.py +304 -0
- praisonai/capabilities/videos.py +141 -0
- praisonai/chainlit_ui.py +304 -0
- praisonai/chat/__init__.py +106 -0
- praisonai/chat/app.py +125 -0
- praisonai/cli/__init__.py +26 -0
- praisonai/cli/app.py +213 -0
- praisonai/cli/commands/__init__.py +75 -0
- praisonai/cli/commands/acp.py +70 -0
- praisonai/cli/commands/completion.py +333 -0
- praisonai/cli/commands/config.py +166 -0
- praisonai/cli/commands/debug.py +142 -0
- praisonai/cli/commands/diag.py +55 -0
- praisonai/cli/commands/doctor.py +166 -0
- praisonai/cli/commands/environment.py +179 -0
- praisonai/cli/commands/lsp.py +112 -0
- praisonai/cli/commands/mcp.py +210 -0
- praisonai/cli/commands/profile.py +457 -0
- praisonai/cli/commands/run.py +228 -0
- praisonai/cli/commands/schedule.py +150 -0
- praisonai/cli/commands/serve.py +97 -0
- praisonai/cli/commands/session.py +212 -0
- praisonai/cli/commands/traces.py +145 -0
- praisonai/cli/commands/version.py +101 -0
- praisonai/cli/configuration/__init__.py +18 -0
- praisonai/cli/configuration/loader.py +353 -0
- praisonai/cli/configuration/paths.py +114 -0
- praisonai/cli/configuration/schema.py +164 -0
- praisonai/cli/features/__init__.py +268 -0
- praisonai/cli/features/acp.py +236 -0
- praisonai/cli/features/action_orchestrator.py +546 -0
- praisonai/cli/features/agent_scheduler.py +773 -0
- praisonai/cli/features/agent_tools.py +474 -0
- praisonai/cli/features/agents.py +375 -0
- praisonai/cli/features/at_mentions.py +471 -0
- praisonai/cli/features/auto_memory.py +182 -0
- praisonai/cli/features/autonomy_mode.py +490 -0
- praisonai/cli/features/background.py +356 -0
- praisonai/cli/features/base.py +168 -0
- praisonai/cli/features/capabilities.py +1326 -0
- praisonai/cli/features/checkpoints.py +338 -0
- praisonai/cli/features/code_intelligence.py +652 -0
- praisonai/cli/features/compaction.py +294 -0
- praisonai/cli/features/compare.py +534 -0
- praisonai/cli/features/cost_tracker.py +514 -0
- praisonai/cli/features/debug.py +810 -0
- praisonai/cli/features/deploy.py +517 -0
- praisonai/cli/features/diag.py +289 -0
- praisonai/cli/features/doctor/__init__.py +63 -0
- praisonai/cli/features/doctor/checks/__init__.py +24 -0
- praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
- praisonai/cli/features/doctor/checks/config_checks.py +366 -0
- praisonai/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai/cli/features/doctor/checks/env_checks.py +543 -0
- praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
- praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
- praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
- praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai/cli/features/doctor/engine.py +266 -0
- praisonai/cli/features/doctor/formatters.py +310 -0
- praisonai/cli/features/doctor/handler.py +397 -0
- praisonai/cli/features/doctor/models.py +264 -0
- praisonai/cli/features/doctor/registry.py +239 -0
- praisonai/cli/features/endpoints.py +1019 -0
- praisonai/cli/features/eval.py +560 -0
- praisonai/cli/features/external_agents.py +231 -0
- praisonai/cli/features/fast_context.py +410 -0
- praisonai/cli/features/flow_display.py +566 -0
- praisonai/cli/features/git_integration.py +651 -0
- praisonai/cli/features/guardrail.py +171 -0
- praisonai/cli/features/handoff.py +185 -0
- praisonai/cli/features/hooks.py +583 -0
- praisonai/cli/features/image.py +384 -0
- praisonai/cli/features/interactive_runtime.py +585 -0
- praisonai/cli/features/interactive_tools.py +380 -0
- praisonai/cli/features/interactive_tui.py +603 -0
- praisonai/cli/features/jobs.py +632 -0
- praisonai/cli/features/knowledge.py +531 -0
- praisonai/cli/features/lite.py +244 -0
- praisonai/cli/features/lsp_cli.py +225 -0
- praisonai/cli/features/mcp.py +169 -0
- praisonai/cli/features/message_queue.py +587 -0
- praisonai/cli/features/metrics.py +211 -0
- praisonai/cli/features/n8n.py +673 -0
- praisonai/cli/features/observability.py +293 -0
- praisonai/cli/features/ollama.py +361 -0
- praisonai/cli/features/output_style.py +273 -0
- praisonai/cli/features/package.py +631 -0
- praisonai/cli/features/performance.py +308 -0
- praisonai/cli/features/persistence.py +636 -0
- praisonai/cli/features/profile.py +226 -0
- praisonai/cli/features/profiler/__init__.py +81 -0
- praisonai/cli/features/profiler/core.py +558 -0
- praisonai/cli/features/profiler/optimizations.py +652 -0
- praisonai/cli/features/profiler/suite.py +386 -0
- praisonai/cli/features/profiling.py +350 -0
- praisonai/cli/features/queue/__init__.py +73 -0
- praisonai/cli/features/queue/manager.py +395 -0
- praisonai/cli/features/queue/models.py +286 -0
- praisonai/cli/features/queue/persistence.py +564 -0
- praisonai/cli/features/queue/scheduler.py +484 -0
- praisonai/cli/features/queue/worker.py +372 -0
- praisonai/cli/features/recipe.py +1723 -0
- praisonai/cli/features/recipes.py +449 -0
- praisonai/cli/features/registry.py +229 -0
- praisonai/cli/features/repo_map.py +860 -0
- praisonai/cli/features/router.py +466 -0
- praisonai/cli/features/sandbox_executor.py +515 -0
- praisonai/cli/features/serve.py +829 -0
- praisonai/cli/features/session.py +222 -0
- praisonai/cli/features/skills.py +856 -0
- praisonai/cli/features/slash_commands.py +650 -0
- praisonai/cli/features/telemetry.py +179 -0
- praisonai/cli/features/templates.py +1384 -0
- praisonai/cli/features/thinking.py +305 -0
- praisonai/cli/features/todo.py +334 -0
- praisonai/cli/features/tools.py +680 -0
- praisonai/cli/features/tui/__init__.py +83 -0
- praisonai/cli/features/tui/app.py +580 -0
- praisonai/cli/features/tui/cli.py +566 -0
- praisonai/cli/features/tui/debug.py +511 -0
- praisonai/cli/features/tui/events.py +99 -0
- praisonai/cli/features/tui/mock_provider.py +328 -0
- praisonai/cli/features/tui/orchestrator.py +652 -0
- praisonai/cli/features/tui/screens/__init__.py +50 -0
- praisonai/cli/features/tui/screens/main.py +245 -0
- praisonai/cli/features/tui/screens/queue.py +174 -0
- praisonai/cli/features/tui/screens/session.py +124 -0
- praisonai/cli/features/tui/screens/settings.py +148 -0
- praisonai/cli/features/tui/widgets/__init__.py +56 -0
- praisonai/cli/features/tui/widgets/chat.py +261 -0
- praisonai/cli/features/tui/widgets/composer.py +224 -0
- praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
- praisonai/cli/features/tui/widgets/status.py +167 -0
- praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
- praisonai/cli/features/workflow.py +720 -0
- praisonai/cli/legacy.py +236 -0
- praisonai/cli/main.py +5559 -0
- praisonai/cli/schedule_cli.py +54 -0
- praisonai/cli/state/__init__.py +31 -0
- praisonai/cli/state/identifiers.py +161 -0
- praisonai/cli/state/sessions.py +313 -0
- praisonai/code/__init__.py +93 -0
- praisonai/code/agent_tools.py +344 -0
- praisonai/code/diff/__init__.py +21 -0
- praisonai/code/diff/diff_strategy.py +432 -0
- praisonai/code/tools/__init__.py +27 -0
- praisonai/code/tools/apply_diff.py +221 -0
- praisonai/code/tools/execute_command.py +275 -0
- praisonai/code/tools/list_files.py +274 -0
- praisonai/code/tools/read_file.py +206 -0
- praisonai/code/tools/search_replace.py +248 -0
- praisonai/code/tools/write_file.py +217 -0
- praisonai/code/utils/__init__.py +46 -0
- praisonai/code/utils/file_utils.py +307 -0
- praisonai/code/utils/ignore_utils.py +308 -0
- praisonai/code/utils/text_utils.py +276 -0
- praisonai/db/__init__.py +64 -0
- praisonai/db/adapter.py +531 -0
- praisonai/deploy/__init__.py +62 -0
- praisonai/deploy/api.py +231 -0
- praisonai/deploy/docker.py +454 -0
- praisonai/deploy/doctor.py +367 -0
- praisonai/deploy/main.py +327 -0
- praisonai/deploy/models.py +179 -0
- praisonai/deploy/providers/__init__.py +33 -0
- praisonai/deploy/providers/aws.py +331 -0
- praisonai/deploy/providers/azure.py +358 -0
- praisonai/deploy/providers/base.py +101 -0
- praisonai/deploy/providers/gcp.py +314 -0
- praisonai/deploy/schema.py +208 -0
- praisonai/deploy.py +185 -0
- praisonai/endpoints/__init__.py +53 -0
- praisonai/endpoints/a2u_server.py +410 -0
- praisonai/endpoints/discovery.py +165 -0
- praisonai/endpoints/providers/__init__.py +28 -0
- praisonai/endpoints/providers/a2a.py +253 -0
- praisonai/endpoints/providers/a2u.py +208 -0
- praisonai/endpoints/providers/agents_api.py +171 -0
- praisonai/endpoints/providers/base.py +231 -0
- praisonai/endpoints/providers/mcp.py +263 -0
- praisonai/endpoints/providers/recipe.py +206 -0
- praisonai/endpoints/providers/tools_mcp.py +150 -0
- praisonai/endpoints/registry.py +131 -0
- praisonai/endpoints/server.py +161 -0
- praisonai/inbuilt_tools/__init__.py +24 -0
- praisonai/inbuilt_tools/autogen_tools.py +117 -0
- praisonai/inc/__init__.py +2 -0
- praisonai/inc/config.py +96 -0
- praisonai/inc/models.py +155 -0
- praisonai/integrations/__init__.py +56 -0
- praisonai/integrations/base.py +303 -0
- praisonai/integrations/claude_code.py +270 -0
- praisonai/integrations/codex_cli.py +255 -0
- praisonai/integrations/cursor_cli.py +195 -0
- praisonai/integrations/gemini_cli.py +222 -0
- praisonai/jobs/__init__.py +67 -0
- praisonai/jobs/executor.py +425 -0
- praisonai/jobs/models.py +230 -0
- praisonai/jobs/router.py +314 -0
- praisonai/jobs/server.py +186 -0
- praisonai/jobs/store.py +203 -0
- praisonai/llm/__init__.py +66 -0
- praisonai/llm/registry.py +382 -0
- praisonai/mcp_server/__init__.py +152 -0
- praisonai/mcp_server/adapters/__init__.py +74 -0
- praisonai/mcp_server/adapters/agents.py +128 -0
- praisonai/mcp_server/adapters/capabilities.py +168 -0
- praisonai/mcp_server/adapters/cli_tools.py +568 -0
- praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
- praisonai/mcp_server/adapters/knowledge.py +93 -0
- praisonai/mcp_server/adapters/memory.py +104 -0
- praisonai/mcp_server/adapters/prompts.py +306 -0
- praisonai/mcp_server/adapters/resources.py +124 -0
- praisonai/mcp_server/adapters/tools_bridge.py +280 -0
- praisonai/mcp_server/auth/__init__.py +48 -0
- praisonai/mcp_server/auth/api_key.py +291 -0
- praisonai/mcp_server/auth/oauth.py +460 -0
- praisonai/mcp_server/auth/oidc.py +289 -0
- praisonai/mcp_server/auth/scopes.py +260 -0
- praisonai/mcp_server/cli.py +852 -0
- praisonai/mcp_server/elicitation.py +445 -0
- praisonai/mcp_server/icons.py +302 -0
- praisonai/mcp_server/recipe_adapter.py +573 -0
- praisonai/mcp_server/recipe_cli.py +824 -0
- praisonai/mcp_server/registry.py +703 -0
- praisonai/mcp_server/sampling.py +422 -0
- praisonai/mcp_server/server.py +490 -0
- praisonai/mcp_server/tasks.py +443 -0
- praisonai/mcp_server/transports/__init__.py +18 -0
- praisonai/mcp_server/transports/http_stream.py +376 -0
- praisonai/mcp_server/transports/stdio.py +132 -0
- praisonai/persistence/__init__.py +84 -0
- praisonai/persistence/config.py +238 -0
- praisonai/persistence/conversation/__init__.py +25 -0
- praisonai/persistence/conversation/async_mysql.py +427 -0
- praisonai/persistence/conversation/async_postgres.py +410 -0
- praisonai/persistence/conversation/async_sqlite.py +371 -0
- praisonai/persistence/conversation/base.py +151 -0
- praisonai/persistence/conversation/json_store.py +250 -0
- praisonai/persistence/conversation/mysql.py +387 -0
- praisonai/persistence/conversation/postgres.py +401 -0
- praisonai/persistence/conversation/singlestore.py +240 -0
- praisonai/persistence/conversation/sqlite.py +341 -0
- praisonai/persistence/conversation/supabase.py +203 -0
- praisonai/persistence/conversation/surrealdb.py +287 -0
- praisonai/persistence/factory.py +301 -0
- praisonai/persistence/hooks/__init__.py +18 -0
- praisonai/persistence/hooks/agent_hooks.py +297 -0
- praisonai/persistence/knowledge/__init__.py +26 -0
- praisonai/persistence/knowledge/base.py +144 -0
- praisonai/persistence/knowledge/cassandra.py +232 -0
- praisonai/persistence/knowledge/chroma.py +295 -0
- praisonai/persistence/knowledge/clickhouse.py +242 -0
- praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
- praisonai/persistence/knowledge/couchbase.py +286 -0
- praisonai/persistence/knowledge/lancedb.py +216 -0
- praisonai/persistence/knowledge/langchain_adapter.py +291 -0
- praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
- praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
- praisonai/persistence/knowledge/milvus.py +277 -0
- praisonai/persistence/knowledge/mongodb_vector.py +306 -0
- praisonai/persistence/knowledge/pgvector.py +335 -0
- praisonai/persistence/knowledge/pinecone.py +253 -0
- praisonai/persistence/knowledge/qdrant.py +301 -0
- praisonai/persistence/knowledge/redis_vector.py +291 -0
- praisonai/persistence/knowledge/singlestore_vector.py +299 -0
- praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
- praisonai/persistence/knowledge/upstash_vector.py +266 -0
- praisonai/persistence/knowledge/weaviate.py +223 -0
- praisonai/persistence/migrations/__init__.py +10 -0
- praisonai/persistence/migrations/manager.py +251 -0
- praisonai/persistence/orchestrator.py +406 -0
- praisonai/persistence/state/__init__.py +21 -0
- praisonai/persistence/state/async_mongodb.py +200 -0
- praisonai/persistence/state/base.py +107 -0
- praisonai/persistence/state/dynamodb.py +226 -0
- praisonai/persistence/state/firestore.py +175 -0
- praisonai/persistence/state/gcs.py +155 -0
- praisonai/persistence/state/memory.py +245 -0
- praisonai/persistence/state/mongodb.py +158 -0
- praisonai/persistence/state/redis.py +190 -0
- praisonai/persistence/state/upstash.py +144 -0
- praisonai/persistence/tests/__init__.py +3 -0
- praisonai/persistence/tests/test_all_backends.py +633 -0
- praisonai/profiler.py +1214 -0
- praisonai/recipe/__init__.py +134 -0
- praisonai/recipe/bridge.py +278 -0
- praisonai/recipe/core.py +893 -0
- praisonai/recipe/exceptions.py +54 -0
- praisonai/recipe/history.py +402 -0
- praisonai/recipe/models.py +266 -0
- praisonai/recipe/operations.py +440 -0
- praisonai/recipe/policy.py +422 -0
- praisonai/recipe/registry.py +849 -0
- praisonai/recipe/runtime.py +214 -0
- praisonai/recipe/security.py +711 -0
- praisonai/recipe/serve.py +859 -0
- praisonai/recipe/server.py +613 -0
- praisonai/scheduler/__init__.py +45 -0
- praisonai/scheduler/agent_scheduler.py +552 -0
- praisonai/scheduler/base.py +124 -0
- praisonai/scheduler/daemon_manager.py +225 -0
- praisonai/scheduler/state_manager.py +155 -0
- praisonai/scheduler/yaml_loader.py +193 -0
- praisonai/scheduler.py +194 -0
- praisonai/setup/__init__.py +1 -0
- praisonai/setup/build.py +21 -0
- praisonai/setup/post_install.py +23 -0
- praisonai/setup/setup_conda_env.py +25 -0
- praisonai/setup.py +16 -0
- praisonai/templates/__init__.py +116 -0
- praisonai/templates/cache.py +364 -0
- praisonai/templates/dependency_checker.py +358 -0
- praisonai/templates/discovery.py +391 -0
- praisonai/templates/loader.py +564 -0
- praisonai/templates/registry.py +511 -0
- praisonai/templates/resolver.py +206 -0
- praisonai/templates/security.py +327 -0
- praisonai/templates/tool_override.py +498 -0
- praisonai/templates/tools_doctor.py +256 -0
- praisonai/test.py +105 -0
- praisonai/train.py +562 -0
- praisonai/train_vision.py +306 -0
- praisonai/ui/agents.py +824 -0
- praisonai/ui/callbacks.py +57 -0
- praisonai/ui/chainlit_compat.py +246 -0
- praisonai/ui/chat.py +532 -0
- praisonai/ui/code.py +717 -0
- praisonai/ui/colab.py +474 -0
- praisonai/ui/colab_chainlit.py +81 -0
- praisonai/ui/components/aicoder.py +284 -0
- praisonai/ui/context.py +283 -0
- praisonai/ui/database_config.py +56 -0
- praisonai/ui/db.py +294 -0
- praisonai/ui/realtime.py +488 -0
- praisonai/ui/realtimeclient/__init__.py +756 -0
- praisonai/ui/realtimeclient/tools.py +242 -0
- praisonai/ui/sql_alchemy.py +710 -0
- praisonai/upload_vision.py +140 -0
- praisonai/version.py +1 -0
- praisonai-3.0.0.dist-info/METADATA +3493 -0
- praisonai-3.0.0.dist-info/RECORD +393 -0
- praisonai-3.0.0.dist-info/WHEEL +5 -0
- praisonai-3.0.0.dist-info/entry_points.txt +4 -0
- praisonai-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Interactive TUI System for PraisonAI CLI.
|
|
3
|
+
|
|
4
|
+
Inspired by Aider's interactive mode and prompt_toolkit usage.
|
|
5
|
+
Provides rich interactive terminal experience with completions and history.
|
|
6
|
+
|
|
7
|
+
Architecture:
|
|
8
|
+
- InteractiveSession: Main interactive session manager
|
|
9
|
+
- CommandCompleter: Auto-completion for commands and files
|
|
10
|
+
- HistoryManager: Persistent command history
|
|
11
|
+
- StatusDisplay: Rich-based status bar and output
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
import logging
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ============================================================================
|
|
23
|
+
# Configuration
|
|
24
|
+
# ============================================================================
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class InteractiveConfig:
|
|
28
|
+
"""Configuration for interactive session."""
|
|
29
|
+
prompt: str = ">>> "
|
|
30
|
+
multiline: bool = True
|
|
31
|
+
history_file: Optional[str] = None
|
|
32
|
+
max_history: int = 1000
|
|
33
|
+
enable_completions: bool = True
|
|
34
|
+
enable_syntax_highlighting: bool = True
|
|
35
|
+
vi_mode: bool = False
|
|
36
|
+
auto_suggest: bool = True
|
|
37
|
+
show_status_bar: bool = True
|
|
38
|
+
color_scheme: str = "monokai"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ============================================================================
|
|
42
|
+
# Command Completer
|
|
43
|
+
# ============================================================================
|
|
44
|
+
|
|
45
|
+
class CommandCompleter:
|
|
46
|
+
"""
|
|
47
|
+
Provides auto-completion for commands, files, and symbols.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
commands: Optional[List[str]] = None,
|
|
53
|
+
file_patterns: Optional[List[str]] = None
|
|
54
|
+
):
|
|
55
|
+
self.commands = commands or []
|
|
56
|
+
self.file_patterns = file_patterns or ["*.py", "*.js", "*.ts"]
|
|
57
|
+
self._file_cache: List[str] = []
|
|
58
|
+
self._symbol_cache: List[str] = []
|
|
59
|
+
|
|
60
|
+
def add_commands(self, commands: List[str]) -> None:
|
|
61
|
+
"""Add commands to completion list."""
|
|
62
|
+
self.commands.extend(commands)
|
|
63
|
+
|
|
64
|
+
def add_symbols(self, symbols: List[str]) -> None:
|
|
65
|
+
"""Add symbols to completion list."""
|
|
66
|
+
self._symbol_cache.extend(symbols)
|
|
67
|
+
|
|
68
|
+
def refresh_files(self, root: Optional[Path] = None) -> None:
|
|
69
|
+
"""Refresh file cache."""
|
|
70
|
+
root = root or Path.cwd()
|
|
71
|
+
self._file_cache = []
|
|
72
|
+
|
|
73
|
+
for pattern in self.file_patterns:
|
|
74
|
+
for file_path in root.rglob(pattern):
|
|
75
|
+
try:
|
|
76
|
+
rel_path = str(file_path.relative_to(root))
|
|
77
|
+
if not any(excl in rel_path for excl in ["__pycache__", "node_modules", ".git"]):
|
|
78
|
+
self._file_cache.append(rel_path)
|
|
79
|
+
except ValueError:
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
def get_completions(self, text: str, cursor_pos: int) -> List[str]:
|
|
83
|
+
"""
|
|
84
|
+
Get completions for the current input.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
text: Current input text
|
|
88
|
+
cursor_pos: Cursor position
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
List of completion suggestions
|
|
92
|
+
"""
|
|
93
|
+
# Get word before cursor
|
|
94
|
+
before_cursor = text[:cursor_pos]
|
|
95
|
+
words = before_cursor.split()
|
|
96
|
+
current_word = words[-1] if words else ""
|
|
97
|
+
|
|
98
|
+
completions = []
|
|
99
|
+
|
|
100
|
+
# Slash commands
|
|
101
|
+
if current_word.startswith("/"):
|
|
102
|
+
cmd_part = current_word[1:].lower()
|
|
103
|
+
for cmd in self.commands:
|
|
104
|
+
if cmd.lower().startswith(cmd_part):
|
|
105
|
+
completions.append(f"/{cmd}")
|
|
106
|
+
|
|
107
|
+
# @ mentions for files
|
|
108
|
+
elif current_word.startswith("@"):
|
|
109
|
+
file_part = current_word[1:].lower()
|
|
110
|
+
for file_path in self._file_cache:
|
|
111
|
+
if file_part in file_path.lower():
|
|
112
|
+
completions.append(f"@{file_path}")
|
|
113
|
+
|
|
114
|
+
# General completions
|
|
115
|
+
else:
|
|
116
|
+
word_lower = current_word.lower()
|
|
117
|
+
|
|
118
|
+
# Check symbols
|
|
119
|
+
for symbol in self._symbol_cache:
|
|
120
|
+
if symbol.lower().startswith(word_lower):
|
|
121
|
+
completions.append(symbol)
|
|
122
|
+
|
|
123
|
+
# Check files
|
|
124
|
+
for file_path in self._file_cache:
|
|
125
|
+
if word_lower in file_path.lower():
|
|
126
|
+
completions.append(file_path)
|
|
127
|
+
|
|
128
|
+
return completions[:20] # Limit results
|
|
129
|
+
|
|
130
|
+
def create_prompt_toolkit_completer(self) -> Any:
|
|
131
|
+
"""Create a prompt_toolkit completer."""
|
|
132
|
+
try:
|
|
133
|
+
from prompt_toolkit.completion import Completer, Completion
|
|
134
|
+
|
|
135
|
+
outer_self = self
|
|
136
|
+
|
|
137
|
+
class PTCompleter(Completer):
|
|
138
|
+
def get_completions(self, document, complete_event):
|
|
139
|
+
text = document.text
|
|
140
|
+
cursor_pos = document.cursor_position
|
|
141
|
+
|
|
142
|
+
for completion in outer_self.get_completions(text, cursor_pos):
|
|
143
|
+
# Calculate start position
|
|
144
|
+
words = text[:cursor_pos].split()
|
|
145
|
+
current_word = words[-1] if words else ""
|
|
146
|
+
start_pos = -len(current_word)
|
|
147
|
+
|
|
148
|
+
yield Completion(completion, start_position=start_pos)
|
|
149
|
+
|
|
150
|
+
return PTCompleter()
|
|
151
|
+
except ImportError:
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# ============================================================================
|
|
156
|
+
# History Manager
|
|
157
|
+
# ============================================================================
|
|
158
|
+
|
|
159
|
+
class HistoryManager:
|
|
160
|
+
"""
|
|
161
|
+
Manages command history with persistence.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
def __init__(
|
|
165
|
+
self,
|
|
166
|
+
history_file: Optional[str] = None,
|
|
167
|
+
max_entries: int = 1000
|
|
168
|
+
):
|
|
169
|
+
self.history_file = Path(history_file) if history_file else None
|
|
170
|
+
self.max_entries = max_entries
|
|
171
|
+
self._history: List[str] = []
|
|
172
|
+
self._position: int = 0
|
|
173
|
+
|
|
174
|
+
if self.history_file:
|
|
175
|
+
self._load_history()
|
|
176
|
+
|
|
177
|
+
def _load_history(self) -> None:
|
|
178
|
+
"""Load history from file."""
|
|
179
|
+
if self.history_file and self.history_file.exists():
|
|
180
|
+
try:
|
|
181
|
+
with open(self.history_file, 'r', encoding='utf-8') as f:
|
|
182
|
+
self._history = [
|
|
183
|
+
line.strip() for line in f.readlines()
|
|
184
|
+
if line.strip()
|
|
185
|
+
][-self.max_entries:]
|
|
186
|
+
except Exception as e:
|
|
187
|
+
logger.debug(f"Could not load history: {e}")
|
|
188
|
+
|
|
189
|
+
def _save_history(self) -> None:
|
|
190
|
+
"""Save history to file."""
|
|
191
|
+
if self.history_file:
|
|
192
|
+
try:
|
|
193
|
+
self.history_file.parent.mkdir(parents=True, exist_ok=True)
|
|
194
|
+
with open(self.history_file, 'w', encoding='utf-8') as f:
|
|
195
|
+
for entry in self._history[-self.max_entries:]:
|
|
196
|
+
f.write(entry + "\n")
|
|
197
|
+
except Exception as e:
|
|
198
|
+
logger.debug(f"Could not save history: {e}")
|
|
199
|
+
|
|
200
|
+
def add(self, entry: str) -> None:
|
|
201
|
+
"""Add an entry to history."""
|
|
202
|
+
entry = entry.strip()
|
|
203
|
+
if entry and (not self._history or self._history[-1] != entry):
|
|
204
|
+
self._history.append(entry)
|
|
205
|
+
self._position = len(self._history)
|
|
206
|
+
self._save_history()
|
|
207
|
+
|
|
208
|
+
def get_previous(self) -> Optional[str]:
|
|
209
|
+
"""Get previous history entry."""
|
|
210
|
+
if self._position > 0:
|
|
211
|
+
self._position -= 1
|
|
212
|
+
return self._history[self._position]
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
def get_next(self) -> Optional[str]:
|
|
216
|
+
"""Get next history entry."""
|
|
217
|
+
if self._position < len(self._history) - 1:
|
|
218
|
+
self._position += 1
|
|
219
|
+
return self._history[self._position]
|
|
220
|
+
elif self._position == len(self._history) - 1:
|
|
221
|
+
self._position = len(self._history)
|
|
222
|
+
return ""
|
|
223
|
+
return None
|
|
224
|
+
|
|
225
|
+
def search(self, prefix: str) -> List[str]:
|
|
226
|
+
"""Search history for entries starting with prefix."""
|
|
227
|
+
return [
|
|
228
|
+
entry for entry in self._history
|
|
229
|
+
if entry.lower().startswith(prefix.lower())
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
def get_all(self) -> List[str]:
|
|
233
|
+
"""Get all history entries."""
|
|
234
|
+
return self._history.copy()
|
|
235
|
+
|
|
236
|
+
def clear(self) -> None:
|
|
237
|
+
"""Clear history."""
|
|
238
|
+
self._history.clear()
|
|
239
|
+
self._position = 0
|
|
240
|
+
if self.history_file and self.history_file.exists():
|
|
241
|
+
self.history_file.unlink()
|
|
242
|
+
|
|
243
|
+
def create_prompt_toolkit_history(self) -> Any:
|
|
244
|
+
"""Create a prompt_toolkit history object."""
|
|
245
|
+
try:
|
|
246
|
+
from prompt_toolkit.history import FileHistory, InMemoryHistory
|
|
247
|
+
|
|
248
|
+
if self.history_file:
|
|
249
|
+
return FileHistory(str(self.history_file))
|
|
250
|
+
return InMemoryHistory()
|
|
251
|
+
except ImportError:
|
|
252
|
+
return None
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# ============================================================================
|
|
256
|
+
# Status Display
|
|
257
|
+
# ============================================================================
|
|
258
|
+
|
|
259
|
+
class StatusDisplay:
|
|
260
|
+
"""
|
|
261
|
+
Rich-based status display for interactive session.
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
def __init__(self, show_status_bar: bool = True):
|
|
265
|
+
self.show_status_bar = show_status_bar
|
|
266
|
+
self._console = None
|
|
267
|
+
self._status_items: Dict[str, str] = {}
|
|
268
|
+
|
|
269
|
+
@property
|
|
270
|
+
def console(self):
|
|
271
|
+
"""Lazy load Rich console."""
|
|
272
|
+
if self._console is None:
|
|
273
|
+
try:
|
|
274
|
+
from rich.console import Console
|
|
275
|
+
self._console = Console()
|
|
276
|
+
except ImportError:
|
|
277
|
+
self._console = None
|
|
278
|
+
return self._console
|
|
279
|
+
|
|
280
|
+
def set_status(self, key: str, value: str) -> None:
|
|
281
|
+
"""Set a status item."""
|
|
282
|
+
self._status_items[key] = value
|
|
283
|
+
|
|
284
|
+
def clear_status(self, key: str) -> None:
|
|
285
|
+
"""Clear a status item."""
|
|
286
|
+
self._status_items.pop(key, None)
|
|
287
|
+
|
|
288
|
+
def print_status_bar(self) -> None:
|
|
289
|
+
"""Print the status bar."""
|
|
290
|
+
if not self.show_status_bar or not self.console:
|
|
291
|
+
return
|
|
292
|
+
|
|
293
|
+
from rich.columns import Columns
|
|
294
|
+
from rich.text import Text
|
|
295
|
+
|
|
296
|
+
items = []
|
|
297
|
+
for key, value in self._status_items.items():
|
|
298
|
+
items.append(Text(f"{key}: {value}", style="dim"))
|
|
299
|
+
|
|
300
|
+
if items:
|
|
301
|
+
self.console.print(Columns(items, equal=True, expand=True))
|
|
302
|
+
|
|
303
|
+
def print_welcome(self, version: str = "1.0.0") -> None:
|
|
304
|
+
"""Print welcome message."""
|
|
305
|
+
if not self.console:
|
|
306
|
+
print(f"PraisonAI CLI v{version}")
|
|
307
|
+
return
|
|
308
|
+
|
|
309
|
+
from rich.panel import Panel
|
|
310
|
+
from rich.text import Text
|
|
311
|
+
|
|
312
|
+
welcome = Text()
|
|
313
|
+
welcome.append("PraisonAI CLI", style="bold cyan")
|
|
314
|
+
welcome.append(f" v{version}\n", style="dim")
|
|
315
|
+
welcome.append("Type ", style="dim")
|
|
316
|
+
welcome.append("/help", style="bold green")
|
|
317
|
+
welcome.append(" for commands, ", style="dim")
|
|
318
|
+
welcome.append("/exit", style="bold yellow")
|
|
319
|
+
welcome.append(" to quit", style="dim")
|
|
320
|
+
|
|
321
|
+
self.console.print(Panel(welcome, border_style="blue"))
|
|
322
|
+
|
|
323
|
+
def print_response(self, response: str, title: str = "Response") -> None:
|
|
324
|
+
"""Print a response with formatting."""
|
|
325
|
+
if not self.console:
|
|
326
|
+
print(response)
|
|
327
|
+
return
|
|
328
|
+
|
|
329
|
+
from rich.panel import Panel
|
|
330
|
+
from rich.markdown import Markdown
|
|
331
|
+
|
|
332
|
+
try:
|
|
333
|
+
md = Markdown(response)
|
|
334
|
+
self.console.print(Panel(md, title=title, border_style="green"))
|
|
335
|
+
except Exception:
|
|
336
|
+
self.console.print(Panel(response, title=title, border_style="green"))
|
|
337
|
+
|
|
338
|
+
def print_error(self, error: str) -> None:
|
|
339
|
+
"""Print an error message."""
|
|
340
|
+
if not self.console:
|
|
341
|
+
print(f"Error: {error}")
|
|
342
|
+
return
|
|
343
|
+
|
|
344
|
+
from rich.panel import Panel
|
|
345
|
+
self.console.print(Panel(error, title="Error", border_style="red"))
|
|
346
|
+
|
|
347
|
+
def print_info(self, message: str) -> None:
|
|
348
|
+
"""Print an info message."""
|
|
349
|
+
if not self.console:
|
|
350
|
+
print(message)
|
|
351
|
+
return
|
|
352
|
+
|
|
353
|
+
self.console.print(f"[cyan]ℹ[/cyan] {message}")
|
|
354
|
+
|
|
355
|
+
def print_success(self, message: str) -> None:
|
|
356
|
+
"""Print a success message."""
|
|
357
|
+
if not self.console:
|
|
358
|
+
print(message)
|
|
359
|
+
return
|
|
360
|
+
|
|
361
|
+
self.console.print(f"[green]✓[/green] {message}")
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
# ============================================================================
|
|
365
|
+
# Interactive Session
|
|
366
|
+
# ============================================================================
|
|
367
|
+
|
|
368
|
+
class InteractiveSession:
|
|
369
|
+
"""
|
|
370
|
+
Main interactive session manager.
|
|
371
|
+
|
|
372
|
+
Provides a rich interactive terminal experience with:
|
|
373
|
+
- Command completion
|
|
374
|
+
- History
|
|
375
|
+
- Syntax highlighting
|
|
376
|
+
- Status bar
|
|
377
|
+
- Keyboard shortcuts
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
def __init__(
|
|
381
|
+
self,
|
|
382
|
+
config: Optional[InteractiveConfig] = None,
|
|
383
|
+
on_input: Optional[Callable[[str], Optional[str]]] = None,
|
|
384
|
+
on_command: Optional[Callable[[str], Optional[Dict[str, Any]]]] = None
|
|
385
|
+
):
|
|
386
|
+
self.config = config or InteractiveConfig()
|
|
387
|
+
self.on_input = on_input
|
|
388
|
+
self.on_command = on_command
|
|
389
|
+
|
|
390
|
+
self.completer = CommandCompleter()
|
|
391
|
+
self.history = HistoryManager(
|
|
392
|
+
history_file=self.config.history_file,
|
|
393
|
+
max_entries=self.config.max_history
|
|
394
|
+
)
|
|
395
|
+
self.display = StatusDisplay(show_status_bar=self.config.show_status_bar)
|
|
396
|
+
|
|
397
|
+
self._running = False
|
|
398
|
+
self._prompt_session = None
|
|
399
|
+
|
|
400
|
+
def _create_prompt_session(self) -> Any:
|
|
401
|
+
"""Create a prompt_toolkit session."""
|
|
402
|
+
try:
|
|
403
|
+
from prompt_toolkit import PromptSession
|
|
404
|
+
from prompt_toolkit.lexers import PygmentsLexer
|
|
405
|
+
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
|
406
|
+
from pygments.lexers import MarkdownLexer
|
|
407
|
+
|
|
408
|
+
session_kwargs = {
|
|
409
|
+
"message": self.config.prompt,
|
|
410
|
+
"multiline": self.config.multiline,
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
# Add completer
|
|
414
|
+
if self.config.enable_completions:
|
|
415
|
+
completer = self.completer.create_prompt_toolkit_completer()
|
|
416
|
+
if completer:
|
|
417
|
+
session_kwargs["completer"] = completer
|
|
418
|
+
|
|
419
|
+
# Add history
|
|
420
|
+
history = self.history.create_prompt_toolkit_history()
|
|
421
|
+
if history:
|
|
422
|
+
session_kwargs["history"] = history
|
|
423
|
+
|
|
424
|
+
# Add syntax highlighting
|
|
425
|
+
if self.config.enable_syntax_highlighting:
|
|
426
|
+
session_kwargs["lexer"] = PygmentsLexer(MarkdownLexer)
|
|
427
|
+
|
|
428
|
+
# Add auto-suggest
|
|
429
|
+
if self.config.auto_suggest:
|
|
430
|
+
session_kwargs["auto_suggest"] = AutoSuggestFromHistory()
|
|
431
|
+
|
|
432
|
+
# VI mode
|
|
433
|
+
if self.config.vi_mode:
|
|
434
|
+
from prompt_toolkit.enums import EditingMode
|
|
435
|
+
session_kwargs["editing_mode"] = EditingMode.VI
|
|
436
|
+
|
|
437
|
+
return PromptSession(**session_kwargs)
|
|
438
|
+
|
|
439
|
+
except ImportError as e:
|
|
440
|
+
logger.debug(f"prompt_toolkit not available: {e}")
|
|
441
|
+
return None
|
|
442
|
+
|
|
443
|
+
def _get_input_fallback(self) -> str:
|
|
444
|
+
"""Fallback input method without prompt_toolkit."""
|
|
445
|
+
try:
|
|
446
|
+
if self.config.multiline:
|
|
447
|
+
print(f"{self.config.prompt}(Enter empty line to submit)")
|
|
448
|
+
lines = []
|
|
449
|
+
while True:
|
|
450
|
+
line = input()
|
|
451
|
+
if not line:
|
|
452
|
+
break
|
|
453
|
+
lines.append(line)
|
|
454
|
+
return "\n".join(lines)
|
|
455
|
+
else:
|
|
456
|
+
return input(self.config.prompt)
|
|
457
|
+
except EOFError:
|
|
458
|
+
return "/exit"
|
|
459
|
+
except KeyboardInterrupt:
|
|
460
|
+
print()
|
|
461
|
+
return ""
|
|
462
|
+
|
|
463
|
+
def get_input(self) -> str:
|
|
464
|
+
"""Get input from user."""
|
|
465
|
+
if self._prompt_session:
|
|
466
|
+
try:
|
|
467
|
+
return self._prompt_session.prompt()
|
|
468
|
+
except KeyboardInterrupt:
|
|
469
|
+
return ""
|
|
470
|
+
except EOFError:
|
|
471
|
+
return "/exit"
|
|
472
|
+
else:
|
|
473
|
+
return self._get_input_fallback()
|
|
474
|
+
|
|
475
|
+
def process_input(self, user_input: str) -> Optional[str]:
|
|
476
|
+
"""
|
|
477
|
+
Process user input.
|
|
478
|
+
|
|
479
|
+
Args:
|
|
480
|
+
user_input: Raw user input
|
|
481
|
+
|
|
482
|
+
Returns:
|
|
483
|
+
Response string or None
|
|
484
|
+
"""
|
|
485
|
+
user_input = user_input.strip()
|
|
486
|
+
|
|
487
|
+
if not user_input:
|
|
488
|
+
return None
|
|
489
|
+
|
|
490
|
+
# Add to history
|
|
491
|
+
self.history.add(user_input)
|
|
492
|
+
|
|
493
|
+
# Check for slash commands
|
|
494
|
+
if user_input.startswith("/"):
|
|
495
|
+
if self.on_command:
|
|
496
|
+
result = self.on_command(user_input)
|
|
497
|
+
if result:
|
|
498
|
+
if result.get("type") == "exit":
|
|
499
|
+
self._running = False
|
|
500
|
+
return None
|
|
501
|
+
return result.get("message")
|
|
502
|
+
return None
|
|
503
|
+
|
|
504
|
+
# Regular input
|
|
505
|
+
if self.on_input:
|
|
506
|
+
return self.on_input(user_input)
|
|
507
|
+
|
|
508
|
+
return None
|
|
509
|
+
|
|
510
|
+
def run(self) -> None:
|
|
511
|
+
"""Run the interactive session."""
|
|
512
|
+
self._running = True
|
|
513
|
+
self._prompt_session = self._create_prompt_session()
|
|
514
|
+
|
|
515
|
+
# Print welcome
|
|
516
|
+
self.display.print_welcome()
|
|
517
|
+
|
|
518
|
+
while self._running:
|
|
519
|
+
try:
|
|
520
|
+
# Get input
|
|
521
|
+
user_input = self.get_input()
|
|
522
|
+
|
|
523
|
+
# Process
|
|
524
|
+
response = self.process_input(user_input)
|
|
525
|
+
|
|
526
|
+
# Display response
|
|
527
|
+
if response:
|
|
528
|
+
self.display.print_response(response)
|
|
529
|
+
|
|
530
|
+
except KeyboardInterrupt:
|
|
531
|
+
self.display.print_info("Use /exit to quit")
|
|
532
|
+
except Exception as e:
|
|
533
|
+
self.display.print_error(str(e))
|
|
534
|
+
logger.exception("Error in interactive session")
|
|
535
|
+
|
|
536
|
+
def stop(self) -> None:
|
|
537
|
+
"""Stop the interactive session."""
|
|
538
|
+
self._running = False
|
|
539
|
+
|
|
540
|
+
def add_commands(self, commands: List[str]) -> None:
|
|
541
|
+
"""Add commands for completion."""
|
|
542
|
+
self.completer.add_commands(commands)
|
|
543
|
+
|
|
544
|
+
def add_symbols(self, symbols: List[str]) -> None:
|
|
545
|
+
"""Add symbols for completion."""
|
|
546
|
+
self.completer.add_symbols(symbols)
|
|
547
|
+
|
|
548
|
+
def refresh_files(self, root: Optional[Path] = None) -> None:
|
|
549
|
+
"""Refresh file completions."""
|
|
550
|
+
self.completer.refresh_files(root)
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
# ============================================================================
|
|
554
|
+
# CLI Integration Handler
|
|
555
|
+
# ============================================================================
|
|
556
|
+
|
|
557
|
+
class InteractiveTUIHandler:
|
|
558
|
+
"""
|
|
559
|
+
Handler for integrating Interactive TUI with PraisonAI CLI.
|
|
560
|
+
"""
|
|
561
|
+
|
|
562
|
+
def __init__(self, verbose: bool = False):
|
|
563
|
+
self.verbose = verbose
|
|
564
|
+
self._session: Optional[InteractiveSession] = None
|
|
565
|
+
|
|
566
|
+
@property
|
|
567
|
+
def feature_name(self) -> str:
|
|
568
|
+
return "interactive_tui"
|
|
569
|
+
|
|
570
|
+
def initialize(
|
|
571
|
+
self,
|
|
572
|
+
config: Optional[InteractiveConfig] = None,
|
|
573
|
+
on_input: Optional[Callable[[str], Optional[str]]] = None,
|
|
574
|
+
on_command: Optional[Callable[[str], Optional[Dict[str, Any]]]] = None
|
|
575
|
+
) -> InteractiveSession:
|
|
576
|
+
"""Initialize the interactive session."""
|
|
577
|
+
self._session = InteractiveSession(
|
|
578
|
+
config=config,
|
|
579
|
+
on_input=on_input,
|
|
580
|
+
on_command=on_command
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
if self.verbose:
|
|
584
|
+
from rich import print as rprint
|
|
585
|
+
rprint("[cyan]Interactive TUI initialized[/cyan]")
|
|
586
|
+
|
|
587
|
+
return self._session
|
|
588
|
+
|
|
589
|
+
def get_session(self) -> Optional[InteractiveSession]:
|
|
590
|
+
"""Get the current session."""
|
|
591
|
+
return self._session
|
|
592
|
+
|
|
593
|
+
def run(self) -> None:
|
|
594
|
+
"""Run the interactive session."""
|
|
595
|
+
if not self._session:
|
|
596
|
+
self._session = self.initialize()
|
|
597
|
+
|
|
598
|
+
self._session.run()
|
|
599
|
+
|
|
600
|
+
def stop(self) -> None:
|
|
601
|
+
"""Stop the interactive session."""
|
|
602
|
+
if self._session:
|
|
603
|
+
self._session.stop()
|