crewai-cli 1.15.2.dev20260708__tar.gz → 1.15.2.dev20260711__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 (164) hide show
  1. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/PKG-INFO +2 -2
  2. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/pyproject.toml +1 -1
  3. crewai_cli-1.15.2.dev20260711/src/crewai_cli/__init__.py +1 -0
  4. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/crew_run_tui.py +234 -3
  5. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/run_declarative_flow.py +176 -3
  6. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_crew_run_tui.py +240 -0
  7. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_run_declarative_flow.py +211 -0
  8. crewai_cli-1.15.2.dev20260708/src/crewai_cli/__init__.py +0 -1
  9. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/.gitignore +0 -0
  10. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/README.md +0 -0
  11. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/add_crew_to_flow.py +0 -0
  12. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/__init__.py +0 -0
  13. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/constants.py +0 -0
  14. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/main.py +0 -0
  15. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/__init__.py +0 -0
  16. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/auth0.py +0 -0
  17. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/base_provider.py +0 -0
  18. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/entra_id.py +0 -0
  19. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/keycloak.py +0 -0
  20. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/okta.py +0 -0
  21. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/providers/workos.py +0 -0
  22. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/token.py +0 -0
  23. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/authentication/utils.py +0 -0
  24. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/checkpoint_cli.py +0 -0
  25. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/checkpoint_tui.py +0 -0
  26. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/cli.py +0 -0
  27. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/command.py +0 -0
  28. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/config.py +0 -0
  29. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/constants.py +0 -0
  30. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/create_crew.py +0 -0
  31. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/create_flow.py +0 -0
  32. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/create_json_crew.py +0 -0
  33. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/crew_chat.py +0 -0
  34. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/deploy/__init__.py +0 -0
  35. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/deploy/archive.py +0 -0
  36. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/deploy/main.py +0 -0
  37. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/deploy/validate.py +0 -0
  38. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/enterprise/__init__.py +0 -0
  39. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/enterprise/main.py +0 -0
  40. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/evaluate_crew.py +0 -0
  41. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/experimental/__init__.py +0 -0
  42. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/experimental/skills/__init__.py +0 -0
  43. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/experimental/skills/main.py +0 -0
  44. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/git.py +0 -0
  45. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/input_prompt.py +0 -0
  46. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/install_crew.py +0 -0
  47. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/kickoff_flow.py +0 -0
  48. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/memory_tui.py +0 -0
  49. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/model_catalog.py +0 -0
  50. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/organization/__init__.py +0 -0
  51. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/organization/main.py +0 -0
  52. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/plot_flow.py +0 -0
  53. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/plus_api.py +0 -0
  54. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/provider.py +0 -0
  55. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/py.typed +0 -0
  56. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/remote_template/__init__.py +0 -0
  57. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/remote_template/main.py +0 -0
  58. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/replay_from_task.py +0 -0
  59. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/reset_memories_command.py +0 -0
  60. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/run_crew.py +0 -0
  61. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/settings/__init__.py +0 -0
  62. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/settings/main.py +0 -0
  63. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/shared/__init__.py +0 -0
  64. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/shared/token_manager.py +0 -0
  65. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/task_outputs.py +0 -0
  66. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/AGENTS.md +0 -0
  67. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/__init__.py +0 -0
  68. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/.gitignore +0 -0
  69. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/README.md +0 -0
  70. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/__init__.py +0 -0
  71. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/config/agents.yaml +0 -0
  72. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/config/tasks.yaml +0 -0
  73. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/crew.py +0 -0
  74. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/knowledge/user_preference.txt +0 -0
  75. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/main.py +0 -0
  76. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/pyproject.toml +0 -0
  77. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/skills/.gitkeep +0 -0
  78. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/tools/__init__.py +0 -0
  79. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/crew/tools/custom_tool.py +0 -0
  80. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/.gitignore +0 -0
  81. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/AGENTS.md +0 -0
  82. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/README.md +0 -0
  83. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/flow.yaml +0 -0
  84. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/declarative_flow/pyproject.toml +0 -0
  85. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/.gitignore +0 -0
  86. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/README.md +0 -0
  87. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/__init__.py +0 -0
  88. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/crews/content_crew/config/agents.yaml +0 -0
  89. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/crews/content_crew/config/tasks.yaml +0 -0
  90. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/crews/content_crew/content_crew.py +0 -0
  91. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/main.py +0 -0
  92. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/pyproject.toml +0 -0
  93. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/skills/.gitkeep +0 -0
  94. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/tools/__init__.py +0 -0
  95. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/flow/tools/custom_tool.py +0 -0
  96. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/.gitignore +0 -0
  97. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/README.md +0 -0
  98. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/agent.jsonc +0 -0
  99. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/agent_settings.jsonc +0 -0
  100. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/crew.jsonc +0 -0
  101. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/knowledge/user_preference.txt +0 -0
  102. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/pyproject.toml +0 -0
  103. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/json_crew/task.jsonc +0 -0
  104. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/.gitignore +0 -0
  105. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/README.md +0 -0
  106. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/pyproject.toml +0 -0
  107. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/src/{{folder_name}}/__init__.py +0 -0
  108. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/templates/tool/src/{{folder_name}}/tool.py +0 -0
  109. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/tools/__init__.py +0 -0
  110. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/tools/main.py +0 -0
  111. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/train_crew.py +0 -0
  112. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/triggers/__init__.py +0 -0
  113. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/triggers/main.py +0 -0
  114. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/tui_picker.py +0 -0
  115. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/update_crew.py +0 -0
  116. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/user_data.py +0 -0
  117. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/utils.py +0 -0
  118. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/src/crewai_cli/version.py +0 -0
  119. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/__init__.py +0 -0
  120. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/__init__.py +0 -0
  121. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/__init__.py +0 -0
  122. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_auth0.py +0 -0
  123. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_entra_id.py +0 -0
  124. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_keycloak.py +0 -0
  125. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_okta.py +0 -0
  126. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/providers/test_workos.py +0 -0
  127. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/test_auth_main.py +0 -0
  128. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/authentication/test_utils.py +0 -0
  129. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/deploy/__init__.py +0 -0
  130. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/deploy/test_archive.py +0 -0
  131. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/deploy/test_deploy_main.py +0 -0
  132. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/deploy/test_validate.py +0 -0
  133. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/enterprise/__init__.py +0 -0
  134. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/enterprise/test_main.py +0 -0
  135. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/experimental/__init__.py +0 -0
  136. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/experimental/skills/__init__.py +0 -0
  137. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/experimental/skills/test_main.py +0 -0
  138. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/organization/__init__.py +0 -0
  139. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/organization/test_main.py +0 -0
  140. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/skills/__init__.py +0 -0
  141. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/skills/test_safe_extract.py +0 -0
  142. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_cli.py +0 -0
  143. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_click_compatibility.py +0 -0
  144. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_config.py +0 -0
  145. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_constants.py +0 -0
  146. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_create_crew.py +0 -0
  147. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_create_flow.py +0 -0
  148. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_crew_test.py +0 -0
  149. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_flow_commands.py +0 -0
  150. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_git.py +0 -0
  151. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_input_prompt.py +0 -0
  152. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_install_crew.py +0 -0
  153. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_kickoff_flow.py +0 -0
  154. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_model_catalog.py +0 -0
  155. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_plus_api.py +0 -0
  156. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_run_crew.py +0 -0
  157. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_settings_command.py +0 -0
  158. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_token_manager.py +0 -0
  159. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_train_crew.py +0 -0
  160. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_utils.py +0 -0
  161. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/test_version.py +0 -0
  162. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/tools/__init__.py +0 -0
  163. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/tools/test_main.py +0 -0
  164. {crewai_cli-1.15.2.dev20260708 → crewai_cli-1.15.2.dev20260711}/tests/triggers/test_main.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crewai-cli
3
- Version: 1.15.2.dev20260708
3
+ Version: 1.15.2.dev20260711
4
4
  Summary: CLI for CrewAI — scaffold, run, deploy and manage AI agent crews.
5
5
  Project-URL: Homepage, https://crewai.com
6
6
  Project-URL: Documentation, https://docs.crewai.com
@@ -10,7 +10,7 @@ Requires-Python: <3.14,>=3.10
10
10
  Requires-Dist: appdirs~=1.4.4
11
11
  Requires-Dist: certifi
12
12
  Requires-Dist: click<9,>=8.1.7
13
- Requires-Dist: crewai-core==1.15.2.dev20260708
13
+ Requires-Dist: crewai-core==1.15.2.dev20260711
14
14
  Requires-Dist: cryptography>=42.0
15
15
  Requires-Dist: httpx~=0.28.1
16
16
  Requires-Dist: packaging>=23.0
@@ -8,7 +8,7 @@ authors = [
8
8
  ]
9
9
  requires-python = ">=3.10, <3.14"
10
10
  dependencies = [
11
- "crewai-core==1.15.2.dev20260708",
11
+ "crewai-core==1.15.2.dev20260711",
12
12
  "click>=8.1.7,<9",
13
13
  "pydantic>=2.11.9,<2.13",
14
14
  "pydantic-settings~=2.10.1",
@@ -0,0 +1 @@
1
+ __version__ = "1.15.2.dev20260711"
@@ -568,12 +568,32 @@ FooterKey .footer-key--key {
568
568
  self._default_inputs: dict[str, Any] | None = None
569
569
  self._crew_result: Any = None
570
570
  self._crew_json_path: Any = None
571
+ # Declarative-flow execution state. A flow renders per-method "STEPS"
572
+ # (built from flow method events) instead of the crew task list.
573
+ self._flow_inputs: dict[str, Any] | None = None
574
+ self._flow_method_types: dict[str, str] = {}
575
+ self._flow_steps: list[dict[str, Any]] = []
576
+ self._current_method: str | None = None
571
577
  self._elapsed_frozen: float | None = None
572
578
  self._want_deploy: bool = False
573
579
  self._trace_url: str | None = None
574
580
  self._consent_screen: TraceConsentScreen | None = None
575
581
  self._telemetry: Telemetry | None = None
576
582
 
583
+ @property
584
+ def _is_flow_run(self) -> bool:
585
+ """True for a non-conversational declarative flow (the STEPS view).
586
+
587
+ Gates every flow-specific rendering branch so crew and conversational
588
+ paths stay byte-identical.
589
+ """
590
+ return self._flow is not None and not self._is_conversational
591
+
592
+ @property
593
+ def _run_noun(self) -> str:
594
+ """User-facing noun for the run — 'flow' for a declarative flow, else 'crew'."""
595
+ return "flow" if self._is_flow_run else "crew"
596
+
577
597
  # ── Layout ──────────────────────────────────────────────
578
598
 
579
599
  def compose(self) -> ComposeResult:
@@ -602,6 +622,8 @@ FooterKey .footer-key--key {
602
622
  self._tick_timer = self.set_interval(1 / 8, self._tick)
603
623
  if self._is_conversational and self._flow:
604
624
  self._start_conversational_session()
625
+ elif self._flow:
626
+ self._run_flow_worker()
605
627
  elif self._crew:
606
628
  self._run_crew_worker()
607
629
  elif self._crew_json_path:
@@ -681,6 +703,49 @@ FooterKey .footer-key--key {
681
703
  except Exception as e:
682
704
  self.call_from_thread(self._on_crew_failed, str(e))
683
705
 
706
+ @work(thread=True, exclusive=True, group="flow")
707
+ def _run_flow_worker(self) -> None:
708
+ from crewai.events.listeners.tracing.utils import (
709
+ set_suppress_tracing_messages,
710
+ set_tui_mode,
711
+ )
712
+
713
+ set_tui_mode(True)
714
+ set_suppress_tracing_messages(True)
715
+ try:
716
+ # A declarative flow returns either a CrewOutput (has ``.raw``) or a
717
+ # bare value (str/dict/pydantic); _stringify_output handles both.
718
+ result = self._flow.kickoff(inputs=self._flow_inputs)
719
+ output = self._stringify_output(result)
720
+ with self._lock:
721
+ self._crew_result = result
722
+ self.call_from_thread(self._on_crew_done, output)
723
+ except Exception as e:
724
+ self.call_from_thread(self._on_crew_failed, str(e))
725
+
726
+ def _set_flow_step_status(self, name: str, status: str) -> None:
727
+ """Update a flow method step's status. Caller must hold ``self._lock``."""
728
+ for step in self._flow_steps:
729
+ if step["name"] == name:
730
+ step["status"] = status
731
+ return
732
+
733
+ def _clear_current_method(self, finished_name: str) -> None:
734
+ """Drop the header's active method once it ends. Caller holds the lock.
735
+
736
+ Falls back to another still-active step (methods can overlap) so the
737
+ header never keeps spinning a method the STEPS list already shows as
738
+ done or failed.
739
+ """
740
+ if self._current_method != finished_name:
741
+ return
742
+ self._current_method = next(
743
+ (s["name"] for s in self._flow_steps if s["status"] == "active"), None
744
+ )
745
+ # The active method changed; drop its agent so the header doesn't show a
746
+ # stale agent until the next method's agent event arrives.
747
+ self._current_agent = ""
748
+
684
749
  def _on_crew_done(self, output: str | None) -> None:
685
750
  with self._lock:
686
751
  self._status = "completed"
@@ -694,13 +759,18 @@ FooterKey .footer-key--key {
694
759
  for k in self._task_statuses:
695
760
  if self._task_statuses[k] == "active":
696
761
  self._task_statuses[k] = "done"
762
+ for step in self._flow_steps:
763
+ if step["status"] == "active":
764
+ step["status"] = "done"
697
765
  now = time.time()
698
766
  for entry in self._log_entries:
699
767
  if entry["status"] == "running":
700
768
  if entry["tool_name"] == "memory_save":
701
769
  continue
702
770
  entry["status"] = "timeout"
703
- entry["error"] = "No result received before crew completed"
771
+ entry["error"] = (
772
+ f"No result received before {self._run_noun} completed"
773
+ )
704
774
  entry["duration"] = now - entry["start_time"]
705
775
  try:
706
776
  from crewai.events.listeners.tracing.trace_listener import (
@@ -739,13 +809,18 @@ FooterKey .footer-key--key {
739
809
  self._is_streaming = False
740
810
  self._current_step = None
741
811
  self._elapsed_frozen = time.time() - self._start_time
812
+ for step in self._flow_steps:
813
+ if step["status"] == "active":
814
+ step["status"] = "failed"
742
815
  now = time.time()
743
816
  for entry in self._log_entries:
744
817
  if entry["status"] == "running":
745
818
  if entry["tool_name"] == "memory_save":
746
819
  continue
747
820
  entry["status"] = "error"
748
- entry["error"] = "No result received before crew failed"
821
+ entry["error"] = (
822
+ f"No result received before {self._run_noun} failed"
823
+ )
749
824
  entry["duration"] = now - entry["start_time"]
750
825
  self._tick()
751
826
  self.call_later(self._focus_activity_log)
@@ -1156,6 +1231,45 @@ FooterKey .footer-key--key {
1156
1231
  widget.update(t)
1157
1232
  return
1158
1233
 
1234
+ if self._is_flow_run:
1235
+ t.append(" STEPS\n", style=f"bold {_C_PRIMARY}")
1236
+ t.append("\n")
1237
+ if not self._flow_steps:
1238
+ t.append(" ○ waiting…\n", style=_C_DIM)
1239
+ for step in self._flow_steps:
1240
+ name = step["name"]
1241
+ max_name = sidebar_width - 6
1242
+ if len(name) > max_name:
1243
+ name = name[: max_name - 1] + "…"
1244
+ status = step.get("status", "pending")
1245
+ if status == "done":
1246
+ t.append(" ✔ ", style=_C_GREEN)
1247
+ t.append(name, style=_C_DIM)
1248
+ elif status == "active":
1249
+ t.append(f" {self._spinner()} ", style=_C_PRIMARY)
1250
+ t.append(name, style=f"bold {_C_TEXT}")
1251
+ elif status == "failed":
1252
+ t.append(" ✘ ", style=_C_RED)
1253
+ t.append(name, style=_C_RED)
1254
+ elif status == "paused":
1255
+ t.append(" ⏸ ", style=_C_TEAL)
1256
+ t.append(name, style=_C_TEAL)
1257
+ else:
1258
+ t.append(" ○ ", style=_C_DIM)
1259
+ t.append(name, style=_C_DIM)
1260
+ if step.get("call_type"):
1261
+ t.append(f" ({step['call_type']})", style=_C_DIM)
1262
+ t.append("\n")
1263
+
1264
+ t.append("\n")
1265
+ t.append(" TOKENS\n", style=f"bold {_C_PRIMARY}")
1266
+ t.append("\n")
1267
+ out = self._output_tokens + self._live_out_tokens
1268
+ t.append(f" ↑ {self._input_tokens:,}\n", style=_C_DIM)
1269
+ t.append(f" ↓ {out:,}\n", style=_C_DIM)
1270
+ widget.update(t)
1271
+ return
1272
+
1159
1273
  t.append(" TASKS\n", style=f"bold {_C_PRIMARY}")
1160
1274
  t.append("\n")
1161
1275
 
@@ -1225,6 +1339,55 @@ FooterKey .footer-key--key {
1225
1339
  widget.update(t)
1226
1340
  return
1227
1341
 
1342
+ if self._is_flow_run:
1343
+ if self._status == "completed":
1344
+ elapsed = self._elapsed_frozen or (time.time() - self._start_time)
1345
+ t.append("✔ ", style=f"bold {_C_GREEN}")
1346
+ t.append("Flow complete", style=f"bold {_C_GREEN}")
1347
+ t.append(f" {elapsed:.1f}s", style=_C_DIM)
1348
+ out = self._output_tokens + self._live_out_tokens
1349
+ parts = []
1350
+ if self._input_tokens:
1351
+ parts.append(f"↑{self._input_tokens:,}")
1352
+ if out:
1353
+ parts.append(f"↓{out:,}")
1354
+ if parts:
1355
+ t.append(f" {' '.join(parts)} tokens", style=_C_DIM)
1356
+ elif self._status == "failed":
1357
+ t.append("✘ ", style=f"bold {_C_RED}")
1358
+ t.append("Failed", style=f"bold {_C_RED}")
1359
+ if self._error:
1360
+ t.append(f"\n{self._error[:120]}", style=_C_RED)
1361
+ elif self._current_method:
1362
+ paused = any(
1363
+ s["name"] == self._current_method and s["status"] == "paused"
1364
+ for s in self._flow_steps
1365
+ )
1366
+ if paused:
1367
+ t.append("⏸ ", style=_C_TEAL)
1368
+ t.append(self._current_method, style=f"bold {_C_TEAL}")
1369
+ else:
1370
+ t.append(f"{self._spinner()} ", style=_C_PRIMARY)
1371
+ t.append(self._current_method, style=f"bold {_C_PRIMARY}")
1372
+ call_type = self._flow_method_types.get(self._current_method)
1373
+ if call_type:
1374
+ t.append(f" ({call_type})", style=_C_DIM)
1375
+ if paused:
1376
+ t.append(" waiting for feedback", style=_C_DIM)
1377
+ elif self._current_agent:
1378
+ t.append("\nAgent: ", style=_C_DIM)
1379
+ t.append(self._current_agent, style=f"bold {_C_TEXT}")
1380
+ else:
1381
+ t.append(f"{self._spinner()} ", style=_C_PRIMARY)
1382
+ # "Working…" once a step has run (between/after methods);
1383
+ # "Starting flow…" only before the first method.
1384
+ t.append(
1385
+ "Working…" if self._flow_steps else "Starting flow…",
1386
+ style=_C_DIM,
1387
+ )
1388
+ widget.update(t)
1389
+ return
1390
+
1228
1391
  if self._status == "completed":
1229
1392
  elapsed = self._elapsed_frozen or (time.time() - self._start_time)
1230
1393
  t.append("✔ ", style=f"bold {_C_GREEN}")
@@ -1839,6 +2002,13 @@ FooterKey .footer-key--key {
1839
2002
  def _subscribe(self) -> None:
1840
2003
  from crewai.events.event_bus import crewai_event_bus
1841
2004
  from crewai.events.types.crew_events import CrewKickoffStartedEvent
2005
+ from crewai.events.types.flow_events import (
2006
+ FlowStartedEvent,
2007
+ MethodExecutionFailedEvent,
2008
+ MethodExecutionFinishedEvent,
2009
+ MethodExecutionPausedEvent,
2010
+ MethodExecutionStartedEvent,
2011
+ )
1842
2012
  from crewai.events.types.llm_events import (
1843
2013
  LLMCallCompletedEvent,
1844
2014
  LLMCallStartedEvent,
@@ -1872,13 +2042,74 @@ FooterKey .footer-key--key {
1872
2042
  @crewai_event_bus.on(CrewKickoffStartedEvent)
1873
2043
  def on_crew_started(source: Any, event: CrewKickoffStartedEvent) -> None:
1874
2044
  with self._lock:
1875
- if event.crew_name:
2045
+ # In flow mode the app is named for the flow; a nested crew's
2046
+ # kickoff (a `call: crew` step) must not rename it.
2047
+ if event.crew_name and not self._is_flow_run:
1876
2048
  self._crew_name = event.crew_name
1877
2049
  self.title = f"CrewAI — {event.crew_name}"
1878
2050
  self._status = "working"
1879
2051
 
1880
2052
  self._register_handler(CrewKickoffStartedEvent, on_crew_started)
1881
2053
 
2054
+ # ── Declarative-flow method events → STEPS panel ────────
2055
+ @crewai_event_bus.on(FlowStartedEvent)
2056
+ def on_flow_started(source: Any, event: FlowStartedEvent) -> None:
2057
+ with self._lock:
2058
+ self._status = "working"
2059
+
2060
+ self._register_handler(FlowStartedEvent, on_flow_started)
2061
+
2062
+ @crewai_event_bus.on(MethodExecutionStartedEvent)
2063
+ def on_method_started(source: Any, event: MethodExecutionStartedEvent) -> None:
2064
+ with self._lock:
2065
+ name = event.method_name
2066
+ self._current_method = name
2067
+ # Agent is per-method; clear it so the header doesn't show the
2068
+ # previous method's agent until a new agent event arrives.
2069
+ self._current_agent = ""
2070
+ for step in self._flow_steps:
2071
+ if step["name"] == name:
2072
+ step["status"] = "active"
2073
+ break
2074
+ else:
2075
+ self._flow_steps.append(
2076
+ {
2077
+ "name": name,
2078
+ "call_type": self._flow_method_types.get(name),
2079
+ "status": "active",
2080
+ }
2081
+ )
2082
+
2083
+ self._register_handler(MethodExecutionStartedEvent, on_method_started)
2084
+
2085
+ @crewai_event_bus.on(MethodExecutionFinishedEvent)
2086
+ def on_method_finished(
2087
+ source: Any, event: MethodExecutionFinishedEvent
2088
+ ) -> None:
2089
+ with self._lock:
2090
+ self._set_flow_step_status(event.method_name, "done")
2091
+ self._clear_current_method(event.method_name)
2092
+
2093
+ self._register_handler(MethodExecutionFinishedEvent, on_method_finished)
2094
+
2095
+ @crewai_event_bus.on(MethodExecutionFailedEvent)
2096
+ def on_method_failed(source: Any, event: MethodExecutionFailedEvent) -> None:
2097
+ with self._lock:
2098
+ self._set_flow_step_status(event.method_name, "failed")
2099
+ self._clear_current_method(event.method_name)
2100
+
2101
+ self._register_handler(MethodExecutionFailedEvent, on_method_failed)
2102
+
2103
+ @crewai_event_bus.on(MethodExecutionPausedEvent)
2104
+ def on_method_paused(source: Any, event: MethodExecutionPausedEvent) -> None:
2105
+ # A @human_feedback method paused; flow status panels are suppressed
2106
+ # in TUI mode, so surface the wait in STEPS/header instead of leaving
2107
+ # a spinner. _current_method stays pointed at it.
2108
+ with self._lock:
2109
+ self._set_flow_step_status(event.method_name, "paused")
2110
+
2111
+ self._register_handler(MethodExecutionPausedEvent, on_method_paused)
2112
+
1882
2113
  @crewai_event_bus.on(TaskStartedEvent)
1883
2114
  def on_task_started(source: Any, event: TaskStartedEvent) -> None:
1884
2115
  with self._lock:
@@ -1,9 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+ import logging
4
5
  from pathlib import Path
5
6
  import subprocess
6
- from typing import Any
7
+ from typing import TYPE_CHECKING, Any
7
8
 
8
9
  import click
9
10
  from crewai_core.project import ProjectDefinitionError, configured_project_definition
@@ -18,6 +19,13 @@ from crewai_cli.input_prompt import (
18
19
  from crewai_cli.utils import build_env_with_all_tool_credentials
19
20
 
20
21
 
22
+ if TYPE_CHECKING:
23
+ from crewai.flow.flow import Flow
24
+
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
21
29
  def run_declarative_flow_in_project_env(
22
30
  definition: str | Path, inputs: str | None = None
23
31
  ) -> None:
@@ -66,17 +74,182 @@ def run_declarative_flow(definition: str | Path, inputs: str | None = None) -> N
66
74
  flow = load_declarative_flow(definition)
67
75
  resolved_inputs = _resolve_flow_inputs(flow, provided)
68
76
 
77
+ # The TUI is the interactive default. Headless contexts run directly on the
78
+ # terminal: deploy/CREWAI_DMN, piped output, CI — anything without an
79
+ # interactive TTY. is_interactive() already folds in the CREWAI_DMN check.
80
+ # Human-feedback flows also run on the terminal: their methods collect input
81
+ # via the flow runtime's blocking input()/Rich prompts (and async feedback
82
+ # returns a pending marker rather than completing), neither of which the
83
+ # Textual TUI can handle correctly.
84
+ if is_interactive() and not _flow_uses_human_feedback(flow):
85
+ _run_declarative_flow_tui(flow, resolved_inputs or None)
86
+ return
87
+
69
88
  try:
70
89
  result = flow.kickoff(inputs=resolved_inputs or None)
71
90
  except Exception as exc:
72
91
  click.echo(
73
- f"An error occurred while running the declarative flow: {exc}", err=True
92
+ f"An error occurred while running the declarative flow: {exc}",
93
+ err=True,
74
94
  )
75
95
  raise SystemExit(1) from exc
76
-
77
96
  click.echo(_format_result(result))
78
97
 
79
98
 
99
+ def _run_declarative_flow_tui(
100
+ flow: Flow[Any], resolved_inputs: dict[str, Any] | None
101
+ ) -> Any:
102
+ """Run a declarative flow on the CrewAI TUI (the interactive default).
103
+
104
+ Mirrors the declarative-crew TUI contract (``run_crew._run_json_crew``):
105
+ a failed flow exits non-zero, a user quit ends the process so in-flight LLM
106
+ work stops, and choosing Deploy chains into the deploy command.
107
+ """
108
+ import os
109
+ import sys
110
+
111
+ from crewai.events.event_listener import EventListener
112
+
113
+ from crewai_cli.crew_run_tui import CrewRunApp
114
+
115
+ # The flow runtime (unlike a Crew constructor) doesn't create the event
116
+ # listener, and the TUI's trace/telemetry features depend on it.
117
+ EventListener()
118
+
119
+ # The STEPS panel and header are driven by flow method events. A flow may
120
+ # declare ``config.suppress_flow_events`` (a headless/production
121
+ # optimization) which would leave STEPS stuck on "waiting…" here — so force
122
+ # emission on for the interactive TUI run. The headless path never reaches
123
+ # this and keeps the flow's declared setting.
124
+ try:
125
+ flow.suppress_flow_events = False
126
+ except Exception:
127
+ logger.debug(
128
+ "Could not disable suppress_flow_events for the flow TUI", exc_info=True
129
+ )
130
+
131
+ app = CrewRunApp(crew_name=flow.name or type(flow).__name__)
132
+ app._flow = flow
133
+ app._flow_inputs = resolved_inputs
134
+ app._flow_method_types = _flow_method_types(flow)
135
+
136
+ app.run()
137
+
138
+ _print_flow_post_tui_summary(app)
139
+
140
+ if app._status == "failed":
141
+ raise SystemExit(1)
142
+
143
+ if app._status not in ("completed", "failed"):
144
+ # User quit mid-run. kickoff runs in a thread worker that cannot be
145
+ # force-cancelled, so end the process to stop in-flight LLM and tool
146
+ # work instead of letting it burn tokens in the background.
147
+ click.secho("\n Run cancelled.", fg="yellow")
148
+ sys.stdout.flush()
149
+ os._exit(130)
150
+
151
+ if getattr(app, "_want_deploy", False):
152
+ from crewai_cli.run_crew import _chain_deploy
153
+
154
+ _chain_deploy()
155
+
156
+ return app._crew_result
157
+
158
+
159
+ def _flow_uses_human_feedback(flow: Flow[Any]) -> bool:
160
+ """True if any declarative method declares ``@human_feedback``.
161
+
162
+ Such flows need the flow runtime's interactive stdin / Rich prompts, which
163
+ don't compose with Textual — so they run on the terminal, not the TUI.
164
+ """
165
+ try:
166
+ return any(
167
+ method.human_feedback is not None
168
+ for method in flow._definition.methods.values()
169
+ )
170
+ except Exception:
171
+ logger.debug("Could not inspect flow for human feedback", exc_info=True)
172
+ return False
173
+
174
+
175
+ def _flow_method_types(flow: Flow[Any]) -> dict[str, str]:
176
+ """Map each declarative method name to its ``call`` type (crew/agent/…).
177
+
178
+ Best-effort: the STEPS panel shows this as a dim label. Method events don't
179
+ carry the call type, so it's read from the flow definition up front.
180
+ """
181
+ method_types: dict[str, str] = {}
182
+ try:
183
+ for name, method_definition in flow._definition.methods.items():
184
+ method_types[name] = method_definition.do.call
185
+ except Exception:
186
+ logger.debug("Could not derive flow method types", exc_info=True)
187
+ return method_types
188
+
189
+
190
+ def _print_flow_post_tui_summary(app: Any) -> None:
191
+ """Print a compact result panel after the flow TUI exits."""
192
+ import time
193
+
194
+ from rich.console import Console
195
+ from rich.markdown import Markdown
196
+ from rich.padding import Padding
197
+ from rich.panel import Panel
198
+ from rich.text import Text
199
+
200
+ console = Console()
201
+ elapsed = (app._elapsed_frozen or (time.time() - app._start_time)) or 0.0
202
+
203
+ out_tokens = app._output_tokens + app._live_out_tokens
204
+ token_parts = []
205
+ if app._input_tokens:
206
+ token_parts.append(f"↑{app._input_tokens:,}")
207
+ if out_tokens:
208
+ token_parts.append(f"↓{out_tokens:,}")
209
+ token_str = " ".join(token_parts)
210
+ if token_str:
211
+ token_str += " tokens"
212
+
213
+ crewai_red = "#FF5A50"
214
+ crewai_teal = "#1F7982"
215
+
216
+ if app._status == "completed":
217
+ summary = Text()
218
+ summary.append(" ✔ Flow complete", style=f"bold {crewai_teal}")
219
+ summary.append(f" in {elapsed:.1f}s", style="dim")
220
+ if token_str:
221
+ summary.append(f" {token_str}", style="dim")
222
+ console.print(
223
+ Panel(
224
+ summary,
225
+ title=f" {app._crew_name} ",
226
+ title_align="left",
227
+ border_style=crewai_teal,
228
+ padding=(0, 1),
229
+ )
230
+ )
231
+ if app._final_output:
232
+ console.print()
233
+ console.print(Text(" Final Result", style=f"bold {crewai_teal}"))
234
+ console.print()
235
+ console.print(Padding(Markdown(app._final_output), (0, 2)))
236
+ elif app._status == "failed":
237
+ content = Text()
238
+ content.append(" ✘ Failed", style=f"bold {crewai_red}")
239
+ content.append(f" after {elapsed:.1f}s\n", style="dim")
240
+ if app._error:
241
+ content.append(f"\n {app._error}\n", style=crewai_red)
242
+ console.print(
243
+ Panel(
244
+ content,
245
+ title=f" {app._crew_name} ",
246
+ title_align="left",
247
+ border_style=crewai_red,
248
+ padding=(0, 1),
249
+ )
250
+ )
251
+
252
+
80
253
  def _resolve_flow_inputs(flow: Any, provided: dict[str, Any]) -> dict[str, Any]:
81
254
  """Resolve kickoff inputs from the flow's state schema.
82
255