ripperdoc 0.2.7__py3-none-any.whl → 0.2.8__py3-none-any.whl
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/__init__.py +1 -1
- ripperdoc/cli/cli.py +5 -0
- ripperdoc/cli/commands/__init__.py +71 -6
- ripperdoc/cli/commands/help_cmd.py +11 -1
- ripperdoc/cli/commands/hooks_cmd.py +636 -0
- ripperdoc/cli/commands/permissions_cmd.py +36 -34
- ripperdoc/cli/commands/resume_cmd.py +1 -1
- ripperdoc/cli/ui/file_mention_completer.py +62 -7
- ripperdoc/cli/ui/interrupt_handler.py +1 -1
- ripperdoc/cli/ui/message_display.py +1 -1
- ripperdoc/cli/ui/panels.py +13 -10
- ripperdoc/cli/ui/rich_ui.py +92 -24
- ripperdoc/core/custom_commands.py +411 -0
- ripperdoc/core/hooks/__init__.py +99 -0
- ripperdoc/core/hooks/config.py +303 -0
- ripperdoc/core/hooks/events.py +540 -0
- ripperdoc/core/hooks/executor.py +498 -0
- ripperdoc/core/hooks/integration.py +353 -0
- ripperdoc/core/hooks/manager.py +720 -0
- ripperdoc/core/providers/anthropic.py +476 -69
- ripperdoc/core/query.py +61 -4
- ripperdoc/tools/bash_tool.py +4 -4
- ripperdoc/tools/file_read_tool.py +1 -1
- ripperdoc/utils/conversation_compaction.py +3 -3
- ripperdoc/utils/path_ignore.py +3 -4
- {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.8.dist-info}/METADATA +24 -3
- {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.8.dist-info}/RECORD +31 -23
- {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.8.dist-info}/WHEEL +0 -0
- {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.8.dist-info}/entry_points.txt +0 -0
- {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.8.dist-info}/licenses/LICENSE +0 -0
- {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.8.dist-info}/top_level.txt +0 -0
ripperdoc/core/query.py
CHANGED
|
@@ -29,6 +29,7 @@ from pydantic import ValidationError
|
|
|
29
29
|
from ripperdoc.core.config import provider_protocol
|
|
30
30
|
from ripperdoc.core.providers import ProviderClient, get_provider_client
|
|
31
31
|
from ripperdoc.core.permissions import PermissionResult
|
|
32
|
+
from ripperdoc.core.hooks.manager import hook_manager
|
|
32
33
|
from ripperdoc.core.query_utils import (
|
|
33
34
|
build_full_system_prompt,
|
|
34
35
|
determine_tool_mode,
|
|
@@ -154,6 +155,52 @@ async def _run_tool_use_generator(
|
|
|
154
155
|
tool_context: ToolUseContext,
|
|
155
156
|
) -> AsyncGenerator[Union[UserMessage, ProgressMessage], None]:
|
|
156
157
|
"""Execute a single tool_use and yield progress/results."""
|
|
158
|
+
# Get tool input as dict for hooks
|
|
159
|
+
tool_input_dict = (
|
|
160
|
+
parsed_input.model_dump()
|
|
161
|
+
if hasattr(parsed_input, "model_dump")
|
|
162
|
+
else dict(parsed_input) if isinstance(parsed_input, dict) else {}
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Run PreToolUse hooks
|
|
166
|
+
pre_result = await hook_manager.run_pre_tool_use_async(
|
|
167
|
+
tool_name, tool_input_dict, tool_use_id=tool_use_id
|
|
168
|
+
)
|
|
169
|
+
if pre_result.should_block:
|
|
170
|
+
block_reason = pre_result.block_reason or f"Blocked by hook: {tool_name}"
|
|
171
|
+
logger.info(
|
|
172
|
+
f"[query] Tool {tool_name} blocked by PreToolUse hook",
|
|
173
|
+
extra={"tool_use_id": tool_use_id, "reason": block_reason},
|
|
174
|
+
)
|
|
175
|
+
yield tool_result_message(tool_use_id, f"Hook blocked: {block_reason}", is_error=True)
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
# Handle updated input from hooks
|
|
179
|
+
if pre_result.updated_input:
|
|
180
|
+
logger.debug(
|
|
181
|
+
f"[query] PreToolUse hook modified input for {tool_name}",
|
|
182
|
+
extra={"tool_use_id": tool_use_id},
|
|
183
|
+
)
|
|
184
|
+
# Re-parse the input with the updated values
|
|
185
|
+
try:
|
|
186
|
+
parsed_input = tool.input_schema(**pre_result.updated_input)
|
|
187
|
+
tool_input_dict = pre_result.updated_input
|
|
188
|
+
except (ValueError, TypeError) as exc:
|
|
189
|
+
logger.warning(
|
|
190
|
+
f"[query] Failed to apply updated input from hook: {exc}",
|
|
191
|
+
extra={"tool_use_id": tool_use_id},
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Add hook context if provided
|
|
195
|
+
if pre_result.additional_context:
|
|
196
|
+
logger.debug(
|
|
197
|
+
f"[query] PreToolUse hook added context for {tool_name}",
|
|
198
|
+
extra={"context": pre_result.additional_context[:100]},
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
tool_output = None
|
|
202
|
+
tool_error = None
|
|
203
|
+
|
|
157
204
|
try:
|
|
158
205
|
async for output in tool.call(parsed_input, tool_context):
|
|
159
206
|
if isinstance(output, ToolProgress):
|
|
@@ -164,6 +211,7 @@ async def _run_tool_use_generator(
|
|
|
164
211
|
)
|
|
165
212
|
logger.debug(f"[query] Progress from tool_use_id={tool_use_id}: {output.content}")
|
|
166
213
|
elif isinstance(output, ToolResult):
|
|
214
|
+
tool_output = output.data
|
|
167
215
|
result_content = output.result_for_assistant or str(output.data)
|
|
168
216
|
result_msg = tool_result_message(
|
|
169
217
|
tool_use_id, result_content, tool_use_result=output.data
|
|
@@ -176,6 +224,7 @@ async def _run_tool_use_generator(
|
|
|
176
224
|
except CancelledError:
|
|
177
225
|
raise # Don't suppress task cancellation
|
|
178
226
|
except (RuntimeError, ValueError, TypeError, OSError, IOError, AttributeError, KeyError) as exc:
|
|
227
|
+
tool_error = str(exc)
|
|
179
228
|
logger.warning(
|
|
180
229
|
"Error executing tool '%s': %s: %s",
|
|
181
230
|
tool_name, type(exc).__name__, exc,
|
|
@@ -183,6 +232,11 @@ async def _run_tool_use_generator(
|
|
|
183
232
|
)
|
|
184
233
|
yield tool_result_message(tool_use_id, f"Error executing tool: {str(exc)}", is_error=True)
|
|
185
234
|
|
|
235
|
+
# Run PostToolUse hooks
|
|
236
|
+
await hook_manager.run_post_tool_use_async(
|
|
237
|
+
tool_name, tool_input_dict, tool_response=tool_output, tool_use_id=tool_use_id
|
|
238
|
+
)
|
|
239
|
+
|
|
186
240
|
|
|
187
241
|
def _group_tool_calls_by_concurrency(prepared_calls: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
188
242
|
"""Group consecutive tool calls by their concurrency safety."""
|
|
@@ -624,12 +678,12 @@ async def query_llm(
|
|
|
624
678
|
)
|
|
625
679
|
duration_ms = (time.time() - start_time) * 1000
|
|
626
680
|
context_error = detect_context_length_error(e)
|
|
627
|
-
|
|
681
|
+
error_metadata: Optional[Dict[str, Any]] = None
|
|
628
682
|
content = f"Error querying AI model: {str(e)}"
|
|
629
683
|
|
|
630
684
|
if context_error:
|
|
631
685
|
content = f"The request exceeded the model's context window. {context_error.message}"
|
|
632
|
-
|
|
686
|
+
error_metadata = {
|
|
633
687
|
"context_length_exceeded": True,
|
|
634
688
|
"context_length_provider": context_error.provider,
|
|
635
689
|
"context_length_error_code": context_error.error_code,
|
|
@@ -645,7 +699,7 @@ async def query_llm(
|
|
|
645
699
|
)
|
|
646
700
|
|
|
647
701
|
error_msg = create_assistant_message(
|
|
648
|
-
content=content, duration_ms=duration_ms, metadata=
|
|
702
|
+
content=content, duration_ms=duration_ms, metadata=error_metadata
|
|
649
703
|
)
|
|
650
704
|
error_msg.is_api_error_message = True
|
|
651
705
|
return error_msg
|
|
@@ -1042,7 +1096,10 @@ async def query(
|
|
|
1042
1096
|
return
|
|
1043
1097
|
|
|
1044
1098
|
# Update messages for next iteration
|
|
1045
|
-
|
|
1099
|
+
if result.assistant_message is not None:
|
|
1100
|
+
messages = messages + [result.assistant_message] + result.tool_results # type: ignore[operator]
|
|
1101
|
+
else:
|
|
1102
|
+
messages = messages + result.tool_results # type: ignore[operator]
|
|
1046
1103
|
logger.debug(
|
|
1047
1104
|
f"[query] Continuing loop with {len(messages)} messages after tools; "
|
|
1048
1105
|
f"tool_results_count={len(result.tool_results)}"
|
ripperdoc/tools/bash_tool.py
CHANGED
|
@@ -652,7 +652,7 @@ build projects, run tests, and interact with the file system."""
|
|
|
652
652
|
# Emit progress updates for newly received output chunks
|
|
653
653
|
while not queue.empty():
|
|
654
654
|
label, text = queue.get_nowait()
|
|
655
|
-
yield ToolProgress(content=f"{label}: {text}")
|
|
655
|
+
yield ToolProgress(content=f"{label}: {text}") # type: ignore[misc]
|
|
656
656
|
|
|
657
657
|
# Report progress at intervals
|
|
658
658
|
if now - last_progress_time >= PROGRESS_INTERVAL_SECONDS:
|
|
@@ -660,7 +660,7 @@ build projects, run tests, and interact with the file system."""
|
|
|
660
660
|
if combined_output:
|
|
661
661
|
preview = get_last_n_lines(combined_output, 5)
|
|
662
662
|
elapsed = format_duration((now - start_time) * 1000)
|
|
663
|
-
yield ToolProgress(content=f"Running... ({elapsed})\n{preview}")
|
|
663
|
+
yield ToolProgress(content=f"Running... ({elapsed})\n{preview}") # type: ignore[misc]
|
|
664
664
|
last_progress_time = now
|
|
665
665
|
|
|
666
666
|
# Check timeout
|
|
@@ -907,14 +907,14 @@ build projects, run tests, and interact with the file system."""
|
|
|
907
907
|
|
|
908
908
|
while not queue.empty():
|
|
909
909
|
label, text = queue.get_nowait()
|
|
910
|
-
yield ToolProgress(content=f"{label}: {text}")
|
|
910
|
+
yield ToolProgress(content=f"{label}: {text}") # type: ignore[misc]
|
|
911
911
|
|
|
912
912
|
if now - last_progress_time >= PROGRESS_INTERVAL_SECONDS:
|
|
913
913
|
combined_output = "".join(stdout_lines + stderr_lines)
|
|
914
914
|
if combined_output:
|
|
915
915
|
preview = get_last_n_lines(combined_output, 5)
|
|
916
916
|
elapsed = format_duration((now - start) * 1000)
|
|
917
|
-
yield ToolProgress(content=f"Running... ({elapsed})\n{preview}")
|
|
917
|
+
yield ToolProgress(content=f"Running... ({elapsed})\n{preview}") # type: ignore[misc]
|
|
918
918
|
last_progress_time = now
|
|
919
919
|
|
|
920
920
|
if deadline is not None and now >= deadline:
|
|
@@ -18,7 +18,7 @@ from ripperdoc.core.tool import (
|
|
|
18
18
|
)
|
|
19
19
|
from ripperdoc.utils.log import get_logger
|
|
20
20
|
from ripperdoc.utils.file_watch import record_snapshot
|
|
21
|
-
from ripperdoc.utils.path_ignore import check_path_for_tool
|
|
21
|
+
from ripperdoc.utils.path_ignore import check_path_for_tool
|
|
22
22
|
|
|
23
23
|
logger = get_logger()
|
|
24
24
|
|
|
@@ -325,7 +325,7 @@ async def summarize_conversation(
|
|
|
325
325
|
user_content = f"{user_prompt}\n\nHere is the conversation to summarize:\n\n{transcript}"
|
|
326
326
|
|
|
327
327
|
assistant_response = await query_llm(
|
|
328
|
-
messages=[
|
|
328
|
+
messages=[create_user_message(user_content)],
|
|
329
329
|
system_prompt=system_prompt,
|
|
330
330
|
tools=[],
|
|
331
331
|
max_thinking_tokens=0,
|
|
@@ -346,7 +346,7 @@ async def compact_conversation(
|
|
|
346
346
|
protocol: str = "anthropic",
|
|
347
347
|
tail_count: int = RECENT_MESSAGES_AFTER_COMPACT,
|
|
348
348
|
attachment_provider: Optional[Callable[[], List[ConversationMessage]]] = None,
|
|
349
|
-
) -> Union[CompactionResult, CompactionError]:
|
|
349
|
+
) -> Union["CompactionResult", "CompactionError"]:
|
|
350
350
|
"""Compact a conversation by summarizing and rebuilding.
|
|
351
351
|
|
|
352
352
|
This is a pure logic function with no UI dependencies.
|
|
@@ -462,7 +462,7 @@ class ConversationCompactor:
|
|
|
462
462
|
custom_instructions: str,
|
|
463
463
|
protocol: str = "anthropic",
|
|
464
464
|
tail_count: int = RECENT_MESSAGES_AFTER_COMPACT,
|
|
465
|
-
) -> Optional[CompactionResult]:
|
|
465
|
+
) -> Optional["CompactionResult"]: # type: ignore[valid-type]
|
|
466
466
|
"""Compact the conversation. Returns None on error."""
|
|
467
467
|
result = await compact_conversation(
|
|
468
468
|
messages=messages,
|
ripperdoc/utils/path_ignore.py
CHANGED
|
@@ -11,8 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
|
|
12
12
|
import re
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
from typing import Dict, List, Optional, Set, Tuple
|
|
15
|
-
from functools import lru_cache
|
|
14
|
+
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
16
15
|
|
|
17
16
|
from ripperdoc.utils.git_utils import (
|
|
18
17
|
get_git_root,
|
|
@@ -361,7 +360,7 @@ class IgnoreFilter:
|
|
|
361
360
|
|
|
362
361
|
return result
|
|
363
362
|
|
|
364
|
-
def test(self, path: str) -> Dict[str,
|
|
363
|
+
def test(self, path: str) -> Dict[str, Any]:
|
|
365
364
|
"""Check if a path should be ignored and return details.
|
|
366
365
|
|
|
367
366
|
Returns:
|
|
@@ -369,7 +368,7 @@ class IgnoreFilter:
|
|
|
369
368
|
"""
|
|
370
369
|
path = path.replace("\\", "/").strip("/")
|
|
371
370
|
|
|
372
|
-
result = {"ignored": False, "rule": None}
|
|
371
|
+
result: Dict[str, Any] = {"ignored": False, "rule": None}
|
|
373
372
|
|
|
374
373
|
for pattern, is_negation in self._patterns:
|
|
375
374
|
if pattern.search(path):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ripperdoc
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: AI-powered terminal assistant for coding tasks
|
|
5
5
|
Author: Ripperdoc Team
|
|
6
6
|
License: Apache-2.0
|
|
@@ -35,9 +35,28 @@ Requires-Dist: black>=23.0.0; extra == "dev"
|
|
|
35
35
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
36
36
|
Dynamic: license-file
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
<div align="center">
|
|
39
39
|
|
|
40
|
-
Ripperdoc
|
|
40
|
+
# Ripperdoc
|
|
41
|
+
|
|
42
|
+
_an open-source, extensible AI coding agent that runs in your terminal_
|
|
43
|
+
|
|
44
|
+
<p align="center">
|
|
45
|
+
<a href="https://opensource.org/licenses/Apache-2.0">
|
|
46
|
+
<img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg">
|
|
47
|
+
</a>
|
|
48
|
+
<a href="https://www.python.org/downloads/">
|
|
49
|
+
<img src="https://img.shields.io/badge/python-3.10+-blue.svg">
|
|
50
|
+
</a>
|
|
51
|
+
<a href="https://github.com/quantmew/ripperdoc/stargazers">
|
|
52
|
+
<img src="https://img.shields.io/github/stars/quantmew/ripperdoc.svg" alt="GitHub stars">
|
|
53
|
+
</a>
|
|
54
|
+
</p>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
Ripperdoc is your on-machine AI coding assistant, similar to [Claude Code](https://claude.com/claude-code), [Codex](https://github.com/openai/codex), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Aider](https://github.com/paul-gauthier/aider), and [Goose](https://github.com/block/goose). It can write code, refactor projects, execute shell commands, and manage files - all through natural language conversations in your terminal.
|
|
58
|
+
|
|
59
|
+
Designed for maximum flexibility, Ripperdoc works with **any LLM** (Anthropic Claude, OpenAI, DeepSeek, local models via OpenAI-compatible APIs), supports **custom hooks** to intercept and control tool execution, and offers both an interactive CLI and a **Python SDK** for headless automation.
|
|
41
60
|
|
|
42
61
|
[中文文档](README_CN.md) | [Contributing](CONTRIBUTING.md) | [Documentation](docs/)
|
|
43
62
|
|
|
@@ -60,6 +79,8 @@ Ripperdoc is an AI-powered terminal assistant for coding tasks, providing an int
|
|
|
60
79
|
- **MCP Server Support** - Integration with Model Context Protocol servers
|
|
61
80
|
- **Session Management** - Persistent session history and usage tracking
|
|
62
81
|
- **Jupyter Notebook Support** - Edit .ipynb files directly
|
|
82
|
+
- **Hooks System** - Execute custom scripts at lifecycle events with decision control
|
|
83
|
+
- **Custom Commands** - Define reusable slash commands with parameter substitution
|
|
63
84
|
|
|
64
85
|
## Installation
|
|
65
86
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
ripperdoc/__init__.py,sha256=
|
|
1
|
+
ripperdoc/__init__.py,sha256=lrY1tU8qp_EIUO-H5GAvKzGaBf8Z5xcFbY1i2_NBgjE,66
|
|
2
2
|
ripperdoc/__main__.py,sha256=1Avq2MceBfwUlNsfasC8n4dqVL_V56Bl3DRsnY4_Nxk,370
|
|
3
3
|
ripperdoc/cli/__init__.py,sha256=03wf6gXBcEgXJrDJS-W_5BEG_DdJ_ep7CxQFPML-73g,35
|
|
4
|
-
ripperdoc/cli/cli.py,sha256=
|
|
5
|
-
ripperdoc/cli/commands/__init__.py,sha256=
|
|
4
|
+
ripperdoc/cli/cli.py,sha256=5H_kIa-kPVyF_KyQA2QROLr6JrHg99RORyHKPrS82qk,14316
|
|
5
|
+
ripperdoc/cli/commands/__init__.py,sha256=Xs69l9O8VglF1z1JkxbmAy_9ylrfXZxFW9G5GiPQBZk,4676
|
|
6
6
|
ripperdoc/cli/commands/agents_cmd.py,sha256=YDE9oIXPmsPyvkHhq95aXxnneN3PqZ1ZOtcn26cXeO8,10438
|
|
7
7
|
ripperdoc/cli/commands/base.py,sha256=4KUjxCM04MwbSMUKVNEBph_jeAKPI8b5MHsUFoz7l5g,386
|
|
8
8
|
ripperdoc/cli/commands/clear_cmd.py,sha256=FDZ0W34VxGyLhLiU4TzukHCyElqsnLwkCmfKJqLfFAQ,366
|
|
@@ -12,24 +12,25 @@ ripperdoc/cli/commands/context_cmd.py,sha256=6Yrz3_Oa2NwEsZo4tLK_PFFYP0Vq-amQCMB
|
|
|
12
12
|
ripperdoc/cli/commands/cost_cmd.py,sha256=yD9LSqgxVvYNTDPnEHxugjyLWcmbtH5dXim7DIW9zXc,2822
|
|
13
13
|
ripperdoc/cli/commands/doctor_cmd.py,sha256=q_PO1mnknRysVG7uopiqDWvkIIcvRX2i-JWgfKN-0gQ,7052
|
|
14
14
|
ripperdoc/cli/commands/exit_cmd.py,sha256=B0CNKQos2eRC4LSjizLdKsFYzFfwRkrUur6Afu3Fh9M,334
|
|
15
|
-
ripperdoc/cli/commands/help_cmd.py,sha256=
|
|
15
|
+
ripperdoc/cli/commands/help_cmd.py,sha256=jyK6U2bsGEIwFpu08slVHKfxRyS3oblnRXdqSgU_W4w,978
|
|
16
|
+
ripperdoc/cli/commands/hooks_cmd.py,sha256=9kTMXl-7vR9Y63Dm8iieuRK5jYnnlsqWKG5NvDsWUxU,21228
|
|
16
17
|
ripperdoc/cli/commands/mcp_cmd.py,sha256=ZCnswx0TIiaiUUsIX7NpHaLZLZtvlUhBnN12s_ZtPCA,2424
|
|
17
18
|
ripperdoc/cli/commands/memory_cmd.py,sha256=gDvRr_-U1gMrOdC3OvujYLL5_CUgyZpwaJdytRP5CBM,6549
|
|
18
19
|
ripperdoc/cli/commands/models_cmd.py,sha256=p6IeV_K9BjOahmtqmI2Gu7xsqRagVsIPYy7FEeuKQWQ,16135
|
|
19
|
-
ripperdoc/cli/commands/permissions_cmd.py,sha256=
|
|
20
|
-
ripperdoc/cli/commands/resume_cmd.py,sha256=
|
|
20
|
+
ripperdoc/cli/commands/permissions_cmd.py,sha256=k2n82VxlESxM7u5TUrUh85NM-n0JHjqnJxzeAaHpDL0,11325
|
|
21
|
+
ripperdoc/cli/commands/resume_cmd.py,sha256=pFuo3_S_6l3F8usQ9NfyJvc-nBliKW9ct8Rma8YXPlA,4121
|
|
21
22
|
ripperdoc/cli/commands/status_cmd.py,sha256=yM_c_GgoAL7CMH_ucGSwUhlbHggxYuvCEb4AXtpN-8s,5534
|
|
22
23
|
ripperdoc/cli/commands/tasks_cmd.py,sha256=QrRF9MKg6LIH9BQz5E39KKdrwMiI3HTvI-c14aM7BU0,8815
|
|
23
24
|
ripperdoc/cli/commands/todos_cmd.py,sha256=7Q0B1NVqGtB3R29ndbn4m0VQQm-YQ7d4Wlk7vJ7dLQI,1848
|
|
24
25
|
ripperdoc/cli/commands/tools_cmd.py,sha256=3cMi0vN4mAUhpKqJtRgNvZfcKzRPaMs_pkYYXlyvSSU,384
|
|
25
26
|
ripperdoc/cli/ui/__init__.py,sha256=TxSzTYdITlrYmYVfins_w_jzPqqWRpqky5u1ikwvmtM,43
|
|
26
27
|
ripperdoc/cli/ui/context_display.py,sha256=3ezdtHVwltkPQ5etYwfqUh-fjnpPu8B3P81UzrdHxZs,10020
|
|
27
|
-
ripperdoc/cli/ui/file_mention_completer.py,sha256=
|
|
28
|
+
ripperdoc/cli/ui/file_mention_completer.py,sha256=U6uZbhCamC-cJTVCbblcXvPqmkaevNgKotMC_ftssug,11648
|
|
28
29
|
ripperdoc/cli/ui/helpers.py,sha256=DmgMMouyQdesjQ5RsErwsRCKVdWiDJnpqJjv90a3neE,2545
|
|
29
|
-
ripperdoc/cli/ui/interrupt_handler.py,sha256=
|
|
30
|
-
ripperdoc/cli/ui/message_display.py,sha256=
|
|
31
|
-
ripperdoc/cli/ui/panels.py,sha256=
|
|
32
|
-
ripperdoc/cli/ui/rich_ui.py,sha256=
|
|
30
|
+
ripperdoc/cli/ui/interrupt_handler.py,sha256=dg15njl4NsFQvwAtxKPETeubuYl5OwiV2VlPECW2aNI,5930
|
|
31
|
+
ripperdoc/cli/ui/message_display.py,sha256=FHvfBY9hvf-lroB6SDzHDMS6bxuh57BfK5iBIifs2Ks,10361
|
|
32
|
+
ripperdoc/cli/ui/panels.py,sha256=lzgg7kP8nzJKqGFjE-0UVbr9a1YZ0i2XlkUy6-LcLnk,1875
|
|
33
|
+
ripperdoc/cli/ui/rich_ui.py,sha256=_VOx1zdt_QV23cwwiV6P8FiAA_H-JLIbC6WqYBLgUwM,47066
|
|
33
34
|
ripperdoc/cli/ui/spinner.py,sha256=XsPRwJ-70InLX9Qw50CEgSHn5oKA5PFIue8Un4edhUk,1449
|
|
34
35
|
ripperdoc/cli/ui/thinking_spinner.py,sha256=9Et5EqPChfkmkiOO8w1OPs8t-sHaisgjn9A__kEYLyg,2824
|
|
35
36
|
ripperdoc/cli/ui/tool_renderers.py,sha256=gVuZM083Nys9KWYAFTdmr1vpJm7ardqNhyUZx7KkL6s,11170
|
|
@@ -37,15 +38,22 @@ ripperdoc/core/__init__.py,sha256=UemJCA-Y8df1466AX-YbRFj071zKajmqO1mi40YVW2g,40
|
|
|
37
38
|
ripperdoc/core/agents.py,sha256=3glBiVM8e9NruCQGYl4inQ6Lt7jWb7C4S44YQXRWWl8,19930
|
|
38
39
|
ripperdoc/core/commands.py,sha256=NXCkljYbAP4dDoRy-_3semFNWxG4YAk9q82u8FTKH60,835
|
|
39
40
|
ripperdoc/core/config.py,sha256=fuzXTSSpPFIkzgZJW-tOf18cNeemrot64ihO4cdM79g,20979
|
|
41
|
+
ripperdoc/core/custom_commands.py,sha256=2Voc1u6WSZ-nJYRvGKmUcpNvzLCotacgGupvXUv6RT8,14289
|
|
40
42
|
ripperdoc/core/default_tools.py,sha256=fHmqIlPIE9qGwmgeYYw-QepKRoQLMhclnCv6Qahews0,3090
|
|
41
43
|
ripperdoc/core/permissions.py,sha256=_WLWE7Kq-Z5j3zEDAPr8JqdT0fz2oFqNs18NL0qoeWQ,9768
|
|
42
|
-
ripperdoc/core/query.py,sha256=
|
|
44
|
+
ripperdoc/core/query.py,sha256=We15XbLl_rAdAgJ5NAufYLNes6kNNeQ7CMj8rcGgBsE,40939
|
|
43
45
|
ripperdoc/core/query_utils.py,sha256=-lBRL5oAV0p6p6LukpFfBZKEcRdztbzCNOt51pEsKBM,24776
|
|
44
46
|
ripperdoc/core/skills.py,sha256=XkMt3WPT2_0xfx2qQhEnBbwJ0121aRFmuXLckw3MtVU,10251
|
|
45
47
|
ripperdoc/core/system_prompt.py,sha256=smhuRfzbvhfzNsQ3D89Mucll16u_40VWpOzKS0kJPFQ,26724
|
|
46
48
|
ripperdoc/core/tool.py,sha256=Hnnt7FYBGlD6lyAr9XhDgp_LfcP7o3yapzd7t6FPlBE,7813
|
|
49
|
+
ripperdoc/core/hooks/__init__.py,sha256=xw7VJQu1ZB0ENHVqL5xtruBnP3d0FNgrBH6NTL2xYgg,2735
|
|
50
|
+
ripperdoc/core/hooks/config.py,sha256=2KZXpkCGWecg3loQkYZbr5Xh68dDZv-XlTvjwQbl29o,10123
|
|
51
|
+
ripperdoc/core/hooks/events.py,sha256=ZDyP_YaRPKeDz23d6wKbfwlb64poRZDpiuPJaz8ZN9w,17957
|
|
52
|
+
ripperdoc/core/hooks/executor.py,sha256=inOAT2-xB_lXiz0io6c3QV4Wnw9ntl0unf-w0nXPMak,16818
|
|
53
|
+
ripperdoc/core/hooks/integration.py,sha256=Gb3ADGoTTYWDrCmkcgjlyLyldu3wRcji77_2VAyuYJw,11213
|
|
54
|
+
ripperdoc/core/hooks/manager.py,sha256=8YqvGPfOL3ianxFz_tnd7c_HbhHeLDHr5cLk1ayKicU,23706
|
|
47
55
|
ripperdoc/core/providers/__init__.py,sha256=yevsHF0AUI4b6Wiq_401NXewJ3dqe8LUUtQm0TLPPNQ,1911
|
|
48
|
-
ripperdoc/core/providers/anthropic.py,sha256=
|
|
56
|
+
ripperdoc/core/providers/anthropic.py,sha256=V5sofBIU1w7bo1FmrrZ_lqVvGRXt9ZkykDa_J0b1xtc,26309
|
|
49
57
|
ripperdoc/core/providers/base.py,sha256=HNOa3_XWszu6DbI8BYixxV0hnZb9qZ_FU4uinFVRHjU,9271
|
|
50
58
|
ripperdoc/core/providers/gemini.py,sha256=3U69Gh6hiL8QWsf-nawZJTfh5oeZP5DAmXYDfWtrEQE,24786
|
|
51
59
|
ripperdoc/core/providers/openai.py,sha256=FiNTCBtFpq0i0K6S0OyC-F-0HssSWJE6jrH3xRsPzD4,20981
|
|
@@ -55,12 +63,12 @@ ripperdoc/tools/__init__.py,sha256=RBFz0DDnztDXMqv_zRxFHVY-ez2HYcncx8zh_y-BX6w,4
|
|
|
55
63
|
ripperdoc/tools/ask_user_question_tool.py,sha256=QgzmIDVR-wdlLf9fSiVPbRm_8tSaIlGJhuuRYOCGiUU,15446
|
|
56
64
|
ripperdoc/tools/background_shell.py,sha256=HangGLwN4iy-udo02zUZF3QRPIqOa7sVDesbv2wL9Js,12854
|
|
57
65
|
ripperdoc/tools/bash_output_tool.py,sha256=ljIOzTOnkbQfe3jExlhpUlMiLT6HpeD-1QI-D1CwHh8,3379
|
|
58
|
-
ripperdoc/tools/bash_tool.py,sha256=
|
|
66
|
+
ripperdoc/tools/bash_tool.py,sha256=Wua9_R7S0fMfV8SmmI6_m4mpJ7gYdyku34dyTPIRA4o,42757
|
|
59
67
|
ripperdoc/tools/dynamic_mcp_tool.py,sha256=GERh7qT1mPVivFUIhlFxPNRUwOGNw5CmCnymEwQ-7vk,15662
|
|
60
68
|
ripperdoc/tools/enter_plan_mode_tool.py,sha256=FYjm_TmBL55pY4GdP7t0ISlqg-Qe3DwpIt-2weL1S4s,7976
|
|
61
69
|
ripperdoc/tools/exit_plan_mode_tool.py,sha256=3smkwGLTITem5fgA8catSSRay_a1OGQrjs8JF1zDdUQ,5756
|
|
62
70
|
ripperdoc/tools/file_edit_tool.py,sha256=pF4ZCBFq3vy2DukxGZjBGoyVJIRH-7UY4A-TpFegzdA,13768
|
|
63
|
-
ripperdoc/tools/file_read_tool.py,sha256=
|
|
71
|
+
ripperdoc/tools/file_read_tool.py,sha256=CvjnYusjolTH-PoQ8CPUVVR37GMLAntT16ffRwqKBto,7396
|
|
64
72
|
ripperdoc/tools/file_write_tool.py,sha256=SUsFvLVvCwegxEDhL8xpppNRlSl_Hcc1xwNR35FbMqU,7044
|
|
65
73
|
ripperdoc/tools/glob_tool.py,sha256=oy1S-MrQl57X_wpNXcqXyE4oHI3kmpOQoTYavx3mzEg,5932
|
|
66
74
|
ripperdoc/tools/grep_tool.py,sha256=n_YNKg8w63JgVJVpg7Qakj75JrymeKByNoapl8IS05U,14125
|
|
@@ -78,7 +86,7 @@ ripperdoc/utils/bash_constants.py,sha256=KNn8bzB6nVU5jid9jvjiH4FAu8pP3DZONJ-OknJ
|
|
|
78
86
|
ripperdoc/utils/bash_output_utils.py,sha256=3Cf5wKJzRbUesmCNy5HtXIBtv0Z2BxklTfFHJ9q1T3w,1210
|
|
79
87
|
ripperdoc/utils/coerce.py,sha256=KOPb4KR4p32nwHWG_6GsGHeVZunJyYc2YhC5DLmEZO8,1015
|
|
80
88
|
ripperdoc/utils/context_length_errors.py,sha256=oyDVr_ME_6j97TLwVZ8bDMb6ISGQx6wEHrY7ckc0GuA,7714
|
|
81
|
-
ripperdoc/utils/conversation_compaction.py,sha256
|
|
89
|
+
ripperdoc/utils/conversation_compaction.py,sha256=m9AHZcRJwbZUHrNYl5Q1esjKQSBKFkARBkO9YNUjm5Q,18364
|
|
82
90
|
ripperdoc/utils/exit_code_handlers.py,sha256=QtO1iDxVAb8Xp03D6_QixPoJC-RQlcp3ssIo_rm4two,7973
|
|
83
91
|
ripperdoc/utils/file_watch.py,sha256=CoUIcLuS-VcfxotuxFkel5KpNluMmLGJKDzx26MG3yY,4039
|
|
84
92
|
ripperdoc/utils/git_utils.py,sha256=Hq-Zx-KPyX4lp_i8ozhic15LyYdX_IfCRm-EyoFu59A,9047
|
|
@@ -90,7 +98,7 @@ ripperdoc/utils/message_compaction.py,sha256=ydTtMqo09ds1qTneJrHaFroZ4UtmzzXlXHE
|
|
|
90
98
|
ripperdoc/utils/message_formatting.py,sha256=M-2zEkjNEiLyda9x4S0-xyIBSsVOQS3eTzbIE3K7G_Q,7492
|
|
91
99
|
ripperdoc/utils/messages.py,sha256=OrUK758mmUx2_u_hE5RFLJMp8VeDy-crLGVADwgFO3c,21665
|
|
92
100
|
ripperdoc/utils/output_utils.py,sha256=R3wqFh9Dko_GK00Exx7XI0DnnldRWMsxZypYX5y6SJo,7448
|
|
93
|
-
ripperdoc/utils/path_ignore.py,sha256=
|
|
101
|
+
ripperdoc/utils/path_ignore.py,sha256=m-cbf5I_1HeV7mjwzpb4O9BXGMTFZ4EnFmmguzD7WeY,17596
|
|
94
102
|
ripperdoc/utils/path_utils.py,sha256=C45Q3OeXnj-0FVEtvf_tdG5922XB6HthUzlUCvfc17Y,1626
|
|
95
103
|
ripperdoc/utils/prompt.py,sha256=zICNEsA_OtKx8t3zo9tHLXXu6G5K8rPO3jFLKz4j5tg,560
|
|
96
104
|
ripperdoc/utils/safe_get_cwd.py,sha256=IvG8dIJd2tC5_glUsfeWXkpcF1EHzdkjFtuUGJd669w,815
|
|
@@ -105,9 +113,9 @@ ripperdoc/utils/permissions/__init__.py,sha256=33FfOaDLepxJSkp0RLvTdVu7qBXuEcnOo
|
|
|
105
113
|
ripperdoc/utils/permissions/path_validation_utils.py,sha256=FWbb21Hwgb9gUPu_WtA14w99UUojVQLVz5HByormoUs,5760
|
|
106
114
|
ripperdoc/utils/permissions/shell_command_validation.py,sha256=94ylqoDUiTF4v4wEiVS35jFJakyaSxdIFqYKumPTrGk,21205
|
|
107
115
|
ripperdoc/utils/permissions/tool_permission_utils.py,sha256=6Fdu9-dMKhLsUExjEjoS0EUeRpEVN5UkqyseIC05YmM,9207
|
|
108
|
-
ripperdoc-0.2.
|
|
109
|
-
ripperdoc-0.2.
|
|
110
|
-
ripperdoc-0.2.
|
|
111
|
-
ripperdoc-0.2.
|
|
112
|
-
ripperdoc-0.2.
|
|
113
|
-
ripperdoc-0.2.
|
|
116
|
+
ripperdoc-0.2.8.dist-info/licenses/LICENSE,sha256=bRv9UhBor6GhnQDj12RciDcRfu0R7sB-lqCy1sWF75c,9242
|
|
117
|
+
ripperdoc-0.2.8.dist-info/METADATA,sha256=aoAeFiQqkUDQpJEt4buP6G1wKlkCMXI88slI-tGSDGg,7474
|
|
118
|
+
ripperdoc-0.2.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
119
|
+
ripperdoc-0.2.8.dist-info/entry_points.txt,sha256=79aohFxFPJmrQ3-Mhain04vb3EWpuc0EyzvDDUnwAu4,81
|
|
120
|
+
ripperdoc-0.2.8.dist-info/top_level.txt,sha256=u8LbdTr1a-laHgCO0Utl_R3QGFUhLxWelCDnP2ZgpCU,10
|
|
121
|
+
ripperdoc-0.2.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|