ripperdoc 0.3.0__tar.gz → 0.3.2__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.
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/PKG-INFO +3 -2
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/README.md +1 -1
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/pyproject.toml +1 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/__init__.py +1 -1
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/cli.py +9 -1
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/agents_cmd.py +93 -53
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/mcp_cmd.py +3 -0
- ripperdoc-0.3.2/ripperdoc/cli/commands/models_cmd.py +971 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/permissions_cmd.py +107 -52
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/resume_cmd.py +61 -51
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/themes_cmd.py +31 -1
- ripperdoc-0.3.2/ripperdoc/cli/ui/agents_tui/__init__.py +3 -0
- ripperdoc-0.3.2/ripperdoc/cli/ui/agents_tui/textual_app.py +1138 -0
- ripperdoc-0.3.2/ripperdoc/cli/ui/choice.py +376 -0
- ripperdoc-0.3.2/ripperdoc/cli/ui/interrupt_listener.py +233 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/message_display.py +7 -0
- ripperdoc-0.3.2/ripperdoc/cli/ui/models_tui/__init__.py +5 -0
- ripperdoc-0.3.2/ripperdoc/cli/ui/models_tui/textual_app.py +698 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/panels.py +19 -4
- ripperdoc-0.3.2/ripperdoc/cli/ui/permissions_tui/__init__.py +3 -0
- ripperdoc-0.3.2/ripperdoc/cli/ui/permissions_tui/textual_app.py +526 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/provider_options.py +220 -80
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/rich_ui.py +91 -83
- ripperdoc-0.3.2/ripperdoc/cli/ui/tips.py +89 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/wizard.py +98 -45
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/config.py +3 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/permissions.py +66 -104
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/providers/anthropic.py +11 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/protocol/stdio.py +3 -1
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/bash_tool.py +2 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/file_edit_tool.py +100 -181
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/file_read_tool.py +101 -25
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/multi_edit_tool.py +239 -91
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/notebook_edit_tool.py +11 -29
- ripperdoc-0.3.2/ripperdoc/utils/file_editing.py +164 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/permissions/tool_permission_utils.py +11 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc.egg-info/PKG-INFO +3 -2
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc.egg-info/SOURCES.txt +10 -2
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc.egg-info/requires.txt +1 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_config.py +1 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_permissions.py +20 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_shell_permissions.py +46 -0
- ripperdoc-0.3.0/ripperdoc/cli/commands/models_cmd.py +0 -486
- ripperdoc-0.3.0/ripperdoc/cli/ui/interrupt_handler.py +0 -208
- ripperdoc-0.3.0/tests/test_interrupt_handler.py +0 -505
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/LICENSE +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/__main__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/base.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/clear_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/compact_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/config_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/context_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/cost_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/doctor_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/exit_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/help_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/hooks_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/memory_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/skills_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/stats_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/status_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/tasks_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/todos_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/commands/tools_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/context_display.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/file_mention_completer.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/helpers.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/spinner.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/thinking_spinner.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/cli/ui/tool_renderers.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/agents.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/commands.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/custom_commands.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/default_tools.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/hooks/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/hooks/config.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/hooks/events.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/hooks/executor.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/hooks/integration.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/hooks/llm_callback.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/hooks/manager.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/providers/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/providers/base.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/providers/gemini.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/providers/openai.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/query.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/query_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/skills.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/system_prompt.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/theme.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/core/tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/protocol/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/protocol/models.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/ask_user_question_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/background_shell.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/bash_output_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/dynamic_mcp_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/enter_plan_mode_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/exit_plan_mode_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/file_write_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/glob_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/grep_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/kill_bash_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/ls_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/lsp_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/mcp_tools.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/skill_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/task_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/todo_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/tools/tool_search_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/bash_constants.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/bash_output_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/coerce.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/context_length_errors.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/conversation_compaction.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/exit_code_handlers.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/file_watch.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/git_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/image_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/json_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/log.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/lsp.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/mcp.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/memory.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/message_compaction.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/message_formatting.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/messages.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/output_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/path_ignore.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/path_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/pending_messages.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/permissions/__init__.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/permissions/path_validation_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/permissions/shell_command_validation.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/platform.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/prompt.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/safe_get_cwd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/sandbox_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/session_heatmap.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/session_history.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/session_stats.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/session_usage.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/shell_token_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/shell_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/todo.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc/utils/token_estimation.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc.egg-info/dependency_links.txt +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc.egg-info/entry_points.txt +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/ripperdoc.egg-info/top_level.txt +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/setup.cfg +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/setup.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_background_notifications.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_background_shell_shutdown.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_background_shell_status.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_cli_commands.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_cli_stdin.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_compact.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_context_length_errors.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_context_limits.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_custom_commands.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_file_edit_tool.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_file_mention_completer.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_git_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_hooks.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_hooks_cmd.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_mcp_config.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_messages.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_output_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_path_ignore.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_pending_messages.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_platform.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_query_abort.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_rich_ui_suggestions.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_shell_utils.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_skills.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_todo.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_tool_search.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_tools.py +0 -0
- {ripperdoc-0.3.0 → ripperdoc-0.3.2}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ripperdoc
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: AI-powered terminal assistant for coding tasks
|
|
5
5
|
Author: Ripperdoc Team
|
|
6
6
|
License: Apache-2.0
|
|
@@ -18,6 +18,7 @@ Requires-Dist: anthropic>=0.39.0
|
|
|
18
18
|
Requires-Dist: openai>=1.0.0
|
|
19
19
|
Requires-Dist: click>=8.1.0
|
|
20
20
|
Requires-Dist: rich>=13.0.0
|
|
21
|
+
Requires-Dist: textual>=0.58.0
|
|
21
22
|
Requires-Dist: pydantic>=2.0.0
|
|
22
23
|
Requires-Dist: python-dotenv>=1.0.0
|
|
23
24
|
Requires-Dist: aiofiles>=23.0.0
|
|
@@ -133,7 +134,7 @@ This launches an interactive session where you can:
|
|
|
133
134
|
|
|
134
135
|
### Python SDK (headless)
|
|
135
136
|
|
|
136
|
-
Use Ripperdoc without the terminal UI via the
|
|
137
|
+
Use Ripperdoc without the terminal UI via the Python SDK. See [SDK Documentation](https://ripperdoc-docs.pages.dev/docs/sdk-overview/) for examples of the one-shot `query` helper and the session-based `RipperdocClient`.
|
|
137
138
|
|
|
138
139
|
#### SDK Examples
|
|
139
140
|
|
|
@@ -89,7 +89,7 @@ This launches an interactive session where you can:
|
|
|
89
89
|
|
|
90
90
|
### Python SDK (headless)
|
|
91
91
|
|
|
92
|
-
Use Ripperdoc without the terminal UI via the
|
|
92
|
+
Use Ripperdoc without the terminal UI via the Python SDK. See [SDK Documentation](https://ripperdoc-docs.pages.dev/docs/sdk-overview/) for examples of the one-shot `query` helper and the session-based `RipperdocClient`.
|
|
93
93
|
|
|
94
94
|
#### SDK Examples
|
|
95
95
|
|
|
@@ -17,7 +17,11 @@ from ripperdoc.core.config import (
|
|
|
17
17
|
get_project_config,
|
|
18
18
|
)
|
|
19
19
|
from ripperdoc.cli.ui.wizard import check_onboarding
|
|
20
|
-
from ripperdoc.core.default_tools import
|
|
20
|
+
from ripperdoc.core.default_tools import (
|
|
21
|
+
BUILTIN_TOOL_NAMES,
|
|
22
|
+
filter_tools_by_names,
|
|
23
|
+
get_default_tools,
|
|
24
|
+
)
|
|
21
25
|
from ripperdoc.core.query import query, QueryContext
|
|
22
26
|
from ripperdoc.core.system_prompt import build_system_prompt
|
|
23
27
|
from ripperdoc.core.skills import build_skill_summary, load_all_skills
|
|
@@ -95,6 +99,7 @@ async def run_query(
|
|
|
95
99
|
custom_system_prompt: Optional[str] = None,
|
|
96
100
|
append_system_prompt: Optional[str] = None,
|
|
97
101
|
model: Optional[str] = None,
|
|
102
|
+
allowed_tools: Optional[List[str]] = None,
|
|
98
103
|
) -> None:
|
|
99
104
|
"""Run a single query and print the response."""
|
|
100
105
|
logger.info(
|
|
@@ -154,6 +159,8 @@ async def run_query(
|
|
|
154
159
|
dynamic_tools = await load_dynamic_mcp_tools_async(Path.cwd())
|
|
155
160
|
if dynamic_tools:
|
|
156
161
|
tools = merge_tools_with_dynamic(tools, dynamic_tools)
|
|
162
|
+
if allowed_tools is not None:
|
|
163
|
+
tools = filter_tools_by_names(tools, allowed_tools)
|
|
157
164
|
query_context.tools = tools
|
|
158
165
|
mcp_instructions = format_mcp_instructions(servers)
|
|
159
166
|
skill_result = load_all_skills(Path.cwd())
|
|
@@ -484,6 +491,7 @@ def cli(
|
|
|
484
491
|
custom_system_prompt=system_prompt,
|
|
485
492
|
append_system_prompt=append_system_prompt,
|
|
486
493
|
model=model,
|
|
494
|
+
allowed_tools=allowed_tools,
|
|
487
495
|
)
|
|
488
496
|
)
|
|
489
497
|
return
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
|
|
2
4
|
from rich import box
|
|
5
|
+
from rich.markup import escape
|
|
3
6
|
from rich.panel import Panel
|
|
4
7
|
from rich.table import Table
|
|
5
8
|
|
|
@@ -18,7 +21,6 @@ from ripperdoc.tools.task_tool import (
|
|
|
18
21
|
)
|
|
19
22
|
from ripperdoc.utils.log import get_logger
|
|
20
23
|
|
|
21
|
-
from typing import Any, Dict
|
|
22
24
|
from .base import SlashCommand
|
|
23
25
|
|
|
24
26
|
logger = get_logger()
|
|
@@ -43,6 +45,77 @@ def _format_duration(duration_ms: float | None) -> str:
|
|
|
43
45
|
return f"{hours}h {mins}m"
|
|
44
46
|
|
|
45
47
|
|
|
48
|
+
def _print_agents_usage(console: Any) -> None:
|
|
49
|
+
console.print("[bold]/agents[/bold] — open interactive agents UI")
|
|
50
|
+
console.print("[bold]/agents tui[/bold] — open interactive agents UI")
|
|
51
|
+
console.print("[bold]/agents list[/bold] — list configured agents (plain)")
|
|
52
|
+
console.print(
|
|
53
|
+
"[bold]/agents create <name> [location] [model][/bold] — "
|
|
54
|
+
"create agent (location: user|project, default user)"
|
|
55
|
+
)
|
|
56
|
+
console.print("[bold]/agents edit <name> [location][/bold] — edit an existing agent")
|
|
57
|
+
console.print(
|
|
58
|
+
"[bold]/agents delete <name> [location][/bold] — "
|
|
59
|
+
"delete agent (location: user|project, default user)"
|
|
60
|
+
)
|
|
61
|
+
console.print("[bold]/agents runs[/bold] — list subagent runs")
|
|
62
|
+
console.print("[bold]/agents show <id>[/bold] — show subagent run details")
|
|
63
|
+
console.print("[bold]/agents cancel <id>[/bold] — cancel a background subagent run")
|
|
64
|
+
console.print(
|
|
65
|
+
f"[dim]Agent files live in ~/.ripperdoc/{AGENT_DIR_NAME} "
|
|
66
|
+
f"or ./.ripperdoc/{AGENT_DIR_NAME}[/dim]"
|
|
67
|
+
)
|
|
68
|
+
console.print(
|
|
69
|
+
"[dim]Model can be a profile name or pointer (main/quick). Defaults to 'main'.[/dim]"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _render_agents_plain(console: Any) -> None:
|
|
74
|
+
agents = load_agent_definitions()
|
|
75
|
+
console.print("\n[bold]Agents:[/bold]")
|
|
76
|
+
_print_agents_usage(console)
|
|
77
|
+
if not agents.active_agents:
|
|
78
|
+
console.print(" • None configured")
|
|
79
|
+
for agent in agents.active_agents:
|
|
80
|
+
location = getattr(agent.location, "value", agent.location)
|
|
81
|
+
tools_str = "all tools" if "*" in agent.tools else ", ".join(agent.tools)
|
|
82
|
+
console.print(f" • {escape(agent.agent_type)} ({escape(str(location))})", markup=False)
|
|
83
|
+
console.print(f" {escape(agent.when_to_use)}", markup=False)
|
|
84
|
+
console.print(f" tools: {escape(tools_str)}", markup=False)
|
|
85
|
+
console.print(f" model: {escape(agent.model or 'main (default)')}", markup=False)
|
|
86
|
+
if agents.failed_files:
|
|
87
|
+
console.print("[yellow]Some agent files could not be loaded:[/yellow]")
|
|
88
|
+
for path, error in agents.failed_files:
|
|
89
|
+
console.print(f" - {escape(str(path))}: {escape(str(error))}", markup=False)
|
|
90
|
+
console.print(
|
|
91
|
+
f"[dim]Add agents in ~/.ripperdoc/{AGENT_DIR_NAME} or ./.ripperdoc/{AGENT_DIR_NAME}[/dim]"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _handle_agents_tui(ui: Any) -> bool:
|
|
96
|
+
console = ui.console
|
|
97
|
+
if not sys.stdin.isatty():
|
|
98
|
+
console.print("[yellow]Interactive UI requires a TTY. Showing plain list instead.[/yellow]")
|
|
99
|
+
_render_agents_plain(console)
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
from ripperdoc.cli.ui.agents_tui import run_agents_tui
|
|
104
|
+
except (ImportError, ModuleNotFoundError) as exc:
|
|
105
|
+
console.print(
|
|
106
|
+
f"[yellow]Textual UI not available ({escape(str(exc))}). Showing plain list.[/yellow]"
|
|
107
|
+
)
|
|
108
|
+
_render_agents_plain(console)
|
|
109
|
+
return True
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
return bool(run_agents_tui())
|
|
113
|
+
except Exception as exc: # noqa: BLE001 - fail safe in interactive UI
|
|
114
|
+
console.print(f"[red]Textual UI failed: {escape(str(exc))}[/red]")
|
|
115
|
+
_render_agents_plain(console)
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
|
|
46
119
|
def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
47
120
|
console = ui.console
|
|
48
121
|
tokens = trimmed_arg.split()
|
|
@@ -50,35 +123,20 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
50
123
|
logger.info(
|
|
51
124
|
"[agents_cmd] Handling /agents command",
|
|
52
125
|
extra={
|
|
53
|
-
"subcommand": subcmd or "
|
|
126
|
+
"subcommand": subcmd or "tui",
|
|
54
127
|
"session_id": getattr(ui, "session_id", None),
|
|
55
128
|
},
|
|
56
129
|
)
|
|
57
130
|
|
|
58
|
-
def print_agents_usage() -> None:
|
|
59
|
-
console.print("[bold]/agents[/bold] — list configured agents")
|
|
60
|
-
console.print(
|
|
61
|
-
"[bold]/agents create <name> [location] [model][/bold] — "
|
|
62
|
-
"create agent (location: user|project, default user)"
|
|
63
|
-
)
|
|
64
|
-
console.print("[bold]/agents edit <name> [location][/bold] — edit an existing agent")
|
|
65
|
-
console.print(
|
|
66
|
-
"[bold]/agents delete <name> [location][/bold] — "
|
|
67
|
-
"delete agent (location: user|project, default user)"
|
|
68
|
-
)
|
|
69
|
-
console.print("[bold]/agents runs[/bold] — list subagent runs")
|
|
70
|
-
console.print("[bold]/agents show <id>[/bold] — show subagent run details")
|
|
71
|
-
console.print("[bold]/agents cancel <id>[/bold] — cancel a background subagent run")
|
|
72
|
-
console.print(
|
|
73
|
-
f"[dim]Agent files live in ~/.ripperdoc/{AGENT_DIR_NAME} "
|
|
74
|
-
f"or ./.ripperdoc/{AGENT_DIR_NAME}[/dim]"
|
|
75
|
-
)
|
|
76
|
-
console.print(
|
|
77
|
-
"[dim]Model can be a profile name or pointer (main/quick). Defaults to 'main'.[/dim]"
|
|
78
|
-
)
|
|
79
|
-
|
|
80
131
|
if subcmd in ("help", "-h", "--help"):
|
|
81
|
-
|
|
132
|
+
_print_agents_usage(console)
|
|
133
|
+
return True
|
|
134
|
+
|
|
135
|
+
if subcmd in ("", "tui", "ui"):
|
|
136
|
+
return _handle_agents_tui(ui)
|
|
137
|
+
|
|
138
|
+
if subcmd in ("list", "ls"):
|
|
139
|
+
_render_agents_plain(console)
|
|
82
140
|
return True
|
|
83
141
|
|
|
84
142
|
if subcmd in ("runs", "run", "tasks", "status"):
|
|
@@ -178,7 +236,7 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
178
236
|
agent_name = tokens[1] if len(tokens) > 1 else console.input("Agent name: ").strip()
|
|
179
237
|
if not agent_name:
|
|
180
238
|
console.print("[red]Agent name is required.[/red]")
|
|
181
|
-
|
|
239
|
+
_print_agents_usage(console)
|
|
182
240
|
return True
|
|
183
241
|
|
|
184
242
|
description = console.input("Description (when to use this agent): ").strip()
|
|
@@ -192,7 +250,7 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
192
250
|
system_prompt = console.input("System prompt (single line, use \\n for newlines): ").strip()
|
|
193
251
|
if not system_prompt:
|
|
194
252
|
console.print("[red]System prompt is required.[/red]")
|
|
195
|
-
|
|
253
|
+
_print_agents_usage(console)
|
|
196
254
|
return True
|
|
197
255
|
|
|
198
256
|
location_arg = tokens[2] if len(tokens) > 2 else ""
|
|
@@ -236,7 +294,7 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
236
294
|
)
|
|
237
295
|
except (OSError, IOError, PermissionError, ValueError) as exc:
|
|
238
296
|
console.print(f"[red]Failed to create agent: {escape(str(exc))}[/red]")
|
|
239
|
-
|
|
297
|
+
_print_agents_usage(console)
|
|
240
298
|
logger.warning(
|
|
241
299
|
"[agents_cmd] Failed to create agent: %s: %s",
|
|
242
300
|
type(exc).__name__,
|
|
@@ -251,7 +309,7 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
251
309
|
)
|
|
252
310
|
if not agent_name:
|
|
253
311
|
console.print("[red]Agent name is required.[/red]")
|
|
254
|
-
|
|
312
|
+
_print_agents_usage(console)
|
|
255
313
|
return True
|
|
256
314
|
|
|
257
315
|
location_raw = (
|
|
@@ -269,7 +327,7 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
269
327
|
console.print(f"[yellow]{escape(str(exc))}[/yellow]")
|
|
270
328
|
except (OSError, IOError, PermissionError, ValueError) as exc:
|
|
271
329
|
console.print(f"[red]Failed to delete agent: {escape(str(exc))}[/red]")
|
|
272
|
-
|
|
330
|
+
_print_agents_usage(console)
|
|
273
331
|
logger.warning(
|
|
274
332
|
"[agents_cmd] Failed to delete agent: %s: %s",
|
|
275
333
|
type(exc).__name__,
|
|
@@ -282,14 +340,14 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
282
340
|
agent_name = tokens[1] if len(tokens) > 1 else console.input("Agent to edit: ").strip()
|
|
283
341
|
if not agent_name:
|
|
284
342
|
console.print("[red]Agent name is required.[/red]")
|
|
285
|
-
|
|
343
|
+
_print_agents_usage(console)
|
|
286
344
|
return True
|
|
287
345
|
|
|
288
346
|
agents = load_agent_definitions()
|
|
289
347
|
target_agent = next((a for a in agents.active_agents if a.agent_type == agent_name), None)
|
|
290
348
|
if not target_agent:
|
|
291
349
|
console.print(f"[red]Agent '{escape(agent_name)}' not found.[/red]")
|
|
292
|
-
|
|
350
|
+
_print_agents_usage(console)
|
|
293
351
|
return True
|
|
294
352
|
if target_agent.location == AgentLocation.BUILT_IN:
|
|
295
353
|
console.print("[yellow]Built-in agents cannot be edited.[/yellow]")
|
|
@@ -348,7 +406,7 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
348
406
|
)
|
|
349
407
|
except (OSError, IOError, PermissionError, ValueError) as exc:
|
|
350
408
|
console.print(f"[red]Failed to update agent: {escape(str(exc))}[/red]")
|
|
351
|
-
|
|
409
|
+
_print_agents_usage(console)
|
|
352
410
|
logger.warning(
|
|
353
411
|
"[agents_cmd] Failed to update agent: %s: %s",
|
|
354
412
|
type(exc).__name__,
|
|
@@ -357,25 +415,7 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
357
415
|
)
|
|
358
416
|
return True
|
|
359
417
|
|
|
360
|
-
|
|
361
|
-
console.print("\n[bold]Agents:[/bold]")
|
|
362
|
-
print_agents_usage()
|
|
363
|
-
if not agents.active_agents:
|
|
364
|
-
console.print(" • None configured")
|
|
365
|
-
for agent in agents.active_agents:
|
|
366
|
-
location = getattr(agent.location, "value", agent.location)
|
|
367
|
-
tools_str = "all tools" if "*" in agent.tools else ", ".join(agent.tools)
|
|
368
|
-
console.print(f" • {escape(agent.agent_type)} ({escape(str(location))})", markup=False)
|
|
369
|
-
console.print(f" {escape(agent.when_to_use)}", markup=False)
|
|
370
|
-
console.print(f" tools: {escape(tools_str)}", markup=False)
|
|
371
|
-
console.print(f" model: {escape(agent.model or 'main (default)')}", markup=False)
|
|
372
|
-
if agents.failed_files:
|
|
373
|
-
console.print("[yellow]Some agent files could not be loaded:[/yellow]")
|
|
374
|
-
for path, error in agents.failed_files:
|
|
375
|
-
console.print(f" - {escape(str(path))}: {escape(str(error))}", markup=False)
|
|
376
|
-
console.print(
|
|
377
|
-
f"[dim]Add agents in ~/.ripperdoc/{AGENT_DIR_NAME} or ./.ripperdoc/{AGENT_DIR_NAME}[/dim]"
|
|
378
|
-
)
|
|
418
|
+
_render_agents_plain(console)
|
|
379
419
|
return True
|
|
380
420
|
|
|
381
421
|
|
|
@@ -48,6 +48,9 @@ def _handle(ui: Any, _: str) -> bool:
|
|
|
48
48
|
ui.console.print(" Tools:")
|
|
49
49
|
for tool in server.tools:
|
|
50
50
|
desc = f" — {tool.description}" if tool.description else ""
|
|
51
|
+
# Truncate long descriptions
|
|
52
|
+
if tool.description and len(tool.description) > 80:
|
|
53
|
+
desc = f" — {tool.description[:77]}..."
|
|
51
54
|
ui.console.print(f" • {tool.name}{desc}", markup=False)
|
|
52
55
|
else:
|
|
53
56
|
ui.console.print(" Tools: none discovered")
|