ripperdoc 0.2.0__py3-none-any.whl → 0.2.2__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 +66 -8
- ripperdoc/cli/commands/__init__.py +4 -0
- ripperdoc/cli/commands/agents_cmd.py +22 -0
- ripperdoc/cli/commands/context_cmd.py +11 -1
- ripperdoc/cli/commands/doctor_cmd.py +200 -0
- ripperdoc/cli/commands/memory_cmd.py +209 -0
- ripperdoc/cli/commands/models_cmd.py +25 -0
- ripperdoc/cli/commands/tasks_cmd.py +27 -0
- ripperdoc/cli/ui/rich_ui.py +156 -9
- ripperdoc/core/agents.py +4 -2
- ripperdoc/core/config.py +48 -3
- ripperdoc/core/default_tools.py +16 -2
- ripperdoc/core/permissions.py +19 -0
- ripperdoc/core/query.py +231 -297
- ripperdoc/core/query_utils.py +537 -0
- ripperdoc/core/system_prompt.py +2 -1
- ripperdoc/core/tool.py +13 -0
- ripperdoc/tools/background_shell.py +9 -3
- ripperdoc/tools/bash_tool.py +15 -0
- ripperdoc/tools/file_edit_tool.py +7 -0
- ripperdoc/tools/file_read_tool.py +7 -0
- ripperdoc/tools/file_write_tool.py +7 -0
- ripperdoc/tools/glob_tool.py +55 -15
- ripperdoc/tools/grep_tool.py +7 -0
- ripperdoc/tools/ls_tool.py +242 -73
- ripperdoc/tools/mcp_tools.py +32 -10
- ripperdoc/tools/multi_edit_tool.py +11 -0
- ripperdoc/tools/notebook_edit_tool.py +6 -3
- ripperdoc/tools/task_tool.py +7 -0
- ripperdoc/tools/todo_tool.py +159 -25
- ripperdoc/tools/tool_search_tool.py +9 -0
- ripperdoc/utils/git_utils.py +276 -0
- ripperdoc/utils/json_utils.py +28 -0
- ripperdoc/utils/log.py +130 -29
- ripperdoc/utils/mcp.py +71 -6
- ripperdoc/utils/memory.py +14 -1
- ripperdoc/utils/message_compaction.py +26 -5
- ripperdoc/utils/messages.py +63 -4
- ripperdoc/utils/output_utils.py +36 -9
- ripperdoc/utils/permissions/path_validation_utils.py +6 -0
- ripperdoc/utils/safe_get_cwd.py +4 -0
- ripperdoc/utils/session_history.py +27 -9
- ripperdoc/utils/todo.py +2 -2
- {ripperdoc-0.2.0.dist-info → ripperdoc-0.2.2.dist-info}/METADATA +4 -2
- ripperdoc-0.2.2.dist-info/RECORD +86 -0
- ripperdoc-0.2.0.dist-info/RECORD +0 -81
- {ripperdoc-0.2.0.dist-info → ripperdoc-0.2.2.dist-info}/WHEEL +0 -0
- {ripperdoc-0.2.0.dist-info → ripperdoc-0.2.2.dist-info}/entry_points.txt +0 -0
- {ripperdoc-0.2.0.dist-info → ripperdoc-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {ripperdoc-0.2.0.dist-info → ripperdoc-0.2.2.dist-info}/top_level.txt +0 -0
ripperdoc/utils/memory.py
CHANGED
|
@@ -6,6 +6,9 @@ import re
|
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import List, Optional, Set
|
|
9
|
+
from ripperdoc.utils.log import get_logger
|
|
10
|
+
|
|
11
|
+
logger = get_logger()
|
|
9
12
|
|
|
10
13
|
MEMORY_FILE_NAME = "AGENTS.md"
|
|
11
14
|
LOCAL_MEMORY_FILE_NAME = "AGENTS.local.md"
|
|
@@ -43,6 +46,10 @@ def _is_path_under_directory(path: Path, directory: Path) -> bool:
|
|
|
43
46
|
path.resolve().relative_to(directory.resolve())
|
|
44
47
|
return True
|
|
45
48
|
except Exception:
|
|
49
|
+
logger.exception(
|
|
50
|
+
"[memory] Failed to compare path containment",
|
|
51
|
+
extra={"path": str(path), "directory": str(directory)},
|
|
52
|
+
)
|
|
46
53
|
return False
|
|
47
54
|
|
|
48
55
|
|
|
@@ -65,8 +72,12 @@ def _read_file_with_type(file_path: Path, file_type: str) -> Optional[MemoryFile
|
|
|
65
72
|
content = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
66
73
|
return MemoryFile(path=str(file_path), type=file_type, content=content)
|
|
67
74
|
except PermissionError:
|
|
75
|
+
logger.exception(
|
|
76
|
+
"[memory] Permission error reading file", extra={"path": str(file_path)}
|
|
77
|
+
)
|
|
68
78
|
return None
|
|
69
79
|
except OSError:
|
|
80
|
+
logger.exception("[memory] OS error reading file", extra={"path": str(file_path)})
|
|
70
81
|
return None
|
|
71
82
|
|
|
72
83
|
|
|
@@ -114,7 +125,9 @@ def _collect_files(
|
|
|
114
125
|
try:
|
|
115
126
|
resolved_path = resolved_path.resolve()
|
|
116
127
|
except Exception:
|
|
117
|
-
|
|
128
|
+
logger.exception(
|
|
129
|
+
"[memory] Failed to resolve memory file path", extra={"path": str(resolved_path)}
|
|
130
|
+
)
|
|
118
131
|
|
|
119
132
|
resolved_key = str(resolved_path)
|
|
120
133
|
if resolved_key in visited:
|
|
@@ -22,7 +22,7 @@ logger = get_logger()
|
|
|
22
22
|
|
|
23
23
|
ConversationMessage = Union[UserMessage, AssistantMessage, ProgressMessage]
|
|
24
24
|
|
|
25
|
-
# Compaction thresholds
|
|
25
|
+
# Compaction thresholds.
|
|
26
26
|
MAX_TOKENS_SOFT = 20_000
|
|
27
27
|
MAX_TOKENS_HARD = 40_000
|
|
28
28
|
MAX_TOOL_USES_TO_PRESERVE = 3
|
|
@@ -172,6 +172,9 @@ def _stringify_content(content: Union[str, List[MessageContent], None]) -> str:
|
|
|
172
172
|
try:
|
|
173
173
|
parts.append(json.dumps(part.get("input"), ensure_ascii=False))
|
|
174
174
|
except Exception:
|
|
175
|
+
logger.exception(
|
|
176
|
+
"[message_compaction] Failed to serialize tool_use input for token estimate"
|
|
177
|
+
)
|
|
175
178
|
parts.append(str(part.get("input")))
|
|
176
179
|
|
|
177
180
|
# OpenAI-style arguments blocks
|
|
@@ -225,7 +228,10 @@ def _estimate_tool_schema_tokens(tools: Sequence[Any]) -> int:
|
|
|
225
228
|
schema_text = json.dumps(schema, sort_keys=True)
|
|
226
229
|
total += estimate_tokens_from_text(schema_text)
|
|
227
230
|
except Exception as exc:
|
|
228
|
-
logger.
|
|
231
|
+
logger.exception(
|
|
232
|
+
"Failed to estimate tokens for tool schema",
|
|
233
|
+
extra={"tool": getattr(tool, "name", None), "error": str(exc)},
|
|
234
|
+
)
|
|
229
235
|
continue
|
|
230
236
|
return total
|
|
231
237
|
|
|
@@ -303,7 +309,7 @@ def get_context_usage_status(
|
|
|
303
309
|
max_context_tokens: Optional[int],
|
|
304
310
|
auto_compact_enabled: bool,
|
|
305
311
|
) -> ContextUsageStatus:
|
|
306
|
-
"""Compute context usage thresholds
|
|
312
|
+
"""Compute context usage thresholds using the compaction heuristics."""
|
|
307
313
|
context_limit = max(max_context_tokens or DEFAULT_CONTEXT_TOKENS, MIN_CONTEXT_TOKENS)
|
|
308
314
|
effective_limit = (
|
|
309
315
|
max(MIN_CONTEXT_TOKENS, context_limit - AUTO_COMPACT_BUFFER)
|
|
@@ -396,6 +402,9 @@ def find_latest_assistant_usage_tokens(
|
|
|
396
402
|
if tokens > 0:
|
|
397
403
|
return tokens
|
|
398
404
|
except Exception:
|
|
405
|
+
logger.debug(
|
|
406
|
+
"[message_compaction] Failed to parse usage tokens", exc_info=True
|
|
407
|
+
)
|
|
399
408
|
continue
|
|
400
409
|
return 0
|
|
401
410
|
|
|
@@ -432,7 +441,9 @@ def _run_cleanup_callbacks() -> None:
|
|
|
432
441
|
try:
|
|
433
442
|
callback()
|
|
434
443
|
except Exception as exc:
|
|
435
|
-
logger.debug(
|
|
444
|
+
logger.debug(
|
|
445
|
+
f"[message_compaction] Cleanup callback failed: {exc}", exc_info=True
|
|
446
|
+
)
|
|
436
447
|
|
|
437
448
|
|
|
438
449
|
def _normalize_tool_use_id(block: Any) -> str:
|
|
@@ -641,16 +652,26 @@ def compact_messages(
|
|
|
641
652
|
_processed_tool_use_ids.add(id_to_remove)
|
|
642
653
|
|
|
643
654
|
tokens_after = estimate_conversation_tokens(compacted_messages, protocol=protocol)
|
|
655
|
+
tokens_saved = max(0, tokens_before - tokens_after)
|
|
644
656
|
|
|
645
657
|
if ids_to_remove:
|
|
646
658
|
_is_compacting = True
|
|
647
659
|
_run_cleanup_callbacks()
|
|
660
|
+
logger.debug(
|
|
661
|
+
"[message_compaction] Compacted conversation",
|
|
662
|
+
extra={
|
|
663
|
+
"tokens_before": tokens_before,
|
|
664
|
+
"tokens_after": tokens_after,
|
|
665
|
+
"tokens_saved": tokens_saved,
|
|
666
|
+
"cleared_tool_ids": list(ids_to_remove),
|
|
667
|
+
},
|
|
668
|
+
)
|
|
648
669
|
|
|
649
670
|
return CompactionResult(
|
|
650
671
|
messages=compacted_messages,
|
|
651
672
|
tokens_before=tokens_before,
|
|
652
673
|
tokens_after=tokens_after,
|
|
653
|
-
tokens_saved=
|
|
674
|
+
tokens_saved=tokens_saved,
|
|
654
675
|
cleared_tool_ids=ids_to_remove,
|
|
655
676
|
was_compacted=bool(ids_to_remove),
|
|
656
677
|
)
|
ripperdoc/utils/messages.py
CHANGED
|
@@ -4,6 +4,7 @@ This module provides utilities for creating and normalizing messages
|
|
|
4
4
|
for communication with AI models.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import json
|
|
7
8
|
from typing import Any, Dict, List, Optional, Union
|
|
8
9
|
from pydantic import BaseModel, ConfigDict
|
|
9
10
|
from uuid import uuid4
|
|
@@ -75,6 +76,7 @@ def _content_block_to_openai(block: MessageContent) -> Dict[str, Any]:
|
|
|
75
76
|
try:
|
|
76
77
|
args_str = json.dumps(args)
|
|
77
78
|
except Exception:
|
|
79
|
+
logger.exception("[_content_block_to_openai] Failed to serialize tool arguments")
|
|
78
80
|
args_str = "{}"
|
|
79
81
|
tool_call_id = (
|
|
80
82
|
getattr(block, "id", None) or getattr(block, "tool_use_id", "") or str(uuid4())
|
|
@@ -187,7 +189,7 @@ def create_user_message(
|
|
|
187
189
|
tool_use_result = tool_use_result.model_dump()
|
|
188
190
|
except Exception:
|
|
189
191
|
# Fallback: keep as-is if conversion fails
|
|
190
|
-
|
|
192
|
+
logger.exception("[create_user_message] Failed to normalize tool_use_result")
|
|
191
193
|
|
|
192
194
|
message = Message(role=MessageRole.USER, content=message_content)
|
|
193
195
|
|
|
@@ -237,6 +239,7 @@ def create_progress_message(
|
|
|
237
239
|
def normalize_messages_for_api(
|
|
238
240
|
messages: List[Union[UserMessage, AssistantMessage, ProgressMessage]],
|
|
239
241
|
protocol: str = "anthropic",
|
|
242
|
+
tool_mode: str = "native",
|
|
240
243
|
) -> List[Dict[str, Any]]:
|
|
241
244
|
"""Normalize messages for API submission.
|
|
242
245
|
|
|
@@ -261,6 +264,62 @@ def normalize_messages_for_api(
|
|
|
261
264
|
return msg.get("content")
|
|
262
265
|
return None
|
|
263
266
|
|
|
267
|
+
def _block_type(block: Any) -> Optional[str]:
|
|
268
|
+
if hasattr(block, "type"):
|
|
269
|
+
return getattr(block, "type", None)
|
|
270
|
+
if isinstance(block, dict):
|
|
271
|
+
return block.get("type")
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
def _block_attr(block: Any, attr: str, default: Any = None) -> Any:
|
|
275
|
+
if hasattr(block, attr):
|
|
276
|
+
return getattr(block, attr, default)
|
|
277
|
+
if isinstance(block, dict):
|
|
278
|
+
return block.get(attr, default)
|
|
279
|
+
return default
|
|
280
|
+
|
|
281
|
+
def _flatten_blocks_to_text(blocks: List[Any]) -> str:
|
|
282
|
+
parts: List[str] = []
|
|
283
|
+
for blk in blocks:
|
|
284
|
+
btype = _block_type(blk)
|
|
285
|
+
if btype == "text":
|
|
286
|
+
text = _block_attr(blk, "text") or _block_attr(blk, "content") or ""
|
|
287
|
+
if text:
|
|
288
|
+
parts.append(str(text))
|
|
289
|
+
elif btype == "tool_result":
|
|
290
|
+
text = _block_attr(blk, "text") or _block_attr(blk, "content") or ""
|
|
291
|
+
tool_id = _block_attr(blk, "tool_use_id") or _block_attr(blk, "id")
|
|
292
|
+
prefix = "Tool error" if _block_attr(blk, "is_error") else "Tool result"
|
|
293
|
+
label = f"{prefix}{f' ({tool_id})' if tool_id else ''}"
|
|
294
|
+
parts.append(f"{label}: {text}" if text else label)
|
|
295
|
+
elif btype == "tool_use":
|
|
296
|
+
name = _block_attr(blk, "name") or ""
|
|
297
|
+
input_data = _block_attr(blk, "input")
|
|
298
|
+
input_preview = ""
|
|
299
|
+
if input_data not in (None, {}):
|
|
300
|
+
try:
|
|
301
|
+
input_preview = json.dumps(input_data)
|
|
302
|
+
except Exception:
|
|
303
|
+
input_preview = str(input_data)
|
|
304
|
+
tool_id = _block_attr(blk, "tool_use_id") or _block_attr(blk, "id")
|
|
305
|
+
desc = "Tool call"
|
|
306
|
+
if name:
|
|
307
|
+
desc += f" {name}"
|
|
308
|
+
if tool_id:
|
|
309
|
+
desc += f" ({tool_id})"
|
|
310
|
+
if input_preview:
|
|
311
|
+
desc += f": {input_preview}"
|
|
312
|
+
parts.append(desc)
|
|
313
|
+
else:
|
|
314
|
+
text = _block_attr(blk, "text") or _block_attr(blk, "content") or ""
|
|
315
|
+
if text:
|
|
316
|
+
parts.append(str(text))
|
|
317
|
+
return "\n".join(p for p in parts if p)
|
|
318
|
+
|
|
319
|
+
effective_tool_mode = (tool_mode or "native").lower()
|
|
320
|
+
if effective_tool_mode not in {"native", "text"}:
|
|
321
|
+
effective_tool_mode = "native"
|
|
322
|
+
|
|
264
323
|
normalized: List[Dict[str, Any]] = []
|
|
265
324
|
tool_results_seen = 0
|
|
266
325
|
tool_uses_seen = 0
|
|
@@ -374,9 +433,9 @@ def normalize_messages_for_api(
|
|
|
374
433
|
)
|
|
375
434
|
|
|
376
435
|
logger.debug(
|
|
377
|
-
f"[normalize_messages_for_api] protocol={protocol}
|
|
378
|
-
f"
|
|
379
|
-
f"tool_uses_seen={tool_uses_seen} "
|
|
436
|
+
f"[normalize_messages_for_api] protocol={protocol} tool_mode={effective_tool_mode} "
|
|
437
|
+
f"input_msgs={len(messages)} normalized={len(normalized)} "
|
|
438
|
+
f"tool_results_seen={tool_results_seen} tool_uses_seen={tool_uses_seen} "
|
|
380
439
|
f"tool_result_positions={len(tool_result_positions)} "
|
|
381
440
|
f"skipped_tool_uses_no_result={skipped_tool_uses_no_result} "
|
|
382
441
|
f"skipped_tool_uses_no_id={skipped_tool_uses_no_id}"
|
ripperdoc/utils/output_utils.py
CHANGED
|
@@ -131,15 +131,42 @@ def truncate_output(text: str, max_chars: int = MAX_OUTPUT_CHARS) -> dict[str, A
|
|
|
131
131
|
"is_image": False,
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
134
|
+
marker_template = "\n\n... [Output truncated: {omitted} characters omitted] ...\n\n"
|
|
135
|
+
short_marker = "... [truncated] ..."
|
|
136
|
+
|
|
137
|
+
def _choose_marker(omitted: int, budget: int) -> str:
|
|
138
|
+
"""Pick the most informative marker that fits within the budget."""
|
|
139
|
+
full_marker = marker_template.format(omitted=omitted)
|
|
140
|
+
if len(full_marker) <= budget:
|
|
141
|
+
return full_marker
|
|
142
|
+
if len(short_marker) <= budget:
|
|
143
|
+
return short_marker
|
|
144
|
+
# Last resort: squeeze an ellipsis into the budget (may be empty for tiny budgets)
|
|
145
|
+
return "..."[: max(budget, 0)]
|
|
146
|
+
|
|
147
|
+
# Iteratively balance how much of the start/end to keep while ensuring we never exceed max_chars.
|
|
148
|
+
marker = _choose_marker(original_length - max_chars, max_chars)
|
|
149
|
+
keep_start = keep_end = 0
|
|
150
|
+
for _ in range(2):
|
|
151
|
+
available = max(0, max_chars - len(marker))
|
|
152
|
+
keep_start = min(TRUNCATE_KEEP_START, available // 2)
|
|
153
|
+
keep_end = min(TRUNCATE_KEEP_END, available - keep_start)
|
|
154
|
+
marker = _choose_marker(
|
|
155
|
+
max(0, original_length - (keep_start + keep_end)), max_chars
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
available = max(0, max_chars - len(marker))
|
|
159
|
+
# Ensure kept sections fit the final budget; trim end first, then start if needed.
|
|
160
|
+
if keep_start + keep_end > available:
|
|
161
|
+
overflow = keep_start + keep_end - available
|
|
162
|
+
trim_end = min(overflow, keep_end)
|
|
163
|
+
keep_end -= trim_end
|
|
164
|
+
overflow -= trim_end
|
|
165
|
+
keep_start = max(0, keep_start - overflow)
|
|
166
|
+
|
|
167
|
+
truncated = text[:keep_start] + marker + (text[-keep_end:] if keep_end else "")
|
|
168
|
+
if len(truncated) > max_chars:
|
|
169
|
+
truncated = truncated[:max_chars]
|
|
143
170
|
|
|
144
171
|
return {
|
|
145
172
|
"truncated_content": truncated,
|
|
@@ -10,6 +10,9 @@ from typing import Iterable, List, Set
|
|
|
10
10
|
|
|
11
11
|
from ripperdoc.utils.safe_get_cwd import safe_get_cwd
|
|
12
12
|
from ripperdoc.utils.shell_token_utils import parse_and_clean_shell_tokens
|
|
13
|
+
from ripperdoc.utils.log import get_logger
|
|
14
|
+
|
|
15
|
+
logger = get_logger()
|
|
13
16
|
|
|
14
17
|
_GLOB_PATTERN = re.compile(r"[*?\[\]{}]")
|
|
15
18
|
_MAX_VISIBLE_ITEMS = 5
|
|
@@ -46,6 +49,9 @@ def _resolve_path(raw_path: str, cwd: str) -> Path:
|
|
|
46
49
|
try:
|
|
47
50
|
return candidate.resolve()
|
|
48
51
|
except Exception:
|
|
52
|
+
logger.exception(
|
|
53
|
+
"[path_validation] Failed to resolve path", extra={"raw_path": raw_path, "cwd": cwd}
|
|
54
|
+
)
|
|
49
55
|
return candidate
|
|
50
56
|
|
|
51
57
|
|
ripperdoc/utils/safe_get_cwd.py
CHANGED
|
@@ -4,6 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from ripperdoc.utils.log import get_logger
|
|
8
|
+
|
|
9
|
+
logger = get_logger()
|
|
7
10
|
|
|
8
11
|
_ORIGINAL_CWD = Path(os.getcwd()).resolve()
|
|
9
12
|
|
|
@@ -18,6 +21,7 @@ def safe_get_cwd() -> str:
|
|
|
18
21
|
try:
|
|
19
22
|
return str(Path(os.getcwd()).resolve())
|
|
20
23
|
except Exception:
|
|
24
|
+
logger.exception("[safe_get_cwd] Failed to resolve cwd")
|
|
21
25
|
return get_original_cwd()
|
|
22
26
|
|
|
23
27
|
|
|
@@ -102,10 +102,16 @@ class SessionHistory:
|
|
|
102
102
|
if isinstance(msg_uuid, str):
|
|
103
103
|
self._seen_ids.add(msg_uuid)
|
|
104
104
|
except Exception as exc:
|
|
105
|
-
logger.debug(
|
|
105
|
+
logger.debug(
|
|
106
|
+
f"Failed to parse session history line: {exc}",
|
|
107
|
+
exc_info=True,
|
|
108
|
+
)
|
|
106
109
|
continue
|
|
107
|
-
except Exception
|
|
108
|
-
logger.
|
|
110
|
+
except Exception:
|
|
111
|
+
logger.exception(
|
|
112
|
+
"Failed to load seen IDs from session",
|
|
113
|
+
extra={"session_id": self.session_id, "path": str(self.path)},
|
|
114
|
+
)
|
|
109
115
|
return
|
|
110
116
|
|
|
111
117
|
def append(self, message: ConversationMessage) -> None:
|
|
@@ -128,9 +134,12 @@ class SessionHistory:
|
|
|
128
134
|
fh.write("\n")
|
|
129
135
|
if isinstance(msg_uuid, str):
|
|
130
136
|
self._seen_ids.add(msg_uuid)
|
|
131
|
-
except Exception
|
|
137
|
+
except Exception:
|
|
132
138
|
# Avoid crashing the UI if logging fails
|
|
133
|
-
logger.
|
|
139
|
+
logger.exception(
|
|
140
|
+
"Failed to append message to session log",
|
|
141
|
+
extra={"session_id": self.session_id, "path": str(self.path)},
|
|
142
|
+
)
|
|
134
143
|
return
|
|
135
144
|
|
|
136
145
|
|
|
@@ -146,7 +155,10 @@ def list_session_summaries(project_path: Path) -> List[SessionSummary]:
|
|
|
146
155
|
with jsonl_path.open("r", encoding="utf-8") as fh:
|
|
147
156
|
messages = [json.loads(line) for line in fh if line.strip()]
|
|
148
157
|
except Exception as exc:
|
|
149
|
-
logger.
|
|
158
|
+
logger.exception(
|
|
159
|
+
"Failed to load session summary",
|
|
160
|
+
extra={"path": str(jsonl_path), "error": str(exc)},
|
|
161
|
+
)
|
|
150
162
|
continue
|
|
151
163
|
|
|
152
164
|
payloads = [entry.get("payload") or {} for entry in messages]
|
|
@@ -206,10 +218,16 @@ def load_session_messages(project_path: Path, session_id: str) -> List[Conversat
|
|
|
206
218
|
if msg is not None and getattr(msg, "type", None) != "progress":
|
|
207
219
|
messages.append(msg)
|
|
208
220
|
except Exception as exc:
|
|
209
|
-
logger.debug(
|
|
221
|
+
logger.debug(
|
|
222
|
+
f"Failed to deserialize message in session {session_id}: {exc}",
|
|
223
|
+
exc_info=True,
|
|
224
|
+
)
|
|
210
225
|
continue
|
|
211
|
-
except Exception
|
|
212
|
-
logger.
|
|
226
|
+
except Exception:
|
|
227
|
+
logger.exception(
|
|
228
|
+
"Failed to load session messages",
|
|
229
|
+
extra={"session_id": session_id, "path": str(path)},
|
|
230
|
+
)
|
|
213
231
|
return []
|
|
214
232
|
|
|
215
233
|
return messages
|
ripperdoc/utils/todo.py
CHANGED
|
@@ -83,8 +83,8 @@ def load_todos(project_root: Optional[Path] = None) -> List[TodoItem]:
|
|
|
83
83
|
|
|
84
84
|
try:
|
|
85
85
|
raw = json.loads(path.read_text())
|
|
86
|
-
except Exception
|
|
87
|
-
logger.
|
|
86
|
+
except Exception:
|
|
87
|
+
logger.exception("Failed to load todos from disk", extra={"path": str(path)})
|
|
88
88
|
return []
|
|
89
89
|
|
|
90
90
|
todos: List[TodoItem] = []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ripperdoc
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: AI-powered terminal assistant for coding tasks
|
|
5
5
|
Author: Ripperdoc Team
|
|
6
6
|
License: Apache-2.0
|
|
@@ -24,6 +24,7 @@ Requires-Dist: aiofiles>=23.0.0
|
|
|
24
24
|
Requires-Dist: prompt-toolkit>=3.0.0
|
|
25
25
|
Requires-Dist: PyYAML>=6.0.0
|
|
26
26
|
Requires-Dist: mcp[cli]>=1.22.0
|
|
27
|
+
Requires-Dist: json_repair>=0.54.2
|
|
27
28
|
Provides-Extra: dev
|
|
28
29
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
29
30
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -37,10 +38,12 @@ Dynamic: license-file
|
|
|
37
38
|
Ripperdoc is an AI-powered terminal assistant for coding tasks, providing an interactive interface for AI-assisted development, file management, and command execution.
|
|
38
39
|
|
|
39
40
|
[中文文档](README_CN.md) | [Contributing](CONTRIBUTING.md) | [Documentation](docs/)
|
|
41
|
+
|
|
40
42
|
## Features
|
|
41
43
|
|
|
42
44
|
- **AI-Powered Assistance** - Uses AI models to understand and respond to coding requests
|
|
43
45
|
- **Multi-Model Support** - Support for Anthropic Claude and OpenAI models
|
|
46
|
+
- **Rich UI** - Beautiful terminal interface with syntax highlighting
|
|
44
47
|
- **Code Editing** - Directly edit files with intelligent suggestions
|
|
45
48
|
- **Codebase Understanding** - Analyzes project structure and code relationships
|
|
46
49
|
- **Command Execution** - Run shell commands with real-time feedback
|
|
@@ -52,7 +55,6 @@ Ripperdoc is an AI-powered terminal assistant for coding tasks, providing an int
|
|
|
52
55
|
- **Permission System** - Safe mode with permission prompts for operations
|
|
53
56
|
- **Multi-Edit Support** - Batch edit operations on files
|
|
54
57
|
- **MCP Server Support** - Integration with Model Context Protocol servers
|
|
55
|
-
- **Subagent System** - Delegate tasks to specialized agents
|
|
56
58
|
- **Session Management** - Persistent session history and usage tracking
|
|
57
59
|
- **Jupyter Notebook Support** - Edit .ipynb files directly
|
|
58
60
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
ripperdoc/__init__.py,sha256=VVORpI3UmHW0atP8i4ThIdElrO8xDwVHSHveq6sUOco,66
|
|
2
|
+
ripperdoc/__main__.py,sha256=7oIFEXI2irIoZ_dhcMd3hCs4Dj8tmMBbwiVACAoeE-k,506
|
|
3
|
+
ripperdoc/cli/__init__.py,sha256=03wf6gXBcEgXJrDJS-W_5BEG_DdJ_ep7CxQFPML-73g,35
|
|
4
|
+
ripperdoc/cli/cli.py,sha256=lm3d4JXaHoLxZ20HmkE38GfNChDyJMGR-5pSRPiZzEA,12843
|
|
5
|
+
ripperdoc/cli/commands/__init__.py,sha256=J13i7g-69PVLhO5IJH5OvVK0FJLIFj0b84mm33JvpcE,2329
|
|
6
|
+
ripperdoc/cli/commands/agents_cmd.py,sha256=nYB_JZI8YIuBflDFXkWZsNBGAMneBFf3IFM2gZLOKfI,10118
|
|
7
|
+
ripperdoc/cli/commands/base.py,sha256=4KUjxCM04MwbSMUKVNEBph_jeAKPI8b5MHsUFoz7l5g,386
|
|
8
|
+
ripperdoc/cli/commands/clear_cmd.py,sha256=zSYT0Nn_htZzLWTTQ4E5KWHfRg0Q5CYvRO4e--7thBY,345
|
|
9
|
+
ripperdoc/cli/commands/compact_cmd.py,sha256=C_qdPTPdg1cOHdmODkaYoRusosgiqRK6c6KID_Gwq0k,330
|
|
10
|
+
ripperdoc/cli/commands/config_cmd.py,sha256=ebIQk7zUFv353liWfbBSSfPiOaaCR7rQsd_eTw7nsvY,884
|
|
11
|
+
ripperdoc/cli/commands/context_cmd.py,sha256=d0KiJyjbuDNXYlfSzVTFmxmkLXJZe3pUDg_Tt67OWqs,4359
|
|
12
|
+
ripperdoc/cli/commands/cost_cmd.py,sha256=AoGRDDu48qsMGuS5zgScg_YdNqkwoj33D2PTh-1uZ34,2637
|
|
13
|
+
ripperdoc/cli/commands/doctor_cmd.py,sha256=SW2f9Z6dQzeBTATqdByWRc1UE_w-132KsoKj8d9VPBY,6577
|
|
14
|
+
ripperdoc/cli/commands/exit_cmd.py,sha256=B0CNKQos2eRC4LSjizLdKsFYzFfwRkrUur6Afu3Fh9M,334
|
|
15
|
+
ripperdoc/cli/commands/help_cmd.py,sha256=iz1vR-rmWsvvfzdebLiIWEWrcMZo5_Eb55_wLr4Ufno,508
|
|
16
|
+
ripperdoc/cli/commands/mcp_cmd.py,sha256=S0iQxclxqgbIxbKcC9oFrckLalzk-1eyAYwkfEZQsGU,2307
|
|
17
|
+
ripperdoc/cli/commands/memory_cmd.py,sha256=W6-jteI_aajw7RaQzwGPWiGOBwfsZcWXKh2HLKsq9B8,6558
|
|
18
|
+
ripperdoc/cli/commands/models_cmd.py,sha256=b6t8UUUTyu4Se_NhYbMDPvkDnWTephFEtOiFjY2oVrk,13080
|
|
19
|
+
ripperdoc/cli/commands/resume_cmd.py,sha256=F99haT29dUHYlgrIYKk2cadSOTrwkLOEs_D2RotNZXI,2977
|
|
20
|
+
ripperdoc/cli/commands/status_cmd.py,sha256=rAhHksegqdLGy551Hh22oVwR6ZSfkDvAPOjNiNQJ9_s,5494
|
|
21
|
+
ripperdoc/cli/commands/tasks_cmd.py,sha256=lgVzN6_KFQGltb7bgn4Wwmkuq91H_mgzCrga67hgjT4,8292
|
|
22
|
+
ripperdoc/cli/commands/todos_cmd.py,sha256=7Q0B1NVqGtB3R29ndbn4m0VQQm-YQ7d4Wlk7vJ7dLQI,1848
|
|
23
|
+
ripperdoc/cli/commands/tools_cmd.py,sha256=3cMi0vN4mAUhpKqJtRgNvZfcKzRPaMs_pkYYXlyvSSU,384
|
|
24
|
+
ripperdoc/cli/ui/__init__.py,sha256=TxSzTYdITlrYmYVfins_w_jzPqqWRpqky5u1ikwvmtM,43
|
|
25
|
+
ripperdoc/cli/ui/context_display.py,sha256=3ezdtHVwltkPQ5etYwfqUh-fjnpPu8B3P81UzrdHxZs,10020
|
|
26
|
+
ripperdoc/cli/ui/helpers.py,sha256=TJCipP0neh-96ETQfGhusCJ4aWt5gLw1HZbI-3bWDpw,739
|
|
27
|
+
ripperdoc/cli/ui/rich_ui.py,sha256=sG1mXHembvDyu_AaokKsoZ23MRnG-GIeVtwBH2RSxpM,49829
|
|
28
|
+
ripperdoc/cli/ui/spinner.py,sha256=XsPRwJ-70InLX9Qw50CEgSHn5oKA5PFIue8Un4edhUk,1449
|
|
29
|
+
ripperdoc/core/__init__.py,sha256=UemJCA-Y8df1466AX-YbRFj071zKajmqO1mi40YVW2g,40
|
|
30
|
+
ripperdoc/core/agents.py,sha256=-v2IkP3QbGtb5AwTT3WoWyWvlUCDieHFnG7vXNMQaZo,10320
|
|
31
|
+
ripperdoc/core/commands.py,sha256=NXCkljYbAP4dDoRy-_3semFNWxG4YAk9q82u8FTKH60,835
|
|
32
|
+
ripperdoc/core/config.py,sha256=L022fgD-yIUP3M-e3txZI1Qo3O1mOa9TP4a-zcXZU-I,15335
|
|
33
|
+
ripperdoc/core/default_tools.py,sha256=t8cLZBOVReF5hvmyhUTziUSnnDMyKDjS7YjuSd_yolw,2568
|
|
34
|
+
ripperdoc/core/permissions.py,sha256=qWaVIaps9Ht0M4jgDk9J0gDErptvf6jzEZ2t48lZ_1I,9187
|
|
35
|
+
ripperdoc/core/query.py,sha256=25qQj3h8G5ad9PVSmrQaRCZf701F9bJL0NdeHlJ6N-w,23299
|
|
36
|
+
ripperdoc/core/query_utils.py,sha256=dnBiYO0zvlsGDt09bb9ozItqLNGUDbI4JCH0pUDM8ns,21404
|
|
37
|
+
ripperdoc/core/system_prompt.py,sha256=QH7Wg8QqwzvAzjuBayr57w-BazqIQrHfuGvC2KqVkgI,24190
|
|
38
|
+
ripperdoc/core/tool.py,sha256=dIEBU4bvzD0oZMJ4fbvmTc3mMOWTjxfb12nRHRsalzg,6872
|
|
39
|
+
ripperdoc/sdk/__init__.py,sha256=aDSgI4lcCDs9cV3bxNmEEV3SuYx2aCd4VnUjs6H-R7E,213
|
|
40
|
+
ripperdoc/sdk/client.py,sha256=21f8viIh3BhSjXcI_MvgzfAcy7r289Thyhc_qgnQrB0,10556
|
|
41
|
+
ripperdoc/tools/__init__.py,sha256=RBFz0DDnztDXMqv_zRxFHVY-ez2HYcncx8zh_y-BX6w,42
|
|
42
|
+
ripperdoc/tools/background_shell.py,sha256=r0F67FoXGnT_QN-fQWQpsZCW-RoZmIaJGIuXX8Eu8nY,9352
|
|
43
|
+
ripperdoc/tools/bash_output_tool.py,sha256=ljIOzTOnkbQfe3jExlhpUlMiLT6HpeD-1QI-D1CwHh8,3379
|
|
44
|
+
ripperdoc/tools/bash_tool.py,sha256=XFvg66mU19OuH-h8wxOa_nu-ThtcwFCHFuO-rc_QXQ0,36698
|
|
45
|
+
ripperdoc/tools/file_edit_tool.py,sha256=YX6ijp8huEtAR9jJiJzLnDmrJ5QUW2beyTTlZsrAhbA,11394
|
|
46
|
+
ripperdoc/tools/file_read_tool.py,sha256=IZwRZACRMn8QNElN8T5quhrx1Wk7B1u4lglASR_WKKg,6109
|
|
47
|
+
ripperdoc/tools/file_write_tool.py,sha256=BQgjaCp2UTe3sgDukoJQRVAFVfZdK1WG2eHMD3NuupM,4811
|
|
48
|
+
ripperdoc/tools/glob_tool.py,sha256=2DtKo8WZgK9_X8WDTXcrfRPm1sCx89SOfnmwvInTsIM,5792
|
|
49
|
+
ripperdoc/tools/grep_tool.py,sha256=LfLpPmqD9CIPk6kFYDDmIcykj7uN0xoKtyodc2412FA,8340
|
|
50
|
+
ripperdoc/tools/kill_bash_tool.py,sha256=36F8w2Rm1IVQitwOAwS-D8NTnyQdWfKWIam44qlXErk,4625
|
|
51
|
+
ripperdoc/tools/ls_tool.py,sha256=-ijEXqNZXeibz5gDkCQV5emQKI0rAwDgYtQNum05iro,15262
|
|
52
|
+
ripperdoc/tools/mcp_tools.py,sha256=ejofb2UEwH0r-ZAEvvq9nWvCgRGTAqiOws_X2T0YBU0,31263
|
|
53
|
+
ripperdoc/tools/multi_edit_tool.py,sha256=cTQjTovOJOs1fTeavFz14akm0NzNt16dsnoIIuvRI64,15360
|
|
54
|
+
ripperdoc/tools/notebook_edit_tool.py,sha256=693wva_Y77Y43Z5OAORPHUs1AL3vzHV_SDYPVzyu37c,12150
|
|
55
|
+
ripperdoc/tools/task_tool.py,sha256=bKvJy0hMJcY4MEmWDXqYH0CKfgMKEtaCO9UF9xdngc0,11983
|
|
56
|
+
ripperdoc/tools/todo_tool.py,sha256=DgKiJAI3W5WflXqdB4R7bJRdvlg6zqEeZ6CZfH9Ohb8,19984
|
|
57
|
+
ripperdoc/tools/tool_search_tool.py,sha256=pj26xBYBThuPioVYNB65wypwPVbGwKURxpd4p918ScI,13693
|
|
58
|
+
ripperdoc/utils/__init__.py,sha256=gdso60znB2hsYZ_YZBKVcuOY3QVfoqD2wHQ4pvr5lSw,37
|
|
59
|
+
ripperdoc/utils/bash_constants.py,sha256=KNn8bzB6nVU5jid9jvjiH4FAu8pP3DZONJ-OknJypAQ,1641
|
|
60
|
+
ripperdoc/utils/bash_output_utils.py,sha256=3Cf5wKJzRbUesmCNy5HtXIBtv0Z2BxklTfFHJ9q1T3w,1210
|
|
61
|
+
ripperdoc/utils/exit_code_handlers.py,sha256=QtO1iDxVAb8Xp03D6_QixPoJC-RQlcp3ssIo_rm4two,7973
|
|
62
|
+
ripperdoc/utils/git_utils.py,sha256=o5ff99CQ5tqe8lgY0zd0f6I3Rb95LAvhv_yLKZCKrv0,9233
|
|
63
|
+
ripperdoc/utils/json_utils.py,sha256=ZA77cDDd0smsIpEtKJk0cfaI6ZD88DyXjDm9bCsEAGc,711
|
|
64
|
+
ripperdoc/utils/log.py,sha256=AT7EMl8Xh02aY3qRF2k1UpBhfAWbpXeNtuogcldBRPo,6099
|
|
65
|
+
ripperdoc/utils/mcp.py,sha256=aIGmJLErQ1xRSzTj9Hm3ns2gW8oTvfrFBIukyNXaURk,17037
|
|
66
|
+
ripperdoc/utils/memory.py,sha256=nBulG1KFTnmYBikcYruNV0qhNDi2gpI46dvB9URdi9I,7894
|
|
67
|
+
ripperdoc/utils/message_compaction.py,sha256=pZY9wLlY46ZQq9zx5rOTzKa6sdoxokxr4w2IQsNI6wg,24857
|
|
68
|
+
ripperdoc/utils/messages.py,sha256=yEvaO8O4FW2dy12qKWfY3u_jimkoS-nSUnfY5nC9gzw,17389
|
|
69
|
+
ripperdoc/utils/output_utils.py,sha256=gAOfw_vZYjhv8qXb5U-r-rRTcidqDQShYWUgwiwCkGM,7470
|
|
70
|
+
ripperdoc/utils/path_utils.py,sha256=C45Q3OeXnj-0FVEtvf_tdG5922XB6HthUzlUCvfc17Y,1626
|
|
71
|
+
ripperdoc/utils/safe_get_cwd.py,sha256=hZXQ1oJBCXuk1QBmmfqgDsr1icVOAfGSxABp032GauI,716
|
|
72
|
+
ripperdoc/utils/sandbox_utils.py,sha256=G91P8dw2VFcCiCpjXZ4LvzbAPiO8REqMhw39eI5Z4dU,1123
|
|
73
|
+
ripperdoc/utils/session_history.py,sha256=Z-stx88yaWzJ5iqOLCeS_z8gg1G4w6j4OMoff9r7JvA,7965
|
|
74
|
+
ripperdoc/utils/session_usage.py,sha256=iz4B9MRhPbwemo9-beeZ8axcpGEe0kEc-Jghlexd_xU,2961
|
|
75
|
+
ripperdoc/utils/shell_token_utils.py,sha256=SduoSU-RERJdM_7gBn0urr5UXtl4XOpPgydBd2fwzWg,2500
|
|
76
|
+
ripperdoc/utils/todo.py,sha256=ejWd42AAVT15GJvCqb21GERSIbsdY-bwZDNnst4xebQ,6903
|
|
77
|
+
ripperdoc/utils/permissions/__init__.py,sha256=-1aKvRC05kuvLacbeu7w1W5ANamOTAho4Y0lY2vz0W0,522
|
|
78
|
+
ripperdoc/utils/permissions/path_validation_utils.py,sha256=jWcvBWUOgiEOncn_b2Fz7FBJL3XiPlyPQhNT4ZJ7p10,5681
|
|
79
|
+
ripperdoc/utils/permissions/shell_command_validation.py,sha256=BkK-wEwAuJPoC4XIx2Zj6MF3gXcWReozIwigXgib0z0,2446
|
|
80
|
+
ripperdoc/utils/permissions/tool_permission_utils.py,sha256=6Fdu9-dMKhLsUExjEjoS0EUeRpEVN5UkqyseIC05YmM,9207
|
|
81
|
+
ripperdoc-0.2.2.dist-info/licenses/LICENSE,sha256=bRv9UhBor6GhnQDj12RciDcRfu0R7sB-lqCy1sWF75c,9242
|
|
82
|
+
ripperdoc-0.2.2.dist-info/METADATA,sha256=K73CYp36dc4bblx3lxqPaJkZK8BxxlATA1v0ARqACq8,5362
|
|
83
|
+
ripperdoc-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
84
|
+
ripperdoc-0.2.2.dist-info/entry_points.txt,sha256=79aohFxFPJmrQ3-Mhain04vb3EWpuc0EyzvDDUnwAu4,81
|
|
85
|
+
ripperdoc-0.2.2.dist-info/top_level.txt,sha256=u8LbdTr1a-laHgCO0Utl_R3QGFUhLxWelCDnP2ZgpCU,10
|
|
86
|
+
ripperdoc-0.2.2.dist-info/RECORD,,
|
ripperdoc-0.2.0.dist-info/RECORD
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
ripperdoc/__init__.py,sha256=8uE0Wb2dqhd3j7g6jm1ObxZ2cn3yf5E3SoVpLzYcFJs,66
|
|
2
|
-
ripperdoc/__main__.py,sha256=7oIFEXI2irIoZ_dhcMd3hCs4Dj8tmMBbwiVACAoeE-k,506
|
|
3
|
-
ripperdoc/cli/__init__.py,sha256=03wf6gXBcEgXJrDJS-W_5BEG_DdJ_ep7CxQFPML-73g,35
|
|
4
|
-
ripperdoc/cli/cli.py,sha256=ldVNPsZIEdwaNwbrwbgAZMfQFQ1tEXw5uz26fP7avGc,10928
|
|
5
|
-
ripperdoc/cli/commands/__init__.py,sha256=2ymRdOj3EekyIioOxhJNMZyjWaSNVixNZZ6DONfTXtc,2189
|
|
6
|
-
ripperdoc/cli/commands/agents_cmd.py,sha256=_4Cf1onhtgVrT4PnVPqHLueiAEbJcM9VP-_usPs77xE,9277
|
|
7
|
-
ripperdoc/cli/commands/base.py,sha256=4KUjxCM04MwbSMUKVNEBph_jeAKPI8b5MHsUFoz7l5g,386
|
|
8
|
-
ripperdoc/cli/commands/clear_cmd.py,sha256=zSYT0Nn_htZzLWTTQ4E5KWHfRg0Q5CYvRO4e--7thBY,345
|
|
9
|
-
ripperdoc/cli/commands/compact_cmd.py,sha256=C_qdPTPdg1cOHdmODkaYoRusosgiqRK6c6KID_Gwq0k,330
|
|
10
|
-
ripperdoc/cli/commands/config_cmd.py,sha256=ebIQk7zUFv353liWfbBSSfPiOaaCR7rQsd_eTw7nsvY,884
|
|
11
|
-
ripperdoc/cli/commands/context_cmd.py,sha256=8PpTi4b0-tcxuxf4Qh59HOyH4eGmGe8TV7T_KrS_9yw,4007
|
|
12
|
-
ripperdoc/cli/commands/cost_cmd.py,sha256=AoGRDDu48qsMGuS5zgScg_YdNqkwoj33D2PTh-1uZ34,2637
|
|
13
|
-
ripperdoc/cli/commands/exit_cmd.py,sha256=B0CNKQos2eRC4LSjizLdKsFYzFfwRkrUur6Afu3Fh9M,334
|
|
14
|
-
ripperdoc/cli/commands/help_cmd.py,sha256=iz1vR-rmWsvvfzdebLiIWEWrcMZo5_Eb55_wLr4Ufno,508
|
|
15
|
-
ripperdoc/cli/commands/mcp_cmd.py,sha256=S0iQxclxqgbIxbKcC9oFrckLalzk-1eyAYwkfEZQsGU,2307
|
|
16
|
-
ripperdoc/cli/commands/models_cmd.py,sha256=fQOwb_5_vNPNKF2NHepvLrsE25qTETPC9zlkvnrRjxs,11915
|
|
17
|
-
ripperdoc/cli/commands/resume_cmd.py,sha256=F99haT29dUHYlgrIYKk2cadSOTrwkLOEs_D2RotNZXI,2977
|
|
18
|
-
ripperdoc/cli/commands/status_cmd.py,sha256=rAhHksegqdLGy551Hh22oVwR6ZSfkDvAPOjNiNQJ9_s,5494
|
|
19
|
-
ripperdoc/cli/commands/tasks_cmd.py,sha256=oCGEdfjCqPSHJOAWGQUABl7X5ltYJWtRPB69b8d6m4w,7286
|
|
20
|
-
ripperdoc/cli/commands/todos_cmd.py,sha256=7Q0B1NVqGtB3R29ndbn4m0VQQm-YQ7d4Wlk7vJ7dLQI,1848
|
|
21
|
-
ripperdoc/cli/commands/tools_cmd.py,sha256=3cMi0vN4mAUhpKqJtRgNvZfcKzRPaMs_pkYYXlyvSSU,384
|
|
22
|
-
ripperdoc/cli/ui/__init__.py,sha256=TxSzTYdITlrYmYVfins_w_jzPqqWRpqky5u1ikwvmtM,43
|
|
23
|
-
ripperdoc/cli/ui/context_display.py,sha256=3ezdtHVwltkPQ5etYwfqUh-fjnpPu8B3P81UzrdHxZs,10020
|
|
24
|
-
ripperdoc/cli/ui/helpers.py,sha256=TJCipP0neh-96ETQfGhusCJ4aWt5gLw1HZbI-3bWDpw,739
|
|
25
|
-
ripperdoc/cli/ui/rich_ui.py,sha256=jBTcJc5hTXEgeih7CtJUqo6sB7nVwEg3NGZ4DvJI9QA,43907
|
|
26
|
-
ripperdoc/cli/ui/spinner.py,sha256=XsPRwJ-70InLX9Qw50CEgSHn5oKA5PFIue8Un4edhUk,1449
|
|
27
|
-
ripperdoc/core/__init__.py,sha256=UemJCA-Y8df1466AX-YbRFj071zKajmqO1mi40YVW2g,40
|
|
28
|
-
ripperdoc/core/agents.py,sha256=sLgMeoDYXciBszRLCdbVCZRfxzXjlwGpWcx8qFk1Xm4,10240
|
|
29
|
-
ripperdoc/core/commands.py,sha256=NXCkljYbAP4dDoRy-_3semFNWxG4YAk9q82u8FTKH60,835
|
|
30
|
-
ripperdoc/core/config.py,sha256=gxR0uOhX11nv9fUQpcnQ1fHRtUEpt6v1GHSItyYxQYA,13240
|
|
31
|
-
ripperdoc/core/default_tools.py,sha256=PpZ49yjDzV5vtSkYq_quxY8u-nk5uJPp25RfMa9wZtA,2086
|
|
32
|
-
ripperdoc/core/permissions.py,sha256=lEKAUX9ksQxOFrPUkwwQe_3PMAr2xKgGBwjTOz8a8hM,8398
|
|
33
|
-
ripperdoc/core/query.py,sha256=f3sfzM9vSZJGbCUMg2wmT7iESCgFrNv2DqGYL38mJK0,26329
|
|
34
|
-
ripperdoc/core/system_prompt.py,sha256=OG_GUm9E30FnvL4p2L3_1A7oG54V0Kw5xRJPRzJrx2o,24066
|
|
35
|
-
ripperdoc/core/tool.py,sha256=GbmQSVc8XQXw4aDVwFpYGZV3OFbU5wIz7n3xNWlNeyI,6446
|
|
36
|
-
ripperdoc/sdk/__init__.py,sha256=aDSgI4lcCDs9cV3bxNmEEV3SuYx2aCd4VnUjs6H-R7E,213
|
|
37
|
-
ripperdoc/sdk/client.py,sha256=21f8viIh3BhSjXcI_MvgzfAcy7r289Thyhc_qgnQrB0,10556
|
|
38
|
-
ripperdoc/tools/__init__.py,sha256=RBFz0DDnztDXMqv_zRxFHVY-ez2HYcncx8zh_y-BX6w,42
|
|
39
|
-
ripperdoc/tools/background_shell.py,sha256=zdea03hpSGHEsVreyApn2bWMLzMQYo5ZmaHDp_Q11SA,9235
|
|
40
|
-
ripperdoc/tools/bash_output_tool.py,sha256=ljIOzTOnkbQfe3jExlhpUlMiLT6HpeD-1QI-D1CwHh8,3379
|
|
41
|
-
ripperdoc/tools/bash_tool.py,sha256=Ww92WIybH_5fqCJTEyR6JcIL6OQgj283uqvkFa1paqU,36071
|
|
42
|
-
ripperdoc/tools/file_edit_tool.py,sha256=zJib_Lqh9MlgPbNat9-LK1TTt8GsAXIuBEusuGWw8v8,11153
|
|
43
|
-
ripperdoc/tools/file_read_tool.py,sha256=EKA-OvDgRRzIMeK4t5ZFavB5ZTk0TzOJwxg-vD5ggho,5868
|
|
44
|
-
ripperdoc/tools/file_write_tool.py,sha256=X4b8PDJszRtp_B6daCsUsQAwUc-4PsNbXpm3FUG5sR0,4569
|
|
45
|
-
ripperdoc/tools/glob_tool.py,sha256=WxTz-cOz-whMxbQGCLpNmXfLgnxH9dh-1EFh11id64Q,4309
|
|
46
|
-
ripperdoc/tools/grep_tool.py,sha256=KyR5abvzy780evWu6tuMv9v6xGyGrTlLliJHan1N3S4,8098
|
|
47
|
-
ripperdoc/tools/kill_bash_tool.py,sha256=36F8w2Rm1IVQitwOAwS-D8NTnyQdWfKWIam44qlXErk,4625
|
|
48
|
-
ripperdoc/tools/ls_tool.py,sha256=H9pYsZKwx7j7Ow98eTx67KNKFbNO0yY-JUX34lAuhy8,8928
|
|
49
|
-
ripperdoc/tools/mcp_tools.py,sha256=msGNVKx8aDoLhs7Xvta1XMdLNP78W8Pi_CqLhwIjKiM,30309
|
|
50
|
-
ripperdoc/tools/multi_edit_tool.py,sha256=EpkCsjVTXTa4fOfETABjXNoKvQ6LRK8Xnv_t22N_Mcg,14968
|
|
51
|
-
ripperdoc/tools/notebook_edit_tool.py,sha256=y7_NuB7NrmUu-KkRQfkSegHRuiyPYdGxpjD9pFb_f5M,12064
|
|
52
|
-
ripperdoc/tools/task_tool.py,sha256=qp8jYLy8VMriny4fqmobYXh1dac2UyCBSAXZNk4iI0w,11739
|
|
53
|
-
ripperdoc/tools/todo_tool.py,sha256=aB0ejA_np3zLWTNUmC7yEVlx46tTtT_WgHEsqrbXIn4,12855
|
|
54
|
-
ripperdoc/tools/tool_search_tool.py,sha256=l3DU2UuCPU-XSvFDsdIrl0VkdwtR_E5dMk0idAP2p2w,13333
|
|
55
|
-
ripperdoc/utils/__init__.py,sha256=gdso60znB2hsYZ_YZBKVcuOY3QVfoqD2wHQ4pvr5lSw,37
|
|
56
|
-
ripperdoc/utils/bash_constants.py,sha256=KNn8bzB6nVU5jid9jvjiH4FAu8pP3DZONJ-OknJypAQ,1641
|
|
57
|
-
ripperdoc/utils/bash_output_utils.py,sha256=3Cf5wKJzRbUesmCNy5HtXIBtv0Z2BxklTfFHJ9q1T3w,1210
|
|
58
|
-
ripperdoc/utils/exit_code_handlers.py,sha256=QtO1iDxVAb8Xp03D6_QixPoJC-RQlcp3ssIo_rm4two,7973
|
|
59
|
-
ripperdoc/utils/log.py,sha256=QoqIxTctArJ3L5dwL6v4AZkMTGQozhDlNdM5BAn3QL8,2361
|
|
60
|
-
ripperdoc/utils/mcp.py,sha256=w2yHygSWNUKyM4AU2xZmfEMyfN3oZAHuswtEAD0v1Dc,14652
|
|
61
|
-
ripperdoc/utils/memory.py,sha256=5Shv8O8VjlUz0JHbIYm6oPLP5GAzzhJ3ZJIf3-GHXnE,7336
|
|
62
|
-
ripperdoc/utils/message_compaction.py,sha256=NVyDU58wsFuW85XWemKJqvtA1BMR-J8qCx10BIYKwnw,24112
|
|
63
|
-
ripperdoc/utils/messages.py,sha256=1vAYabUXbuywYQETH7GStQGehPnkxrZ7ZkzeXbv4JC4,14725
|
|
64
|
-
ripperdoc/utils/output_utils.py,sha256=9vROdxdZ_8FO1I_OxuTuTeUPWcJoWy9laTUFzTCDths,6162
|
|
65
|
-
ripperdoc/utils/path_utils.py,sha256=C45Q3OeXnj-0FVEtvf_tdG5922XB6HthUzlUCvfc17Y,1626
|
|
66
|
-
ripperdoc/utils/safe_get_cwd.py,sha256=R0zQYhM8kHpZDz12-JHx6ryF3Os2wncOOHXY45ZD7kg,585
|
|
67
|
-
ripperdoc/utils/sandbox_utils.py,sha256=G91P8dw2VFcCiCpjXZ4LvzbAPiO8REqMhw39eI5Z4dU,1123
|
|
68
|
-
ripperdoc/utils/session_history.py,sha256=xo4_Qaoy0odzElYcdnzU70TGlIak5e8uybkgFs9kSPQ,7478
|
|
69
|
-
ripperdoc/utils/session_usage.py,sha256=iz4B9MRhPbwemo9-beeZ8axcpGEe0kEc-Jghlexd_xU,2961
|
|
70
|
-
ripperdoc/utils/shell_token_utils.py,sha256=SduoSU-RERJdM_7gBn0urr5UXtl4XOpPgydBd2fwzWg,2500
|
|
71
|
-
ripperdoc/utils/todo.py,sha256=ZnYqCBX28U7viC7TPuNIf86TWmONMeHgsH7HrG_euPc,6889
|
|
72
|
-
ripperdoc/utils/permissions/__init__.py,sha256=-1aKvRC05kuvLacbeu7w1W5ANamOTAho4Y0lY2vz0W0,522
|
|
73
|
-
ripperdoc/utils/permissions/path_validation_utils.py,sha256=0saGffF-IwCHc_GrDimU8Vz_SAczJb_Ui29ea_hkj4E,5482
|
|
74
|
-
ripperdoc/utils/permissions/shell_command_validation.py,sha256=BkK-wEwAuJPoC4XIx2Zj6MF3gXcWReozIwigXgib0z0,2446
|
|
75
|
-
ripperdoc/utils/permissions/tool_permission_utils.py,sha256=6Fdu9-dMKhLsUExjEjoS0EUeRpEVN5UkqyseIC05YmM,9207
|
|
76
|
-
ripperdoc-0.2.0.dist-info/licenses/LICENSE,sha256=bRv9UhBor6GhnQDj12RciDcRfu0R7sB-lqCy1sWF75c,9242
|
|
77
|
-
ripperdoc-0.2.0.dist-info/METADATA,sha256=dwxYrx56ASM7ZbKyF5n6ZfZq9DwGfHU8sJWnOVCTY7M,5317
|
|
78
|
-
ripperdoc-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
79
|
-
ripperdoc-0.2.0.dist-info/entry_points.txt,sha256=79aohFxFPJmrQ3-Mhain04vb3EWpuc0EyzvDDUnwAu4,81
|
|
80
|
-
ripperdoc-0.2.0.dist-info/top_level.txt,sha256=u8LbdTr1a-laHgCO0Utl_R3QGFUhLxWelCDnP2ZgpCU,10
|
|
81
|
-
ripperdoc-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|