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.
Files changed (51) hide show
  1. ripperdoc/__init__.py +1 -1
  2. ripperdoc/cli/cli.py +66 -8
  3. ripperdoc/cli/commands/__init__.py +4 -0
  4. ripperdoc/cli/commands/agents_cmd.py +22 -0
  5. ripperdoc/cli/commands/context_cmd.py +11 -1
  6. ripperdoc/cli/commands/doctor_cmd.py +200 -0
  7. ripperdoc/cli/commands/memory_cmd.py +209 -0
  8. ripperdoc/cli/commands/models_cmd.py +25 -0
  9. ripperdoc/cli/commands/tasks_cmd.py +27 -0
  10. ripperdoc/cli/ui/rich_ui.py +156 -9
  11. ripperdoc/core/agents.py +4 -2
  12. ripperdoc/core/config.py +48 -3
  13. ripperdoc/core/default_tools.py +16 -2
  14. ripperdoc/core/permissions.py +19 -0
  15. ripperdoc/core/query.py +231 -297
  16. ripperdoc/core/query_utils.py +537 -0
  17. ripperdoc/core/system_prompt.py +2 -1
  18. ripperdoc/core/tool.py +13 -0
  19. ripperdoc/tools/background_shell.py +9 -3
  20. ripperdoc/tools/bash_tool.py +15 -0
  21. ripperdoc/tools/file_edit_tool.py +7 -0
  22. ripperdoc/tools/file_read_tool.py +7 -0
  23. ripperdoc/tools/file_write_tool.py +7 -0
  24. ripperdoc/tools/glob_tool.py +55 -15
  25. ripperdoc/tools/grep_tool.py +7 -0
  26. ripperdoc/tools/ls_tool.py +242 -73
  27. ripperdoc/tools/mcp_tools.py +32 -10
  28. ripperdoc/tools/multi_edit_tool.py +11 -0
  29. ripperdoc/tools/notebook_edit_tool.py +6 -3
  30. ripperdoc/tools/task_tool.py +7 -0
  31. ripperdoc/tools/todo_tool.py +159 -25
  32. ripperdoc/tools/tool_search_tool.py +9 -0
  33. ripperdoc/utils/git_utils.py +276 -0
  34. ripperdoc/utils/json_utils.py +28 -0
  35. ripperdoc/utils/log.py +130 -29
  36. ripperdoc/utils/mcp.py +71 -6
  37. ripperdoc/utils/memory.py +14 -1
  38. ripperdoc/utils/message_compaction.py +26 -5
  39. ripperdoc/utils/messages.py +63 -4
  40. ripperdoc/utils/output_utils.py +36 -9
  41. ripperdoc/utils/permissions/path_validation_utils.py +6 -0
  42. ripperdoc/utils/safe_get_cwd.py +4 -0
  43. ripperdoc/utils/session_history.py +27 -9
  44. ripperdoc/utils/todo.py +2 -2
  45. {ripperdoc-0.2.0.dist-info → ripperdoc-0.2.2.dist-info}/METADATA +4 -2
  46. ripperdoc-0.2.2.dist-info/RECORD +86 -0
  47. ripperdoc-0.2.0.dist-info/RECORD +0 -81
  48. {ripperdoc-0.2.0.dist-info → ripperdoc-0.2.2.dist-info}/WHEEL +0 -0
  49. {ripperdoc-0.2.0.dist-info → ripperdoc-0.2.2.dist-info}/entry_points.txt +0 -0
  50. {ripperdoc-0.2.0.dist-info → ripperdoc-0.2.2.dist-info}/licenses/LICENSE +0 -0
  51. {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
- pass
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 mirror the claude-code compact implementation.
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.error(f"Failed to estimate tokens for tool schema: {exc}")
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 following claude-code semantics."""
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(f"[message_compaction] Cleanup callback failed: {exc}")
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=max(0, tokens_before - tokens_after),
674
+ tokens_saved=tokens_saved,
654
675
  cleared_tool_ids=ids_to_remove,
655
676
  was_compacted=bool(ids_to_remove),
656
677
  )
@@ -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
- pass
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} input_msgs={len(messages)} "
378
- f"normalized={len(normalized)} tool_results_seen={tool_results_seen} "
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}"
@@ -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
- # Truncate: keep start and end
135
- start_chars = min(TRUNCATE_KEEP_START, max_chars // 2)
136
- end_chars = min(TRUNCATE_KEEP_END, max_chars - start_chars - 100)
137
-
138
- truncated = (
139
- text[:start_chars]
140
- + f"\n\n... [Output truncated: {original_length - start_chars - end_chars} characters omitted] ...\n\n"
141
- + text[-end_chars:]
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
 
@@ -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(f"Failed to parse session history line: {exc}")
105
+ logger.debug(
106
+ f"Failed to parse session history line: {exc}",
107
+ exc_info=True,
108
+ )
106
109
  continue
107
- except Exception as exc:
108
- logger.error(f"Failed to load seen IDs from session {self.session_id}: {exc}")
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 as exc:
137
+ except Exception:
132
138
  # Avoid crashing the UI if logging fails
133
- logger.error(f"Failed to append message to session {self.session_id}: {exc}")
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.error(f"Failed to load session summary from {jsonl_path}: {exc}")
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(f"Failed to deserialize message in session {session_id}: {exc}")
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 as exc:
212
- logger.error(f"Failed to load session messages for {session_id}: {exc}")
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 as exc:
87
- logger.error(f"Failed to load todos from {path}: {exc}")
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.0
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,,
@@ -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,,