aru-code 0.58.0__tar.gz → 0.60.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 (222) hide show
  1. {aru_code-0.58.0/aru_code.egg-info → aru_code-0.60.0}/PKG-INFO +10 -7
  2. {aru_code-0.58.0 → aru_code-0.60.0}/README.md +9 -6
  3. aru_code-0.60.0/aru/__init__.py +1 -0
  4. {aru_code-0.58.0 → aru_code-0.60.0}/aru/auth.py +3 -0
  5. aru_code-0.60.0/aru/cli.py +319 -0
  6. aru_code-0.60.0/aru/codex_oauth.py +588 -0
  7. {aru_code-0.58.0 → aru_code-0.60.0}/aru/commands.py +118 -3
  8. {aru_code-0.58.0 → aru_code-0.60.0}/aru/display.py +0 -53
  9. {aru_code-0.58.0 → aru_code-0.60.0}/aru/providers.py +209 -1
  10. aru_code-0.60.0/aru/state.py +181 -0
  11. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/app.py +24 -5
  12. {aru_code-0.58.0 → aru_code-0.60.0/aru_code.egg-info}/PKG-INFO +10 -7
  13. {aru_code-0.58.0 → aru_code-0.60.0}/aru_code.egg-info/SOURCES.txt +5 -3
  14. {aru_code-0.58.0 → aru_code-0.60.0}/pyproject.toml +1 -1
  15. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_cli.py +0 -190
  16. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_cli_advanced.py +2 -127
  17. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_cli_session.py +1 -32
  18. aru_code-0.60.0/tests/test_codex_oauth.py +406 -0
  19. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_connect_command.py +3 -1
  20. aru_code-0.60.0/tests/test_connect_oauth.py +387 -0
  21. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_main.py +0 -12
  22. aru_code-0.60.0/tests/test_state_recent_models.py +239 -0
  23. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_app_boot.py +4 -39
  24. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_chat_adversarial.py +125 -73
  25. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_permission_flow.py +6 -1
  26. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_worktree_session_restore.py +1 -1
  27. aru_code-0.58.0/aru/__init__.py +0 -1
  28. aru_code-0.58.0/aru/cli.py +0 -1151
  29. aru_code-0.58.0/aru/completers.py +0 -383
  30. aru_code-0.58.0/tests/test_cli_completers.py +0 -690
  31. aru_code-0.58.0/tests/test_cli_run_cli.py +0 -1
  32. {aru_code-0.58.0 → aru_code-0.60.0}/LICENSE +0 -0
  33. {aru_code-0.58.0 → aru_code-0.60.0}/aru/_debug/__init__.py +0 -0
  34. {aru_code-0.58.0 → aru_code-0.60.0}/aru/_debug/analyze_trace.py +0 -0
  35. {aru_code-0.58.0 → aru_code-0.60.0}/aru/_debug/loop_tracer.py +0 -0
  36. {aru_code-0.58.0 → aru_code-0.60.0}/aru/agent_factory.py +0 -0
  37. {aru_code-0.58.0 → aru_code-0.60.0}/aru/agents/__init__.py +0 -0
  38. {aru_code-0.58.0 → aru_code-0.60.0}/aru/agents/base.py +0 -0
  39. {aru_code-0.58.0 → aru_code-0.60.0}/aru/agents/catalog.py +0 -0
  40. {aru_code-0.58.0 → aru_code-0.60.0}/aru/agents/planner.py +0 -0
  41. {aru_code-0.58.0 → aru_code-0.60.0}/aru/cache_patch.py +0 -0
  42. {aru_code-0.58.0 → aru_code-0.60.0}/aru/checkpoints.py +0 -0
  43. {aru_code-0.58.0 → aru_code-0.60.0}/aru/config.py +0 -0
  44. {aru_code-0.58.0 → aru_code-0.60.0}/aru/context.py +0 -0
  45. {aru_code-0.58.0 → aru_code-0.60.0}/aru/doom_loop.py +0 -0
  46. {aru_code-0.58.0 → aru_code-0.60.0}/aru/events.py +0 -0
  47. {aru_code-0.58.0 → aru_code-0.60.0}/aru/format/__init__.py +0 -0
  48. {aru_code-0.58.0 → aru_code-0.60.0}/aru/format/manager.py +0 -0
  49. {aru_code-0.58.0 → aru_code-0.60.0}/aru/format/runner.py +0 -0
  50. {aru_code-0.58.0 → aru_code-0.60.0}/aru/history_blocks.py +0 -0
  51. {aru_code-0.58.0 → aru_code-0.60.0}/aru/lsp/__init__.py +0 -0
  52. {aru_code-0.58.0 → aru_code-0.60.0}/aru/lsp/client.py +0 -0
  53. {aru_code-0.58.0 → aru_code-0.60.0}/aru/lsp/manager.py +0 -0
  54. {aru_code-0.58.0 → aru_code-0.60.0}/aru/lsp/protocol.py +0 -0
  55. {aru_code-0.58.0 → aru_code-0.60.0}/aru/memory/__init__.py +0 -0
  56. {aru_code-0.58.0 → aru_code-0.60.0}/aru/memory/extractor.py +0 -0
  57. {aru_code-0.58.0 → aru_code-0.60.0}/aru/memory/loader.py +0 -0
  58. {aru_code-0.58.0 → aru_code-0.60.0}/aru/memory/store.py +0 -0
  59. {aru_code-0.58.0 → aru_code-0.60.0}/aru/permissions.py +0 -0
  60. {aru_code-0.58.0 → aru_code-0.60.0}/aru/plugin_cache.py +0 -0
  61. {aru_code-0.58.0 → aru_code-0.60.0}/aru/plugins/__init__.py +0 -0
  62. {aru_code-0.58.0 → aru_code-0.60.0}/aru/plugins/custom_tools.py +0 -0
  63. {aru_code-0.58.0 → aru_code-0.60.0}/aru/plugins/hooks.py +0 -0
  64. {aru_code-0.58.0 → aru_code-0.60.0}/aru/plugins/manager.py +0 -0
  65. {aru_code-0.58.0 → aru_code-0.60.0}/aru/plugins/tool_api.py +0 -0
  66. {aru_code-0.58.0 → aru_code-0.60.0}/aru/runner.py +0 -0
  67. {aru_code-0.58.0 → aru_code-0.60.0}/aru/runtime.py +0 -0
  68. {aru_code-0.58.0 → aru_code-0.60.0}/aru/select.py +0 -0
  69. {aru_code-0.58.0 → aru_code-0.60.0}/aru/session.py +0 -0
  70. {aru_code-0.58.0 → aru_code-0.60.0}/aru/sinks.py +0 -0
  71. {aru_code-0.58.0 → aru_code-0.60.0}/aru/streaming.py +0 -0
  72. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tool_policy.py +0 -0
  73. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/__init__.py +0 -0
  74. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/_diff.py +0 -0
  75. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/_shared.py +0 -0
  76. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/apply_patch.py +0 -0
  77. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/apply_patch_prompt.txt +0 -0
  78. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/ast_tools.py +0 -0
  79. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/codebase.py +0 -0
  80. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/delegate.py +0 -0
  81. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/delegate_prompt.txt +0 -0
  82. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/file_ops.py +0 -0
  83. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/gitignore.py +0 -0
  84. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/lsp.py +0 -0
  85. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/mcp_client.py +0 -0
  86. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/memory_tool.py +0 -0
  87. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/plan_mode.py +0 -0
  88. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/ranker.py +0 -0
  89. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/registry.py +0 -0
  90. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/search.py +0 -0
  91. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/shell.py +0 -0
  92. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/skill.py +0 -0
  93. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/tasklist.py +0 -0
  94. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/web.py +0 -0
  95. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tools/worktree.py +0 -0
  96. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/__init__.py +0 -0
  97. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/log_bridge.py +0 -0
  98. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/notifications.py +0 -0
  99. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/sanitize.py +0 -0
  100. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/screens/__init__.py +0 -0
  101. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/screens/choice.py +0 -0
  102. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/screens/confirm.py +0 -0
  103. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/screens/keymap.py +0 -0
  104. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/screens/search.py +0 -0
  105. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/screens/session_picker.py +0 -0
  106. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/screens/text_input.py +0 -0
  107. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/sinks.py +0 -0
  108. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/slash_bridge.py +0 -0
  109. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/themes.py +0 -0
  110. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/ui.py +0 -0
  111. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/__init__.py +0 -0
  112. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/chat.py +0 -0
  113. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/completer.py +0 -0
  114. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/context_pane.py +0 -0
  115. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/file_link.py +0 -0
  116. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/header.py +0 -0
  117. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/inline_choice.py +0 -0
  118. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/loaded_pane.py +0 -0
  119. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/prompt_area.py +0 -0
  120. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/prompt_queue.py +0 -0
  121. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/status.py +0 -0
  122. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/subagent_panel.py +0 -0
  123. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/tasklist_panel.py +0 -0
  124. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/thinking.py +0 -0
  125. {aru_code-0.58.0 → aru_code-0.60.0}/aru/tui/widgets/tools.py +0 -0
  126. {aru_code-0.58.0 → aru_code-0.60.0}/aru/ui.py +0 -0
  127. {aru_code-0.58.0 → aru_code-0.60.0}/aru_code.egg-info/dependency_links.txt +0 -0
  128. {aru_code-0.58.0 → aru_code-0.60.0}/aru_code.egg-info/entry_points.txt +0 -0
  129. {aru_code-0.58.0 → aru_code-0.60.0}/aru_code.egg-info/requires.txt +0 -0
  130. {aru_code-0.58.0 → aru_code-0.60.0}/aru_code.egg-info/top_level.txt +0 -0
  131. {aru_code-0.58.0 → aru_code-0.60.0}/setup.cfg +0 -0
  132. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_agents_base.py +0 -0
  133. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_agents_md_coverage.py +0 -0
  134. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_apply_patch.py +0 -0
  135. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_async_tool_permission.py +0 -0
  136. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_auth_store.py +0 -0
  137. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_cache_patch_metrics.py +0 -0
  138. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_cache_patch_stop_reason.py +0 -0
  139. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_catalog.py +0 -0
  140. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_chat_scrollable.py +0 -0
  141. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_checkpoints.py +0 -0
  142. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_cli_base.py +0 -0
  143. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_cli_new.py +0 -0
  144. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_cli_shell.py +0 -0
  145. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_codebase.py +0 -0
  146. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_confabulation_regression.py +0 -0
  147. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_config.py +0 -0
  148. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_context.py +0 -0
  149. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_context_pane.py +0 -0
  150. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_cwd_awareness.py +0 -0
  151. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_delegate.py +0 -0
  152. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_doom_loop.py +0 -0
  153. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_events_backward_compat.py +0 -0
  154. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_events_schema.py +0 -0
  155. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_fork_ctx_concurrency.py +0 -0
  156. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_format.py +0 -0
  157. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_gitignore.py +0 -0
  158. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_guardrails_scenarios.py +0 -0
  159. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_invoke_skill.py +0 -0
  160. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_invoked_skills.py +0 -0
  161. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_loaded_pane_path.py +0 -0
  162. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_lsp.py +0 -0
  163. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_lsp_rename.py +0 -0
  164. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_markdown_to_text.py +0 -0
  165. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_mcp_client.py +0 -0
  166. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_mcp_health.py +0 -0
  167. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_memory.py +0 -0
  168. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_memory_tool.py +0 -0
  169. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_microcompact.py +0 -0
  170. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_permission_timeout_suspension.py +0 -0
  171. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_permissions.py +0 -0
  172. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_plan_mode_refactor.py +0 -0
  173. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_plugin_cache.py +0 -0
  174. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_plugin_errors.py +0 -0
  175. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_plugin_hooks_v2.py +0 -0
  176. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_plugins.py +0 -0
  177. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_providers.py +0 -0
  178. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_ranker.py +0 -0
  179. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_reasoning.py +0 -0
  180. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_runner_interrupt.py +0 -0
  181. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_runner_recovery.py +0 -0
  182. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_runtime.py +0 -0
  183. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_select.py +0 -0
  184. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_session_free_cost.py +0 -0
  185. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_skill_disallowed_tools.py +0 -0
  186. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_status_breakdown.py +0 -0
  187. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_status_cost.py +0 -0
  188. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_streaming_sink.py +0 -0
  189. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_subagent_tool_events.py +0 -0
  190. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tasklist.py +0 -0
  191. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_thread_tool_timeout.py +0 -0
  192. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tool_policy.py +0 -0
  193. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_truncation_marker.py +0 -0
  194. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_bindings.py +0 -0
  195. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_bus_flow.py +0 -0
  196. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_chat.py +0 -0
  197. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_completer.py +0 -0
  198. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_completer_dynamic.py +0 -0
  199. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_connect_wiring.py +0 -0
  200. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_copy.py +0 -0
  201. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_error_display.py +0 -0
  202. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_file_link.py +0 -0
  203. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_input_behaviour.py +0 -0
  204. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_layer12_recovery.py +0 -0
  205. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_layer13_recovery.py +0 -0
  206. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_mention_expand.py +0 -0
  207. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_modals.py +0 -0
  208. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_mode_cycle.py +0 -0
  209. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_native_selection.py +0 -0
  210. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_plan_task_render.py +0 -0
  211. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_prompt_queue.py +0 -0
  212. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_shell_bang.py +0 -0
  213. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_sidebar_toggle.py +0 -0
  214. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_slash_bridge.py +0 -0
  215. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_slash_model.py +0 -0
  216. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_snapshot_smoke.py +0 -0
  217. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_subagent_panel.py +0 -0
  218. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_theme.py +0 -0
  219. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_thinking_and_boot.py +0 -0
  220. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_tui_widgets_visual.py +0 -0
  221. {aru_code-0.58.0 → aru_code-0.60.0}/tests/test_ui_adapter.py +0 -0
  222. {aru_code-0.58.0 → aru_code-0.60.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.60.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.60.0"
@@ -13,6 +13,9 @@ Schema (``info``) — a tagged union on ``type`` so future auth methods
13
13
  "provider_type": "openai", "default_model": "...", # custom provider
14
14
  "context_limit": 128000}
15
15
  {"type": "local", "base_url": "http://..."} # keyless (e.g. Ollama)
16
+ {"type": "oauth", "refresh": "...", # ChatGPT (Codex) — wired
17
+ "access": "...", "expires": 1735689600000, # by /connect → "ChatGPT
18
+ "accountId": "acc-..."} # Pro/Plus (browser)"
16
19
 
17
20
  Consumption lives in :func:`aru.providers.apply_stored_credentials`, which
18
21
  layers these onto the in-memory provider registry at startup (and again
@@ -0,0 +1,319 @@
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
+ # Same precedence as run_tui: aru.json default_model wins, otherwise
183
+ # fall back to the most-recent /connect or /model selection persisted
184
+ # in ~/.aru/state.json. Built-in default kicks in only when neither
185
+ # source provides a usable ref.
186
+ if config.default_model:
187
+ session.model_ref = config.default_model
188
+ else:
189
+ try:
190
+ from aru import state as _state
191
+ last = _state.get_last_model()
192
+ except Exception:
193
+ last = None
194
+ if last:
195
+ session.model_ref = last
196
+
197
+ ctx.session = session
198
+ ctx.model_id = session.model_id
199
+ small_ref = config.model_aliases.get("small") if config else None
200
+ if not small_ref:
201
+ from aru.providers import resolve_model_ref
202
+ provider_key, _ = resolve_model_ref(session.model_ref)
203
+ _small_defaults = {
204
+ "anthropic": "anthropic/claude-haiku-4-5",
205
+ "openai": "openai/gpt-4o-mini",
206
+ "groq": "groq/llama-3.1-8b-instant",
207
+ "deepseek": "deepseek/deepseek-chat",
208
+ "ollama": "ollama/llama3.1",
209
+ }
210
+ small_ref = _small_defaults.get(provider_key, session.model_ref)
211
+ ctx.small_model_ref = small_ref
212
+
213
+ extra_instructions = config.get_extra_instructions()
214
+
215
+ if print_only:
216
+ # Text-only mode: no tools, just a direct LLM call
217
+ from agno.agent import Agent
218
+ from aru.providers import create_model
219
+ from aru.agents.base import build_instructions
220
+
221
+ agent = Agent(
222
+ name="Aru",
223
+ model=create_model(session.model_ref, reasoning_override=session.reasoning_override),
224
+ tools=[],
225
+ instructions=build_instructions("general", extra_instructions),
226
+ markdown=True,
227
+ )
228
+ response = await agent.arun(prompt)
229
+ if response and response.content:
230
+ # Print raw text to stdout for piping
231
+ print(response.content)
232
+ else:
233
+ # Full mode with tools
234
+ from aru.runner import build_env_context
235
+ env_ctx = build_env_context(session)
236
+ agent = await create_general_agent(session, config, env_context=env_ctx)
237
+ session.add_message("user", prompt)
238
+ await run_agent_capture(agent, prompt, session)
239
+
240
+ if session.token_summary:
241
+ console.print(f"[dim]{session.token_summary}[/dim]")
242
+
243
+
244
+ def main():
245
+ """Entry point for the aru CLI."""
246
+ from dotenv import load_dotenv
247
+
248
+ load_dotenv()
249
+ args = sys.argv[1:]
250
+ skip_permissions = "--dangerously-skip-permissions" in args
251
+ print_only = "--print" in args or "-p" in args
252
+
253
+ if "--list" in args:
254
+ _list_sessions_and_exit()
255
+ return
256
+
257
+ resume_id = None
258
+ if "--resume" in args:
259
+ idx = args.index("--resume")
260
+ if idx + 1 < len(args) and not args[idx + 1].startswith("--"):
261
+ resume_id = args[idx + 1]
262
+ else:
263
+ resume_id = "last"
264
+
265
+ # Collect positional arguments (non-flag, non-flag-value)
266
+ flags_with_value = {"--resume"}
267
+ positional = []
268
+ skip_next = False
269
+ for i, arg in enumerate(args):
270
+ if skip_next:
271
+ skip_next = False
272
+ continue
273
+ if arg.startswith("--") or arg.startswith("-"):
274
+ if arg in flags_with_value:
275
+ skip_next = True
276
+ continue
277
+ positional.append(arg)
278
+
279
+ # Piped stdin: echo "fix bug" | aru
280
+ if not sys.stdin.isatty() and not positional:
281
+ piped_input = sys.stdin.read().strip()
282
+ if piped_input:
283
+ positional = [piped_input]
284
+
285
+ # One-shot mode: aru "fix the bug" or aru --print "explain this"
286
+ if positional:
287
+ prompt = " ".join(positional)
288
+ try:
289
+ asyncio.run(run_oneshot(prompt, print_only=print_only, skip_permissions=skip_permissions))
290
+ except (KeyboardInterrupt, asyncio.CancelledError, SystemExit):
291
+ pass
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
+ return
296
+
297
+ # Interactive mode — the Textual TUI is the only interactive interface.
298
+ # `--repl` / `--tui` are still accepted as no-op flags for backwards compat.
299
+ from aru.tui import run_tui
300
+ try:
301
+ asyncio.run(run_tui(skip_permissions=skip_permissions, resume_id=resume_id))
302
+ except (KeyboardInterrupt, asyncio.CancelledError, SystemExit):
303
+ _graceful_exit()
304
+ except Exception as e:
305
+ from rich.markup import escape
306
+ console.print(f"\n[bold red]Fatal error: {escape(str(e))}[/bold red]")
307
+ _graceful_exit()
308
+
309
+
310
+ def _graceful_exit():
311
+ """Save session and show resume hint on exit."""
312
+ try:
313
+ store = SessionStore()
314
+ last = store.load_last()
315
+ if last:
316
+ console.print(f"\n[dim]Session saved: {last.session_id}[/dim]")
317
+ console.print(f"[dim]Resume with:[/dim] [bold cyan]aru --resume {last.session_id}[/bold cyan]")
318
+ except Exception:
319
+ pass