ripperdoc 0.2.10__tar.gz → 0.3.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.
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/PKG-INFO +49 -17
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/README.md +46 -15
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/pyproject.toml +2 -1
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/__init__.py +1 -1
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/cli.py +164 -57
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/__init__.py +4 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/agents_cmd.py +3 -7
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/doctor_cmd.py +29 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/memory_cmd.py +2 -1
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/models_cmd.py +61 -5
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/resume_cmd.py +1 -0
- ripperdoc-0.3.0/ripperdoc/cli/commands/skills_cmd.py +103 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/stats_cmd.py +4 -4
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/status_cmd.py +10 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/tasks_cmd.py +6 -3
- ripperdoc-0.3.0/ripperdoc/cli/commands/themes_cmd.py +139 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/file_mention_completer.py +63 -13
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/helpers.py +6 -3
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/interrupt_handler.py +34 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/panels.py +13 -8
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/rich_ui.py +451 -32
- ripperdoc-0.3.0/ripperdoc/cli/ui/spinner.py +148 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/tool_renderers.py +10 -9
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/wizard.py +18 -11
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/agents.py +4 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/config.py +235 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/default_tools.py +1 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/hooks/llm_callback.py +0 -1
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/hooks/manager.py +6 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/permissions.py +82 -5
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/providers/openai.py +55 -9
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/query.py +349 -108
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/query_utils.py +17 -14
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/skills.py +1 -0
- ripperdoc-0.3.0/ripperdoc/core/theme.py +298 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/tool.py +8 -3
- ripperdoc-0.3.0/ripperdoc/protocol/__init__.py +14 -0
- ripperdoc-0.3.0/ripperdoc/protocol/models.py +300 -0
- ripperdoc-0.3.0/ripperdoc/protocol/stdio.py +1453 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/background_shell.py +49 -5
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/bash_tool.py +75 -9
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/file_edit_tool.py +98 -29
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/file_read_tool.py +139 -8
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/file_write_tool.py +46 -3
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/grep_tool.py +98 -8
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/lsp_tool.py +9 -15
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/multi_edit_tool.py +26 -3
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/skill_tool.py +52 -1
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/task_tool.py +33 -8
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/file_watch.py +12 -6
- ripperdoc-0.3.0/ripperdoc/utils/image_utils.py +125 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/log.py +30 -3
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/lsp.py +9 -3
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/mcp.py +80 -18
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/message_formatting.py +2 -2
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/messages.py +177 -32
- ripperdoc-0.3.0/ripperdoc/utils/pending_messages.py +50 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/permissions/shell_command_validation.py +3 -3
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/permissions/tool_permission_utils.py +9 -3
- ripperdoc-0.3.0/ripperdoc/utils/platform.py +198 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/session_heatmap.py +1 -3
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/session_history.py +2 -2
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/session_stats.py +1 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/shell_utils.py +8 -5
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/todo.py +0 -6
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc.egg-info/PKG-INFO +49 -17
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc.egg-info/SOURCES.txt +19 -3
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc.egg-info/requires.txt +2 -1
- ripperdoc-0.3.0/tests/test_background_notifications.py +57 -0
- ripperdoc-0.3.0/tests/test_background_shell_status.py +33 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_cli_commands.py +2 -0
- ripperdoc-0.3.0/tests/test_cli_stdin.py +43 -0
- ripperdoc-0.3.0/tests/test_file_edit_tool.py +705 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_file_mention_completer.py +3 -3
- ripperdoc-0.3.0/tests/test_git_utils.py +527 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_hooks.py +608 -396
- ripperdoc-0.3.0/tests/test_interrupt_handler.py +505 -0
- ripperdoc-0.3.0/tests/test_pending_messages.py +110 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_permissions.py +4 -4
- ripperdoc-0.3.0/tests/test_platform.py +362 -0
- ripperdoc-0.3.0/tests/test_rich_ui_suggestions.py +20 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_shell_permissions.py +6 -5
- ripperdoc-0.3.0/tests/test_shell_utils.py +423 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_utils.py +23 -23
- ripperdoc-0.2.10/ripperdoc/cli/ui/spinner.py +0 -85
- ripperdoc-0.2.10/ripperdoc/sdk/__init__.py +0 -9
- ripperdoc-0.2.10/ripperdoc/sdk/client.py +0 -408
- ripperdoc-0.2.10/tests/test_sdk.py +0 -46
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/LICENSE +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/__main__.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/__init__.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/base.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/clear_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/compact_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/config_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/context_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/cost_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/exit_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/help_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/hooks_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/mcp_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/permissions_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/todos_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/commands/tools_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/__init__.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/context_display.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/message_display.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/provider_options.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/cli/ui/thinking_spinner.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/__init__.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/commands.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/custom_commands.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/hooks/__init__.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/hooks/config.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/hooks/events.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/hooks/executor.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/hooks/integration.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/providers/__init__.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/providers/anthropic.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/providers/base.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/providers/gemini.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/core/system_prompt.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/__init__.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/ask_user_question_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/bash_output_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/dynamic_mcp_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/enter_plan_mode_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/exit_plan_mode_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/glob_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/kill_bash_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/ls_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/mcp_tools.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/notebook_edit_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/todo_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/tools/tool_search_tool.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/__init__.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/bash_constants.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/bash_output_utils.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/coerce.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/context_length_errors.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/conversation_compaction.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/exit_code_handlers.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/git_utils.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/json_utils.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/memory.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/message_compaction.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/output_utils.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/path_ignore.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/path_utils.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/permissions/__init__.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/permissions/path_validation_utils.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/prompt.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/safe_get_cwd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/sandbox_utils.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/session_usage.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/shell_token_utils.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc/utils/token_estimation.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc.egg-info/dependency_links.txt +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc.egg-info/entry_points.txt +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/ripperdoc.egg-info/top_level.txt +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/setup.cfg +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/setup.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_background_shell_shutdown.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_compact.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_config.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_context_length_errors.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_context_limits.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_custom_commands.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_hooks_cmd.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_mcp_config.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_messages.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_output_utils.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_path_ignore.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_query_abort.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_skills.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_todo.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_tool_search.py +0 -0
- {ripperdoc-0.2.10 → ripperdoc-0.3.0}/tests/test_tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ripperdoc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: AI-powered terminal assistant for coding tasks
|
|
5
5
|
Author: Ripperdoc Team
|
|
6
6
|
License: Apache-2.0
|
|
@@ -23,10 +23,11 @@ Requires-Dist: python-dotenv>=1.0.0
|
|
|
23
23
|
Requires-Dist: aiofiles>=23.0.0
|
|
24
24
|
Requires-Dist: prompt-toolkit>=3.0.0
|
|
25
25
|
Requires-Dist: PyYAML>=6.0.0
|
|
26
|
-
Requires-Dist: mcp[cli]>=1.
|
|
26
|
+
Requires-Dist: mcp[cli]>=1.25.0
|
|
27
27
|
Requires-Dist: json_repair>=0.54.2
|
|
28
28
|
Requires-Dist: tiktoken>=0.7.0
|
|
29
29
|
Requires-Dist: google-genai>=0.3.0
|
|
30
|
+
Requires-Dist: charset-normalizer>=3.0.0
|
|
30
31
|
Provides-Extra: dev
|
|
31
32
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
32
33
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -99,27 +100,22 @@ pip install git+https://github.com/quantmew/ripperdoc.git
|
|
|
99
100
|
Or install from source:
|
|
100
101
|
```bash
|
|
101
102
|
# Clone the repository
|
|
102
|
-
git clone
|
|
103
|
-
cd
|
|
103
|
+
git clone https://github.com/quantmew/ripperdoc.git
|
|
104
|
+
cd ripperdoc
|
|
104
105
|
|
|
105
106
|
# Install from source
|
|
106
107
|
pip install -e .
|
|
107
108
|
```
|
|
108
109
|
|
|
109
|
-
### Configuration
|
|
110
110
|
|
|
111
|
-
Set your API key as an environment variable:
|
|
112
|
-
```bash
|
|
113
|
-
export OPENAI_API_KEY="your-api-key-here"
|
|
114
|
-
# or for Anthropic Claude
|
|
115
|
-
export ANTHROPIC_API_KEY="your-api-key-here"
|
|
116
|
-
```
|
|
117
111
|
|
|
118
112
|
## Usage
|
|
119
113
|
|
|
120
114
|
### Interactive Mode (Recommended)
|
|
121
115
|
```bash
|
|
122
116
|
ripperdoc
|
|
117
|
+
# or use the short alias
|
|
118
|
+
rd
|
|
123
119
|
```
|
|
124
120
|
|
|
125
121
|
This launches an interactive session where you can:
|
|
@@ -128,6 +124,13 @@ This launches an interactive session where you can:
|
|
|
128
124
|
- Execute commands
|
|
129
125
|
- Navigate and explore files
|
|
130
126
|
|
|
127
|
+
**Options:**
|
|
128
|
+
- `--yolo` - Skip permission prompts (safe mode is on by default)
|
|
129
|
+
- `--model <model_name>` - Specify a model (e.g., `claude-sonnet-4-20250514`, `gpt-4o`)
|
|
130
|
+
- `--tools <tool_list>` - Filter available tools (comma-separated, or "" for none)
|
|
131
|
+
- `--no-mcp` - Disable MCP server integration
|
|
132
|
+
- `--verbose` - Enable verbose logging
|
|
133
|
+
|
|
131
134
|
### Python SDK (headless)
|
|
132
135
|
|
|
133
136
|
Use Ripperdoc without the terminal UI via the new Python SDK. See [docs/SDK_USAGE.md](docs/SDK_USAGE.md) for examples of the one-shot `query` helper and the session-based `RipperdocClient`. 中文指南见 [docs/SDK_USAGE_CN.md](docs/SDK_USAGE_CN.md)。
|
|
@@ -143,38 +146,67 @@ See the [examples/](examples/) directory for complete SDK usage examples.
|
|
|
143
146
|
|
|
144
147
|
### Safe Mode Permissions
|
|
145
148
|
|
|
146
|
-
Safe mode is
|
|
149
|
+
Safe mode is enabled by default. When prompted:
|
|
150
|
+
- Type `y` or `yes` to allow a single operation
|
|
151
|
+
- Type `a` or `always` to allow all operations of that type for the session
|
|
152
|
+
- Type `n` or `no` to deny the operation
|
|
153
|
+
|
|
154
|
+
Use `--yolo` flag to skip all permission prompts:
|
|
155
|
+
```bash
|
|
156
|
+
ripperdoc --yolo
|
|
157
|
+
```
|
|
147
158
|
|
|
148
159
|
### Agent Skills
|
|
149
160
|
|
|
150
161
|
Extend Ripperdoc with reusable Skill bundles:
|
|
151
162
|
|
|
152
|
-
- Personal skills
|
|
153
|
-
- Project skills
|
|
154
|
-
- Each `SKILL.md` starts with YAML frontmatter
|
|
155
|
-
-
|
|
156
|
-
-
|
|
163
|
+
- **Personal skills**: `~/.ripperdoc/skills/<skill-name>/SKILL.md`
|
|
164
|
+
- **Project skills**: `.ripperdoc/skills/<skill-name>/SKILL.md` (can be checked into git)
|
|
165
|
+
- Each `SKILL.md` starts with YAML frontmatter:
|
|
166
|
+
- `name` - Skill identifier
|
|
167
|
+
- `description` - What the skill does
|
|
168
|
+
- `allowed-tools` (optional) - Restrict which tools the skill can use
|
|
169
|
+
- `model` (optional) - Suggest a specific model for this skill
|
|
170
|
+
- `max-thinking-tokens` (optional) - Control thinking budget
|
|
171
|
+
- `disable-model-invocation` (optional) - Use skill without calling the model
|
|
172
|
+
- Add supporting files alongside `SKILL.md` as needed
|
|
173
|
+
- Skills are auto-discovered and loaded on demand via the `Skill` tool
|
|
174
|
+
|
|
175
|
+
**Built-in skills:** PDF manipulation (`pdf`), PowerPoint (`pptx`), Excel (`xlsx`)
|
|
157
176
|
|
|
158
177
|
## Examples
|
|
159
178
|
|
|
160
179
|
### Code Analysis
|
|
161
180
|
```
|
|
162
181
|
> Can you explain what this function does?
|
|
182
|
+
> Find all references to the `parse_config` function
|
|
163
183
|
```
|
|
164
184
|
|
|
165
185
|
### File Operations
|
|
166
186
|
```
|
|
167
187
|
> Read the main.py file and suggest improvements
|
|
188
|
+
> Create a new component called UserProfile.tsx
|
|
189
|
+
> Update all imports to use the new package structure
|
|
168
190
|
```
|
|
169
191
|
|
|
170
192
|
### Code Generation
|
|
171
193
|
```
|
|
172
194
|
> Create a new Python script that implements a REST API client
|
|
195
|
+
> Generate unit tests for the auth module
|
|
196
|
+
> Add error handling to the database connection code
|
|
173
197
|
```
|
|
174
198
|
|
|
175
199
|
### Project Navigation
|
|
176
200
|
```
|
|
177
201
|
> Show me all the Python files in the project
|
|
202
|
+
> Find where the user authentication logic is implemented
|
|
203
|
+
> List all API endpoints in the project
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### MCP Integration
|
|
207
|
+
```
|
|
208
|
+
> What MCP servers are available?
|
|
209
|
+
> Query the context7 documentation for React hooks
|
|
178
210
|
```
|
|
179
211
|
|
|
180
212
|
## Development
|
|
@@ -56,27 +56,22 @@ pip install git+https://github.com/quantmew/ripperdoc.git
|
|
|
56
56
|
Or install from source:
|
|
57
57
|
```bash
|
|
58
58
|
# Clone the repository
|
|
59
|
-
git clone
|
|
60
|
-
cd
|
|
59
|
+
git clone https://github.com/quantmew/ripperdoc.git
|
|
60
|
+
cd ripperdoc
|
|
61
61
|
|
|
62
62
|
# Install from source
|
|
63
63
|
pip install -e .
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
### Configuration
|
|
67
66
|
|
|
68
|
-
Set your API key as an environment variable:
|
|
69
|
-
```bash
|
|
70
|
-
export OPENAI_API_KEY="your-api-key-here"
|
|
71
|
-
# or for Anthropic Claude
|
|
72
|
-
export ANTHROPIC_API_KEY="your-api-key-here"
|
|
73
|
-
```
|
|
74
67
|
|
|
75
68
|
## Usage
|
|
76
69
|
|
|
77
70
|
### Interactive Mode (Recommended)
|
|
78
71
|
```bash
|
|
79
72
|
ripperdoc
|
|
73
|
+
# or use the short alias
|
|
74
|
+
rd
|
|
80
75
|
```
|
|
81
76
|
|
|
82
77
|
This launches an interactive session where you can:
|
|
@@ -85,6 +80,13 @@ This launches an interactive session where you can:
|
|
|
85
80
|
- Execute commands
|
|
86
81
|
- Navigate and explore files
|
|
87
82
|
|
|
83
|
+
**Options:**
|
|
84
|
+
- `--yolo` - Skip permission prompts (safe mode is on by default)
|
|
85
|
+
- `--model <model_name>` - Specify a model (e.g., `claude-sonnet-4-20250514`, `gpt-4o`)
|
|
86
|
+
- `--tools <tool_list>` - Filter available tools (comma-separated, or "" for none)
|
|
87
|
+
- `--no-mcp` - Disable MCP server integration
|
|
88
|
+
- `--verbose` - Enable verbose logging
|
|
89
|
+
|
|
88
90
|
### Python SDK (headless)
|
|
89
91
|
|
|
90
92
|
Use Ripperdoc without the terminal UI via the new Python SDK. See [docs/SDK_USAGE.md](docs/SDK_USAGE.md) for examples of the one-shot `query` helper and the session-based `RipperdocClient`. 中文指南见 [docs/SDK_USAGE_CN.md](docs/SDK_USAGE_CN.md)。
|
|
@@ -100,38 +102,67 @@ See the [examples/](examples/) directory for complete SDK usage examples.
|
|
|
100
102
|
|
|
101
103
|
### Safe Mode Permissions
|
|
102
104
|
|
|
103
|
-
Safe mode is
|
|
105
|
+
Safe mode is enabled by default. When prompted:
|
|
106
|
+
- Type `y` or `yes` to allow a single operation
|
|
107
|
+
- Type `a` or `always` to allow all operations of that type for the session
|
|
108
|
+
- Type `n` or `no` to deny the operation
|
|
109
|
+
|
|
110
|
+
Use `--yolo` flag to skip all permission prompts:
|
|
111
|
+
```bash
|
|
112
|
+
ripperdoc --yolo
|
|
113
|
+
```
|
|
104
114
|
|
|
105
115
|
### Agent Skills
|
|
106
116
|
|
|
107
117
|
Extend Ripperdoc with reusable Skill bundles:
|
|
108
118
|
|
|
109
|
-
- Personal skills
|
|
110
|
-
- Project skills
|
|
111
|
-
- Each `SKILL.md` starts with YAML frontmatter
|
|
112
|
-
-
|
|
113
|
-
-
|
|
119
|
+
- **Personal skills**: `~/.ripperdoc/skills/<skill-name>/SKILL.md`
|
|
120
|
+
- **Project skills**: `.ripperdoc/skills/<skill-name>/SKILL.md` (can be checked into git)
|
|
121
|
+
- Each `SKILL.md` starts with YAML frontmatter:
|
|
122
|
+
- `name` - Skill identifier
|
|
123
|
+
- `description` - What the skill does
|
|
124
|
+
- `allowed-tools` (optional) - Restrict which tools the skill can use
|
|
125
|
+
- `model` (optional) - Suggest a specific model for this skill
|
|
126
|
+
- `max-thinking-tokens` (optional) - Control thinking budget
|
|
127
|
+
- `disable-model-invocation` (optional) - Use skill without calling the model
|
|
128
|
+
- Add supporting files alongside `SKILL.md` as needed
|
|
129
|
+
- Skills are auto-discovered and loaded on demand via the `Skill` tool
|
|
130
|
+
|
|
131
|
+
**Built-in skills:** PDF manipulation (`pdf`), PowerPoint (`pptx`), Excel (`xlsx`)
|
|
114
132
|
|
|
115
133
|
## Examples
|
|
116
134
|
|
|
117
135
|
### Code Analysis
|
|
118
136
|
```
|
|
119
137
|
> Can you explain what this function does?
|
|
138
|
+
> Find all references to the `parse_config` function
|
|
120
139
|
```
|
|
121
140
|
|
|
122
141
|
### File Operations
|
|
123
142
|
```
|
|
124
143
|
> Read the main.py file and suggest improvements
|
|
144
|
+
> Create a new component called UserProfile.tsx
|
|
145
|
+
> Update all imports to use the new package structure
|
|
125
146
|
```
|
|
126
147
|
|
|
127
148
|
### Code Generation
|
|
128
149
|
```
|
|
129
150
|
> Create a new Python script that implements a REST API client
|
|
151
|
+
> Generate unit tests for the auth module
|
|
152
|
+
> Add error handling to the database connection code
|
|
130
153
|
```
|
|
131
154
|
|
|
132
155
|
### Project Navigation
|
|
133
156
|
```
|
|
134
157
|
> Show me all the Python files in the project
|
|
158
|
+
> Find where the user authentication logic is implemented
|
|
159
|
+
> List all API endpoints in the project
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### MCP Integration
|
|
163
|
+
```
|
|
164
|
+
> What MCP servers are available?
|
|
165
|
+
> Query the context7 documentation for React hooks
|
|
135
166
|
```
|
|
136
167
|
|
|
137
168
|
## Development
|
|
@@ -32,10 +32,11 @@ dependencies = [
|
|
|
32
32
|
"aiofiles>=23.0.0",
|
|
33
33
|
"prompt-toolkit>=3.0.0",
|
|
34
34
|
"PyYAML>=6.0.0",
|
|
35
|
-
"mcp[cli]>=1.
|
|
35
|
+
"mcp[cli]>=1.25.0", # Fixed stdio_client async generator cleanup issue
|
|
36
36
|
"json_repair>=0.54.2",
|
|
37
37
|
"tiktoken>=0.7.0",
|
|
38
38
|
"google-genai>=0.3.0",
|
|
39
|
+
"charset-normalizer>=3.0.0",
|
|
39
40
|
]
|
|
40
41
|
|
|
41
42
|
[project.optional-dependencies]
|
|
@@ -44,7 +44,6 @@ from ripperdoc.utils.log import enable_session_file_logging, get_logger
|
|
|
44
44
|
|
|
45
45
|
from rich.console import Console
|
|
46
46
|
from rich.markdown import Markdown
|
|
47
|
-
from rich.panel import Panel
|
|
48
47
|
from rich.markup import escape
|
|
49
48
|
|
|
50
49
|
console = Console()
|
|
@@ -98,7 +97,6 @@ async def run_query(
|
|
|
98
97
|
model: Optional[str] = None,
|
|
99
98
|
) -> None:
|
|
100
99
|
"""Run a single query and print the response."""
|
|
101
|
-
|
|
102
100
|
logger.info(
|
|
103
101
|
"[cli] Running single prompt session",
|
|
104
102
|
extra={
|
|
@@ -212,55 +210,37 @@ async def run_query(
|
|
|
212
210
|
mcp_instructions=mcp_instructions,
|
|
213
211
|
)
|
|
214
212
|
|
|
215
|
-
# Run the query
|
|
213
|
+
# Run the query - collect final response text
|
|
214
|
+
final_response_parts: List[str] = []
|
|
216
215
|
try:
|
|
217
216
|
async for message in query(
|
|
218
217
|
messages, system_prompt, context, query_context, can_use_tool
|
|
219
218
|
):
|
|
220
219
|
if message.type == "assistant" and hasattr(message, "message"):
|
|
221
|
-
#
|
|
220
|
+
# Collect assistant message text for final output
|
|
222
221
|
if isinstance(message.message.content, str):
|
|
223
|
-
|
|
224
|
-
Panel(
|
|
225
|
-
Markdown(message.message.content),
|
|
226
|
-
title="Ripperdoc",
|
|
227
|
-
border_style="cyan",
|
|
228
|
-
padding=(0, 1),
|
|
229
|
-
)
|
|
230
|
-
)
|
|
222
|
+
final_response_parts.append(message.message.content)
|
|
231
223
|
else:
|
|
232
224
|
# Handle structured content
|
|
233
225
|
for block in message.message.content:
|
|
234
226
|
if isinstance(block, dict):
|
|
235
227
|
if block.get("type") == "text":
|
|
236
|
-
|
|
237
|
-
Panel(
|
|
238
|
-
Markdown(block["text"]),
|
|
239
|
-
title="Ripperdoc",
|
|
240
|
-
border_style="cyan",
|
|
241
|
-
padding=(0, 1),
|
|
242
|
-
)
|
|
243
|
-
)
|
|
228
|
+
final_response_parts.append(block["text"])
|
|
244
229
|
else:
|
|
245
230
|
if hasattr(block, "type") and block.type == "text":
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
title="Ripperdoc",
|
|
250
|
-
border_style="cyan",
|
|
251
|
-
padding=(0, 1),
|
|
252
|
-
)
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
elif message.type == "progress" and hasattr(message, "content"):
|
|
256
|
-
# Print progress
|
|
257
|
-
if verbose:
|
|
258
|
-
console.print(f"[dim]Progress: {escape(str(message.content))}[/dim]")
|
|
231
|
+
final_response_parts.append(block.text or "")
|
|
232
|
+
|
|
233
|
+
# Skip progress messages entirely for -p mode
|
|
259
234
|
|
|
260
235
|
# Add message to history
|
|
261
236
|
messages.append(message) # type: ignore[arg-type]
|
|
262
237
|
session_history.append(message) # type: ignore[arg-type]
|
|
263
238
|
|
|
239
|
+
# Print final response as clean markdown (no panel, no decoration)
|
|
240
|
+
if final_response_parts:
|
|
241
|
+
final_text = "\n".join(final_response_parts)
|
|
242
|
+
console.print(Markdown(final_text))
|
|
243
|
+
|
|
264
244
|
except KeyboardInterrupt:
|
|
265
245
|
console.print("\n[yellow]Interrupted by user[/yellow]")
|
|
266
246
|
except asyncio.CancelledError:
|
|
@@ -308,7 +288,6 @@ async def run_query(
|
|
|
308
288
|
logger.debug("[cli] Shutdown MCP runtime", extra={"session_id": session_id})
|
|
309
289
|
|
|
310
290
|
|
|
311
|
-
|
|
312
291
|
@click.group(invoke_without_command=True)
|
|
313
292
|
@click.version_option(version=__version__)
|
|
314
293
|
@click.option("--cwd", type=click.Path(exists=True), help="Working directory")
|
|
@@ -374,19 +353,51 @@ def cli(
|
|
|
374
353
|
) -> None:
|
|
375
354
|
"""Ripperdoc - AI-powered coding agent"""
|
|
376
355
|
session_id = str(uuid.uuid4())
|
|
356
|
+
cwd_changed: Optional[str] = None
|
|
377
357
|
|
|
378
358
|
# Set working directory
|
|
379
359
|
if cwd:
|
|
380
360
|
import os
|
|
381
361
|
|
|
382
362
|
os.chdir(cwd)
|
|
363
|
+
cwd_changed = cwd
|
|
364
|
+
|
|
365
|
+
project_path = Path.cwd()
|
|
366
|
+
|
|
367
|
+
# Handle --continue option: load the most recent session
|
|
368
|
+
resume_messages = None
|
|
369
|
+
most_recent = None
|
|
370
|
+
if continue_session:
|
|
371
|
+
summaries = list_session_summaries(project_path)
|
|
372
|
+
if summaries:
|
|
373
|
+
most_recent = summaries[0]
|
|
374
|
+
session_id = most_recent.session_id
|
|
375
|
+
resume_messages = load_session_messages(project_path, session_id)
|
|
376
|
+
console.print(f"[dim]Continuing session: {most_recent.last_prompt}[/dim]")
|
|
377
|
+
else:
|
|
378
|
+
console.print("[yellow]No previous sessions found in this directory.[/yellow]")
|
|
379
|
+
|
|
380
|
+
log_file = enable_session_file_logging(project_path, session_id)
|
|
381
|
+
|
|
382
|
+
if cwd_changed:
|
|
383
383
|
logger.debug(
|
|
384
384
|
"[cli] Changed working directory via --cwd",
|
|
385
|
-
extra={"cwd":
|
|
385
|
+
extra={"cwd": cwd_changed, "session_id": session_id},
|
|
386
386
|
)
|
|
387
387
|
|
|
388
|
-
|
|
389
|
-
|
|
388
|
+
if most_recent:
|
|
389
|
+
logger.info(
|
|
390
|
+
"[cli] Continuing session",
|
|
391
|
+
extra={
|
|
392
|
+
"session_id": session_id,
|
|
393
|
+
"message_count": len(resume_messages) if resume_messages else 0,
|
|
394
|
+
"last_prompt": most_recent.last_prompt,
|
|
395
|
+
"log_file": str(log_file),
|
|
396
|
+
},
|
|
397
|
+
)
|
|
398
|
+
elif continue_session:
|
|
399
|
+
logger.warning("[cli] No previous sessions found to continue")
|
|
400
|
+
|
|
390
401
|
logger.info(
|
|
391
402
|
"[cli] Starting CLI invocation",
|
|
392
403
|
extra={
|
|
@@ -412,26 +423,39 @@ def cli(
|
|
|
412
423
|
# Parse --tools option
|
|
413
424
|
allowed_tools = parse_tools_option(tools)
|
|
414
425
|
|
|
415
|
-
# Handle
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
426
|
+
# Handle piped stdin input
|
|
427
|
+
# - With -p flag: Not applicable (prompt comes from -p argument)
|
|
428
|
+
# - Without -p: stdin becomes the initial query in interactive mode
|
|
429
|
+
initial_query: Optional[str] = None
|
|
430
|
+
if prompt is None and ctx.invoked_subcommand is None:
|
|
431
|
+
stdin_stream = click.get_text_stream("stdin")
|
|
432
|
+
try:
|
|
433
|
+
stdin_is_tty = stdin_stream.isatty()
|
|
434
|
+
except Exception:
|
|
435
|
+
stdin_is_tty = True
|
|
436
|
+
|
|
437
|
+
if not stdin_is_tty:
|
|
438
|
+
try:
|
|
439
|
+
stdin_data = stdin_stream.read()
|
|
440
|
+
except (OSError, ValueError) as exc:
|
|
441
|
+
logger.warning(
|
|
442
|
+
"[cli] Failed to read stdin for initial query: %s: %s",
|
|
443
|
+
type(exc).__name__,
|
|
444
|
+
exc,
|
|
445
|
+
extra={"session_id": session_id},
|
|
446
|
+
)
|
|
447
|
+
else:
|
|
448
|
+
trimmed = stdin_data.rstrip("\n")
|
|
449
|
+
if trimmed.strip():
|
|
450
|
+
initial_query = trimmed
|
|
451
|
+
logger.info(
|
|
452
|
+
"[cli] Received initial query from stdin",
|
|
453
|
+
extra={
|
|
454
|
+
"session_id": session_id,
|
|
455
|
+
"query_length": len(initial_query),
|
|
456
|
+
"query_preview": initial_query[:200],
|
|
457
|
+
},
|
|
458
|
+
)
|
|
435
459
|
|
|
436
460
|
logger.debug(
|
|
437
461
|
"[cli] Configuration initialized",
|
|
@@ -480,6 +504,7 @@ def cli(
|
|
|
480
504
|
append_system_prompt=append_system_prompt,
|
|
481
505
|
model=model,
|
|
482
506
|
resume_messages=resume_messages,
|
|
507
|
+
initial_query=initial_query,
|
|
483
508
|
)
|
|
484
509
|
return
|
|
485
510
|
|
|
@@ -507,6 +532,88 @@ def config_cmd() -> None:
|
|
|
507
532
|
console.print()
|
|
508
533
|
|
|
509
534
|
|
|
535
|
+
@cli.command(name="stdio")
|
|
536
|
+
@click.option(
|
|
537
|
+
"--input-format",
|
|
538
|
+
type=click.Choice(["stream-json", "auto"]),
|
|
539
|
+
default="stream-json",
|
|
540
|
+
help="Input format for messages.",
|
|
541
|
+
)
|
|
542
|
+
@click.option(
|
|
543
|
+
"--output-format",
|
|
544
|
+
type=click.Choice(["stream-json"]),
|
|
545
|
+
default="stream-json",
|
|
546
|
+
help="Output format for messages.",
|
|
547
|
+
)
|
|
548
|
+
@click.option(
|
|
549
|
+
"--model",
|
|
550
|
+
type=str,
|
|
551
|
+
default=None,
|
|
552
|
+
help="Model profile for the current session.",
|
|
553
|
+
)
|
|
554
|
+
@click.option(
|
|
555
|
+
"--permission-mode",
|
|
556
|
+
type=click.Choice(["default", "acceptEdits", "plan", "bypassPermissions"]),
|
|
557
|
+
default="default",
|
|
558
|
+
help="Permission mode for tool usage.",
|
|
559
|
+
)
|
|
560
|
+
@click.option(
|
|
561
|
+
"--max-turns",
|
|
562
|
+
type=int,
|
|
563
|
+
default=None,
|
|
564
|
+
help="Maximum number of conversation turns.",
|
|
565
|
+
)
|
|
566
|
+
@click.option(
|
|
567
|
+
"--system-prompt",
|
|
568
|
+
type=str,
|
|
569
|
+
default=None,
|
|
570
|
+
help="System prompt to use for the session.",
|
|
571
|
+
)
|
|
572
|
+
@click.option(
|
|
573
|
+
"--print",
|
|
574
|
+
"-p",
|
|
575
|
+
is_flag=True,
|
|
576
|
+
help="Print mode (for single prompt queries).",
|
|
577
|
+
)
|
|
578
|
+
@click.option(
|
|
579
|
+
"--",
|
|
580
|
+
"prompt",
|
|
581
|
+
type=str,
|
|
582
|
+
default=None,
|
|
583
|
+
help="Direct prompt (for print mode).",
|
|
584
|
+
)
|
|
585
|
+
def stdio_cmd(
|
|
586
|
+
input_format: str,
|
|
587
|
+
output_format: str,
|
|
588
|
+
model: str | None,
|
|
589
|
+
permission_mode: str,
|
|
590
|
+
max_turns: int | None,
|
|
591
|
+
system_prompt: str | None,
|
|
592
|
+
print: bool,
|
|
593
|
+
prompt: str | None,
|
|
594
|
+
) -> None:
|
|
595
|
+
"""Stdio mode for SDK subprocess communication.
|
|
596
|
+
|
|
597
|
+
This command enables Ripperdoc to communicate with SDKs via JSON Control
|
|
598
|
+
Protocol over stdin/stdout.
|
|
599
|
+
"""
|
|
600
|
+
from ripperdoc.protocol.stdio import _run_stdio
|
|
601
|
+
import asyncio
|
|
602
|
+
|
|
603
|
+
asyncio.run(
|
|
604
|
+
_run_stdio(
|
|
605
|
+
input_format=input_format,
|
|
606
|
+
output_format=output_format,
|
|
607
|
+
model=model,
|
|
608
|
+
permission_mode=permission_mode,
|
|
609
|
+
max_turns=max_turns,
|
|
610
|
+
system_prompt=system_prompt,
|
|
611
|
+
print_mode=print,
|
|
612
|
+
prompt=prompt,
|
|
613
|
+
)
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
|
|
510
617
|
@cli.command(name="version")
|
|
511
618
|
def version_cmd() -> None:
|
|
512
619
|
"""Show version information"""
|
|
@@ -21,9 +21,11 @@ from .mcp_cmd import command as mcp_command
|
|
|
21
21
|
from .models_cmd import command as models_command
|
|
22
22
|
from .permissions_cmd import command as permissions_command
|
|
23
23
|
from .resume_cmd import command as resume_command
|
|
24
|
+
from .skills_cmd import command as skills_command
|
|
24
25
|
from .stats_cmd import command as stats_command
|
|
25
26
|
from .tasks_cmd import command as tasks_command
|
|
26
27
|
from .status_cmd import command as status_command
|
|
28
|
+
from .themes_cmd import command as themes_command
|
|
27
29
|
from .todos_cmd import command as todos_command
|
|
28
30
|
from .tools_cmd import command as tools_command
|
|
29
31
|
|
|
@@ -64,7 +66,9 @@ ALL_COMMANDS: List[SlashCommand] = [
|
|
|
64
66
|
context_command,
|
|
65
67
|
compact_command,
|
|
66
68
|
resume_command,
|
|
69
|
+
skills_command,
|
|
67
70
|
agents_command,
|
|
71
|
+
themes_command,
|
|
68
72
|
]
|
|
69
73
|
|
|
70
74
|
COMMAND_REGISTRY: Dict[str, SlashCommand] = _build_registry(ALL_COMMANDS)
|
|
@@ -18,7 +18,7 @@ from ripperdoc.tools.task_tool import (
|
|
|
18
18
|
)
|
|
19
19
|
from ripperdoc.utils.log import get_logger
|
|
20
20
|
|
|
21
|
-
from typing import Any, Dict
|
|
21
|
+
from typing import Any, Dict
|
|
22
22
|
from .base import SlashCommand
|
|
23
23
|
|
|
24
24
|
logger = get_logger()
|
|
@@ -101,9 +101,7 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
101
101
|
for run_id in sorted(run_ids):
|
|
102
102
|
snapshot: Dict[Any, Any] = get_agent_run_snapshot(run_id) or {}
|
|
103
103
|
result_text = snapshot.get("result_text") or snapshot.get("error") or ""
|
|
104
|
-
result_preview = (
|
|
105
|
-
result_text if len(result_text) <= 80 else result_text[:77] + "..."
|
|
106
|
-
)
|
|
104
|
+
result_preview = result_text if len(result_text) <= 80 else result_text[:77] + "..."
|
|
107
105
|
table.add_row(
|
|
108
106
|
escape(run_id),
|
|
109
107
|
escape(snapshot.get("status") or "unknown"),
|
|
@@ -136,9 +134,7 @@ def _handle(ui: Any, trimmed_arg: str) -> bool:
|
|
|
136
134
|
details.add_row("Status", escape(snapshot.get("status") or "unknown"))
|
|
137
135
|
details.add_row("Agent", escape(snapshot.get("agent_type") or "unknown"))
|
|
138
136
|
details.add_row("Duration", _format_duration(snapshot.get("duration_ms")))
|
|
139
|
-
details.add_row(
|
|
140
|
-
"Background", "yes" if snapshot.get("is_background") else "no"
|
|
141
|
-
)
|
|
137
|
+
details.add_row("Background", "yes" if snapshot.get("is_background") else "no")
|
|
142
138
|
if snapshot.get("model_used"):
|
|
143
139
|
details.add_row("Model", escape(str(snapshot.get("model_used"))))
|
|
144
140
|
if snapshot.get("tool_use_count"):
|