praisonai-code 0.0.38__tar.gz → 0.0.40__tar.gz
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-0.0.38 → praisonai_code-0.0.40}/PKG-INFO +1 -1
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/__init__.py +1 -1
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/command.py +69 -2
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/session_checkpoints.py +118 -1
- praisonai_code-0.0.40/praisonai_code/cli/interactive/command_registry.py +396 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/repl.py +50 -1
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code.egg-info/PKG-INFO +1 -1
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code.egg-info/SOURCES.txt +1 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/pyproject.toml +1 -1
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/README.md +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/__main__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/_bot_bridge.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/_framework_availability.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/_logging.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/_registry.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/_safe_loader.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/_version.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/_wrapper_bridge.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/_forward_shim.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/_paths.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/_warnings.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/_wrapper_reexport.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/app.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/approval_backend.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/branding.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/acp.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/agent.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/agents.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/attach.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/auth.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/benchmark.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/browser.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/call.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/chat.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/checkpoint.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/code.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/commit.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/completion.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/config.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/daemon.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/debug.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/deploy.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/diag.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/doctor.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/endpoints.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/environment.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/eval.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/github.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/hooks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/init.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/loop.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/lsp.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/memory.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/models.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/obs.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/package.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/paths.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/permissions.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/plugins.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/port.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/publish.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/registry.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/research.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/retrieval.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/rules.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/run.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/sandbox.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/serve.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/session.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/setup.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/skills.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/templates.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/test.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/todo.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/tools.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/traces.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/tracker.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/ui.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/up.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/version.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/commands/workflow.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/config_loader.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/configuration/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/configuration/config.schema.json +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/configuration/credentials.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/configuration/loader.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/configuration/model_resolver.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/configuration/oauth.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/configuration/paths.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/configuration/resolver.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/configuration/schema.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/execution/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/execution/core.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/execution/profiler.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/execution/request.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/execution/result.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/fallback_schema.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/_approval_bridge.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/_endpoint_registry.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/_search_registry.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/action_orchestrator.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/agents.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/at_mentions.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/audit_cli.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/auto_memory.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/auto_mode.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/autonomy_mode.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/base.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/benchmark.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/capabilities.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/checkpoints.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/cli_profiler.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/code_intelligence.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/compaction.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/compare.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/config_hierarchy.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/context_manager.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/cost_tracker.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/csv_test_runner.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/custom_definitions.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/debug.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/diag.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/display_jsonl.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/_wrapper_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/acp_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/bot_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/config_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/db_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/env_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/gateway_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/lsp_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/mcp_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/memory_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/network_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/obs_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/packaging_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/performance_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/permissions_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/runtime_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/selftest_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/serve_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/skills_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/checks/tools_checks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/engine.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/formatters.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/handler.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/models.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/doctor/registry.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/endpoints.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/examples.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/external_agents.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/fast_context.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/file_history.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/flow_display.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/git_attribution.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/git_integration.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/guardrail.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/handoff.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/hooks.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/hybrid_workflow.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/image.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/interactive_core_headless.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/interactive_runtime.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/interactive_test_harness.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/interactive_tools.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/interactive_tui.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/job_workflow.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/jobs.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/knowledge.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/knowledge_cli.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/lite.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/logs.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/lsp_cli.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/lsp_diagnostics.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/mcp.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/message_queue.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/metrics.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/migrate.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/migration_flow.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/migration_spec.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/n8n.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/observability.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/output_modes.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/output_style.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/package.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/performance.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/profiler/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/profiler/core.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/profiler/optimizations.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/profiler/suite.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/queue/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/queue/manager.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/queue/models.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/queue/persistence.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/queue/scheduler.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/queue/worker.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/recipe_creator.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/recipe_prompts.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/repo_map.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/router.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/safe_shell.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/sandbox_executor.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/sdk_knowledge.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/session.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/setup/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/setup/handler.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/setup/templates.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/skills.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/slash_commands.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/telemetry.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/thinking.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/todo.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tools.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/cli.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/config.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/debug.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/events.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/mock_provider.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/orchestrator.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/screens/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/screens/help.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/screens/main.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/screens/queue.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/screens/session.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/screens/settings.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/session_store.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/widgets/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/widgets/chat.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/widgets/command_popup.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/widgets/composer.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/widgets/file_popup.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/widgets/queue_panel.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/widgets/status.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/tui/widgets/tool_panel.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/wizard.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/workflow.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/yaml_utils.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/async_tui.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/config.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/core.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/events.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/frontends/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/frontends/rich_frontend.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/frontends/textual_frontend.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/praison_io.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/split_tui.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/interactive/tui_app.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/legacy/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/legacy/env_security.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/legacy/praison_ai.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/legacy/prompt_dispatch.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/main.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/output/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/output/console.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/output/event_bridge.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/schedule_cli.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/schema_provider.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/session/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/session/resume.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/session/unified.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/state/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/state/identifiers.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/state/project_sessions.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/state/sessions.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/ui/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/ui/config.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/ui/events.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/ui/mg_backend.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/ui/plain.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/ui/rich_backend.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/unified_schema.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/utils/env_utils.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/utils/project.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/utils/stdin.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli_backends/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli_backends/claude.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli_backends/registry.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/llm/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/llm/catalogue.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/llm/config.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/llm/credentials.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/llm/env.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/runtime/__init__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/runtime/__main__.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/runtime/client.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/runtime/descriptor.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/runtime/server.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/tool_registry.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/tool_resolver.py +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code.egg-info/dependency_links.txt +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code.egg-info/entry_points.txt +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code.egg-info/requires.txt +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code.egg-info/top_level.txt +0 -0
- {praisonai_code-0.0.38 → praisonai_code-0.0.40}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: praisonai-code
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.40
|
|
4
4
|
Summary: Agentic terminal CLI for PraisonAI — the terminal-native agent (run, chat, code, runtime, cli backends) extracted from the praisonai wrapper.
|
|
5
5
|
Author: Mervin Praison
|
|
6
6
|
License: MIT
|
|
@@ -16,10 +16,24 @@ app = typer.Typer(help="Manage custom commands")
|
|
|
16
16
|
@app.command(name="list")
|
|
17
17
|
def list_commands(
|
|
18
18
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed information"),
|
|
19
|
+
all_sources: bool = typer.Option(
|
|
20
|
+
False,
|
|
21
|
+
"--all",
|
|
22
|
+
"-a",
|
|
23
|
+
help="List the full interactive command namespace (built-ins, custom, skills, MCP)",
|
|
24
|
+
),
|
|
19
25
|
):
|
|
20
|
-
"""List all discovered custom commands.
|
|
26
|
+
"""List all discovered custom commands.
|
|
27
|
+
|
|
28
|
+
By default only custom ``.praisonai/commands/*.md`` commands are shown.
|
|
29
|
+
Pass ``--all`` to list the same unified namespace the interactive session
|
|
30
|
+
resolves ``/name`` from, so listing and invocation cannot drift.
|
|
31
|
+
"""
|
|
21
32
|
output = get_output_controller()
|
|
22
|
-
|
|
33
|
+
|
|
34
|
+
if all_sources:
|
|
35
|
+
return _list_registry(output)
|
|
36
|
+
|
|
23
37
|
try:
|
|
24
38
|
from praisonai_code.cli.features.custom_definitions import CustomDefinitionsDiscovery
|
|
25
39
|
|
|
@@ -109,6 +123,59 @@ def show(
|
|
|
109
123
|
syntax = Syntax(preview_text, "markdown", theme="monokai", line_numbers=False)
|
|
110
124
|
console.print(Panel(syntax, title=f"Preview with args: '{sample_args}'", border_style="yellow"))
|
|
111
125
|
|
|
126
|
+
except Exception as e:
|
|
127
|
+
output.print_error(str(e))
|
|
128
|
+
raise typer.Exit(1)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _list_registry(output) -> None:
|
|
132
|
+
"""List the full unified command namespace via ``CommandRegistry``.
|
|
133
|
+
|
|
134
|
+
This is the same registry every interactive surface drives ``/name``
|
|
135
|
+
resolution and ``/help`` from, so what is listed here is exactly what can
|
|
136
|
+
be invoked interactively.
|
|
137
|
+
"""
|
|
138
|
+
try:
|
|
139
|
+
from praisonai_code.cli.interactive.command_registry import (
|
|
140
|
+
create_default_registry,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
from praisonai_code.cli.interactive.repl import DEFAULT_COMMANDS as builtins
|
|
145
|
+
except Exception: # pragma: no cover - defensive
|
|
146
|
+
builtins = None
|
|
147
|
+
|
|
148
|
+
registry = create_default_registry(
|
|
149
|
+
builtins,
|
|
150
|
+
include_custom=True,
|
|
151
|
+
include_skills=True,
|
|
152
|
+
)
|
|
153
|
+
commands = registry.list_commands()
|
|
154
|
+
|
|
155
|
+
if not commands:
|
|
156
|
+
output.print_info("No commands found.")
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
from rich.console import Console
|
|
160
|
+
from rich.table import Table
|
|
161
|
+
|
|
162
|
+
console = Console()
|
|
163
|
+
table = Table(title="Commands", show_header=True)
|
|
164
|
+
table.add_column("Name", style="cyan")
|
|
165
|
+
table.add_column("Kind", style="magenta")
|
|
166
|
+
table.add_column("Source", style="yellow")
|
|
167
|
+
table.add_column("Description", style="green")
|
|
168
|
+
|
|
169
|
+
for cmd in commands:
|
|
170
|
+
table.add_row(
|
|
171
|
+
cmd.name,
|
|
172
|
+
cmd.kind.value,
|
|
173
|
+
cmd.source,
|
|
174
|
+
cmd.description or "No description",
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
console.print(table)
|
|
178
|
+
|
|
112
179
|
except Exception as e:
|
|
113
180
|
output.print_error(str(e))
|
|
114
181
|
raise typer.Exit(1)
|
{praisonai_code-0.0.38 → praisonai_code-0.0.40}/praisonai_code/cli/features/session_checkpoints.py
RENAMED
|
@@ -33,6 +33,11 @@ class _Turn:
|
|
|
33
33
|
checkpoint_id: str
|
|
34
34
|
short_id: str
|
|
35
35
|
message: str
|
|
36
|
+
# Number of conversation messages captured at turn start. Used to rewind
|
|
37
|
+
# the conversation store to the same boundary as the file checkpoint so
|
|
38
|
+
# files and history stay coherent after an undo. ``None`` when no
|
|
39
|
+
# conversation store is wired in (legacy / file-only sessions).
|
|
40
|
+
message_count: Optional[int] = None
|
|
36
41
|
|
|
37
42
|
|
|
38
43
|
@dataclass
|
|
@@ -54,6 +59,12 @@ class SessionCheckpointManager:
|
|
|
54
59
|
enabled: bool = False
|
|
55
60
|
verbose: bool = False
|
|
56
61
|
storage_dir: Optional[str] = None
|
|
62
|
+
# Optional conversation store + session id. When both are set, a revert
|
|
63
|
+
# rewinds the conversation history to the same turn boundary as the file
|
|
64
|
+
# checkpoint, keeping files and chat_history coherent. Left unset for
|
|
65
|
+
# file-only / legacy sessions, which keeps existing behaviour unchanged.
|
|
66
|
+
session_store: Optional[object] = None
|
|
67
|
+
session_id: Optional[str] = None
|
|
57
68
|
_handler: Optional[object] = field(default=None, repr=False)
|
|
58
69
|
_turns: List[_Turn] = field(default_factory=list)
|
|
59
70
|
_turn_counter: int = 0
|
|
@@ -65,6 +76,8 @@ class SessionCheckpointManager:
|
|
|
65
76
|
workspace_dir: Optional[str] = None,
|
|
66
77
|
config: Optional[dict] = None,
|
|
67
78
|
verbose: bool = False,
|
|
79
|
+
session_store: Optional[object] = None,
|
|
80
|
+
session_id: Optional[str] = None,
|
|
68
81
|
) -> "SessionCheckpointManager":
|
|
69
82
|
"""
|
|
70
83
|
Build a manager from a resolved ``checkpoints`` config section.
|
|
@@ -90,6 +103,8 @@ class SessionCheckpointManager:
|
|
|
90
103
|
enabled=enabled,
|
|
91
104
|
verbose=verbose,
|
|
92
105
|
storage_dir=storage_dir,
|
|
106
|
+
session_store=session_store,
|
|
107
|
+
session_id=session_id,
|
|
93
108
|
)
|
|
94
109
|
|
|
95
110
|
def _get_handler(self):
|
|
@@ -121,6 +136,68 @@ class SessionCheckpointManager:
|
|
|
121
136
|
def turns(self) -> List[_Turn]:
|
|
122
137
|
return list(self._turns)
|
|
123
138
|
|
|
139
|
+
def _conversation_message_count(self) -> Optional[int]:
|
|
140
|
+
"""
|
|
141
|
+
Best-effort count of messages currently in the conversation store.
|
|
142
|
+
|
|
143
|
+
Returns ``None`` when no conversation store is wired in or the count
|
|
144
|
+
cannot be determined, so callers can skip conversation bookkeeping and
|
|
145
|
+
preserve the previous file-only behaviour.
|
|
146
|
+
"""
|
|
147
|
+
store = self.session_store
|
|
148
|
+
if store is None or not self.session_id:
|
|
149
|
+
return None
|
|
150
|
+
try:
|
|
151
|
+
getter = getattr(store, "get_messages", None)
|
|
152
|
+
if callable(getter):
|
|
153
|
+
messages = getter(self.session_id)
|
|
154
|
+
if messages is not None:
|
|
155
|
+
return len(messages)
|
|
156
|
+
session = getattr(store, "get_extended_session", None)
|
|
157
|
+
if callable(session):
|
|
158
|
+
data = session(self.session_id)
|
|
159
|
+
msgs = getattr(data, "messages", None)
|
|
160
|
+
if msgs is not None:
|
|
161
|
+
return len(msgs)
|
|
162
|
+
except Exception:
|
|
163
|
+
pass
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
def _rewind_conversation(self, message_count: Optional[int]) -> None:
|
|
167
|
+
"""
|
|
168
|
+
Rewind the conversation store to ``message_count`` messages.
|
|
169
|
+
|
|
170
|
+
Uses the core ``revert_to_message`` primitive so that undoing a turn
|
|
171
|
+
drops the assistant/tool messages produced by the reverted turn(s),
|
|
172
|
+
keeping ``chat_history`` consistent with the restored files. Best-effort
|
|
173
|
+
and non-raising: a conversation-revert failure must not corrupt the
|
|
174
|
+
already-restored workspace.
|
|
175
|
+
"""
|
|
176
|
+
store = self.session_store
|
|
177
|
+
if store is None or not self.session_id or message_count is None:
|
|
178
|
+
return
|
|
179
|
+
try:
|
|
180
|
+
if message_count <= 0:
|
|
181
|
+
# Keep nothing. The core ``revert_to_message`` contract keeps
|
|
182
|
+
# ``messages[:index + 1]`` and rejects out-of-range indices, so
|
|
183
|
+
# there is no index that clears to empty (index 0 would leave a
|
|
184
|
+
# stale first message). Clear explicitly where the store exposes
|
|
185
|
+
# a primitive; otherwise no-op safely rather than leaving a ghost
|
|
186
|
+
# message behind.
|
|
187
|
+
for name in ("clear_messages", "clear_history", "clear"):
|
|
188
|
+
clear = getattr(store, name, None)
|
|
189
|
+
if callable(clear):
|
|
190
|
+
clear(self.session_id)
|
|
191
|
+
return
|
|
192
|
+
return
|
|
193
|
+
revert = getattr(store, "revert_to_message", None)
|
|
194
|
+
if callable(revert):
|
|
195
|
+
# revert_to_message keeps messages[:index + 1]; to keep
|
|
196
|
+
# ``message_count`` messages we target the last kept index.
|
|
197
|
+
revert(self.session_id, message_count - 1)
|
|
198
|
+
except Exception:
|
|
199
|
+
pass
|
|
200
|
+
|
|
124
201
|
def checkpoint_turn(self, message: str) -> Optional[str]:
|
|
125
202
|
"""
|
|
126
203
|
Save a checkpoint for the upcoming turn and record it on the timeline.
|
|
@@ -144,6 +221,10 @@ class SessionCheckpointManager:
|
|
|
144
221
|
result = await service.save(label, allow_empty=True)
|
|
145
222
|
return result
|
|
146
223
|
|
|
224
|
+
# Capture the conversation boundary *before* the turn runs so a
|
|
225
|
+
# later revert rewinds history to exactly this point.
|
|
226
|
+
message_count = self._conversation_message_count()
|
|
227
|
+
|
|
147
228
|
result = self._run(_save())
|
|
148
229
|
if result and getattr(result, "success", False):
|
|
149
230
|
cp = result.checkpoint
|
|
@@ -153,6 +234,7 @@ class SessionCheckpointManager:
|
|
|
153
234
|
checkpoint_id=cp.id,
|
|
154
235
|
short_id=cp.short_id,
|
|
155
236
|
message=label,
|
|
237
|
+
message_count=message_count,
|
|
156
238
|
)
|
|
157
239
|
)
|
|
158
240
|
self._initialized = True
|
|
@@ -181,6 +263,11 @@ class SessionCheckpointManager:
|
|
|
181
263
|
handler = self._get_handler()
|
|
182
264
|
ok = self._run(handler.restore(target.checkpoint_id))
|
|
183
265
|
if ok:
|
|
266
|
+
# Files are restored; now rewind the conversation history to the
|
|
267
|
+
# same turn boundary so the agent's chat_history no longer
|
|
268
|
+
# references the edits that were just undone. Best-effort: a
|
|
269
|
+
# conversation-revert failure leaves the restored files intact.
|
|
270
|
+
self._rewind_conversation(target.message_count)
|
|
184
271
|
# The workspace now matches `target`'s checkpoint. Drop the
|
|
185
272
|
# restored turn *and* every turn above it from the timeline so
|
|
186
273
|
# the next /undo walks further back instead of restoring the
|
|
@@ -192,8 +279,29 @@ class SessionCheckpointManager:
|
|
|
192
279
|
pass
|
|
193
280
|
return None
|
|
194
281
|
|
|
282
|
+
def dropped_message_count(self, n: int = 1) -> Optional[int]:
|
|
283
|
+
"""
|
|
284
|
+
How many conversation messages ``revert(n)`` would drop.
|
|
285
|
+
|
|
286
|
+
Returns ``None`` when no conversation store is wired in or the boundary
|
|
287
|
+
was not captured, so callers can present a file-only preview unchanged.
|
|
288
|
+
"""
|
|
289
|
+
if not self.enabled or not self._turns:
|
|
290
|
+
return None
|
|
291
|
+
if n < 1:
|
|
292
|
+
n = 1
|
|
293
|
+
if n > len(self._turns):
|
|
294
|
+
return None
|
|
295
|
+
target = self._turns[-n]
|
|
296
|
+
if target.message_count is None:
|
|
297
|
+
return None
|
|
298
|
+
current = self._conversation_message_count()
|
|
299
|
+
if current is None:
|
|
300
|
+
return None
|
|
301
|
+
return max(0, current - target.message_count)
|
|
302
|
+
|
|
195
303
|
def preview(self, n: int = 1) -> None:
|
|
196
|
-
"""Print the diff that ``revert(n)`` would undo
|
|
304
|
+
"""Print the diff and conversation rollback that ``revert(n)`` would undo."""
|
|
197
305
|
if not self.enabled or not self._turns:
|
|
198
306
|
return
|
|
199
307
|
if n < 1:
|
|
@@ -206,3 +314,12 @@ class SessionCheckpointManager:
|
|
|
206
314
|
self._run(handler.diff(target.checkpoint_id, None))
|
|
207
315
|
except Exception:
|
|
208
316
|
pass
|
|
317
|
+
try:
|
|
318
|
+
dropped = self.dropped_message_count(n)
|
|
319
|
+
if dropped:
|
|
320
|
+
print(
|
|
321
|
+
f"This will also drop {dropped} conversation "
|
|
322
|
+
f"message(s) to keep history in sync with the files."
|
|
323
|
+
)
|
|
324
|
+
except Exception:
|
|
325
|
+
pass
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unified command registry for interactive slash commands.
|
|
3
|
+
|
|
4
|
+
This module aggregates invocable commands from several pluggable sources into
|
|
5
|
+
one namespace so every interactive surface (async TUI, REPL, and future
|
|
6
|
+
frontends) resolves ``/name``, ``/help``, and autocomplete from the same place.
|
|
7
|
+
|
|
8
|
+
Sources (later sources override earlier ones on name collision):
|
|
9
|
+
|
|
10
|
+
1. Built-in commands (registered by each interactive surface).
|
|
11
|
+
2. User/project custom commands discovered from ``.praisonai/commands/*.md``
|
|
12
|
+
via :class:`CustomDefinitionsDiscovery` — the exact same commands that
|
|
13
|
+
``praisonai run --command <name>`` executes.
|
|
14
|
+
3. Skills (``praisonaiagents.skills``) — optional, discovered lazily.
|
|
15
|
+
4. MCP server prompts — optional, discovered lazily.
|
|
16
|
+
5. Third-party sources registered via the ``praisonai.commands`` entry-point
|
|
17
|
+
group, mirroring the existing ``praisonai.tool_sources`` extensibility.
|
|
18
|
+
|
|
19
|
+
The registry is intentionally lightweight: it only *describes* commands.
|
|
20
|
+
Execution of custom commands reuses the shared ``interpolate_command_template``
|
|
21
|
+
path so interactive and CLI invocation are byte-for-byte identical.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import logging
|
|
27
|
+
from dataclasses import dataclass, field
|
|
28
|
+
from enum import Enum
|
|
29
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CommandKind(str, Enum):
|
|
35
|
+
"""Origin of a command, used for help grouping and behaviour."""
|
|
36
|
+
|
|
37
|
+
BUILTIN = "builtin"
|
|
38
|
+
CUSTOM = "custom"
|
|
39
|
+
SKILL = "skill"
|
|
40
|
+
MCP = "mcp"
|
|
41
|
+
PLUGIN = "plugin"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class Command:
|
|
46
|
+
"""A single invocable slash command descriptor.
|
|
47
|
+
|
|
48
|
+
Attributes:
|
|
49
|
+
name: Primary invocation name (without the leading ``/``).
|
|
50
|
+
description: Short one-line help text.
|
|
51
|
+
kind: Where the command came from.
|
|
52
|
+
source: Free-form origin label (``user``/``project``/``builtin``/...).
|
|
53
|
+
handler: Optional callable that performs the command. Built-in surfaces
|
|
54
|
+
usually leave this ``None`` and dispatch via their own branches;
|
|
55
|
+
custom/skill/mcp commands carry a handler that returns the prompt
|
|
56
|
+
text (or performs the action) when invoked.
|
|
57
|
+
aliases: Alternative names that resolve to this command.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
name: str
|
|
61
|
+
description: str = ""
|
|
62
|
+
kind: CommandKind = CommandKind.BUILTIN
|
|
63
|
+
source: str = "builtin"
|
|
64
|
+
handler: Optional[Callable[[str], Any]] = None
|
|
65
|
+
aliases: List[str] = field(default_factory=list)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class CommandSourceProtocol:
|
|
69
|
+
"""Structural protocol for a command source.
|
|
70
|
+
|
|
71
|
+
A source yields :class:`Command` descriptors. Any object exposing a
|
|
72
|
+
``discover() -> List[Command]`` method is a valid source; using a plain
|
|
73
|
+
base class (rather than ``typing.Protocol``) keeps runtime ``isinstance``
|
|
74
|
+
checks cheap and avoids importing ``typing_extensions`` on older Pythons.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def discover(self) -> List[Command]: # pragma: no cover - interface
|
|
78
|
+
raise NotImplementedError
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class BuiltinCommandSource:
|
|
82
|
+
"""Wraps a static mapping of built-in commands into a source.
|
|
83
|
+
|
|
84
|
+
Interactive surfaces pass their existing hard-coded ``{name: description}``
|
|
85
|
+
help mapping here so the built-ins become first-class registry entries with
|
|
86
|
+
no behaviour change (the surface still dispatches them via its own
|
|
87
|
+
branches; the registry only powers help/autocomplete/collision handling).
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def __init__(self, commands: Dict[str, str]):
|
|
91
|
+
self._commands = dict(commands)
|
|
92
|
+
|
|
93
|
+
def discover(self) -> List[Command]:
|
|
94
|
+
return [
|
|
95
|
+
Command(
|
|
96
|
+
name=name,
|
|
97
|
+
description=description,
|
|
98
|
+
kind=CommandKind.BUILTIN,
|
|
99
|
+
source="builtin",
|
|
100
|
+
)
|
|
101
|
+
for name, description in self._commands.items()
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class CustomCommandSource:
|
|
106
|
+
"""Source backed by ``.praisonai/commands/*.md`` custom command files.
|
|
107
|
+
|
|
108
|
+
Reuses :class:`CustomDefinitionsDiscovery` (the same discovery that powers
|
|
109
|
+
``praisonai run --command``) so interactive ``/name`` invocation stays in
|
|
110
|
+
lock-step with the CLI. Each command's handler interpolates the template
|
|
111
|
+
via the shared ``interpolate_command_template`` helper.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def discover(self) -> List[Command]:
|
|
115
|
+
try:
|
|
116
|
+
from ..features.custom_definitions import (
|
|
117
|
+
CustomDefinitionsDiscovery,
|
|
118
|
+
interpolate_command_template,
|
|
119
|
+
)
|
|
120
|
+
except ImportError: # pragma: no cover - defensive
|
|
121
|
+
return []
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
discovery = CustomDefinitionsDiscovery()
|
|
125
|
+
discovery.discover()
|
|
126
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
127
|
+
logger.warning("Custom command discovery failed: %s", exc)
|
|
128
|
+
return []
|
|
129
|
+
|
|
130
|
+
commands: List[Command] = []
|
|
131
|
+
for cmd in discovery.list_commands():
|
|
132
|
+
def make_handler(cmd_name: str) -> Callable[[str], Optional[str]]:
|
|
133
|
+
def handler(args: str) -> Optional[str]:
|
|
134
|
+
return interpolate_command_template(cmd_name, args)
|
|
135
|
+
|
|
136
|
+
return handler
|
|
137
|
+
|
|
138
|
+
commands.append(
|
|
139
|
+
Command(
|
|
140
|
+
name=cmd.name,
|
|
141
|
+
description=cmd.description
|
|
142
|
+
or f"Custom command from {cmd.source}",
|
|
143
|
+
kind=CommandKind.CUSTOM,
|
|
144
|
+
source=cmd.source,
|
|
145
|
+
handler=make_handler(cmd.name),
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
return commands
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class SkillCommandSource:
|
|
152
|
+
"""Optional source exposing discovered skills as invocable commands.
|
|
153
|
+
|
|
154
|
+
Skills live in the core SDK (``praisonaiagents.skills``); this source only
|
|
155
|
+
*consumes* them. It fails silently (returns ``[]``) when the skills module
|
|
156
|
+
or any project skills are unavailable, so it never adds import cost or
|
|
157
|
+
breaks surfaces that do not use skills.
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
def discover(self) -> List[Command]:
|
|
161
|
+
try:
|
|
162
|
+
from praisonaiagents.skills.discovery import discover_skills
|
|
163
|
+
except Exception:
|
|
164
|
+
return []
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
skills = discover_skills()
|
|
168
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
169
|
+
logger.debug("Skill discovery unavailable: %s", exc)
|
|
170
|
+
return []
|
|
171
|
+
|
|
172
|
+
commands: List[Command] = []
|
|
173
|
+
for skill in skills or []:
|
|
174
|
+
name = getattr(skill, "name", None)
|
|
175
|
+
if not name:
|
|
176
|
+
continue
|
|
177
|
+
commands.append(
|
|
178
|
+
Command(
|
|
179
|
+
name=str(name),
|
|
180
|
+
description=getattr(skill, "description", "") or "Skill",
|
|
181
|
+
kind=CommandKind.SKILL,
|
|
182
|
+
source="skill",
|
|
183
|
+
)
|
|
184
|
+
)
|
|
185
|
+
return commands
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class MCPPromptCommandSource:
|
|
189
|
+
"""Optional source exposing MCP server prompts as invocable commands.
|
|
190
|
+
|
|
191
|
+
MCP is a core protocol; this source consumes prompts exposed by configured
|
|
192
|
+
MCP servers. It is best-effort and lazy: any failure yields ``[]`` so the
|
|
193
|
+
registry degrades gracefully when MCP is not configured or installed.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
def __init__(self, prompts: Optional[List[Any]] = None):
|
|
197
|
+
self._prompts = prompts
|
|
198
|
+
|
|
199
|
+
def discover(self) -> List[Command]:
|
|
200
|
+
prompts = self._prompts
|
|
201
|
+
if prompts is None:
|
|
202
|
+
return []
|
|
203
|
+
|
|
204
|
+
commands: List[Command] = []
|
|
205
|
+
for prompt in prompts:
|
|
206
|
+
name = getattr(prompt, "name", None) or (
|
|
207
|
+
prompt.get("name") if isinstance(prompt, dict) else None
|
|
208
|
+
)
|
|
209
|
+
if not name:
|
|
210
|
+
continue
|
|
211
|
+
description = getattr(prompt, "description", None) or (
|
|
212
|
+
prompt.get("description") if isinstance(prompt, dict) else ""
|
|
213
|
+
)
|
|
214
|
+
commands.append(
|
|
215
|
+
Command(
|
|
216
|
+
name=str(name),
|
|
217
|
+
description=description or "MCP prompt",
|
|
218
|
+
kind=CommandKind.MCP,
|
|
219
|
+
source="mcp",
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
return commands
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# Entry-point group third parties use to contribute command sources, mirroring
|
|
226
|
+
# the existing ``praisonai.tool_sources`` extensibility for tools.
|
|
227
|
+
ENTRY_POINT_GROUP = "praisonai.commands"
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _discover_entry_point_sources() -> List[Any]:
|
|
231
|
+
"""Load command sources registered via the ``praisonai.commands`` group.
|
|
232
|
+
|
|
233
|
+
Each entry point may resolve to either a source instance or a
|
|
234
|
+
zero-argument callable/class returning a source. Failures are logged and
|
|
235
|
+
skipped so a broken third-party plugin never takes down the registry.
|
|
236
|
+
"""
|
|
237
|
+
sources: List[Any] = []
|
|
238
|
+
try:
|
|
239
|
+
from importlib.metadata import entry_points
|
|
240
|
+
except Exception: # pragma: no cover - very old Pythons
|
|
241
|
+
return sources
|
|
242
|
+
|
|
243
|
+
try:
|
|
244
|
+
eps = entry_points()
|
|
245
|
+
# Python 3.10+ returns a SelectableGroups object.
|
|
246
|
+
if hasattr(eps, "select"):
|
|
247
|
+
group = eps.select(group=ENTRY_POINT_GROUP)
|
|
248
|
+
else: # pragma: no cover - legacy mapping API
|
|
249
|
+
group = eps.get(ENTRY_POINT_GROUP, [])
|
|
250
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
251
|
+
logger.debug("Entry-point command discovery failed: %s", exc)
|
|
252
|
+
return sources
|
|
253
|
+
|
|
254
|
+
for ep in group:
|
|
255
|
+
try:
|
|
256
|
+
obj = ep.load()
|
|
257
|
+
source = obj() if callable(obj) else obj
|
|
258
|
+
if hasattr(source, "discover"):
|
|
259
|
+
sources.append(source)
|
|
260
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
261
|
+
logger.warning("Failed to load command source %r: %s", ep, exc)
|
|
262
|
+
return sources
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class CommandRegistry:
|
|
266
|
+
"""Aggregates command sources into a single ``/name`` namespace.
|
|
267
|
+
|
|
268
|
+
Later sources override earlier ones on name collision, matching the
|
|
269
|
+
user/project override semantics of :class:`CustomDefinitionsDiscovery`.
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
def __init__(
|
|
273
|
+
self,
|
|
274
|
+
sources: Optional[List[Any]] = None,
|
|
275
|
+
*,
|
|
276
|
+
discover_entry_points: bool = True,
|
|
277
|
+
):
|
|
278
|
+
self._sources: List[Any] = list(sources or [])
|
|
279
|
+
self._discover_entry_points = discover_entry_points
|
|
280
|
+
self._commands: Dict[str, Command] = {}
|
|
281
|
+
self._aliases: Dict[str, str] = {}
|
|
282
|
+
self._discovered = False
|
|
283
|
+
|
|
284
|
+
def add_source(self, source: Any) -> None:
|
|
285
|
+
"""Append a command source (invalidates the discovery cache)."""
|
|
286
|
+
self._sources.append(source)
|
|
287
|
+
self._discovered = False
|
|
288
|
+
|
|
289
|
+
def discover(self, force: bool = False) -> Dict[str, Command]:
|
|
290
|
+
"""Resolve all sources into ``{name: Command}`` (cached)."""
|
|
291
|
+
if self._discovered and not force:
|
|
292
|
+
return self._commands
|
|
293
|
+
|
|
294
|
+
self._commands.clear()
|
|
295
|
+
self._aliases.clear()
|
|
296
|
+
|
|
297
|
+
sources = list(self._sources)
|
|
298
|
+
if self._discover_entry_points:
|
|
299
|
+
sources.extend(_discover_entry_point_sources())
|
|
300
|
+
|
|
301
|
+
for source in sources:
|
|
302
|
+
try:
|
|
303
|
+
for command in source.discover():
|
|
304
|
+
existing = self._commands.get(command.name)
|
|
305
|
+
# Built-in commands are dispatched by the interactive
|
|
306
|
+
# surface's own branches, which fire *before* the registry
|
|
307
|
+
# is consulted. A later (custom/skill/mcp) source that
|
|
308
|
+
# reuses a built-in name would therefore be registered but
|
|
309
|
+
# never actually execute. Keep the built-in so listing and
|
|
310
|
+
# runtime behaviour stay consistent, and warn about the
|
|
311
|
+
# shadowed definition rather than silently dropping it.
|
|
312
|
+
if (
|
|
313
|
+
existing is not None
|
|
314
|
+
and existing.kind is CommandKind.BUILTIN
|
|
315
|
+
and command.kind is not CommandKind.BUILTIN
|
|
316
|
+
):
|
|
317
|
+
logger.warning(
|
|
318
|
+
"Command /%s from %s is shadowed by a built-in "
|
|
319
|
+
"command and will not be invoked interactively.",
|
|
320
|
+
command.name,
|
|
321
|
+
command.source,
|
|
322
|
+
)
|
|
323
|
+
continue
|
|
324
|
+
self._commands[command.name] = command
|
|
325
|
+
for alias in command.aliases:
|
|
326
|
+
self._aliases[alias] = command.name
|
|
327
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
328
|
+
logger.warning("Command source %r failed: %s", source, exc)
|
|
329
|
+
|
|
330
|
+
self._discovered = True
|
|
331
|
+
return self._commands
|
|
332
|
+
|
|
333
|
+
def get(self, name: str) -> Optional[Command]:
|
|
334
|
+
"""Look up a command by name or alias."""
|
|
335
|
+
self.discover()
|
|
336
|
+
if name in self._commands:
|
|
337
|
+
return self._commands[name]
|
|
338
|
+
primary = self._aliases.get(name)
|
|
339
|
+
if primary:
|
|
340
|
+
return self._commands.get(primary)
|
|
341
|
+
return None
|
|
342
|
+
|
|
343
|
+
def has(self, name: str) -> bool:
|
|
344
|
+
"""Return True if ``name`` resolves to a command."""
|
|
345
|
+
return self.get(name) is not None
|
|
346
|
+
|
|
347
|
+
def list_commands(self) -> List[Command]:
|
|
348
|
+
"""Return all commands sorted by name."""
|
|
349
|
+
self.discover()
|
|
350
|
+
return sorted(self._commands.values(), key=lambda c: c.name)
|
|
351
|
+
|
|
352
|
+
def names(self) -> List[str]:
|
|
353
|
+
"""Return all command names and aliases, sorted."""
|
|
354
|
+
self.discover()
|
|
355
|
+
return sorted(set(self._commands) | set(self._aliases))
|
|
356
|
+
|
|
357
|
+
def completions(self, partial: str) -> List[str]:
|
|
358
|
+
"""Return ``/name`` completions for a partial ``/`` input."""
|
|
359
|
+
if not partial.startswith("/"):
|
|
360
|
+
return []
|
|
361
|
+
stub = partial[1:].lower()
|
|
362
|
+
return sorted(
|
|
363
|
+
f"/{name}" for name in self.names() if name.lower().startswith(stub)
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def create_default_registry(
|
|
368
|
+
builtins: Optional[Dict[str, str]] = None,
|
|
369
|
+
*,
|
|
370
|
+
include_custom: bool = True,
|
|
371
|
+
include_skills: bool = False,
|
|
372
|
+
include_mcp: bool = False,
|
|
373
|
+
mcp_prompts: Optional[List[Any]] = None,
|
|
374
|
+
discover_entry_points: bool = True,
|
|
375
|
+
) -> CommandRegistry:
|
|
376
|
+
"""Build a registry wired with the standard sources.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
builtins: Optional ``{name: description}`` mapping of a surface's
|
|
380
|
+
built-in commands, registered first (lowest precedence).
|
|
381
|
+
include_custom: Register the ``.praisonai/commands/*.md`` source.
|
|
382
|
+
include_skills: Register the (optional) skills source.
|
|
383
|
+
include_mcp: Register the (optional) MCP prompt source.
|
|
384
|
+
mcp_prompts: Pre-resolved MCP prompts to expose (avoids a live probe).
|
|
385
|
+
discover_entry_points: Scan the ``praisonai.commands`` entry-point group.
|
|
386
|
+
"""
|
|
387
|
+
sources: List[Any] = []
|
|
388
|
+
if builtins:
|
|
389
|
+
sources.append(BuiltinCommandSource(builtins))
|
|
390
|
+
if include_custom:
|
|
391
|
+
sources.append(CustomCommandSource())
|
|
392
|
+
if include_skills:
|
|
393
|
+
sources.append(SkillCommandSource())
|
|
394
|
+
if include_mcp:
|
|
395
|
+
sources.append(MCPPromptCommandSource(mcp_prompts))
|
|
396
|
+
return CommandRegistry(sources, discover_entry_points=discover_entry_points)
|