aru-code 0.58.0__tar.gz → 0.59.0__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 (217) hide show
  1. {aru_code-0.58.0/aru_code.egg-info → aru_code-0.59.0}/PKG-INFO +10 -7
  2. {aru_code-0.58.0 → aru_code-0.59.0}/README.md +9 -6
  3. aru_code-0.59.0/aru/__init__.py +1 -0
  4. aru_code-0.59.0/aru/cli.py +307 -0
  5. {aru_code-0.58.0 → aru_code-0.59.0}/aru/display.py +0 -53
  6. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/app.py +5 -5
  7. {aru_code-0.58.0 → aru_code-0.59.0/aru_code.egg-info}/PKG-INFO +10 -7
  8. {aru_code-0.58.0 → aru_code-0.59.0}/aru_code.egg-info/SOURCES.txt +0 -3
  9. {aru_code-0.58.0 → aru_code-0.59.0}/pyproject.toml +1 -1
  10. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_cli.py +0 -190
  11. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_cli_advanced.py +2 -127
  12. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_cli_session.py +1 -32
  13. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_main.py +0 -12
  14. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_app_boot.py +4 -39
  15. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_chat_adversarial.py +125 -73
  16. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_permission_flow.py +6 -1
  17. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_worktree_session_restore.py +1 -1
  18. aru_code-0.58.0/aru/__init__.py +0 -1
  19. aru_code-0.58.0/aru/cli.py +0 -1151
  20. aru_code-0.58.0/aru/completers.py +0 -383
  21. aru_code-0.58.0/tests/test_cli_completers.py +0 -690
  22. aru_code-0.58.0/tests/test_cli_run_cli.py +0 -1
  23. {aru_code-0.58.0 → aru_code-0.59.0}/LICENSE +0 -0
  24. {aru_code-0.58.0 → aru_code-0.59.0}/aru/_debug/__init__.py +0 -0
  25. {aru_code-0.58.0 → aru_code-0.59.0}/aru/_debug/analyze_trace.py +0 -0
  26. {aru_code-0.58.0 → aru_code-0.59.0}/aru/_debug/loop_tracer.py +0 -0
  27. {aru_code-0.58.0 → aru_code-0.59.0}/aru/agent_factory.py +0 -0
  28. {aru_code-0.58.0 → aru_code-0.59.0}/aru/agents/__init__.py +0 -0
  29. {aru_code-0.58.0 → aru_code-0.59.0}/aru/agents/base.py +0 -0
  30. {aru_code-0.58.0 → aru_code-0.59.0}/aru/agents/catalog.py +0 -0
  31. {aru_code-0.58.0 → aru_code-0.59.0}/aru/agents/planner.py +0 -0
  32. {aru_code-0.58.0 → aru_code-0.59.0}/aru/auth.py +0 -0
  33. {aru_code-0.58.0 → aru_code-0.59.0}/aru/cache_patch.py +0 -0
  34. {aru_code-0.58.0 → aru_code-0.59.0}/aru/checkpoints.py +0 -0
  35. {aru_code-0.58.0 → aru_code-0.59.0}/aru/commands.py +0 -0
  36. {aru_code-0.58.0 → aru_code-0.59.0}/aru/config.py +0 -0
  37. {aru_code-0.58.0 → aru_code-0.59.0}/aru/context.py +0 -0
  38. {aru_code-0.58.0 → aru_code-0.59.0}/aru/doom_loop.py +0 -0
  39. {aru_code-0.58.0 → aru_code-0.59.0}/aru/events.py +0 -0
  40. {aru_code-0.58.0 → aru_code-0.59.0}/aru/format/__init__.py +0 -0
  41. {aru_code-0.58.0 → aru_code-0.59.0}/aru/format/manager.py +0 -0
  42. {aru_code-0.58.0 → aru_code-0.59.0}/aru/format/runner.py +0 -0
  43. {aru_code-0.58.0 → aru_code-0.59.0}/aru/history_blocks.py +0 -0
  44. {aru_code-0.58.0 → aru_code-0.59.0}/aru/lsp/__init__.py +0 -0
  45. {aru_code-0.58.0 → aru_code-0.59.0}/aru/lsp/client.py +0 -0
  46. {aru_code-0.58.0 → aru_code-0.59.0}/aru/lsp/manager.py +0 -0
  47. {aru_code-0.58.0 → aru_code-0.59.0}/aru/lsp/protocol.py +0 -0
  48. {aru_code-0.58.0 → aru_code-0.59.0}/aru/memory/__init__.py +0 -0
  49. {aru_code-0.58.0 → aru_code-0.59.0}/aru/memory/extractor.py +0 -0
  50. {aru_code-0.58.0 → aru_code-0.59.0}/aru/memory/loader.py +0 -0
  51. {aru_code-0.58.0 → aru_code-0.59.0}/aru/memory/store.py +0 -0
  52. {aru_code-0.58.0 → aru_code-0.59.0}/aru/permissions.py +0 -0
  53. {aru_code-0.58.0 → aru_code-0.59.0}/aru/plugin_cache.py +0 -0
  54. {aru_code-0.58.0 → aru_code-0.59.0}/aru/plugins/__init__.py +0 -0
  55. {aru_code-0.58.0 → aru_code-0.59.0}/aru/plugins/custom_tools.py +0 -0
  56. {aru_code-0.58.0 → aru_code-0.59.0}/aru/plugins/hooks.py +0 -0
  57. {aru_code-0.58.0 → aru_code-0.59.0}/aru/plugins/manager.py +0 -0
  58. {aru_code-0.58.0 → aru_code-0.59.0}/aru/plugins/tool_api.py +0 -0
  59. {aru_code-0.58.0 → aru_code-0.59.0}/aru/providers.py +0 -0
  60. {aru_code-0.58.0 → aru_code-0.59.0}/aru/runner.py +0 -0
  61. {aru_code-0.58.0 → aru_code-0.59.0}/aru/runtime.py +0 -0
  62. {aru_code-0.58.0 → aru_code-0.59.0}/aru/select.py +0 -0
  63. {aru_code-0.58.0 → aru_code-0.59.0}/aru/session.py +0 -0
  64. {aru_code-0.58.0 → aru_code-0.59.0}/aru/sinks.py +0 -0
  65. {aru_code-0.58.0 → aru_code-0.59.0}/aru/streaming.py +0 -0
  66. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tool_policy.py +0 -0
  67. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/__init__.py +0 -0
  68. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/_diff.py +0 -0
  69. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/_shared.py +0 -0
  70. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/apply_patch.py +0 -0
  71. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/apply_patch_prompt.txt +0 -0
  72. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/ast_tools.py +0 -0
  73. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/codebase.py +0 -0
  74. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/delegate.py +0 -0
  75. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/delegate_prompt.txt +0 -0
  76. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/file_ops.py +0 -0
  77. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/gitignore.py +0 -0
  78. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/lsp.py +0 -0
  79. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/mcp_client.py +0 -0
  80. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/memory_tool.py +0 -0
  81. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/plan_mode.py +0 -0
  82. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/ranker.py +0 -0
  83. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/registry.py +0 -0
  84. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/search.py +0 -0
  85. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/shell.py +0 -0
  86. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/skill.py +0 -0
  87. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/tasklist.py +0 -0
  88. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/web.py +0 -0
  89. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tools/worktree.py +0 -0
  90. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/__init__.py +0 -0
  91. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/log_bridge.py +0 -0
  92. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/notifications.py +0 -0
  93. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/sanitize.py +0 -0
  94. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/screens/__init__.py +0 -0
  95. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/screens/choice.py +0 -0
  96. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/screens/confirm.py +0 -0
  97. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/screens/keymap.py +0 -0
  98. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/screens/search.py +0 -0
  99. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/screens/session_picker.py +0 -0
  100. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/screens/text_input.py +0 -0
  101. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/sinks.py +0 -0
  102. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/slash_bridge.py +0 -0
  103. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/themes.py +0 -0
  104. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/ui.py +0 -0
  105. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/__init__.py +0 -0
  106. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/chat.py +0 -0
  107. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/completer.py +0 -0
  108. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/context_pane.py +0 -0
  109. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/file_link.py +0 -0
  110. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/header.py +0 -0
  111. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/inline_choice.py +0 -0
  112. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/loaded_pane.py +0 -0
  113. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/prompt_area.py +0 -0
  114. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/prompt_queue.py +0 -0
  115. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/status.py +0 -0
  116. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/subagent_panel.py +0 -0
  117. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/tasklist_panel.py +0 -0
  118. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/thinking.py +0 -0
  119. {aru_code-0.58.0 → aru_code-0.59.0}/aru/tui/widgets/tools.py +0 -0
  120. {aru_code-0.58.0 → aru_code-0.59.0}/aru/ui.py +0 -0
  121. {aru_code-0.58.0 → aru_code-0.59.0}/aru_code.egg-info/dependency_links.txt +0 -0
  122. {aru_code-0.58.0 → aru_code-0.59.0}/aru_code.egg-info/entry_points.txt +0 -0
  123. {aru_code-0.58.0 → aru_code-0.59.0}/aru_code.egg-info/requires.txt +0 -0
  124. {aru_code-0.58.0 → aru_code-0.59.0}/aru_code.egg-info/top_level.txt +0 -0
  125. {aru_code-0.58.0 → aru_code-0.59.0}/setup.cfg +0 -0
  126. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_agents_base.py +0 -0
  127. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_agents_md_coverage.py +0 -0
  128. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_apply_patch.py +0 -0
  129. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_async_tool_permission.py +0 -0
  130. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_auth_store.py +0 -0
  131. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_cache_patch_metrics.py +0 -0
  132. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_cache_patch_stop_reason.py +0 -0
  133. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_catalog.py +0 -0
  134. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_chat_scrollable.py +0 -0
  135. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_checkpoints.py +0 -0
  136. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_cli_base.py +0 -0
  137. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_cli_new.py +0 -0
  138. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_cli_shell.py +0 -0
  139. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_codebase.py +0 -0
  140. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_confabulation_regression.py +0 -0
  141. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_config.py +0 -0
  142. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_connect_command.py +0 -0
  143. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_context.py +0 -0
  144. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_context_pane.py +0 -0
  145. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_cwd_awareness.py +0 -0
  146. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_delegate.py +0 -0
  147. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_doom_loop.py +0 -0
  148. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_events_backward_compat.py +0 -0
  149. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_events_schema.py +0 -0
  150. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_fork_ctx_concurrency.py +0 -0
  151. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_format.py +0 -0
  152. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_gitignore.py +0 -0
  153. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_guardrails_scenarios.py +0 -0
  154. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_invoke_skill.py +0 -0
  155. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_invoked_skills.py +0 -0
  156. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_loaded_pane_path.py +0 -0
  157. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_lsp.py +0 -0
  158. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_lsp_rename.py +0 -0
  159. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_markdown_to_text.py +0 -0
  160. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_mcp_client.py +0 -0
  161. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_mcp_health.py +0 -0
  162. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_memory.py +0 -0
  163. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_memory_tool.py +0 -0
  164. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_microcompact.py +0 -0
  165. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_permission_timeout_suspension.py +0 -0
  166. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_permissions.py +0 -0
  167. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_plan_mode_refactor.py +0 -0
  168. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_plugin_cache.py +0 -0
  169. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_plugin_errors.py +0 -0
  170. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_plugin_hooks_v2.py +0 -0
  171. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_plugins.py +0 -0
  172. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_providers.py +0 -0
  173. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_ranker.py +0 -0
  174. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_reasoning.py +0 -0
  175. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_runner_interrupt.py +0 -0
  176. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_runner_recovery.py +0 -0
  177. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_runtime.py +0 -0
  178. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_select.py +0 -0
  179. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_session_free_cost.py +0 -0
  180. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_skill_disallowed_tools.py +0 -0
  181. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_status_breakdown.py +0 -0
  182. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_status_cost.py +0 -0
  183. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_streaming_sink.py +0 -0
  184. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_subagent_tool_events.py +0 -0
  185. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tasklist.py +0 -0
  186. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_thread_tool_timeout.py +0 -0
  187. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tool_policy.py +0 -0
  188. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_truncation_marker.py +0 -0
  189. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_bindings.py +0 -0
  190. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_bus_flow.py +0 -0
  191. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_chat.py +0 -0
  192. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_completer.py +0 -0
  193. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_completer_dynamic.py +0 -0
  194. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_connect_wiring.py +0 -0
  195. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_copy.py +0 -0
  196. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_error_display.py +0 -0
  197. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_file_link.py +0 -0
  198. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_input_behaviour.py +0 -0
  199. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_layer12_recovery.py +0 -0
  200. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_layer13_recovery.py +0 -0
  201. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_mention_expand.py +0 -0
  202. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_modals.py +0 -0
  203. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_mode_cycle.py +0 -0
  204. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_native_selection.py +0 -0
  205. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_plan_task_render.py +0 -0
  206. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_prompt_queue.py +0 -0
  207. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_shell_bang.py +0 -0
  208. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_sidebar_toggle.py +0 -0
  209. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_slash_bridge.py +0 -0
  210. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_slash_model.py +0 -0
  211. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_snapshot_smoke.py +0 -0
  212. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_subagent_panel.py +0 -0
  213. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_theme.py +0 -0
  214. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_thinking_and_boot.py +0 -0
  215. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_tui_widgets_visual.py +0 -0
  216. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_ui_adapter.py +0 -0
  217. {aru_code-0.58.0 → aru_code-0.59.0}/tests/test_worktree.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aru-code
3
- Version: 0.58.0
3
+ Version: 0.59.0
4
4
  Summary: A Claude Code clone built with Agno agents
5
5
  Author-email: Estevao <estevaofon@gmail.com>
6
6
  License-Expression: MIT
@@ -116,16 +116,19 @@ Key bindings (TUI):
116
116
  Local slash commands inside the TUI: `/help`, `/clear`, `/quit`,
117
117
  `/plan`. Any other input is sent to the agent.
118
118
 
119
- ### Classic REPL (opt-in)
119
+ ### Non-interactive (one-shot)
120
120
 
121
- Prefer the single-line prompt? Pass `--repl` to use the classic REPL:
121
+ For scripting and pipes, pass a prompt directly instead of launching the
122
+ TUI:
122
123
 
123
124
  ```bash
124
- aru --repl
125
+ aru "fix the failing test in auth" # one-shot, with tools
126
+ aru --print "explain this module" # text-only, no tools
127
+ echo "summarize TODOs" | aru # piped stdin
125
128
  ```
126
129
 
127
- Both modes share the same sessions, plugins, permissions, and tools
128
- only presentation differs.
130
+ One-shot mode shares the same sessions, plugins, permissions, and tools
131
+ as the TUI — only presentation differs.
129
132
 
130
133
  ## Usage
131
134
 
@@ -706,7 +709,7 @@ Once a plan is stored, every following turn prepends a `<system-reminder>` listi
706
709
  ```
707
710
  aru-code/
708
711
  ├── aru/
709
- │ ├── cli.py # Main REPL loop, argument parsing, and entry point
712
+ │ ├── cli.py # Argument parsing, one-shot execution, and entry point
710
713
  │ ├── agent_factory.py # Single factory — builds Agno Agents from catalog specs
711
714
  │ ├── commands.py # Slash commands, help display, shell execution
712
715
  │ ├── completers.py # Input completions, paste detection, @file mentions
@@ -68,16 +68,19 @@ Key bindings (TUI):
68
68
  Local slash commands inside the TUI: `/help`, `/clear`, `/quit`,
69
69
  `/plan`. Any other input is sent to the agent.
70
70
 
71
- ### Classic REPL (opt-in)
71
+ ### Non-interactive (one-shot)
72
72
 
73
- Prefer the single-line prompt? Pass `--repl` to use the classic REPL:
73
+ For scripting and pipes, pass a prompt directly instead of launching the
74
+ TUI:
74
75
 
75
76
  ```bash
76
- aru --repl
77
+ aru "fix the failing test in auth" # one-shot, with tools
78
+ aru --print "explain this module" # text-only, no tools
79
+ echo "summarize TODOs" | aru # piped stdin
77
80
  ```
78
81
 
79
- Both modes share the same sessions, plugins, permissions, and tools
80
- only presentation differs.
82
+ One-shot mode shares the same sessions, plugins, permissions, and tools
83
+ as the TUI — only presentation differs.
81
84
 
82
85
  ## Usage
83
86
 
@@ -658,7 +661,7 @@ Once a plan is stored, every following turn prepends a `<system-reminder>` listi
658
661
  ```
659
662
  aru-code/
660
663
  ├── aru/
661
- │ ├── cli.py # Main REPL loop, argument parsing, and entry point
664
+ │ ├── cli.py # Argument parsing, one-shot execution, and entry point
662
665
  │ ├── agent_factory.py # Single factory — builds Agno Agents from catalog specs
663
666
  │ ├── commands.py # Slash commands, help display, shell execution
664
667
  │ ├── completers.py # Input completions, paste detection, @file mentions
@@ -0,0 +1 @@
1
+ __version__ = "0.59.0"
@@ -0,0 +1,307 @@
1
+ """Non-interactive CLI for aru - a Claude Code clone.
2
+
3
+ This module is the slim orchestrator: arg parsing, one-shot execution, and the
4
+ entrypoint that launches the Textual TUI. All domain logic lives in dedicated
5
+ modules; public names are re-exported here for backward compatibility.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ import io as _io
12
+ import logging as _logging
13
+ import os
14
+ import sys
15
+
16
+ # ── Re-exports for backward compatibility ─────────────────────────────
17
+ # Tests and external code import these from aru.cli; keep them accessible.
18
+
19
+ from aru.session import ( # noqa: F401
20
+ DEFAULT_MODEL,
21
+ PlanStep,
22
+ Session,
23
+ SessionStore,
24
+ SESSIONS_DIR,
25
+ _generate_session_id,
26
+ parse_plan_steps,
27
+ )
28
+
29
+ from aru.display import ( # noqa: F401
30
+ StatusBar,
31
+ StreamingDisplay,
32
+ ToolTracker,
33
+ THINKING_PHRASES,
34
+ TOOL_DISPLAY_NAMES,
35
+ TOOL_PRIMARY_ARG,
36
+ _build_logo_with_shadow,
37
+ _format_tool_label,
38
+ aru_logo,
39
+ console,
40
+ format_duration,
41
+ neon_green,
42
+ shadow_green,
43
+ )
44
+
45
+ from aru.commands import ( # noqa: F401
46
+ SLASH_COMMANDS,
47
+ _show_help,
48
+ ask_yes_no,
49
+ run_shell,
50
+ )
51
+
52
+ from aru.runner import ( # noqa: F401
53
+ AgentRunResult,
54
+ _MUTATION_TOOLS,
55
+ build_env_context,
56
+ run_agent_capture,
57
+ )
58
+
59
+ from aru.agent_factory import ( # noqa: F401
60
+ create_custom_agent_instance,
61
+ create_general_agent,
62
+ )
63
+
64
+ # ── Platform setup ─────────────────────────────────────────────────────
65
+
66
+ if sys.platform == "win32" and not hasattr(sys, "_called_from_test"):
67
+ sys.stdout = _io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
68
+ sys.stderr = _io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
69
+
70
+ _logging.getLogger("agno").setLevel(_logging.WARNING)
71
+
72
+
73
+ def _restore_worktree_from_session(session) -> str:
74
+ """Re-enter the worktree persisted on *session* (Tier 3 #2 R11).
75
+
76
+ Called at the top of ``run_tui`` right after the session is bound to
77
+ the runtime context. Three branches:
78
+
79
+ - ``worktree_path`` empty or missing → no-op, returns ``"none"``.
80
+ - ``worktree_path`` set AND directory exists on disk → ``enter_worktree``
81
+ is invoked so ``ctx.cwd`` matches the previous run. Returns
82
+ ``"entered"``.
83
+ - ``worktree_path`` set but directory is gone → warn, null the
84
+ session fields, return ``"stale"``.
85
+
86
+ Returns a short outcome label (``"none"``/``"entered"``/``"stale"``/
87
+ ``"error"``) so tests can pin the branch chosen without re-parsing
88
+ console output.
89
+ """
90
+ saved_wt = getattr(session, "worktree_path", None)
91
+ saved_branch = getattr(session, "worktree_branch", None)
92
+ if not saved_wt:
93
+ return "none"
94
+ if os.path.isdir(saved_wt):
95
+ from aru.runtime import enter_worktree as _re_enter
96
+ try:
97
+ _re_enter(saved_wt, saved_branch)
98
+ console.print(
99
+ f"[dim]Resumed inside worktree: {saved_branch} ({saved_wt})[/dim]"
100
+ )
101
+ return "entered"
102
+ except Exception as exc:
103
+ console.print(
104
+ f"[yellow]Could not re-enter worktree {saved_wt}: {exc}[/yellow]"
105
+ )
106
+ return "error"
107
+ console.print(
108
+ f"[yellow]Saved worktree path no longer exists: {saved_wt} — "
109
+ f"using project root[/yellow]"
110
+ )
111
+ session.worktree_path = None
112
+ session.worktree_branch = None
113
+ return "stale"
114
+
115
+
116
+ def _configure_plugin_logger(verbose: bool = False) -> None:
117
+ """Attach a stderr handler to the ``aru.plugins`` logger.
118
+
119
+ Without this, ``logger.error(...)`` inside ``PluginManager`` (e.g. when a
120
+ subscriber raises) has no handler and disappears silently. Idempotent —
121
+ a marker attribute on the logger prevents double-registration when
122
+ ``run_oneshot`` is invoked multiple times in the same process (tests).
123
+ """
124
+ lg = _logging.getLogger("aru.plugins")
125
+ if getattr(lg, "_aru_handler_attached", False):
126
+ return
127
+ handler = _logging.StreamHandler(sys.stderr)
128
+ handler.setFormatter(
129
+ _logging.Formatter("[aru.plugins] %(levelname)s: %(message)s")
130
+ )
131
+ lg.addHandler(handler)
132
+ lg.setLevel(_logging.DEBUG if verbose else _logging.WARNING)
133
+ lg._aru_handler_attached = True # type: ignore[attr-defined]
134
+
135
+
136
+ # ── CLI entrypoint ─────────────────────────────────────────────────────
137
+
138
+ def _list_sessions_and_exit():
139
+ """Print saved sessions and exit."""
140
+ store = SessionStore()
141
+ sessions = store.list_sessions()
142
+ if not sessions:
143
+ console.print("[dim]No saved sessions.[/dim]")
144
+ return
145
+ console.print("[bold]Recent sessions:[/bold]\n")
146
+ for s in sessions:
147
+ sid = s["session_id"]
148
+ title = s["title"][:50]
149
+ msgs = s["messages"]
150
+ updated = s["updated_at"]
151
+ model = s["model"]
152
+ console.print(f" [bold cyan]{sid}[/bold cyan] {title} [dim]({msgs} msgs, {model}, {updated})[/dim]")
153
+ console.print(f"\n[dim]Resume with: aru --resume <id>[/dim]")
154
+
155
+
156
+ async def run_oneshot(prompt: str, print_only: bool = False, skip_permissions: bool = False):
157
+ """Run a single prompt non-interactively and exit.
158
+
159
+ Args:
160
+ prompt: The user prompt to execute.
161
+ print_only: If True, run without tools (text-only response).
162
+ skip_permissions: If True, skip all permission checks.
163
+ """
164
+ from aru.runtime import init_ctx
165
+ from aru.config import load_config
166
+ from aru.cache_patch import apply_cache_patch
167
+
168
+ apply_cache_patch()
169
+ _configure_plugin_logger(verbose=bool(os.environ.get("ARU_VERBOSE")))
170
+ ctx = init_ctx(console=console, skip_permissions=skip_permissions)
171
+
172
+ # E6a: install REPL UI so migrated call sites work in one-shot mode.
173
+ from aru.ui import install_repl_ui_on_ctx
174
+ install_repl_ui_on_ctx(ctx)
175
+
176
+ config = load_config()
177
+ ctx.config = config
178
+ # Populate invoke_skill's dynamic docstring (same as interactive path)
179
+ from aru.tools.skill import _update_invoke_skill_docstring
180
+ _update_invoke_skill_docstring(config.skills)
181
+ session = Session()
182
+ if config.default_model:
183
+ session.model_ref = config.default_model
184
+
185
+ ctx.session = session
186
+ ctx.model_id = session.model_id
187
+ small_ref = config.model_aliases.get("small") if config else None
188
+ if not small_ref:
189
+ from aru.providers import resolve_model_ref
190
+ provider_key, _ = resolve_model_ref(session.model_ref)
191
+ _small_defaults = {
192
+ "anthropic": "anthropic/claude-haiku-4-5",
193
+ "openai": "openai/gpt-4o-mini",
194
+ "groq": "groq/llama-3.1-8b-instant",
195
+ "deepseek": "deepseek/deepseek-chat",
196
+ "ollama": "ollama/llama3.1",
197
+ }
198
+ small_ref = _small_defaults.get(provider_key, session.model_ref)
199
+ ctx.small_model_ref = small_ref
200
+
201
+ extra_instructions = config.get_extra_instructions()
202
+
203
+ if print_only:
204
+ # Text-only mode: no tools, just a direct LLM call
205
+ from agno.agent import Agent
206
+ from aru.providers import create_model
207
+ from aru.agents.base import build_instructions
208
+
209
+ agent = Agent(
210
+ name="Aru",
211
+ model=create_model(session.model_ref, reasoning_override=session.reasoning_override),
212
+ tools=[],
213
+ instructions=build_instructions("general", extra_instructions),
214
+ markdown=True,
215
+ )
216
+ response = await agent.arun(prompt)
217
+ if response and response.content:
218
+ # Print raw text to stdout for piping
219
+ print(response.content)
220
+ else:
221
+ # Full mode with tools
222
+ from aru.runner import build_env_context
223
+ env_ctx = build_env_context(session)
224
+ agent = await create_general_agent(session, config, env_context=env_ctx)
225
+ session.add_message("user", prompt)
226
+ await run_agent_capture(agent, prompt, session)
227
+
228
+ if session.token_summary:
229
+ console.print(f"[dim]{session.token_summary}[/dim]")
230
+
231
+
232
+ def main():
233
+ """Entry point for the aru CLI."""
234
+ from dotenv import load_dotenv
235
+
236
+ load_dotenv()
237
+ args = sys.argv[1:]
238
+ skip_permissions = "--dangerously-skip-permissions" in args
239
+ print_only = "--print" in args or "-p" in args
240
+
241
+ if "--list" in args:
242
+ _list_sessions_and_exit()
243
+ return
244
+
245
+ resume_id = None
246
+ if "--resume" in args:
247
+ idx = args.index("--resume")
248
+ if idx + 1 < len(args) and not args[idx + 1].startswith("--"):
249
+ resume_id = args[idx + 1]
250
+ else:
251
+ resume_id = "last"
252
+
253
+ # Collect positional arguments (non-flag, non-flag-value)
254
+ flags_with_value = {"--resume"}
255
+ positional = []
256
+ skip_next = False
257
+ for i, arg in enumerate(args):
258
+ if skip_next:
259
+ skip_next = False
260
+ continue
261
+ if arg.startswith("--") or arg.startswith("-"):
262
+ if arg in flags_with_value:
263
+ skip_next = True
264
+ continue
265
+ positional.append(arg)
266
+
267
+ # Piped stdin: echo "fix bug" | aru
268
+ if not sys.stdin.isatty() and not positional:
269
+ piped_input = sys.stdin.read().strip()
270
+ if piped_input:
271
+ positional = [piped_input]
272
+
273
+ # One-shot mode: aru "fix the bug" or aru --print "explain this"
274
+ if positional:
275
+ prompt = " ".join(positional)
276
+ try:
277
+ asyncio.run(run_oneshot(prompt, print_only=print_only, skip_permissions=skip_permissions))
278
+ except (KeyboardInterrupt, asyncio.CancelledError, SystemExit):
279
+ pass
280
+ except Exception as e:
281
+ from rich.markup import escape
282
+ console.print(f"\n[bold red]Fatal error: {escape(str(e))}[/bold red]")
283
+ return
284
+
285
+ # Interactive mode — the Textual TUI is the only interactive interface.
286
+ # `--repl` / `--tui` are still accepted as no-op flags for backwards compat.
287
+ from aru.tui import run_tui
288
+ try:
289
+ asyncio.run(run_tui(skip_permissions=skip_permissions, resume_id=resume_id))
290
+ except (KeyboardInterrupt, asyncio.CancelledError, SystemExit):
291
+ _graceful_exit()
292
+ except Exception as e:
293
+ from rich.markup import escape
294
+ console.print(f"\n[bold red]Fatal error: {escape(str(e))}[/bold red]")
295
+ _graceful_exit()
296
+
297
+
298
+ def _graceful_exit():
299
+ """Save session and show resume hint on exit."""
300
+ try:
301
+ store = SessionStore()
302
+ last = store.load_last()
303
+ if last:
304
+ console.print(f"\n[dim]Session saved: {last.session_id}[/dim]")
305
+ console.print(f"[dim]Resume with:[/dim] [bold cyan]aru --resume {last.session_id}[/bold cyan]")
306
+ except Exception:
307
+ pass
@@ -9,7 +9,6 @@ import time
9
9
  from rich.console import Console, ConsoleOptions, RenderResult
10
10
  from rich.markdown import Markdown
11
11
  from rich.measure import Measurement
12
- from rich.rule import Rule
13
12
  from rich.spinner import Spinner
14
13
  from rich.text import Text
15
14
 
@@ -88,58 +87,6 @@ def format_duration(seconds: float) -> str:
88
87
  return f"{secs}s"
89
88
 
90
89
 
91
- def _sanitize_input(text: str) -> str:
92
- """Remove lone UTF-16 surrogates that Windows clipboard can introduce."""
93
- return text.encode("utf-8", errors="replace").decode("utf-8")
94
-
95
-
96
- def _render_input_separator() -> None:
97
- """Print a green separator line above the input prompt."""
98
- console.print(Rule(style=f"dim {neon_green}"))
99
-
100
-
101
- def _render_home(session, skip_permissions: bool) -> None:
102
- """Render a clean home screen inspired by Claude Code."""
103
- import os
104
-
105
- from rich.table import Table
106
-
107
- from aru import __version__
108
-
109
- logo = _build_logo_with_shadow(aru_logo)
110
- console.print(logo)
111
- console.print(
112
- Text.from_markup(f" [dim]A coding agent powered by OpenSource[/dim] [bold {neon_green}]v{__version__}[/bold {neon_green}]"),
113
- )
114
- console.print()
115
-
116
- cmds = Table(show_header=False, box=None, padding=(0, 2), expand=False)
117
- cmds.add_column(style="bold cyan", min_width=12)
118
- cmds.add_column(style="dim")
119
- cmds.add_row("/help", "Show all commands")
120
- console.print(cmds)
121
- console.print()
122
-
123
- mode_label = "[bold red]🔥 YOLO mode — permissions bypassed[/bold red]" if skip_permissions else "[green]safe mode[/green]"
124
- console.print(
125
- Text.from_markup(
126
- f" [dim]model:[/dim] [bold]{session.model_display}[/bold] [dim]({session.model_id})[/dim]"
127
- f" [dim]|[/dim] {mode_label}"
128
- )
129
- )
130
- # Prefer ctx.cwd so the "cwd:" line reflects the active worktree (Tier 3 #2).
131
- # Falls back to os.getcwd() when no ctx is installed (pre-init, tests).
132
- try:
133
- from aru.runtime import get_cwd as _get_cwd
134
- _cwd_display = _get_cwd()
135
- except Exception:
136
- _cwd_display = os.getcwd()
137
- console.print(
138
- Text.from_markup(f" [dim]cwd:[/dim] {_cwd_display}")
139
- )
140
- console.print()
141
-
142
-
143
90
  THINKING_PHRASES = [
144
91
  "Thinking...",
145
92
  "Cooking...",
@@ -2572,9 +2572,9 @@ async def run_tui(
2572
2572
  ) -> None:
2573
2573
  """Bootstrap Aru in TUI mode and run the Textual App.
2574
2574
 
2575
- Mirrors ``cli.run_cli`` bootstrap sequence so the TUI gets the same
2576
- config resolution, custom tools/agents/plugins/MCP loading,
2577
- formatter wiring, LSP, and session/worktree restoration as the REPL.
2575
+ Performs the full Aru bootstrap: config resolution, custom
2576
+ tools/agents/plugins/MCP loading, formatter wiring, LSP, and
2577
+ session/worktree restoration.
2578
2578
  """
2579
2579
  import atexit
2580
2580
  import logging as _logging
@@ -2643,8 +2643,8 @@ async def run_tui(
2643
2643
  session.model_ref = config.default_model
2644
2644
  ctx.session = session
2645
2645
 
2646
- # Mirror _sync_model from run_cli update RuntimeContext with the
2647
- # session's model and resolve the small-model reference.
2646
+ # Update RuntimeContext with the session's model and resolve the
2647
+ # small-model reference.
2648
2648
  try:
2649
2649
  from aru.providers import resolve_model_ref
2650
2650
  ctx.model_id = session.model_id
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aru-code
3
- Version: 0.58.0
3
+ Version: 0.59.0
4
4
  Summary: A Claude Code clone built with Agno agents
5
5
  Author-email: Estevao <estevaofon@gmail.com>
6
6
  License-Expression: MIT
@@ -116,16 +116,19 @@ Key bindings (TUI):
116
116
  Local slash commands inside the TUI: `/help`, `/clear`, `/quit`,
117
117
  `/plan`. Any other input is sent to the agent.
118
118
 
119
- ### Classic REPL (opt-in)
119
+ ### Non-interactive (one-shot)
120
120
 
121
- Prefer the single-line prompt? Pass `--repl` to use the classic REPL:
121
+ For scripting and pipes, pass a prompt directly instead of launching the
122
+ TUI:
122
123
 
123
124
  ```bash
124
- aru --repl
125
+ aru "fix the failing test in auth" # one-shot, with tools
126
+ aru --print "explain this module" # text-only, no tools
127
+ echo "summarize TODOs" | aru # piped stdin
125
128
  ```
126
129
 
127
- Both modes share the same sessions, plugins, permissions, and tools
128
- only presentation differs.
130
+ One-shot mode shares the same sessions, plugins, permissions, and tools
131
+ as the TUI — only presentation differs.
129
132
 
130
133
  ## Usage
131
134
 
@@ -706,7 +709,7 @@ Once a plan is stored, every following turn prepends a `<system-reminder>` listi
706
709
  ```
707
710
  aru-code/
708
711
  ├── aru/
709
- │ ├── cli.py # Main REPL loop, argument parsing, and entry point
712
+ │ ├── cli.py # Argument parsing, one-shot execution, and entry point
710
713
  │ ├── agent_factory.py # Single factory — builds Agno Agents from catalog specs
711
714
  │ ├── commands.py # Slash commands, help display, shell execution
712
715
  │ ├── completers.py # Input completions, paste detection, @file mentions
@@ -8,7 +8,6 @@ aru/cache_patch.py
8
8
  aru/checkpoints.py
9
9
  aru/cli.py
10
10
  aru/commands.py
11
- aru/completers.py
12
11
  aru/config.py
13
12
  aru/context.py
14
13
  aru/display.py
@@ -122,9 +121,7 @@ tests/test_checkpoints.py
122
121
  tests/test_cli.py
123
122
  tests/test_cli_advanced.py
124
123
  tests/test_cli_base.py
125
- tests/test_cli_completers.py
126
124
  tests/test_cli_new.py
127
- tests/test_cli_run_cli.py
128
125
  tests/test_cli_session.py
129
126
  tests/test_cli_shell.py
130
127
  tests/test_codebase.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "aru-code"
7
- version = "0.58.0"
7
+ version = "0.59.0"
8
8
  description = "A Claude Code clone built with Agno agents"
9
9
  readme = "README.md"
10
10
  license = "MIT"