praisonai-code 0.0.53__tar.gz → 0.0.55__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.53 → praisonai_code-0.0.55}/PKG-INFO +1 -1
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/__init__.py +1 -1
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/app.py +46 -30
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/__init__.py +4 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/run.py +276 -82
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/session.py +12 -3
- praisonai_code-0.0.55/praisonai_code/cli/commands/usage.py +235 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/configuration/loader.py +13 -6
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/configuration/model_resolver.py +25 -1
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/configuration/paths.py +72 -8
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/code_intelligence.py +92 -28
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/interactive_tools.py +80 -17
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/setup/handler.py +8 -2
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/widgets/tool_panel.py +2 -1
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/events.py +62 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/frontends/rich_frontend.py +30 -1
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/frontends/textual_frontend.py +31 -6
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/legacy/praison_ai.py +10 -10
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/state/project_sessions.py +33 -32
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/state/session_resolver.py +7 -16
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli_backends/__init__.py +22 -4
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/llm/__init__.py +5 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/llm/credentials.py +14 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/llm/env.py +17 -0
- praisonai_code-0.0.55/praisonai_code/llm/local_detect.py +160 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code.egg-info/PKG-INFO +1 -1
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code.egg-info/SOURCES.txt +2 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/pyproject.toml +1 -1
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/README.md +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/__main__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_bot_bridge.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_browser_bridge.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_framework_availability.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_logging.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_mcp_bridge.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_registry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_safe_loader.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_train_bridge.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_version.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/_wrapper_bridge.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/_forward_shim.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/_paths.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/_warnings.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/_wrapper_reexport.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/approval_backend.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/branding.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/acp.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/agent.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/agents.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/attach.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/auth.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/benchmark.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/browser_tool.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/call.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/chat.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/checkpoint.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/code.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/command.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/commit.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/completion.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/config.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/daemon.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/debug.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/deploy.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/diag.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/doctor.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/endpoints.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/environment.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/eval.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/github.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/hooks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/init.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/loop.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/lsp.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/memory.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/models.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/obs.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/package.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/paths.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/permissions.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/plugins.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/port.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/publish.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/registry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/research.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/retrieval.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/rules.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/sandbox.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/serve.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/setup.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/skills.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/templates.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/test.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/todo.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/tools.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/traces.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/tracker.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/ui.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/uninstall.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/up.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/upgrade.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/version.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/commands/workflow.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/config_loader.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/configuration/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/configuration/config.schema.json +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/configuration/credentials.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/configuration/oauth.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/configuration/resolver.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/configuration/schema.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/execution/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/execution/core.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/execution/profiler.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/execution/request.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/execution/result.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/fallback_schema.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/_approval_bridge.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/_endpoint_registry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/_search_registry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/action_orchestrator.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/agents.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/at_mentions.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/audit_cli.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/auto_memory.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/auto_mode.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/autonomy_mode.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/base.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/benchmark.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/capabilities.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/checkpoints.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/cli_profiler.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/compaction.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/compare.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/config_hierarchy.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/context_manager.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/cost_tracker.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/csv_test_runner.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/custom_definitions.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/debug.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/diag.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/display_jsonl.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/_wrapper_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/acp_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/bot_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/config_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/db_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/env_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/gateway_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/lsp_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/mcp_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/memory_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/network_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/obs_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/packaging_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/performance_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/permissions_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/runtime_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/selftest_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/serve_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/skills_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/checks/tools_checks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/engine.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/formatters.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/handler.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/models.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/doctor/registry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/endpoints.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/examples.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/external_agents.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/fast_context.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/file_history.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/flow_display.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/git_attribution.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/git_integration.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/guardrail.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/handoff.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/hooks.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/hybrid_workflow.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/image.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/interactive_core_headless.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/interactive_runtime.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/interactive_test_harness.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/interactive_tui.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/job_workflow.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/jobs.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/knowledge.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/knowledge_cli.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/lite.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/logs.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/lsp_cli.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/lsp_diagnostics.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/mcp.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/message_queue.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/metrics.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/migrate.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/migration_flow.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/migration_spec.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/n8n.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/observability.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/output_modes.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/output_style.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/package.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/performance.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/profiler/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/profiler/core.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/profiler/optimizations.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/profiler/suite.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/queue/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/queue/manager.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/queue/models.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/queue/persistence.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/queue/scheduler.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/queue/worker.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/recipe_creator.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/recipe_prompts.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/registry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/repo_map.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/router.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/safe_shell.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/sandbox_executor.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/sdk_knowledge.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/self_manage.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/session.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/session_checkpoints.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/setup/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/setup/templates.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/skills.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/slash_commands.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/telemetry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/thinking.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/todo.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tools.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/cli.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/config.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/debug.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/events.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/mock_provider.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/orchestrator.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/screens/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/screens/help.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/screens/main.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/screens/queue.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/screens/session.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/screens/settings.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/session_store.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/widgets/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/widgets/chat.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/widgets/command_popup.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/widgets/composer.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/widgets/file_popup.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/widgets/queue_panel.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/tui/widgets/status.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/wizard.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/workflow.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/features/yaml_utils.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/help_categories.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/async_tui.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/command_registry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/config.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/core.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/frontends/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/praison_io.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/repl.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/split_tui.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/interactive/tui_app.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/legacy/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/legacy/env_security.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/legacy/prompt_dispatch.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/main.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/output/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/output/console.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/output/event_bridge.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/schedule_cli.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/schema_provider.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/session/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/session/resume.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/session/unified.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/state/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/state/identifiers.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/state/sessions.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/ui/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/ui/config.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/ui/events.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/ui/mg_backend.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/ui/plain.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/ui/rich_backend.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/unified_schema.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/utils/env_utils.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/utils/project.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli/utils/stdin.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli_backends/claude.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/cli_backends/registry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/data/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/data/fixtures/interactive/multi_agent.csv +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/data/fixtures/interactive/refactor.csv +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/data/fixtures/interactive/smoke.csv +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/data/fixtures/interactive/tools.csv +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/llm/catalogue.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/llm/config.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/runtime/__init__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/runtime/__main__.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/runtime/client.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/runtime/descriptor.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/runtime/server.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/tool_registry.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code/tool_resolver.py +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code.egg-info/dependency_links.txt +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code.egg-info/entry_points.txt +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code.egg-info/requires.txt +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/praisonai_code.egg-info/top_level.txt +0 -0
- {praisonai_code-0.0.53 → praisonai_code-0.0.55}/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.55
|
|
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
|
|
@@ -147,6 +147,7 @@ _LAZY_COMMANDS: Dict[str, Tuple[str, str, str]] = {
|
|
|
147
147
|
"env": (".commands.environment", "app", "Environment and diagnostics"),
|
|
148
148
|
"auth": (".commands.auth", "app", "Credential management"),
|
|
149
149
|
"session": (".commands.session", "app", "Session management"),
|
|
150
|
+
"usage": (".commands.usage", "app", "Local token/cost usage reporting"),
|
|
150
151
|
"completion": (".commands.completion", "app", "Shell completion scripts"),
|
|
151
152
|
"version": (".commands.version", "app", "Version information"),
|
|
152
153
|
"upgrade": (".commands.upgrade", "app", "Update the managed PraisonAI CLI install"),
|
|
@@ -852,6 +853,7 @@ def main_callback(
|
|
|
852
853
|
if ctx.invoked_subcommand is None:
|
|
853
854
|
# Check for credentials before starting TUI
|
|
854
855
|
from praisonai_code.llm.credentials import (
|
|
856
|
+
detect_local_endpoint,
|
|
855
857
|
inject_credentials_into_env,
|
|
856
858
|
is_configured,
|
|
857
859
|
)
|
|
@@ -859,43 +861,57 @@ def main_callback(
|
|
|
859
861
|
|
|
860
862
|
inject_credentials_into_env()
|
|
861
863
|
if not is_configured(): # Check for any configured credentials
|
|
864
|
+
# Keyless local-first: if a local OpenAI-compatible endpoint is
|
|
865
|
+
# reachable (e.g. Ollama), use it as the zero-config default so the
|
|
866
|
+
# first run works before any auth. Detection is timeout-bounded.
|
|
867
|
+
local = detect_local_endpoint()
|
|
868
|
+
if local is not None:
|
|
869
|
+
typer.echo(
|
|
870
|
+
f"No cloud key found; using local model {local.model}. "
|
|
871
|
+
"Run `praisonai setup` to add a hosted provider.",
|
|
872
|
+
err=True,
|
|
873
|
+
)
|
|
874
|
+
# Fall through to the TUI; no gate.
|
|
862
875
|
# In non-interactive mode, just show error
|
|
863
|
-
|
|
876
|
+
elif not sys.stdin.isatty() or quiet:
|
|
864
877
|
typer.echo(
|
|
865
|
-
"Error: No API key configured. Run: praisonai setup"
|
|
878
|
+
"Error: No API key configured. Run: praisonai setup\n"
|
|
879
|
+
"(a running local endpoint such as Ollama would be used "
|
|
880
|
+
"automatically)",
|
|
866
881
|
err=True
|
|
867
882
|
)
|
|
868
883
|
raise typer.Exit(1)
|
|
869
884
|
|
|
870
|
-
# In interactive mode, offer to run setup
|
|
871
|
-
typer.echo("No API key configured.")
|
|
872
|
-
run_setup = typer.confirm("Would you like to run the setup wizard now?")
|
|
873
|
-
|
|
874
|
-
if run_setup:
|
|
875
|
-
# Import and run setup
|
|
876
|
-
from .commands.setup import _run_setup
|
|
877
|
-
exit_code = _run_setup(
|
|
878
|
-
non_interactive=False,
|
|
879
|
-
provider=None,
|
|
880
|
-
api_key=None,
|
|
881
|
-
model=None
|
|
882
|
-
)
|
|
883
|
-
if exit_code != 0:
|
|
884
|
-
typer.echo("Setup failed. Exiting.", err=True)
|
|
885
|
-
raise typer.Exit(exit_code)
|
|
886
|
-
|
|
887
|
-
# Re-check credentials after setup
|
|
888
|
-
inject_credentials_into_env()
|
|
889
|
-
if not is_configured():
|
|
890
|
-
typer.echo("Setup completed but credentials still not detected.", err=True)
|
|
891
|
-
raise typer.Exit(1)
|
|
892
|
-
|
|
893
|
-
# After successful setup, continue to TUI
|
|
894
|
-
typer.echo("\nSetup complete! Starting interactive mode...\n")
|
|
885
|
+
# In interactive mode, offer to run setup (non-blocking suggestion)
|
|
895
886
|
else:
|
|
896
|
-
typer.echo("
|
|
897
|
-
typer.
|
|
898
|
-
|
|
887
|
+
typer.echo("No API key configured.")
|
|
888
|
+
run_setup = typer.confirm("Would you like to run the setup wizard now?")
|
|
889
|
+
|
|
890
|
+
if run_setup:
|
|
891
|
+
# Import and run setup
|
|
892
|
+
from .commands.setup import _run_setup
|
|
893
|
+
exit_code = _run_setup(
|
|
894
|
+
non_interactive=False,
|
|
895
|
+
provider=None,
|
|
896
|
+
api_key=None,
|
|
897
|
+
model=None
|
|
898
|
+
)
|
|
899
|
+
if exit_code != 0:
|
|
900
|
+
typer.echo("Setup failed. Exiting.", err=True)
|
|
901
|
+
raise typer.Exit(exit_code)
|
|
902
|
+
|
|
903
|
+
# Re-check credentials after setup
|
|
904
|
+
inject_credentials_into_env()
|
|
905
|
+
if not is_configured():
|
|
906
|
+
typer.echo("Setup completed but credentials still not detected.", err=True)
|
|
907
|
+
raise typer.Exit(1)
|
|
908
|
+
|
|
909
|
+
# After successful setup, continue to TUI
|
|
910
|
+
typer.echo("\nSetup complete! Starting interactive mode...\n")
|
|
911
|
+
else:
|
|
912
|
+
typer.echo("\nTo configure credentials later, run: praisonai setup")
|
|
913
|
+
typer.echo("or set environment variables like OPENAI_API_KEY")
|
|
914
|
+
raise typer.Exit(0)
|
|
899
915
|
|
|
900
916
|
from .interactive.async_tui import AsyncTUI, AsyncTUIConfig
|
|
901
917
|
|
|
@@ -15,6 +15,7 @@ __all__ = [
|
|
|
15
15
|
'traces_app',
|
|
16
16
|
'env_app',
|
|
17
17
|
'session_app',
|
|
18
|
+
'usage_app',
|
|
18
19
|
'schedule_app',
|
|
19
20
|
'serve_app',
|
|
20
21
|
'completion_app',
|
|
@@ -54,6 +55,9 @@ def __getattr__(name: str):
|
|
|
54
55
|
elif name == 'session_app':
|
|
55
56
|
from .session import app as session_app
|
|
56
57
|
return session_app
|
|
58
|
+
elif name == 'usage_app':
|
|
59
|
+
from .usage import app as usage_app
|
|
60
|
+
return usage_app
|
|
57
61
|
elif name == 'schedule_app':
|
|
58
62
|
from .schedule import app as schedule_app
|
|
59
63
|
return schedule_app
|
|
@@ -4,6 +4,7 @@ Run command group for PraisonAI CLI.
|
|
|
4
4
|
Provides agent execution commands.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from contextlib import contextmanager
|
|
7
8
|
from typing import Any, Dict, Optional, List
|
|
8
9
|
|
|
9
10
|
import typer
|
|
@@ -663,6 +664,140 @@ def _try_attach_runtime(
|
|
|
663
664
|
return True
|
|
664
665
|
|
|
665
666
|
|
|
667
|
+
@contextmanager
|
|
668
|
+
def _worktree_isolation(enabled: bool, name: str, *, keep: bool = False):
|
|
669
|
+
"""Run the enclosed block inside an isolated git worktree/branch.
|
|
670
|
+
|
|
671
|
+
Provisions a fresh worktree via the core ``GitWorktreeAdapter`` and chdirs
|
|
672
|
+
into it for the duration of the run so the agent edits an isolated branch
|
|
673
|
+
instead of the working tree. On exit it reports the branch name and a
|
|
674
|
+
summary of changes (tracked *and* untracked), then tears the worktree down.
|
|
675
|
+
Degrades to a transparent no-op when isolation is disabled or the directory
|
|
676
|
+
is not a git repository (the adapter reports ``available=False``), so callers
|
|
677
|
+
can wrap unconditionally.
|
|
678
|
+
|
|
679
|
+
Per-run isolation: a short random token is appended to ``name`` so two
|
|
680
|
+
concurrent or repeated runs of the same target never resolve to the same
|
|
681
|
+
worktree/branch and mix each other's uncommitted changes.
|
|
682
|
+
|
|
683
|
+
Data-safety on teardown: the agent's output may be entirely *untracked* new
|
|
684
|
+
files, which ``git diff`` does not see. So before removing the worktree we
|
|
685
|
+
snapshot any change (tracked or untracked, via ``git status --porcelain``)
|
|
686
|
+
onto the branch with an automatic commit and *retain that branch* — only the
|
|
687
|
+
worktree checkout directory is pruned. A run that produced no changes is
|
|
688
|
+
torn down completely (worktree + branch). ``--keep`` additionally retains the
|
|
689
|
+
worktree checkout itself for in-place review.
|
|
690
|
+
"""
|
|
691
|
+
if not enabled:
|
|
692
|
+
yield None
|
|
693
|
+
return
|
|
694
|
+
|
|
695
|
+
import os
|
|
696
|
+
import subprocess
|
|
697
|
+
import uuid
|
|
698
|
+
|
|
699
|
+
from praisonaiagents.workspace import GitWorktreeAdapter
|
|
700
|
+
|
|
701
|
+
output = get_output_controller()
|
|
702
|
+
adapter = GitWorktreeAdapter()
|
|
703
|
+
if not adapter.available:
|
|
704
|
+
output.print_warning(
|
|
705
|
+
"Not a git repository; running without worktree isolation."
|
|
706
|
+
)
|
|
707
|
+
yield None
|
|
708
|
+
return
|
|
709
|
+
|
|
710
|
+
def _git(*args, cwd):
|
|
711
|
+
try:
|
|
712
|
+
return subprocess.run(
|
|
713
|
+
["git", *args], cwd=cwd, capture_output=True, text=True
|
|
714
|
+
)
|
|
715
|
+
except (FileNotFoundError, OSError):
|
|
716
|
+
return None
|
|
717
|
+
|
|
718
|
+
def _branch_of(worktree_path: str) -> str:
|
|
719
|
+
result = _git("rev-parse", "--abbrev-ref", "HEAD", cwd=worktree_path)
|
|
720
|
+
if result is not None and result.returncode == 0:
|
|
721
|
+
return result.stdout.strip() or "?"
|
|
722
|
+
return "?"
|
|
723
|
+
|
|
724
|
+
def _has_changes(worktree_path: str) -> bool:
|
|
725
|
+
# ``--porcelain`` reports staged, unstaged *and* untracked entries, so a
|
|
726
|
+
# run that only creates brand-new files (invisible to ``git diff``) is
|
|
727
|
+
# still recognised as having produced output.
|
|
728
|
+
result = _git("status", "--porcelain", cwd=worktree_path)
|
|
729
|
+
if result is None or result.returncode != 0:
|
|
730
|
+
return False
|
|
731
|
+
return bool((result.stdout or "").strip())
|
|
732
|
+
|
|
733
|
+
def _summary(worktree_path: str) -> str:
|
|
734
|
+
result = _git("status", "--short", cwd=worktree_path)
|
|
735
|
+
if result is None or result.returncode != 0:
|
|
736
|
+
return ""
|
|
737
|
+
return (result.stdout or "").strip()
|
|
738
|
+
|
|
739
|
+
# Make the run's worktree/branch unique per invocation so identical targets
|
|
740
|
+
# (same prompt/YAML) run concurrently without sharing state.
|
|
741
|
+
unique_name = f"{name}-{uuid.uuid4().hex[:8]}"
|
|
742
|
+
|
|
743
|
+
original_cwd = os.getcwd()
|
|
744
|
+
path = adapter.create(unique_name)
|
|
745
|
+
branch = _branch_of(path)
|
|
746
|
+
if not output.is_json_mode:
|
|
747
|
+
output.print_info(f"Isolated run on branch '{branch}' ({path})")
|
|
748
|
+
os.chdir(path)
|
|
749
|
+
try:
|
|
750
|
+
yield path
|
|
751
|
+
finally:
|
|
752
|
+
os.chdir(original_cwd)
|
|
753
|
+
|
|
754
|
+
summary = _summary(path)
|
|
755
|
+
changed = _has_changes(path)
|
|
756
|
+
if not output.is_json_mode:
|
|
757
|
+
if summary:
|
|
758
|
+
output.print_info(f"Changes on '{branch}':\n{summary}")
|
|
759
|
+
else:
|
|
760
|
+
output.print_info(f"No changes on '{branch}'.")
|
|
761
|
+
|
|
762
|
+
if keep:
|
|
763
|
+
if not output.is_json_mode:
|
|
764
|
+
output.print_info(
|
|
765
|
+
f"Worktree kept at {path} (branch '{branch}'). "
|
|
766
|
+
"Review/merge then remove with: git worktree remove."
|
|
767
|
+
)
|
|
768
|
+
return
|
|
769
|
+
|
|
770
|
+
if changed:
|
|
771
|
+
# Never destroy the agent's output. Persist every change (tracked +
|
|
772
|
+
# untracked) as a commit on the isolated branch and retain the
|
|
773
|
+
# branch; only the worktree checkout directory is pruned.
|
|
774
|
+
_git("add", "-A", cwd=path)
|
|
775
|
+
committed = _git(
|
|
776
|
+
"commit", "--no-verify", "-m", f"praisonai run: {name}", cwd=path
|
|
777
|
+
)
|
|
778
|
+
if committed is None or committed.returncode != 0:
|
|
779
|
+
# Couldn't persist the work (e.g. no git identity configured):
|
|
780
|
+
# keep the worktree checkout in place so output is never lost.
|
|
781
|
+
if not output.is_json_mode:
|
|
782
|
+
output.print_warning(
|
|
783
|
+
f"Could not commit isolated changes; worktree kept at "
|
|
784
|
+
f"{path} (branch '{branch}') for manual review."
|
|
785
|
+
)
|
|
786
|
+
return
|
|
787
|
+
# ``worktree remove`` deletes the checkout but leaves the branch
|
|
788
|
+
# intact for review/merge (unlike ``adapter.remove`` which also
|
|
789
|
+
# force-deletes the branch and would lose the committed work).
|
|
790
|
+
_git("worktree", "remove", "--force", path, cwd=original_cwd)
|
|
791
|
+
if not output.is_json_mode:
|
|
792
|
+
output.print_info(
|
|
793
|
+
f"Committed changes to branch '{branch}'. "
|
|
794
|
+
f"Review/merge with: git merge {branch}"
|
|
795
|
+
)
|
|
796
|
+
else:
|
|
797
|
+
# No output produced: safe to remove worktree and branch entirely.
|
|
798
|
+
adapter.remove(unique_name)
|
|
799
|
+
|
|
800
|
+
|
|
666
801
|
@app.callback(invoke_without_command=True)
|
|
667
802
|
def run_main(
|
|
668
803
|
ctx: typer.Context,
|
|
@@ -706,6 +841,9 @@ def run_main(
|
|
|
706
841
|
restore: Optional[str] = typer.Option(None, "--restore", help="Restore the workspace to a checkpoint id (or 'last') and exit"),
|
|
707
842
|
# Warm-runtime live session: tag this run so other terminals can `attach`.
|
|
708
843
|
attach: Optional[str] = typer.Option(None, "--attach", help="Run on the warm runtime under this session id so other terminals can observe it via `praisonai attach <id>`"),
|
|
844
|
+
# Per-run git-worktree isolation: run on a fresh branch/worktree.
|
|
845
|
+
worktree: bool = typer.Option(False, "--worktree", help="Run on an isolated git worktree/branch (branch-per-task); no-op when not a git repo"),
|
|
846
|
+
keep: bool = typer.Option(False, "--keep", help="With --worktree, keep the worktree/branch after the run for review instead of tearing it down"),
|
|
709
847
|
):
|
|
710
848
|
"""
|
|
711
849
|
Run agents from a file or prompt.
|
|
@@ -760,6 +898,7 @@ def run_main(
|
|
|
760
898
|
# Early credential check before any processing
|
|
761
899
|
if target: # Only check if we actually have something to run
|
|
762
900
|
from praisonai_code.llm.credentials import (
|
|
901
|
+
detect_local_endpoint,
|
|
763
902
|
inject_credentials_into_env,
|
|
764
903
|
is_configured,
|
|
765
904
|
)
|
|
@@ -768,43 +907,62 @@ def run_main(
|
|
|
768
907
|
# Check if credentials are configured (use model if provided, else check general)
|
|
769
908
|
inject_credentials_into_env()
|
|
770
909
|
if not is_configured(model):
|
|
910
|
+
# Keyless local-first: when no explicit model was requested and no
|
|
911
|
+
# cloud key is configured, prefer a reachable local endpoint (e.g.
|
|
912
|
+
# Ollama) so `praisonai run "..."` just works before any auth. An
|
|
913
|
+
# explicit --model is left to its own provider gate.
|
|
914
|
+
local = detect_local_endpoint() if not model else None
|
|
915
|
+
if local is not None:
|
|
916
|
+
output.print_info(
|
|
917
|
+
f"No cloud key found; using local model {local.model}. "
|
|
918
|
+
"Run `praisonai setup` to add a hosted provider."
|
|
919
|
+
)
|
|
920
|
+
# Adopt the detected local model + base URL for this run so the
|
|
921
|
+
# Agent reaches the local endpoint. An explicit env base_url,
|
|
922
|
+
# if any, is left untouched.
|
|
923
|
+
import os as _os_local
|
|
924
|
+
model = local.model
|
|
925
|
+
_os_local.environ.setdefault("OPENAI_BASE_URL", local.base_url)
|
|
771
926
|
# In non-interactive mode, show clear error
|
|
772
|
-
|
|
927
|
+
elif not sys.stdin.isatty() or output.is_json_mode:
|
|
773
928
|
output.print_error(
|
|
774
929
|
"No API key configured. Run: praisonai setup\n"
|
|
775
|
-
"or set environment variables like OPENAI_API_KEY"
|
|
930
|
+
"or set environment variables like OPENAI_API_KEY\n"
|
|
931
|
+
"(a running local endpoint such as Ollama would be used "
|
|
932
|
+
"automatically)"
|
|
776
933
|
)
|
|
777
934
|
raise typer.Exit(1)
|
|
778
935
|
|
|
779
936
|
# In interactive mode, offer to run setup
|
|
780
|
-
typer.echo(f"No API key configured{f' for model {model}' if model else ''}.")
|
|
781
|
-
run_setup = typer.confirm("Would you like to run the setup wizard now?")
|
|
782
|
-
|
|
783
|
-
if run_setup:
|
|
784
|
-
from praisonai_code.cli.commands.setup import _run_setup
|
|
785
|
-
exit_code = _run_setup(
|
|
786
|
-
non_interactive=False,
|
|
787
|
-
provider=None,
|
|
788
|
-
api_key=None,
|
|
789
|
-
model=None
|
|
790
|
-
)
|
|
791
|
-
if exit_code != 0:
|
|
792
|
-
output.print_error("Setup failed. Exiting.")
|
|
793
|
-
raise typer.Exit(exit_code)
|
|
794
|
-
|
|
795
|
-
output.print_success("Setup complete! Continuing with your run...")
|
|
796
|
-
# Re-check after setup
|
|
797
|
-
inject_credentials_into_env()
|
|
798
|
-
if not is_configured(model):
|
|
799
|
-
output.print_error("Setup completed but credentials still not detected.")
|
|
800
|
-
raise typer.Exit(1)
|
|
801
937
|
else:
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
938
|
+
typer.echo(f"No API key configured{f' for model {model}' if model else ''}.")
|
|
939
|
+
run_setup = typer.confirm("Would you like to run the setup wizard now?")
|
|
940
|
+
|
|
941
|
+
if run_setup:
|
|
942
|
+
from praisonai_code.cli.commands.setup import _run_setup
|
|
943
|
+
exit_code = _run_setup(
|
|
944
|
+
non_interactive=False,
|
|
945
|
+
provider=None,
|
|
946
|
+
api_key=None,
|
|
947
|
+
model=None
|
|
948
|
+
)
|
|
949
|
+
if exit_code != 0:
|
|
950
|
+
output.print_error("Setup failed. Exiting.")
|
|
951
|
+
raise typer.Exit(exit_code)
|
|
952
|
+
|
|
953
|
+
output.print_success("Setup complete! Continuing with your run...")
|
|
954
|
+
# Re-check after setup
|
|
955
|
+
inject_credentials_into_env()
|
|
956
|
+
if not is_configured(model):
|
|
957
|
+
output.print_error("Setup completed but credentials still not detected.")
|
|
958
|
+
raise typer.Exit(1)
|
|
959
|
+
else:
|
|
960
|
+
output.print_info(
|
|
961
|
+
"To configure credentials:\n"
|
|
962
|
+
" - Run: praisonai setup\n"
|
|
963
|
+
" - Or set environment variables like OPENAI_API_KEY"
|
|
964
|
+
)
|
|
965
|
+
raise typer.Exit(0)
|
|
808
966
|
|
|
809
967
|
# Resolve configuration if model not explicitly provided
|
|
810
968
|
if model is None:
|
|
@@ -828,6 +986,24 @@ def run_main(
|
|
|
828
986
|
output.print_error("Cannot use both --continue and --session together")
|
|
829
987
|
raise typer.Exit(1)
|
|
830
988
|
|
|
989
|
+
# Worktree isolation runs the agent in a chdir'd worktree in-process; the
|
|
990
|
+
# warm runtime is a separate process whose cwd we can't redirect, so reject
|
|
991
|
+
# the combination up front rather than silently ignoring isolation.
|
|
992
|
+
if worktree and attach:
|
|
993
|
+
output.print_error("--worktree cannot be combined with --attach")
|
|
994
|
+
raise typer.Exit(1)
|
|
995
|
+
if keep and not worktree:
|
|
996
|
+
output.print_error("--keep requires --worktree")
|
|
997
|
+
raise typer.Exit(1)
|
|
998
|
+
# Scope isolation to the primary `run "<task>"` / `run agents.yaml` surfaces.
|
|
999
|
+
# Custom agent/command and profiling flows have their own execution paths;
|
|
1000
|
+
# keep the feature focused rather than threading a worktree through each.
|
|
1001
|
+
if worktree and (agent or command or profile or profile_deep):
|
|
1002
|
+
output.print_error(
|
|
1003
|
+
"--worktree is only supported for direct prompt and YAML file runs"
|
|
1004
|
+
)
|
|
1005
|
+
raise typer.Exit(1)
|
|
1006
|
+
|
|
831
1007
|
# --attach tags a warm-runtime run so other terminals can observe it, but
|
|
832
1008
|
# only the direct-prompt path forwards to the warm runtime. Reject it up
|
|
833
1009
|
# front on profile/custom-agent/custom-command flows so users never
|
|
@@ -1017,58 +1193,72 @@ def run_main(
|
|
|
1017
1193
|
)
|
|
1018
1194
|
return
|
|
1019
1195
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1196
|
+
# Resolve a YAML file target to an absolute path *before* isolation chdirs
|
|
1197
|
+
# away. The config is loaded from the original checkout so an untracked or
|
|
1198
|
+
# git-ignored ``./agents.yaml`` (absent from the fresh worktree) still loads;
|
|
1199
|
+
# the agent then produces its output inside the isolated worktree.
|
|
1200
|
+
run_target = target
|
|
1201
|
+
if worktree and is_file:
|
|
1202
|
+
import os as _os_ff
|
|
1203
|
+
run_target = _os_ff.path.abspath(target)
|
|
1204
|
+
|
|
1205
|
+
# Provision a per-run git worktree/branch when --worktree is set and the cwd
|
|
1206
|
+
# is a git repo; otherwise this is a transparent no-op. The agent runs with
|
|
1207
|
+
# its cwd redirected into the isolated worktree for the duration of the run.
|
|
1208
|
+
with _worktree_isolation(worktree, target, keep=keep):
|
|
1209
|
+
if is_file:
|
|
1210
|
+
# Run from file
|
|
1211
|
+
_run_from_file(
|
|
1212
|
+
run_target,
|
|
1213
|
+
model=model,
|
|
1214
|
+
framework=framework,
|
|
1215
|
+
interactive=interactive,
|
|
1216
|
+
verbose=verbose,
|
|
1217
|
+
stream=stream,
|
|
1218
|
+
trace=trace,
|
|
1219
|
+
memory=memory,
|
|
1220
|
+
tools=tools,
|
|
1221
|
+
max_tokens=max_tokens,
|
|
1222
|
+
output_mode=output_mode,
|
|
1223
|
+
continue_session=continue_session,
|
|
1224
|
+
session=session,
|
|
1225
|
+
fork=fork,
|
|
1226
|
+
no_save=no_save,
|
|
1227
|
+
)
|
|
1228
|
+
else:
|
|
1229
|
+
# Run as prompt
|
|
1230
|
+
permissions_config = _parse_permissions(allow, deny, permissions, permission_default)
|
|
1231
|
+
mcp_command, mcp_env, permissions_config, mcp_servers = _apply_config_defaults(
|
|
1232
|
+
None, None, permissions_config
|
|
1233
|
+
)
|
|
1234
|
+
_run_prompt(
|
|
1235
|
+
target,
|
|
1236
|
+
model=model,
|
|
1237
|
+
verbose=verbose,
|
|
1238
|
+
stream=stream,
|
|
1239
|
+
trace=trace,
|
|
1240
|
+
memory=memory,
|
|
1241
|
+
tools=tools,
|
|
1242
|
+
toolset=toolset,
|
|
1243
|
+
max_tokens=max_tokens,
|
|
1244
|
+
output_mode=output_mode,
|
|
1245
|
+
approval=approval,
|
|
1246
|
+
approve_all_tools=approve_all_tools,
|
|
1247
|
+
approval_timeout=approval_timeout,
|
|
1248
|
+
no_rules=no_rules,
|
|
1249
|
+
permissions_config=permissions_config,
|
|
1250
|
+
mcp=mcp_command,
|
|
1251
|
+
mcp_env=mcp_env,
|
|
1252
|
+
mcp_servers=mcp_servers,
|
|
1253
|
+
continue_session=continue_session,
|
|
1254
|
+
session=session,
|
|
1255
|
+
fork=fork,
|
|
1256
|
+
no_save=no_save,
|
|
1257
|
+
attach_session=attach,
|
|
1258
|
+
thinking_budget=thinking_budget,
|
|
1259
|
+
allow_local_tools=allow_local_tools,
|
|
1260
|
+
isolated=worktree,
|
|
1261
|
+
)
|
|
1072
1262
|
|
|
1073
1263
|
|
|
1074
1264
|
def _run_from_file(
|
|
@@ -1203,6 +1393,7 @@ def _run_prompt(
|
|
|
1203
1393
|
attach_session: Optional[str] = None,
|
|
1204
1394
|
thinking_budget: Optional[int] = None,
|
|
1205
1395
|
allow_local_tools: bool = False,
|
|
1396
|
+
isolated: bool = False,
|
|
1206
1397
|
):
|
|
1207
1398
|
"""Run a direct prompt."""
|
|
1208
1399
|
output = get_output_controller()
|
|
@@ -1280,7 +1471,10 @@ def _run_prompt(
|
|
|
1280
1471
|
# approval/memory), so it stays in-process: the warm runtime reuses a
|
|
1281
1472
|
# cached agent and does not carry a per-call thinking budget, so attaching
|
|
1282
1473
|
# would silently drop the requested setting.
|
|
1283
|
-
|
|
1474
|
+
# Isolated (--worktree) runs must stay in-process: the warm runtime is a
|
|
1475
|
+
# separate process whose cwd we can't redirect into the worktree, so
|
|
1476
|
+
# attaching would run the task outside the isolated branch.
|
|
1477
|
+
runtime_eligible = no_save and thinking_budget is None and not isolated and not any([
|
|
1284
1478
|
mcp, mcp_servers, tools, toolset, approval, approve_all_tools,
|
|
1285
1479
|
memory, permissions_config, continue_session, session, fork,
|
|
1286
1480
|
])
|
|
@@ -19,14 +19,23 @@ app = typer.Typer(help="Session management")
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def _create_backend(backend_type: str, storage_path: Optional[str]):
|
|
22
|
-
"""Create storage backend from CLI options.
|
|
22
|
+
"""Create storage backend from CLI options.
|
|
23
|
+
|
|
24
|
+
Defaults anchor under the *canonical* data home (``get_sessions_dir()`` →
|
|
25
|
+
``~/.praisonai/sessions``) rather than the legacy ``~/.praison`` root, so a
|
|
26
|
+
backend-selected store lives under the same home as the project/global
|
|
27
|
+
stores instead of silently splitting sessions across two home roots
|
|
28
|
+
(Issue #3201).
|
|
29
|
+
"""
|
|
23
30
|
try:
|
|
31
|
+
from praisonaiagents.paths import get_data_dir, get_sessions_dir
|
|
32
|
+
|
|
24
33
|
if backend_type == "file":
|
|
25
34
|
from praisonaiagents.storage import FileBackend
|
|
26
|
-
return FileBackend(storage_dir=storage_path or
|
|
35
|
+
return FileBackend(storage_dir=storage_path or str(get_sessions_dir()))
|
|
27
36
|
elif backend_type == "sqlite":
|
|
28
37
|
from praisonaiagents.storage import SQLiteBackend
|
|
29
|
-
db_path = storage_path or "
|
|
38
|
+
db_path = storage_path or str(get_data_dir() / "sessions.db")
|
|
30
39
|
return SQLiteBackend(db_path=db_path)
|
|
31
40
|
elif backend_type.startswith("redis://"):
|
|
32
41
|
from praisonaiagents.storage import RedisBackend
|