ayder-cli 2.1.2__tar.gz → 2.1.5__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 (242) hide show
  1. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/PKG-INFO +6 -3
  2. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/README.md +3 -2
  3. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/docs/config.toml.example +6 -1
  4. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/pyproject.toml +2 -1
  5. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/application/runtime_factory.py +8 -1
  6. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/cli.py +74 -16
  7. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/cli_runner.py +19 -4
  8. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/core/config.py +16 -1
  9. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/core/ollama_context_manager.py +2 -2
  10. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/themes/claude.py +27 -0
  11. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/themes/original.py +21 -0
  12. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/definition.py +10 -4
  13. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/plugin_manager.py +9 -4
  14. ayder_cli-2.1.5/src/ayder_cli/tools/plugin_status.py +33 -0
  15. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/__init__.py +4 -1
  16. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/app.py +94 -31
  17. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/commands.py +38 -8
  18. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/keybindings.py +3 -3
  19. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/widgets.py +147 -14
  20. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/application/test_runtime_factory.py +62 -0
  21. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_config_coverage.py +13 -9
  22. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_config_v2.py +38 -0
  23. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_ollama_context_manager.py +15 -0
  24. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/test_cli.py +208 -26
  25. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_plugin_manager.py +82 -0
  26. ayder_cli-2.1.5/tests/tools/test_plugin_status.py +36 -0
  27. ayder_cli-2.1.5/tests/tui/test_input_box.py +114 -0
  28. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_multiline_input.py +37 -40
  29. ayder_cli-2.1.5/tests/tui/test_status_bar_badges.py +70 -0
  30. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_widgets.py +77 -1
  31. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_confirm_screen.py +2 -0
  32. ayder_cli-2.1.5/tests/ui/test_plugin_autoenable.py +44 -0
  33. ayder_cli-2.1.5/tests/ui/test_tui_commands_plugin.py +72 -0
  34. ayder_cli-2.1.2/CHANGELOG.md +0 -14
  35. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/.github/workflows/ci.yml +0 -0
  36. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/.github/workflows/python-package.yml +0 -0
  37. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/.gitignore +0 -0
  38. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/.python-version +0 -0
  39. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/AGENTS.md +0 -0
  40. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/LICENSE +0 -0
  41. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/docs/PROJECT_STRUCTURE.md +0 -0
  42. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/docs/README_AGENT_WORKFLOW.md +0 -0
  43. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/docs/README_OLLAMA.md +0 -0
  44. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/docs/cc.png +0 -0
  45. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/__init__.py +0 -0
  46. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/__main__.py +0 -0
  47. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/agents/__init__.py +0 -0
  48. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/agents/callbacks.py +0 -0
  49. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/agents/config.py +0 -0
  50. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/agents/registry.py +0 -0
  51. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/agents/run.py +0 -0
  52. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/agents/runner.py +0 -0
  53. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/agents/tool.py +0 -0
  54. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/application/README.md +0 -0
  55. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/application/__init__.py +0 -0
  56. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/application/execution_policy.py +0 -0
  57. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/application/message_contract.py +0 -0
  58. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/application/validation.py +0 -0
  59. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/cli_callbacks.py +0 -0
  60. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/console.py +0 -0
  61. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/core/cache_monitor.py +0 -0
  62. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/core/config_migration.py +0 -0
  63. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/core/context.py +0 -0
  64. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/core/context_manager.py +0 -0
  65. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/core/context_manager_factory.py +0 -0
  66. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/core/default_context_manager.py +0 -0
  67. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/core/result.py +0 -0
  68. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/logging_config.py +0 -0
  69. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/loops/__init__.py +0 -0
  70. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/loops/chat_loop.py +0 -0
  71. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/parser.py +0 -0
  72. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/process_manager.py +0 -0
  73. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/prompts.py +0 -0
  74. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/__init__.py +0 -0
  75. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/base.py +0 -0
  76. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/claude.py +0 -0
  77. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/deepseek.py +0 -0
  78. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/gemini.py +0 -0
  79. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/glm.py +0 -0
  80. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama.py +0 -0
  81. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/__init__.py +0 -0
  82. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/_errors.py +0 -0
  83. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/base.py +0 -0
  84. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/deepseek.py +0 -0
  85. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/generic_native.py +0 -0
  86. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/generic_xml.py +0 -0
  87. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/matrix.py +0 -0
  88. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/minimax.py +0 -0
  89. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/qwen3.py +0 -0
  90. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_drivers/registry.py +0 -0
  91. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/ollama_inspector.py +0 -0
  92. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/openai.py +0 -0
  93. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/impl/qwen.py +0 -0
  94. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/orchestrator.py +0 -0
  95. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/providers/retry.py +0 -0
  96. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/services/__init__.py +0 -0
  97. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/services/interactions.py +0 -0
  98. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/themes/__init__.py +0 -0
  99. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/__init__.py +0 -0
  100. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/__init__.py +0 -0
  101. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/context.py +0 -0
  102. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/context_definitions.py +0 -0
  103. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/filesystem.py +0 -0
  104. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/filesystem_definitions.py +0 -0
  105. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/notes.py +0 -0
  106. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/notes_definitions.py +0 -0
  107. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/process_manager_definitions.py +0 -0
  108. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/search.py +0 -0
  109. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/search_definitions.py +0 -0
  110. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/shell.py +0 -0
  111. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/shell_definitions.py +0 -0
  112. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/tasks.py +0 -0
  113. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/tasks_definitions.py +0 -0
  114. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/utils_tools.py +0 -0
  115. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/utils_tools_definitions.py +0 -0
  116. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/web.py +0 -0
  117. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/builtins/web_definitions.py +0 -0
  118. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/execution.py +0 -0
  119. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/hooks.py +0 -0
  120. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/normalization.py +0 -0
  121. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/plugin_api.py +0 -0
  122. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/plugin_github.py +0 -0
  123. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/registry.py +0 -0
  124. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/schemas.py +0 -0
  125. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tools/utils.py +0 -0
  126. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/adapter.py +0 -0
  127. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/helpers.py +0 -0
  128. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/parser.py +0 -0
  129. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/screens.py +0 -0
  130. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/theme_manager.py +0 -0
  131. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/tui/types.py +0 -0
  132. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/ui.py +0 -0
  133. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/src/ayder_cli/version.py +0 -0
  134. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/COVERAGE.md +0 -0
  135. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/__init__.py +0 -0
  136. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/__init__.py +0 -0
  137. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/test_agent_tools.py +0 -0
  138. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/test_callbacks.py +0 -0
  139. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/test_config.py +0 -0
  140. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/test_integration.py +0 -0
  141. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/test_registry.py +0 -0
  142. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/test_run.py +0 -0
  143. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/test_runner.py +0 -0
  144. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/test_runner_provider_unavailable.py +0 -0
  145. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/agents/test_tool.py +0 -0
  146. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/application/test_message_contract.py +0 -0
  147. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/client/test_main.py +0 -0
  148. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/convergence/__init__.py +0 -0
  149. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/convergence/test_execution_policy_parity.py +0 -0
  150. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/convergence/test_runtime_wiring.py +0 -0
  151. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/convergence/test_validation_path.py +0 -0
  152. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_cache_monitor.py +0 -0
  153. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_config.py +0 -0
  154. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_config_migration.py +0 -0
  155. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_config_provider_logging.py +0 -0
  156. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_config_retry.py +0 -0
  157. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_context_manager_factory.py +0 -0
  158. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_default_context_manager.py +0 -0
  159. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_default_context_manager_should_compact.py +0 -0
  160. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_ollama_context_manager_cache_monitor.py +0 -0
  161. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_ollama_context_manager_max_history.py +0 -0
  162. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_parameter_aliasing.py +0 -0
  163. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/core/test_parser.py +0 -0
  164. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/loops/__init__.py +0 -0
  165. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/loops/test_base.py +0 -0
  166. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/loops/test_chat_loop_hook.py +0 -0
  167. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/loops/test_chat_loop_tool_truncation.py +0 -0
  168. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/__init__.py +0 -0
  169. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/__init__.py +0 -0
  170. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_base.py +0 -0
  171. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_deepseek.py +0 -0
  172. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_errors.py +0 -0
  173. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_fallback.py +0 -0
  174. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_generic_native.py +0 -0
  175. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_generic_xml.py +0 -0
  176. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_matrix.py +0 -0
  177. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_minimax.py +0 -0
  178. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_provider_integration.py +0 -0
  179. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_qwen3.py +0 -0
  180. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/ollama_drivers/test_registry.py +0 -0
  181. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_glm_async.py +0 -0
  182. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_ollama_inspector.py +0 -0
  183. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_ollama_native.py +0 -0
  184. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_ollama_xml.py +0 -0
  185. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_ollama_xml_autoroute.py +0 -0
  186. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_ollama_xml_usage.py +0 -0
  187. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_orchestrator_capabilities.py +0 -0
  188. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_qwen_async.py +0 -0
  189. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_retry_classifier.py +0 -0
  190. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_retry_integration.py +0 -0
  191. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/providers/test_retrying_provider.py +0 -0
  192. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/services/test_boundary.py +0 -0
  193. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/services/test_interaction_sink.py +0 -0
  194. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/test_cli_callbacks.py +0 -0
  195. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/test_context.py +0 -0
  196. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/test_env_manager.py +0 -0
  197. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/test_logging_config.py +0 -0
  198. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/test_notes.py +0 -0
  199. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/test_process_manager.py +0 -0
  200. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/test_tasks.py +0 -0
  201. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/__init__.py +0 -0
  202. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_agent_notes.py +0 -0
  203. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_definition_discovery.py +0 -0
  204. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_di_injection.py +0 -0
  205. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_impl.py +0 -0
  206. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_impl_coverage.py +0 -0
  207. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_path_security.py +0 -0
  208. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_plugin_api.py +0 -0
  209. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_plugin_github.py +0 -0
  210. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_plugin_loading.py +0 -0
  211. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_registry.py +0 -0
  212. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_registry_coverage.py +0 -0
  213. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_result.py +0 -0
  214. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_schemas.py +0 -0
  215. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_search_codebase.py +0 -0
  216. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_utils.py +0 -0
  217. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tools/test_web.py +0 -0
  218. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/__init__.py +0 -0
  219. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_agent_list_screen.py +0 -0
  220. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_do_clear_coordination.py +0 -0
  221. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_follow_mode.py +0 -0
  222. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_help_screen.py +0 -0
  223. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_keybindings.py +0 -0
  224. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_multi_select_screen.py +0 -0
  225. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_paste.py +0 -0
  226. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_pending_compact_consumer.py +0 -0
  227. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_pull_delivery.py +0 -0
  228. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/tui/test_turn_consumer.py +0 -0
  229. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_diff_preview.py +0 -0
  230. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_provider_switch.py +0 -0
  231. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_run_tui_startup.py +0 -0
  232. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_tui_assistant_sanitization.py +0 -0
  233. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_tui_chat_loop.py +0 -0
  234. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_tui_commands_agent.py +0 -0
  235. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_tui_commands_logging.py +0 -0
  236. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_tui_commands_provider.py +0 -0
  237. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_tui_helpers.py +0 -0
  238. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_tui_temporal_command.py +0 -0
  239. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_tui_widgets.py +0 -0
  240. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_ui.py +0 -0
  241. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_ui_coverage.py +0 -0
  242. {ayder_cli-2.1.2 → ayder_cli-2.1.5}/tests/ui/test_ui_verbose.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ayder-cli
3
- Version: 2.1.2
3
+ Version: 2.1.5
4
4
  Summary: AI agent for any LLMs
5
5
  Project-URL: Homepage, https://github.com/ayder/ayder-cli
6
6
  Project-URL: Repository, https://github.com/ayder/ayder-cli.git
@@ -34,6 +34,8 @@ Provides-Extra: glm
34
34
  Requires-Dist: zhipuai; extra == 'glm'
35
35
  Provides-Extra: google
36
36
  Requires-Dist: google-genai; extra == 'google'
37
+ Provides-Extra: mcp
38
+ Requires-Dist: mcp; extra == 'mcp'
37
39
  Provides-Extra: qwen
38
40
  Requires-Dist: dashscope; extra == 'qwen'
39
41
  Description-Content-Type: text/markdown
@@ -286,8 +288,9 @@ ayder -f instructions.txt
286
288
  # Explicit stdin mode
287
289
  ayder --stdin < prompt.txt
288
290
 
289
- # Use a custom system prompt file
290
- ayder --prompt prompt-file.md "refactor this code"
291
+ # Override the main LLM system prompt with a file
292
+ # (tool instructions + project structure are still appended)
293
+ ayder --system-prompt prompt-file.md "refactor this code"
291
294
  ```
292
295
 
293
296
  ### Task Commands (CLI Mode)
@@ -246,8 +246,9 @@ ayder -f instructions.txt
246
246
  # Explicit stdin mode
247
247
  ayder --stdin < prompt.txt
248
248
 
249
- # Use a custom system prompt file
250
- ayder --prompt prompt-file.md "refactor this code"
249
+ # Override the main LLM system prompt with a file
250
+ # (tool instructions + project structure are still appended)
251
+ ayder --system-prompt prompt-file.md "refactor this code"
251
252
  ```
252
253
 
253
254
  ### Task Commands (CLI Mode)
@@ -82,7 +82,12 @@ verbose = false
82
82
  prompt = "STANDARD" # MINIMAL | STANDARD | EXTENDED
83
83
  max_background_processes = 5 # cap on concurrent background processes (e.g. test runs)
84
84
  max_output_tokens = 8192 # orchestrator response cap
85
- max_history_messages = 30
85
+ # Max conversation messages kept per turn. 0 = unlimited (default): the context
86
+ # manager's token budget + compaction are the bound, so the model uses its real
87
+ # window. A small fixed cap (the old default was 30) thrashes a tiny history
88
+ # window on a large-context model and wastes most of it. Set a finite number
89
+ # only if you want a hard message cap regardless of window size.
90
+ max_history_messages = 0
86
91
  agent_timeout = 1800 # seconds before a background agent is cancelled (30 min; reasoning+coding can be slow)
87
92
  # Tools the agents inherit. A coding harness needs file/shell/search (core),
88
93
  # tasks/notes (metadata), background process control for test suites
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ayder-cli"
7
- version = "2.1.2"
7
+ version = "2.1.5"
8
8
  description = "AI agent for any LLMs"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -37,6 +37,7 @@ google = ["google-genai"]
37
37
  qwen = ["dashscope"]
38
38
  glm = ["zhipuai"]
39
39
  all = ["ayder-cli[anthropic,google,qwen,glm]"]
40
+ mcp = ["mcp"]
40
41
 
41
42
  [project.urls]
42
43
  Homepage = "https://github.com/ayder/ayder-cli"
@@ -44,6 +44,7 @@ def create_runtime(
44
44
  project_root: str = ".",
45
45
  model_name: str | None = None,
46
46
  prompt_tier: str | None = None,
47
+ system_prompt_override: str | None = None,
47
48
  ) -> RuntimeComponents:
48
49
  """Assemble and return all shared runtime components.
49
50
 
@@ -53,6 +54,9 @@ def create_runtime(
53
54
  model_name: Override model name from config when provided.
54
55
  prompt_tier: Override the system-prompt tier from config when provided
55
56
  (e.g. "AGENTIC" for `ayder-cli --agent`). See prompts.get_system_prompt.
57
+ system_prompt_override: When set, use this text as the system-prompt base
58
+ instead of prompts.get_system_prompt (ayder --system-prompt FILE). Tool
59
+ prompts and the project-structure macro are still appended.
56
60
 
57
61
  Returns:
58
62
  RuntimeComponents with all dependencies wired.
@@ -84,7 +88,10 @@ def create_runtime(
84
88
  macro = ""
85
89
 
86
90
  # Format the final prompt (protocol injection now handled dynamically by chat_loop and protocols)
87
- base_prompt = get_system_prompt(cfg.prompt)
91
+ if system_prompt_override is not None:
92
+ base_prompt = system_prompt_override
93
+ else:
94
+ base_prompt = get_system_prompt(cfg.prompt)
88
95
  tool_tags = frozenset(cfg.tool_tags) if cfg.tool_tags else None
89
96
  tool_prompts = tool_registry.get_system_prompts(tags=tool_tags)
90
97
  system_prompt = base_prompt + tool_prompts + macro
@@ -56,11 +56,28 @@ def _add_common_args(parser: argparse.ArgumentParser) -> None:
56
56
  "--stdin", action="store_true", help="Read prompt from stdin"
57
57
  )
58
58
  parser.add_argument(
59
- "--prompt",
59
+ "--temporal-prompt",
60
60
  type=str,
61
61
  default=None,
62
62
  metavar="FILE",
63
- help="Inject custom system prompt from file",
63
+ help="Prompt file for the Temporal worker (only used with --temporal-task-queue)",
64
+ )
65
+ parser.add_argument(
66
+ "--system-prompt",
67
+ type=str,
68
+ default=None,
69
+ metavar="FILE",
70
+ help="Use FILE's contents as the main LLM system prompt, overriding the "
71
+ "built-in prompt from prompts.py (tool instructions and project structure "
72
+ "are still appended)",
73
+ )
74
+ parser.add_argument(
75
+ "-c",
76
+ "--config",
77
+ type=str,
78
+ default=None,
79
+ metavar="FILE",
80
+ help="Path to a config.toml to use instead of ~/.ayder/config.toml",
64
81
  )
65
82
 
66
83
  # Permission flags: r=read, w=write, x=execute, http=web/network
@@ -93,13 +110,10 @@ def _add_common_args(parser: argparse.ArgumentParser) -> None:
93
110
 
94
111
  parser.add_argument(
95
112
  "--verbose",
96
- nargs="?",
97
- const="INFO",
98
- default=None,
99
- type=str.upper,
100
- choices=LOG_LEVELS,
101
- metavar="LEVEL",
102
- help="Enable verbose console output and logging; default level is INFO",
113
+ action="store_true",
114
+ help="Show logs on the console. The level comes from --logging-level (or "
115
+ "config); if neither is set, defaults to INFO. Does not otherwise change "
116
+ "the log level.",
103
117
  )
104
118
  parser.add_argument(
105
119
  "--logging-level",
@@ -214,6 +228,16 @@ def main():
214
228
  args = parser.parse_args()
215
229
  args.subcommand = None
216
230
 
231
+ # Apply the -c/--config override before anything reads the config file.
232
+ if getattr(args, "config", None):
233
+ from ayder_cli.core.config import set_config_path
234
+
235
+ config_file = Path(args.config).expanduser()
236
+ if not config_file.is_file():
237
+ print(f"Error: Config file not found: {args.config}", file=sys.stderr)
238
+ sys.exit(1)
239
+ set_config_path(config_file)
240
+
217
241
  # Handle plugin subcommands
218
242
  if args.subcommand == "install-plugin":
219
243
  from ayder_cli.tools.plugin_manager import (
@@ -310,13 +334,17 @@ def main():
310
334
 
311
335
  cfg = load_config(notify_migration=True, output=print)
312
336
 
313
- # Priority: 1. --verbose level, 2. --logging-level, 3. config.logging_level
314
- effective_log_level = args.verbose or args.logging_level
315
-
337
+ # --verbose only enables console output; the level comes from --logging-level
338
+ # (or config.logging_level). When --verbose is used with no level configured
339
+ # anywhere, default the console to INFO so it isn't empty.
340
+ effective_log_level = args.logging_level
341
+ if args.verbose and effective_log_level is None and cfg.logging_level is None:
342
+ effective_log_level = "INFO"
343
+
316
344
  setup_logging(
317
345
  cfg,
318
346
  level_override=effective_log_level,
319
- console_stream=sys.stdout if args.verbose is not None else None,
347
+ console_stream=sys.stdout if args.verbose else None,
320
348
  )
321
349
 
322
350
  # --agent: warn early if the harness has nothing to orchestrate.
@@ -342,11 +370,30 @@ def main():
342
370
  sys.exit(
343
371
  _run_temporal_queue_cli(
344
372
  queue_name=args.temporal_task_queue,
345
- prompt_path=args.prompt,
373
+ prompt_path=args.temporal_prompt,
346
374
  permissions=granted,
347
375
  )
348
376
  )
349
377
 
378
+ # Read the --system-prompt override file (overrides prompts.py base prompt).
379
+ system_prompt_override = None
380
+ if args.system_prompt:
381
+ sp_file = Path(args.system_prompt).expanduser()
382
+ try:
383
+ system_prompt_override = sp_file.read_text()
384
+ except FileNotFoundError:
385
+ print(
386
+ f"Error: System prompt file not found: {args.system_prompt}",
387
+ file=sys.stderr,
388
+ )
389
+ sys.exit(1)
390
+ except Exception as e:
391
+ print(
392
+ f"Error reading system prompt file {args.system_prompt}: {e}",
393
+ file=sys.stderr,
394
+ )
395
+ sys.exit(1)
396
+
350
397
  # Handle file/stdin input
351
398
  context = None
352
399
  question = args.command
@@ -376,10 +423,21 @@ def main():
376
423
  # Default: TUI mode
377
424
  from ayder_cli.tui import run_tui
378
425
 
379
- run_tui(permissions=granted, agent_mode=args.agent)
426
+ run_tui(
427
+ permissions=granted,
428
+ agent_mode=args.agent,
429
+ system_prompt_override=system_prompt_override,
430
+ )
380
431
  return
381
432
 
382
- sys.exit(run_command(prompt, permissions=granted, agent_mode=args.agent))
433
+ sys.exit(
434
+ run_command(
435
+ prompt,
436
+ permissions=granted,
437
+ agent_mode=args.agent,
438
+ system_prompt_override=system_prompt_override,
439
+ )
440
+ )
383
441
 
384
442
 
385
443
  if __name__ == "__main__":
@@ -36,6 +36,7 @@ def _run_loop(
36
36
  prompt: str,
37
37
  permissions: set | None = None,
38
38
  agent_mode: bool = False,
39
+ system_prompt_override: str | None = None,
39
40
  ) -> int:
40
41
  """Create a ChatLoop with CliCallbacks and run it.
41
42
 
@@ -47,11 +48,16 @@ def _run_loop(
47
48
  permissions: Granted permission categories.
48
49
  agent_mode: When True, inject the AGENTIC orchestrator system prompt
49
50
  (ayder-cli --agent) so the main LLM drives the multi-agent harness.
51
+ system_prompt_override: When set, use this text as the system prompt base
52
+ instead of the built-in prompts.py prompt (ayder --system-prompt FILE).
50
53
 
51
54
  Returns:
52
55
  Exit code (0 for success, 1 for error).
53
56
  """
54
- rt = create_runtime(prompt_tier="AGENTIC" if agent_mode else None)
57
+ rt = create_runtime(
58
+ prompt_tier="AGENTIC" if agent_mode else None,
59
+ system_prompt_override=system_prompt_override,
60
+ )
55
61
 
56
62
  messages: list[dict] = [
57
63
  {"role": "system", "content": rt.system_prompt},
@@ -119,10 +125,12 @@ def _run_loop(
119
125
  class CommandRunner:
120
126
  """Runner for single command execution mode."""
121
127
 
122
- def __init__(self, prompt: str, permissions=None, agent_mode: bool = False):
128
+ def __init__(self, prompt: str, permissions=None, agent_mode: bool = False,
129
+ system_prompt_override: str | None = None):
123
130
  self.prompt = prompt
124
131
  self.permissions = permissions
125
132
  self.agent_mode = agent_mode
133
+ self.system_prompt_override = system_prompt_override
126
134
 
127
135
  def run(self) -> int:
128
136
  """Execute the command and return exit code.
@@ -135,6 +143,7 @@ class CommandRunner:
135
143
  self.prompt,
136
144
  permissions=self.permissions,
137
145
  agent_mode=self.agent_mode,
146
+ system_prompt_override=self.system_prompt_override,
138
147
  )
139
148
  except ProviderUnavailableError as e:
140
149
  print(str(e), file=sys.stderr) # message already starts with "Error:"
@@ -144,18 +153,24 @@ class CommandRunner:
144
153
  return 1
145
154
 
146
155
 
147
- def run_command(prompt: str, permissions=None, agent_mode: bool = False) -> int:
156
+ def run_command(prompt: str, permissions=None, agent_mode: bool = False,
157
+ system_prompt_override: str | None = None) -> int:
148
158
  """Execute a single command and return exit code.
149
159
 
150
160
  Args:
151
161
  prompt: The command/prompt to execute
152
162
  permissions: Set of granted permission categories (e.g. {"r", "w", "x", "http"})
153
163
  agent_mode: When True, inject the AGENTIC orchestrator system prompt (ayder-cli --agent).
164
+ system_prompt_override: When set, use this text as the system prompt base
165
+ instead of the built-in prompts.py prompt (ayder --system-prompt FILE).
154
166
 
155
167
  Returns:
156
168
  Exit code (0 for success, 1 for error)
157
169
  """
158
- runner = CommandRunner(prompt, permissions=permissions, agent_mode=agent_mode)
170
+ runner = CommandRunner(
171
+ prompt, permissions=permissions, agent_mode=agent_mode,
172
+ system_prompt_override=system_prompt_override,
173
+ )
159
174
  return runner.run()
160
175
 
161
176
 
@@ -9,6 +9,18 @@ logger = logging.getLogger(__name__)
9
9
  CONFIG_DIR = Path("~/.ayder").expanduser()
10
10
  CONFIG_PATH = CONFIG_DIR / "config.toml"
11
11
 
12
+
13
+ def set_config_path(path: "str | Path") -> None:
14
+ """Redirect the global config file location (used by the ``-c/--config`` flag).
15
+
16
+ Updates CONFIG_PATH and CONFIG_DIR so every subsequent ``load_config`` (and the
17
+ provider/profile loaders, which read these module globals at call time) use
18
+ *path* instead of the default ``~/.ayder/config.toml``.
19
+ """
20
+ global CONFIG_PATH, CONFIG_DIR
21
+ CONFIG_PATH = Path(path).expanduser().resolve()
22
+ CONFIG_DIR = CONFIG_PATH.parent
23
+
12
24
  # Maintained for test compatibility and initial file generation
13
25
  DEFAULTS: Dict[str, Any] = {
14
26
  "provider": "openai",
@@ -288,7 +300,10 @@ class Config(BaseModel):
288
300
  logging_retention: str = Field(default="7 days")
289
301
  max_background_processes: int = Field(default=5)
290
302
  max_output_tokens: int = Field(default=4096)
291
- max_history_messages: int = Field(default=30)
303
+ # 0 = unlimited: let the context manager's token budget + compaction be the
304
+ # bound. The old fixed 30 predates large-context models and thrashes a tiny
305
+ # history window on a big context.
306
+ max_history_messages: int = Field(default=0)
292
307
  prompt: str = Field(default="STANDARD")
293
308
  chat_protocol: str = Field(default="ollama")
294
309
  stop_sequences: list[str] = Field(default_factory=list)
@@ -237,8 +237,8 @@ class OllamaContextManager:
237
237
  cache_state = f", cache={status.state}({status.hit_ratio:.0%})"
238
238
 
239
239
  logger.info(
240
- "Context: %d/%d tokens (%.0f%%), completion=%d, speed=%s%s",
241
- self._real_prompt_tokens, ceiling, utilization,
240
+ "Context[%s]: %d/%d tokens (%.0f%%), completion=%d, speed=%s%s",
241
+ self._model or "?", self._real_prompt_tokens, ceiling, utilization,
242
242
  self._real_completion_tokens, prompt_speed, cache_state,
243
243
  )
244
244
 
@@ -633,6 +633,27 @@ AgentPanel .agent-detail {
633
633
  padding: 0 0 0 4;
634
634
  }
635
635
 
636
+ /* ThinkingPanel - Scrollable panel showing the model's reasoning stream.
637
+ Toggled with Ctrl+T. Taller than the tool/agent panels because reasoning is
638
+ long-form. Targets 'ThinkingPanel' in widgets.py. */
639
+ ThinkingPanel {
640
+ layout: vertical;
641
+ height: auto;
642
+ max-height: 60%;
643
+ background: #0a0a18;
644
+ border-top: solid #333350;
645
+ padding: 1 1;
646
+ overflow-y: scroll;
647
+ display: none;
648
+ }
649
+
650
+ ThinkingPanel .thinking-content {
651
+ height: auto;
652
+ color: #8888aa;
653
+ text-style: italic;
654
+ padding: 0 1;
655
+ }
656
+
636
657
  /* AyderApp - The root application screen. */
637
658
  Screen {
638
659
  layout: vertical;
@@ -669,6 +690,12 @@ Screen:inline {
669
690
  width: 100%;
670
691
  }
671
692
 
693
+ #thinking-panel {
694
+ min-height: 0;
695
+ max-height: 60%;
696
+ width: 100%;
697
+ }
698
+
672
699
  #input-bar {
673
700
  height: auto;
674
701
  min-height: 1;
@@ -514,6 +514,27 @@ ToolPanel .tool-item.completed {
514
514
  color: $success;
515
515
  }
516
516
 
517
+ /* ThinkingPanel - Scrollable reasoning stream, toggled with Ctrl+T.
518
+ Taller than the tool/agent panels because reasoning is long-form. */
519
+ ThinkingPanel {
520
+ layout: vertical;
521
+ height: auto;
522
+ min-height: 6;
523
+ max-height: 24;
524
+ background: $surface-darken-1;
525
+ border-top: heavy $primary;
526
+ padding: 1 1;
527
+ overflow-y: scroll;
528
+ display: none;
529
+ }
530
+
531
+ ThinkingPanel .thinking-content {
532
+ height: auto;
533
+ color: $text-muted;
534
+ text-style: italic;
535
+ padding: 0 1;
536
+ }
537
+
517
538
  /* AyderApp - Main application */
518
539
  Screen {
519
540
  layout: vertical;
@@ -168,7 +168,15 @@ def _discover_definitions() -> Tuple["ToolDefinition", ...]:
168
168
 
169
169
  _BUILTIN_DEFINITIONS: Tuple[ToolDefinition, ...] = _discover_definitions()
170
170
 
171
- # Phase 1: Merge global plugins at import time
171
+ # Phase 1: Merge global plugins at import time.
172
+ #
173
+ # Discovery runs *inside this module's own body*, so a plugin whose definitions
174
+ # module reads ``TOOL_DEFINITIONS`` at import time (e.g. to avoid tool-name
175
+ # collisions, as mcp-tool does) would otherwise hit a circular import — the name
176
+ # isn't bound yet. Bind it provisionally to the builtins first; those are the
177
+ # only definitions that exist during discovery anyway. It is reassigned to the
178
+ # full set (builtins + plugins) immediately after discovery completes.
179
+ TOOL_DEFINITIONS: Tuple[ToolDefinition, ...] = _BUILTIN_DEFINITIONS
172
180
  _GLOBAL_PLUGIN_DEFS: Tuple[ToolDefinition, ...] = ()
173
181
  _PLUGIN_HANDLERS: Dict[str, Any] = {}
174
182
 
@@ -179,9 +187,7 @@ try:
179
187
  except Exception as e:
180
188
  logger.warning(f"Failed to load global plugins: {e}")
181
189
 
182
- TOOL_DEFINITIONS: Tuple[ToolDefinition, ...] = (
183
- _BUILTIN_DEFINITIONS + _GLOBAL_PLUGIN_DEFS
184
- )
190
+ TOOL_DEFINITIONS = _BUILTIN_DEFINITIONS + _GLOBAL_PLUGIN_DEFS
185
191
  TOOL_DEFINITIONS_BY_NAME: Dict[str, ToolDefinition] = {
186
192
  td.name: td for td in TOOL_DEFINITIONS
187
193
  }
@@ -147,10 +147,15 @@ def install_plugin_from_local(
147
147
  "Use --force to overwrite."
148
148
  )
149
149
 
150
- # Copy plugin files
151
- if target_dir.exists():
152
- shutil.rmtree(target_dir)
153
- shutil.copytree(source_dir, target_dir)
150
+ # Copy plugin files. When the source IS the install target — e.g. reinstalling
151
+ # an already-installed plugin from its own directory with --force, which is
152
+ # exactly what the missing-dependency warning recommends — the files are
153
+ # already in place. Skip the copy so we don't rmtree the source out from under
154
+ # ourselves (the dependency reinstall + registry refresh below still run).
155
+ if source_dir.resolve() != target_dir.resolve():
156
+ if target_dir.exists():
157
+ shutil.rmtree(target_dir)
158
+ shutil.copytree(source_dir, target_dir)
154
159
 
155
160
  # Update plugins.json
156
161
  data = read_plugins_json(plugins_dir)
@@ -0,0 +1,33 @@
1
+ """Plugin status-badge registry.
2
+
3
+ A lightweight, process-global registry that plugins use to publish a status
4
+ badge (a short label plus a colour) for display in the TUI status bar. The
5
+ mcp-tool plugin, for example, calls ``set_status("mcp", "MCP: news-digest",
6
+ "green")`` once it connects to its MCP servers, and ``set_status("mcp", "MCP",
7
+ "red")`` when configured servers are unreachable.
8
+
9
+ The TUI ``StatusBar`` reads :func:`get_all` to render the badges. Keeping this
10
+ in ayder core (rather than inside a plugin) means the badge survives even when
11
+ the plugin's own modules are loaded under throwaway names during discovery, and
12
+ gives the plugin a stable import target instead of a no-op fallback.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ # plugin name -> (label, colour). Colour is a Rich colour/style name ("green").
18
+ _status: dict[str, tuple[str, str]] = {}
19
+
20
+
21
+ def set_status(name: str, label: str, color: str) -> None:
22
+ """Register or update a plugin's status badge."""
23
+ _status[name] = (label, color)
24
+
25
+
26
+ def get_all() -> dict[str, tuple[str, str]]:
27
+ """Return a copy of all registered status badges (name -> (label, color))."""
28
+ return dict(_status)
29
+
30
+
31
+ def clear() -> None:
32
+ """Remove all registered badges (primarily for tests)."""
33
+ _status.clear()
@@ -32,6 +32,7 @@ def run_tui(
32
32
  safe_mode: bool = False,
33
33
  permissions: set | None = None,
34
34
  agent_mode: bool = False,
35
+ system_prompt_override: str | None = None,
35
36
  ) -> None:
36
37
  """
37
38
  Run the CLI-style TUI application.
@@ -42,6 +43,8 @@ def run_tui(
42
43
  permissions: Set of granted permission levels ("r", "w", "x")
43
44
  agent_mode: When True, inject the AGENTIC orchestrator system prompt
44
45
  so the main LLM drives the multi-agent harness (ayder-cli --agent).
46
+ system_prompt_override: When set, use this text as the system-prompt base
47
+ instead of the built-in prompts.py prompt (ayder --system-prompt FILE).
45
48
  """
46
49
  import sys
47
50
  from ayder_cli.providers import ProviderUnavailableError
@@ -49,7 +52,7 @@ def run_tui(
49
52
  try:
50
53
  app = AyderApp(
51
54
  model=model, safe_mode=safe_mode, permissions=permissions,
52
- agent_mode=agent_mode,
55
+ agent_mode=agent_mode, system_prompt_override=system_prompt_override,
53
56
  )
54
57
  except ProviderUnavailableError as e:
55
58
  print(str(e), file=sys.stderr)