praisonai-code 0.0.44__tar.gz → 0.0.46__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.
Files changed (314) hide show
  1. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/PKG-INFO +1 -1
  2. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/__init__.py +1 -1
  3. praisonai_code-0.0.46/praisonai_code/_train_bridge.py +35 -0
  4. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/app.py +37 -3
  5. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/auth.py +231 -31
  6. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/init.py +27 -0
  7. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/run.py +99 -0
  8. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/session.py +9 -2
  9. praisonai_code-0.0.46/praisonai_code/cli/commands/uninstall.py +73 -0
  10. praisonai_code-0.0.46/praisonai_code/cli/commands/upgrade.py +105 -0
  11. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/config.schema.json +36 -1
  12. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/resolver.py +366 -21
  13. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/custom_definitions.py +259 -4
  14. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_tools.py +147 -1
  15. praisonai_code-0.0.46/praisonai_code/cli/features/self_manage.py +310 -0
  16. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/setup/handler.py +116 -21
  17. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/help_categories.py +2 -0
  18. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/legacy/praison_ai.py +28 -17
  19. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/state/project_sessions.py +48 -2
  20. praisonai_code-0.0.46/praisonai_code/cli/utils/project.py +338 -0
  21. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/llm/catalogue.py +43 -0
  22. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/tool_resolver.py +32 -5
  23. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code.egg-info/PKG-INFO +1 -1
  24. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code.egg-info/SOURCES.txt +4 -0
  25. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/pyproject.toml +1 -1
  26. praisonai_code-0.0.44/praisonai_code/cli/utils/project.py +0 -131
  27. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/README.md +0 -0
  28. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/__main__.py +0 -0
  29. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/_bot_bridge.py +0 -0
  30. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/_framework_availability.py +0 -0
  31. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/_logging.py +0 -0
  32. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/_registry.py +0 -0
  33. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/_safe_loader.py +0 -0
  34. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/_version.py +0 -0
  35. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/_wrapper_bridge.py +0 -0
  36. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/__init__.py +0 -0
  37. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/_forward_shim.py +0 -0
  38. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/_paths.py +0 -0
  39. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/_warnings.py +0 -0
  40. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/_wrapper_reexport.py +0 -0
  41. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/approval_backend.py +0 -0
  42. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/branding.py +0 -0
  43. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/__init__.py +0 -0
  44. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/acp.py +0 -0
  45. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/agent.py +0 -0
  46. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/agents.py +0 -0
  47. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/attach.py +0 -0
  48. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/benchmark.py +0 -0
  49. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/browser.py +0 -0
  50. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/call.py +0 -0
  51. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/chat.py +0 -0
  52. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/checkpoint.py +0 -0
  53. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/code.py +0 -0
  54. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/command.py +0 -0
  55. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/commit.py +0 -0
  56. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/completion.py +0 -0
  57. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/config.py +0 -0
  58. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/daemon.py +0 -0
  59. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/debug.py +0 -0
  60. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/deploy.py +0 -0
  61. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/diag.py +0 -0
  62. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/doctor.py +0 -0
  63. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/endpoints.py +0 -0
  64. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/environment.py +0 -0
  65. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/eval.py +0 -0
  66. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/github.py +0 -0
  67. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/hooks.py +0 -0
  68. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/loop.py +0 -0
  69. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/lsp.py +0 -0
  70. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/memory.py +0 -0
  71. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/models.py +0 -0
  72. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/obs.py +0 -0
  73. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/package.py +0 -0
  74. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/paths.py +0 -0
  75. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/permissions.py +0 -0
  76. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/plugins.py +0 -0
  77. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/port.py +0 -0
  78. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/publish.py +0 -0
  79. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/registry.py +0 -0
  80. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/research.py +0 -0
  81. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/retrieval.py +0 -0
  82. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/rules.py +0 -0
  83. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/sandbox.py +0 -0
  84. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/serve.py +0 -0
  85. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/setup.py +0 -0
  86. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/skills.py +0 -0
  87. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/templates.py +0 -0
  88. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/test.py +0 -0
  89. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/todo.py +0 -0
  90. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/tools.py +0 -0
  91. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/traces.py +0 -0
  92. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/tracker.py +0 -0
  93. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/ui.py +0 -0
  94. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/up.py +0 -0
  95. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/version.py +0 -0
  96. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/commands/workflow.py +0 -0
  97. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/config_loader.py +0 -0
  98. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/__init__.py +0 -0
  99. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/credentials.py +0 -0
  100. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/loader.py +0 -0
  101. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/model_resolver.py +0 -0
  102. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/oauth.py +0 -0
  103. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/paths.py +0 -0
  104. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/schema.py +0 -0
  105. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/execution/__init__.py +0 -0
  106. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/execution/core.py +0 -0
  107. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/execution/profiler.py +0 -0
  108. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/execution/request.py +0 -0
  109. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/execution/result.py +0 -0
  110. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/fallback_schema.py +0 -0
  111. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/__init__.py +0 -0
  112. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/_approval_bridge.py +0 -0
  113. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/_endpoint_registry.py +0 -0
  114. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/_search_registry.py +0 -0
  115. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/action_orchestrator.py +0 -0
  116. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/agents.py +0 -0
  117. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/at_mentions.py +0 -0
  118. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/audit_cli.py +0 -0
  119. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/auto_memory.py +0 -0
  120. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/auto_mode.py +0 -0
  121. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/autonomy_mode.py +0 -0
  122. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/base.py +0 -0
  123. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/benchmark.py +0 -0
  124. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/capabilities.py +0 -0
  125. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/checkpoints.py +0 -0
  126. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/cli_profiler.py +0 -0
  127. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/code_intelligence.py +0 -0
  128. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/compaction.py +0 -0
  129. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/compare.py +0 -0
  130. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/config_hierarchy.py +0 -0
  131. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/context_manager.py +0 -0
  132. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/cost_tracker.py +0 -0
  133. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/csv_test_runner.py +0 -0
  134. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/debug.py +0 -0
  135. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/diag.py +0 -0
  136. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/display_jsonl.py +0 -0
  137. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/__init__.py +0 -0
  138. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/__init__.py +0 -0
  139. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/_wrapper_checks.py +0 -0
  140. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/acp_checks.py +0 -0
  141. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/bot_checks.py +0 -0
  142. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/config_checks.py +0 -0
  143. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/db_checks.py +0 -0
  144. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/env_checks.py +0 -0
  145. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/gateway_checks.py +0 -0
  146. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/lsp_checks.py +0 -0
  147. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/mcp_checks.py +0 -0
  148. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/memory_checks.py +0 -0
  149. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/network_checks.py +0 -0
  150. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/obs_checks.py +0 -0
  151. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/packaging_checks.py +0 -0
  152. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/performance_checks.py +0 -0
  153. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/permissions_checks.py +0 -0
  154. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/runtime_checks.py +0 -0
  155. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +0 -0
  156. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/selftest_checks.py +0 -0
  157. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/serve_checks.py +0 -0
  158. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/skills_checks.py +0 -0
  159. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/tools_checks.py +0 -0
  160. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/engine.py +0 -0
  161. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/formatters.py +0 -0
  162. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/handler.py +0 -0
  163. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/models.py +0 -0
  164. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/registry.py +0 -0
  165. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/endpoints.py +0 -0
  166. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/examples.py +0 -0
  167. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/external_agents.py +0 -0
  168. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/fast_context.py +0 -0
  169. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/file_history.py +0 -0
  170. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/flow_display.py +0 -0
  171. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/git_attribution.py +0 -0
  172. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/git_integration.py +0 -0
  173. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/guardrail.py +0 -0
  174. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/handoff.py +0 -0
  175. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/hooks.py +0 -0
  176. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/hybrid_workflow.py +0 -0
  177. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/image.py +0 -0
  178. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_core_headless.py +0 -0
  179. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_runtime.py +0 -0
  180. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_test_harness.py +0 -0
  181. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_tui.py +0 -0
  182. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/job_workflow.py +0 -0
  183. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/jobs.py +0 -0
  184. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/knowledge.py +0 -0
  185. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/knowledge_cli.py +0 -0
  186. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/lite.py +0 -0
  187. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/logs.py +0 -0
  188. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/lsp_cli.py +0 -0
  189. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/lsp_diagnostics.py +0 -0
  190. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/mcp.py +0 -0
  191. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/message_queue.py +0 -0
  192. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/metrics.py +0 -0
  193. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/migrate.py +0 -0
  194. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/migration_flow.py +0 -0
  195. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/migration_spec.py +0 -0
  196. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/n8n.py +0 -0
  197. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/observability.py +0 -0
  198. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/output_modes.py +0 -0
  199. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/output_style.py +0 -0
  200. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/package.py +0 -0
  201. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/performance.py +0 -0
  202. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/profiler/__init__.py +0 -0
  203. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/profiler/core.py +0 -0
  204. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/profiler/optimizations.py +0 -0
  205. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/profiler/suite.py +0 -0
  206. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/__init__.py +0 -0
  207. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/manager.py +0 -0
  208. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/models.py +0 -0
  209. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/persistence.py +0 -0
  210. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/scheduler.py +0 -0
  211. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/worker.py +0 -0
  212. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/recipe_creator.py +0 -0
  213. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/recipe_prompts.py +0 -0
  214. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/registry.py +0 -0
  215. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/repo_map.py +0 -0
  216. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/router.py +0 -0
  217. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/safe_shell.py +0 -0
  218. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/sandbox_executor.py +0 -0
  219. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/sdk_knowledge.py +0 -0
  220. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/session.py +0 -0
  221. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/session_checkpoints.py +0 -0
  222. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/setup/__init__.py +0 -0
  223. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/setup/templates.py +0 -0
  224. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/skills.py +0 -0
  225. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/slash_commands.py +0 -0
  226. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/telemetry.py +0 -0
  227. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/thinking.py +0 -0
  228. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/todo.py +0 -0
  229. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tools.py +0 -0
  230. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/__init__.py +0 -0
  231. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/cli.py +0 -0
  232. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/config.py +0 -0
  233. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/debug.py +0 -0
  234. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/events.py +0 -0
  235. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/mock_provider.py +0 -0
  236. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/orchestrator.py +0 -0
  237. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/__init__.py +0 -0
  238. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/help.py +0 -0
  239. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/main.py +0 -0
  240. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/queue.py +0 -0
  241. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/session.py +0 -0
  242. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/settings.py +0 -0
  243. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/session_store.py +0 -0
  244. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/__init__.py +0 -0
  245. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/chat.py +0 -0
  246. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/command_popup.py +0 -0
  247. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/composer.py +0 -0
  248. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/file_popup.py +0 -0
  249. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/queue_panel.py +0 -0
  250. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/status.py +0 -0
  251. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/tool_panel.py +0 -0
  252. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/wizard.py +0 -0
  253. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/workflow.py +0 -0
  254. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/features/yaml_utils.py +0 -0
  255. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/__init__.py +0 -0
  256. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/async_tui.py +0 -0
  257. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/command_registry.py +0 -0
  258. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/config.py +0 -0
  259. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/core.py +0 -0
  260. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/events.py +0 -0
  261. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/frontends/__init__.py +0 -0
  262. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/frontends/rich_frontend.py +0 -0
  263. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/frontends/textual_frontend.py +0 -0
  264. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/praison_io.py +0 -0
  265. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/repl.py +0 -0
  266. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/split_tui.py +0 -0
  267. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/tui_app.py +0 -0
  268. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/legacy/__init__.py +0 -0
  269. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/legacy/env_security.py +0 -0
  270. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/legacy/prompt_dispatch.py +0 -0
  271. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/main.py +0 -0
  272. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/output/__init__.py +0 -0
  273. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/output/console.py +0 -0
  274. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/output/event_bridge.py +0 -0
  275. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/schedule_cli.py +0 -0
  276. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/schema_provider.py +0 -0
  277. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/session/__init__.py +0 -0
  278. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/session/resume.py +0 -0
  279. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/session/unified.py +0 -0
  280. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/state/__init__.py +0 -0
  281. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/state/identifiers.py +0 -0
  282. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/state/sessions.py +0 -0
  283. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/ui/__init__.py +0 -0
  284. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/ui/config.py +0 -0
  285. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/ui/events.py +0 -0
  286. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/ui/mg_backend.py +0 -0
  287. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/ui/plain.py +0 -0
  288. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/ui/rich_backend.py +0 -0
  289. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/unified_schema.py +0 -0
  290. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/utils/env_utils.py +0 -0
  291. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli/utils/stdin.py +0 -0
  292. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli_backends/__init__.py +0 -0
  293. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli_backends/claude.py +0 -0
  294. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/cli_backends/registry.py +0 -0
  295. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/data/__init__.py +0 -0
  296. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/data/fixtures/interactive/multi_agent.csv +0 -0
  297. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/data/fixtures/interactive/refactor.csv +0 -0
  298. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/data/fixtures/interactive/smoke.csv +0 -0
  299. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/data/fixtures/interactive/tools.csv +0 -0
  300. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/llm/__init__.py +0 -0
  301. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/llm/config.py +0 -0
  302. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/llm/credentials.py +0 -0
  303. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/llm/env.py +0 -0
  304. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/runtime/__init__.py +0 -0
  305. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/runtime/__main__.py +0 -0
  306. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/runtime/client.py +0 -0
  307. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/runtime/descriptor.py +0 -0
  308. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/runtime/server.py +0 -0
  309. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code/tool_registry.py +0 -0
  310. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code.egg-info/dependency_links.txt +0 -0
  311. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code.egg-info/entry_points.txt +0 -0
  312. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code.egg-info/requires.txt +0 -0
  313. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/praisonai_code.egg-info/top_level.txt +0 -0
  314. {praisonai_code-0.0.44 → praisonai_code-0.0.46}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: praisonai-code
3
- Version: 0.0.44
3
+ Version: 0.0.46
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
@@ -12,6 +12,6 @@ the remaining terminal-agent modules, with PEP 562 shims left behind at the
12
12
  old ``praisonai.*`` paths for backward compatibility.
13
13
  """
14
14
 
15
- __version__ = "0.0.44"
15
+ __version__ = "0.0.46"
16
16
 
17
17
  __all__ = ["__version__"]
@@ -0,0 +1,35 @@
1
+ """Lazy access to ``praisonai-train`` from ``praisonai-code``."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib
6
+ from types import ModuleType
7
+ from typing import Any, TypeVar
8
+
9
+ T = TypeVar("T")
10
+
11
+ _INSTALL_HINT = "Install the training package: pip install praisonai-train"
12
+
13
+
14
+ def train_package_available() -> bool:
15
+ import importlib.util
16
+
17
+ return importlib.util.find_spec("praisonai_train") is not None
18
+
19
+
20
+ def import_train_module(name: str) -> ModuleType:
21
+ if not name.startswith("praisonai_train"):
22
+ raise ValueError(f"Expected praisonai_train module name, got {name!r}")
23
+ try:
24
+ return importlib.import_module(name)
25
+ except ImportError as exc:
26
+ raise ImportError(f"{name} requires praisonai-train. {_INSTALL_HINT}") from exc
27
+
28
+
29
+ def optional_train_attr(module_name: str, attr: str, default: T | None = None) -> Any | T | None:
30
+ if not train_package_available():
31
+ return default
32
+ try:
33
+ return getattr(import_train_module(module_name), attr)
34
+ except (ImportError, AttributeError):
35
+ return default
@@ -149,6 +149,8 @@ _LAZY_COMMANDS: Dict[str, Tuple[str, str, str]] = {
149
149
  "session": (".commands.session", "app", "Session management"),
150
150
  "completion": (".commands.completion", "app", "Shell completion scripts"),
151
151
  "version": (".commands.version", "app", "Version information"),
152
+ "upgrade": (".commands.upgrade", "app", "Update the managed PraisonAI CLI install"),
153
+ "uninstall": (".commands.uninstall", "app", "Remove the managed PraisonAI CLI install"),
152
154
  "debug": (".commands.debug", "app", "Debug and test interactive flows"),
153
155
  "lsp": (".commands.lsp", "app", "LSP service lifecycle"),
154
156
  "diag": (".commands.diag", "app", "Diagnostics export"),
@@ -262,8 +264,7 @@ _WRAPPER_RESIDENT_COMMANDS = frozenset({
262
264
  "flow",
263
265
  "n8n",
264
266
  "replay",
265
- # C8.2 Batch B — training / managed / examples
266
- "train",
267
+ # C8.2 Batch B — managed / examples (train extracted to praisonai-train in C10)
267
268
  "managed",
268
269
  "examples",
269
270
  "standardise",
@@ -285,6 +286,13 @@ _WRAPPER_RESIDENT_COMMANDS = frozenset({
285
286
  "validate",
286
287
  })
287
288
 
289
+ # C10: Training commands implemented in ``praisonai_train.cli.commands.*``.
290
+ # ``get_command()`` loads them via ``praisonai_train.cli.commands.{name}`` when the
291
+ # train package is installed; standalone ``praisonai-code`` hides them from ``--help``.
292
+ _TRAIN_RESIDENT_COMMANDS = frozenset({
293
+ "train",
294
+ })
295
+
288
296
  # Backward-compatible alias (C7.1 name).
289
297
  _WRAPPER_COMMANDS = _WRAPPER_RESIDENT_COMMANDS
290
298
 
@@ -297,6 +305,7 @@ _SPECIAL_COMMANDS = {
297
305
 
298
306
  from praisonai_code._wrapper_bridge import wrapper_available
299
307
  from praisonai_code._bot_bridge import bot_package_available
308
+ from praisonai_code._train_bridge import train_package_available
300
309
 
301
310
 
302
311
  class LazyCommandGroup(TyperGroup):
@@ -312,10 +321,12 @@ class LazyCommandGroup(TyperGroup):
312
321
  # install does not surface commands it cannot resolve.
313
322
  wrapper_ok = wrapper_available()
314
323
  bot_ok = bot_package_available()
324
+ train_ok = train_package_available()
315
325
  commands.update(
316
326
  name for name in _LAZY_COMMANDS
317
327
  if (wrapper_ok or name not in _WRAPPER_RESIDENT_COMMANDS)
318
328
  and (bot_ok or name not in _BOT_RESIDENT_COMMANDS)
329
+ and (train_ok or name not in _TRAIN_RESIDENT_COMMANDS)
319
330
  )
320
331
  commands.update(_SPECIAL_COMMANDS.keys())
321
332
 
@@ -361,6 +372,10 @@ class LazyCommandGroup(TyperGroup):
361
372
  if not bot_package_available():
362
373
  return None
363
374
  module = importlib.import_module(f"praisonai_bot.cli.commands.{name}")
375
+ elif name in _TRAIN_RESIDENT_COMMANDS:
376
+ if not train_package_available():
377
+ return None
378
+ module = importlib.import_module(f"praisonai_train.cli.commands.{name}")
364
379
  elif name in _WRAPPER_RESIDENT_COMMANDS:
365
380
  if not wrapper_available():
366
381
  return None
@@ -787,7 +802,26 @@ def main_callback(
787
802
  trace_id=context.trace_id,
788
803
  )
789
804
  set_output_controller(state.output_controller)
790
-
805
+
806
+ # Non-blocking "update available" hint from the cached background check.
807
+ # Text-mode only, opt-out via PRAISONAI_NO_UPDATE_CHECK; never blocks or
808
+ # raises (only reads a time-boxed cache, never performs network I/O here).
809
+ if mode == OutputMode.TEXT and not state.quiet:
810
+ try:
811
+ from .features.self_manage import (
812
+ maybe_schedule_update_check,
813
+ read_cached_hint,
814
+ )
815
+
816
+ hint = read_cached_hint()
817
+ if hint:
818
+ typer.echo(hint, err=True)
819
+ # Warm the cache in a detached child for the next invocation. Never
820
+ # performs network I/O here and never blocks or raises.
821
+ maybe_schedule_update_check()
822
+ except Exception:
823
+ pass
824
+
791
825
  # If no command provided, start interactive mode
792
826
  if ctx.invoked_subcommand is None:
793
827
  # Check for credentials before starting TUI
@@ -21,6 +21,85 @@ from ..configuration.credentials import CredentialStore, redact_key, validate_ap
21
21
  app = typer.Typer(help="Manage API credentials")
22
22
 
23
23
 
24
+ # Provider id -> environment variable holding its API key. Used to fold active
25
+ # env-sourced credentials into `auth list`/`status` so users can tell which
26
+ # credential is live (env vs stored).
27
+ _PROVIDER_ENV_KEYS = {
28
+ "openai": "OPENAI_API_KEY",
29
+ "anthropic": "ANTHROPIC_API_KEY",
30
+ "google": "GOOGLE_API_KEY",
31
+ "gemini": "GEMINI_API_KEY",
32
+ "groq": "GROQ_API_KEY",
33
+ "openrouter": "OPENROUTER_API_KEY",
34
+ "mistral": "MISTRAL_API_KEY",
35
+ "deepseek": "DEEPSEEK_API_KEY",
36
+ "xai": "XAI_API_KEY",
37
+ "cohere": "COHERE_API_KEY",
38
+ "together": "TOGETHER_API_KEY",
39
+ "perplexity": "PERPLEXITYAI_API_KEY",
40
+ }
41
+
42
+
43
+ def _env_credentials() -> dict[str, tuple[str, str]]:
44
+ """Return ``{provider: (env_var, api_key)}`` for env-sourced keys present."""
45
+ found = {}
46
+ for provider, env_var in _PROVIDER_ENV_KEYS.items():
47
+ value = os.environ.get(env_var)
48
+ if value:
49
+ found[provider] = (env_var, value)
50
+ return found
51
+
52
+
53
+ def _select_provider_interactively(output) -> Optional[str]:
54
+ """Catalogue-driven provider picker for when no provider id is supplied.
55
+
56
+ Returns the chosen provider id, or ``None`` if selection is unavailable
57
+ (non-tty / rich missing) so the caller can prompt for a free-form id.
58
+ """
59
+ try:
60
+ from praisonai_code.llm.catalogue import ModelCatalogue
61
+
62
+ providers = ModelCatalogue().list_providers()
63
+ except Exception:
64
+ providers = []
65
+
66
+ ordered = [p for p in ("openai", "anthropic", "google", "ollama") if p in providers]
67
+ for p in providers:
68
+ if p not in ordered:
69
+ ordered.append(p)
70
+ ordered.append("custom")
71
+
72
+ try:
73
+ from rich.prompt import Prompt
74
+ except Exception:
75
+ return None
76
+
77
+ output.console.print("[bold]Choose your LLM provider:[/bold]")
78
+ choices = {}
79
+ for idx, pid in enumerate(ordered, start=1):
80
+ choices[str(idx)] = pid
81
+ label = "Other/custom" if pid == "custom" else pid
82
+ output.console.print(f" {idx}) {label}")
83
+
84
+ selected = Prompt.ask("Select provider", choices=list(choices.keys()), default="1")
85
+ pid = choices[selected]
86
+ if pid == "custom":
87
+ return Prompt.ask("Enter provider id").strip() or None
88
+ return pid
89
+
90
+
91
+ def _print_key_url_hint(provider: str, output) -> None:
92
+ """Print a one-line 'Get your key' hint for well-known providers."""
93
+ try:
94
+ from praisonai_code.llm.catalogue import key_url_for_provider
95
+
96
+ url = key_url_for_provider(provider)
97
+ except Exception:
98
+ url = None
99
+ if url:
100
+ output.print_info(f"Get your key: {url}")
101
+
102
+
24
103
  def _format_expiry(cred) -> str:
25
104
  """Format an OAuth credential's expiry for display ('(n/a)' for keys)."""
26
105
  if not getattr(cred, "auth_method", "apikey") == "oauth":
@@ -148,7 +227,7 @@ def _run_oauth_login(
148
227
 
149
228
  @app.command("login")
150
229
  def auth_login(
151
- provider: str = typer.Argument(help="Provider name (e.g., openai, anthropic)"),
230
+ provider: Optional[str] = typer.Argument(None, help="Provider name (e.g., openai, anthropic); prompts a picker if omitted"),
152
231
  method: str = typer.Option("auto", "--method", help="Auth method: auto, apikey, or oauth"),
153
232
  key: Optional[str] = typer.Option(None, "--key", help="API key (will prompt if not provided)"),
154
233
  key_stdin: bool = typer.Option(False, "--key-stdin", help="Read API key from stdin"),
@@ -173,6 +252,15 @@ def auth_login(
173
252
  """
174
253
  output = get_output_controller()
175
254
 
255
+ # Provider is optional: when omitted, present a catalogue-driven picker so
256
+ # users don't need to know the exact provider id up front. The positional
257
+ # argument still works for scripts.
258
+ if not provider:
259
+ provider = _select_provider_interactively(output)
260
+ if not provider:
261
+ output.print_error("A provider is required")
262
+ raise typer.Exit(1)
263
+
176
264
  # Assemble any OAuth endpoint overrides supplied on the command line. These
177
265
  # let users sign in to a built-in provider that needs an app client id, or
178
266
  # to a provider not in the registry (e.g. a self-hosted gateway).
@@ -232,6 +320,7 @@ def auth_login(
232
320
  api_key = key
233
321
  else:
234
322
  # Prompt for key
323
+ _print_key_url_hint(provider, output)
235
324
  try:
236
325
  api_key = typer.prompt(
237
326
  f"Enter API key for {provider}",
@@ -357,46 +446,74 @@ def auth_list():
357
446
  try:
358
447
  store = CredentialStore()
359
448
  providers = store.list_providers()
360
-
361
- if not providers:
362
- output.print_info("No stored credentials")
363
- if output.is_json_mode:
364
- output.print_json({"providers": []})
365
- return
366
-
367
- # Get detailed info for each provider
449
+
450
+ # Get detailed info for each stored provider.
368
451
  provider_info = []
452
+ stored_names = set()
369
453
  for provider_name in providers:
370
454
  cred = store.get_credential(provider_name)
371
455
  if cred:
372
- info = {
456
+ stored_names.add(provider_name.lower())
457
+ provider_info.append({
373
458
  "provider": provider_name,
374
459
  "auth_method": cred.auth_method,
460
+ "source": "stored",
461
+ "env_var": None,
375
462
  "key_redacted": redact_key(cred.api_key),
376
463
  "base_url": cred.base_url,
377
464
  "model": cred.model,
378
465
  "expires_at": cred.expires_at,
379
466
  "expires": _format_expiry(cred),
380
- }
381
- provider_info.append(info)
382
-
467
+ })
468
+
469
+ # Fold in active environment-variable keys (redacted) so the live
470
+ # credential is unambiguous. An env key is ALWAYS surfaced when present
471
+ # — even if the provider also has a stored key — because the env value
472
+ # overrides the stored one at runtime, so hiding it would point users at
473
+ # the wrong secret when they inspect or rotate credentials.
474
+ for provider_name, (env_var, value) in _env_credentials().items():
475
+ provider_info.append({
476
+ "provider": provider_name,
477
+ "auth_method": "apikey",
478
+ "source": "env",
479
+ "env_var": env_var,
480
+ "key_redacted": redact_key(value),
481
+ "base_url": None,
482
+ "model": None,
483
+ "expires_at": None,
484
+ "expires": "(n/a)",
485
+ "overrides_stored": provider_name in stored_names,
486
+ })
487
+
488
+ if not provider_info:
489
+ output.print_info("No stored credentials")
490
+ if output.is_json_mode:
491
+ output.print_json({"providers": []})
492
+ return
493
+
383
494
  if output.is_json_mode:
384
495
  output.print_json({"providers": provider_info})
385
496
  else:
386
497
  # Create table
387
- headers = ["Provider", "Method", "Secret", "Expires", "Base URL", "Model"]
498
+ headers = ["Provider", "Method", "Source", "Secret", "Expires", "Base URL", "Model"]
388
499
  rows = []
389
500
  for info in provider_info:
501
+ source = info["source"]
502
+ if source == "env" and info.get("env_var"):
503
+ source = f"env ({info['env_var']})"
504
+ if info.get("overrides_stored"):
505
+ source += " [live, overrides stored]"
390
506
  rows.append([
391
507
  info["provider"],
392
508
  info["auth_method"],
509
+ source,
393
510
  info["key_redacted"],
394
511
  info["expires"],
395
512
  info["base_url"] or "(default)",
396
513
  info["model"] or "(none)"
397
514
  ])
398
515
 
399
- output.print_table(headers, rows, title="Stored Credentials")
516
+ output.print_table(headers, rows, title="Credentials")
400
517
 
401
518
  except Exception as e:
402
519
  output.print_error(f"Failed to list credentials: {e}")
@@ -425,6 +542,40 @@ def auth_status(
425
542
  # Check specific provider
426
543
  cred = store.get_credential(provider)
427
544
  if not cred:
545
+ # Fall back to an active environment-variable key so the user
546
+ # can tell the credential is live from the env, not just missing
547
+ # from the store.
548
+ env_var = _PROVIDER_ENV_KEYS.get(provider.lower())
549
+ env_value = os.environ.get(env_var) if env_var else None
550
+ if env_value:
551
+ format_valid, format_msg = validate_api_key(provider, env_value)
552
+ status_info = {
553
+ "provider": provider,
554
+ "status": "found",
555
+ "auth_method": "apikey",
556
+ "source": "env",
557
+ "env_var": env_var,
558
+ "key_redacted": redact_key(env_value),
559
+ "format_valid": format_valid,
560
+ "format_message": format_msg,
561
+ "base_url": None,
562
+ "model": None,
563
+ "expires_at": None,
564
+ "expires": "(n/a)",
565
+ }
566
+ if output.is_json_mode:
567
+ output.print_json(status_info)
568
+ else:
569
+ output.print_panel(
570
+ f"Provider: {provider}\n"
571
+ f"Method: apikey\n"
572
+ f"Source: env ({env_var})\n"
573
+ f"Secret: {redact_key(env_value)}\n"
574
+ f"Format: {'✅' if format_valid else '❌'} {format_msg}",
575
+ title=f"Credentials Status: {provider}"
576
+ )
577
+ return
578
+
428
579
  output.print_warning(f"No credentials found for {provider}")
429
580
  if output.is_json_mode:
430
581
  output.print_json({
@@ -433,17 +584,34 @@ def auth_status(
433
584
  })
434
585
  raise typer.Exit(1)
435
586
 
436
- # Basic format validation (OAuth tokens have no static format)
587
+ # A live env var overrides the stored credential at runtime. When
588
+ # both exist, validate/report the env key (the credential actually
589
+ # in effect) so status never claims the wrong secret is active.
590
+ env_var = _PROVIDER_ENV_KEYS.get(provider.lower())
591
+ env_value = os.environ.get(env_var) if env_var else None
592
+ active_from_env = bool(env_value) and not cred.is_oauth()
593
+
437
594
  if cred.is_oauth():
438
595
  format_valid, format_msg = True, "OAuth token"
596
+ secret = cred.api_key
597
+ source = "stored"
598
+ elif active_from_env:
599
+ format_valid, format_msg = validate_api_key(provider, env_value)
600
+ secret = env_value
601
+ source = f"env ({env_var})"
439
602
  else:
440
603
  format_valid, format_msg = validate_api_key(provider, cred.api_key)
441
-
604
+ secret = cred.api_key
605
+ source = "stored"
606
+
442
607
  status_info = {
443
608
  "provider": provider,
444
609
  "status": "found",
445
610
  "auth_method": cred.auth_method,
446
- "key_redacted": redact_key(cred.api_key),
611
+ "source": source,
612
+ "env_var": env_var if active_from_env else None,
613
+ "overrides_stored": active_from_env,
614
+ "key_redacted": redact_key(secret),
447
615
  "format_valid": format_valid,
448
616
  "format_message": format_msg,
449
617
  "base_url": cred.base_url,
@@ -454,9 +622,11 @@ def auth_status(
454
622
 
455
623
  # Live validation if requested
456
624
  if validate:
457
- # Use a freshly-refreshed token for OAuth so we don't validate a
458
- # stale mirrored access token.
459
- live_secret = store.get_valid_token(provider) if cred.is_oauth() else cred.api_key
625
+ if cred.is_oauth():
626
+ # Freshly-refreshed token so we don't validate a stale mirror.
627
+ live_secret = store.get_valid_token(provider)
628
+ else:
629
+ live_secret = secret
460
630
  live_valid, live_msg = _validate_with_live_call(provider, live_secret, cred.base_url)
461
631
  status_info["live_valid"] = live_valid
462
632
  status_info["live_message"] = live_msg
@@ -467,7 +637,9 @@ def auth_status(
467
637
  output.print_panel(
468
638
  f"Provider: {provider}\n"
469
639
  f"Method: {cred.auth_method}\n"
470
- f"Secret: {redact_key(cred.api_key)}\n"
640
+ f"Source: {source}\n"
641
+ + ("Note: env var overrides stored key at runtime\n" if active_from_env else "") +
642
+ f"Secret: {redact_key(secret)}\n"
471
643
  + (f"Expires: {_format_expiry(cred)}\n" if cred.is_oauth() else "") +
472
644
  f"Format: {'✅' if format_valid else '❌'} {format_msg}\n"
473
645
  + (f"Live Test: {'✅' if status_info.get('live_valid') else '❌'} {status_info.get('live_message', 'Not tested')}\n" if validate else "") +
@@ -479,17 +651,13 @@ def auth_status(
479
651
  else:
480
652
  # Check all providers
481
653
  providers = store.list_providers()
482
-
483
- if not providers:
484
- output.print_info("No stored credentials")
485
- if output.is_json_mode:
486
- output.print_json({"providers": []})
487
- return
488
-
654
+
489
655
  all_status = []
656
+ stored_names = set()
490
657
  for provider_name in providers:
491
658
  cred = store.get_credential(provider_name)
492
659
  if cred:
660
+ stored_names.add(provider_name.lower())
493
661
  if cred.is_oauth():
494
662
  format_valid, format_msg = True, "OAuth token"
495
663
  else:
@@ -498,6 +666,7 @@ def auth_status(
498
666
  status = {
499
667
  "provider": provider_name,
500
668
  "auth_method": cred.auth_method,
669
+ "source": "stored",
501
670
  "key_redacted": redact_key(cred.api_key),
502
671
  "format_valid": format_valid,
503
672
  "format_message": format_msg,
@@ -516,12 +685,42 @@ def auth_status(
516
685
  status["live_message"] = live_msg
517
686
 
518
687
  all_status.append(status)
519
-
688
+
689
+ # Fold in active env-var keys (redacted), marked env-sourced. Always
690
+ # surfaced even when the provider also has a stored key, since the
691
+ # env value is the credential in effect at runtime.
692
+ for provider_name, (env_var, value) in _env_credentials().items():
693
+ format_valid, format_msg = validate_api_key(provider_name, value)
694
+ source = f"env ({env_var})"
695
+ if provider_name in stored_names:
696
+ source += " [live, overrides stored]"
697
+ status = {
698
+ "provider": provider_name,
699
+ "auth_method": "apikey",
700
+ "source": source,
701
+ "key_redacted": redact_key(value),
702
+ "format_valid": format_valid,
703
+ "format_message": format_msg,
704
+ "expires_at": None,
705
+ "expires": "(n/a)",
706
+ }
707
+ if validate:
708
+ live_valid, live_msg = _validate_with_live_call(provider_name, value, None)
709
+ status["live_valid"] = live_valid
710
+ status["live_message"] = live_msg
711
+ all_status.append(status)
712
+
713
+ if not all_status:
714
+ output.print_info("No stored credentials")
715
+ if output.is_json_mode:
716
+ output.print_json({"providers": []})
717
+ return
718
+
520
719
  if output.is_json_mode:
521
720
  output.print_json({"providers": all_status})
522
721
  else:
523
722
  # Create table
524
- headers = ["Provider", "Method", "Secret", "Expires", "Format"]
723
+ headers = ["Provider", "Method", "Source", "Secret", "Expires", "Format"]
525
724
  if validate:
526
725
  headers.append("Live Test")
527
726
 
@@ -530,6 +729,7 @@ def auth_status(
530
729
  row = [
531
730
  status["provider"],
532
731
  status["auth_method"],
732
+ status.get("source", "stored"),
533
733
  status["key_redacted"],
534
734
  status["expires"],
535
735
  "✅" if status["format_valid"] else "❌"
@@ -8,9 +8,12 @@ Project scaffolding command for the `.praisonai/` convention.
8
8
  config.yaml # sensible defaults (model, output mode)
9
9
  agents/assistant.md # working starter agent (frontmatter + body)
10
10
  commands/review.md # working starter command using $ARGUMENTS / @file
11
+ tools/example.py # commented @tool example, auto-discovered on run
11
12
 
12
13
  The scaffolded files are immediately discoverable and runnable via
13
14
  `praisonai run --agent assistant ...` and `praisonai run --command review ...`.
15
+ Tools dropped in `.praisonai/tools/*.py` are auto-loaded on every `run`
16
+ (gated by PRAISONAI_ALLOW_LOCAL_TOOLS).
14
17
  """
15
18
 
16
19
  from pathlib import Path
@@ -62,6 +65,29 @@ If a file path is provided, here are its contents:
62
65
  @$ARGUMENTS
63
66
  """
64
67
 
68
+ STARTER_TOOL_PY = '''\
69
+ """Project-local tools for this .praisonai/ project.
70
+
71
+ Every public callable in this directory is auto-discovered and made available
72
+ to the agent on `praisonai run` — no --tools flag required. Decorate a function
73
+ with @tool for a rich schema, or just define a plain function.
74
+
75
+ Loading executes this file, so it is gated by the PRAISONAI_ALLOW_LOCAL_TOOLS
76
+ opt-in (set PRAISONAI_ALLOW_LOCAL_TOOLS=true to enable local tool loading).
77
+ Uncomment the example below to try it:
78
+
79
+ praisonai run "use the greet tool to greet Ada"
80
+ """
81
+
82
+ # from praisonaiagents import tool
83
+ #
84
+ #
85
+ # @tool
86
+ # def greet(name: str) -> str:
87
+ # """Return a friendly greeting for the given name."""
88
+ # return f"Hello, {name}!"
89
+ '''
90
+
65
91
 
66
92
  def _any_provider_credential() -> bool:
67
93
  """Return True if any supported provider credential is present in env."""
@@ -136,6 +162,7 @@ def init(
136
162
  (base / "config.yaml", STARTER_CONFIG.format(model=scaffold_model)),
137
163
  (base / "agents" / "assistant.md", STARTER_AGENT_MD.format(model=scaffold_model)),
138
164
  (base / "commands" / "review.md", STARTER_COMMAND_MD),
165
+ (base / "tools" / "example.py", STARTER_TOOL_PY),
139
166
  ]
140
167
 
141
168
  written = []