ripperdoc 0.2.7__py3-none-any.whl → 0.2.9__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 (87) hide show
  1. ripperdoc/__init__.py +1 -1
  2. ripperdoc/cli/cli.py +33 -115
  3. ripperdoc/cli/commands/__init__.py +70 -6
  4. ripperdoc/cli/commands/agents_cmd.py +6 -3
  5. ripperdoc/cli/commands/clear_cmd.py +1 -4
  6. ripperdoc/cli/commands/config_cmd.py +1 -1
  7. ripperdoc/cli/commands/context_cmd.py +3 -2
  8. ripperdoc/cli/commands/doctor_cmd.py +18 -4
  9. ripperdoc/cli/commands/help_cmd.py +11 -1
  10. ripperdoc/cli/commands/hooks_cmd.py +610 -0
  11. ripperdoc/cli/commands/models_cmd.py +26 -9
  12. ripperdoc/cli/commands/permissions_cmd.py +57 -37
  13. ripperdoc/cli/commands/resume_cmd.py +6 -4
  14. ripperdoc/cli/commands/status_cmd.py +4 -4
  15. ripperdoc/cli/commands/tasks_cmd.py +8 -4
  16. ripperdoc/cli/ui/file_mention_completer.py +64 -8
  17. ripperdoc/cli/ui/interrupt_handler.py +3 -4
  18. ripperdoc/cli/ui/message_display.py +5 -3
  19. ripperdoc/cli/ui/panels.py +13 -10
  20. ripperdoc/cli/ui/provider_options.py +247 -0
  21. ripperdoc/cli/ui/rich_ui.py +196 -77
  22. ripperdoc/cli/ui/spinner.py +25 -1
  23. ripperdoc/cli/ui/tool_renderers.py +8 -2
  24. ripperdoc/cli/ui/wizard.py +215 -0
  25. ripperdoc/core/agents.py +9 -3
  26. ripperdoc/core/config.py +49 -12
  27. ripperdoc/core/custom_commands.py +412 -0
  28. ripperdoc/core/default_tools.py +11 -2
  29. ripperdoc/core/hooks/__init__.py +99 -0
  30. ripperdoc/core/hooks/config.py +301 -0
  31. ripperdoc/core/hooks/events.py +535 -0
  32. ripperdoc/core/hooks/executor.py +496 -0
  33. ripperdoc/core/hooks/integration.py +344 -0
  34. ripperdoc/core/hooks/manager.py +745 -0
  35. ripperdoc/core/permissions.py +40 -8
  36. ripperdoc/core/providers/anthropic.py +548 -68
  37. ripperdoc/core/providers/gemini.py +70 -5
  38. ripperdoc/core/providers/openai.py +60 -5
  39. ripperdoc/core/query.py +140 -39
  40. ripperdoc/core/query_utils.py +2 -0
  41. ripperdoc/core/skills.py +9 -3
  42. ripperdoc/core/system_prompt.py +4 -2
  43. ripperdoc/core/tool.py +9 -5
  44. ripperdoc/sdk/client.py +2 -2
  45. ripperdoc/tools/ask_user_question_tool.py +5 -3
  46. ripperdoc/tools/background_shell.py +2 -1
  47. ripperdoc/tools/bash_output_tool.py +1 -1
  48. ripperdoc/tools/bash_tool.py +30 -20
  49. ripperdoc/tools/dynamic_mcp_tool.py +29 -8
  50. ripperdoc/tools/enter_plan_mode_tool.py +1 -1
  51. ripperdoc/tools/exit_plan_mode_tool.py +1 -1
  52. ripperdoc/tools/file_edit_tool.py +8 -4
  53. ripperdoc/tools/file_read_tool.py +9 -5
  54. ripperdoc/tools/file_write_tool.py +9 -5
  55. ripperdoc/tools/glob_tool.py +3 -2
  56. ripperdoc/tools/grep_tool.py +3 -2
  57. ripperdoc/tools/kill_bash_tool.py +1 -1
  58. ripperdoc/tools/ls_tool.py +1 -1
  59. ripperdoc/tools/mcp_tools.py +13 -10
  60. ripperdoc/tools/multi_edit_tool.py +8 -7
  61. ripperdoc/tools/notebook_edit_tool.py +7 -4
  62. ripperdoc/tools/skill_tool.py +1 -1
  63. ripperdoc/tools/task_tool.py +5 -4
  64. ripperdoc/tools/todo_tool.py +2 -2
  65. ripperdoc/tools/tool_search_tool.py +3 -2
  66. ripperdoc/utils/conversation_compaction.py +11 -7
  67. ripperdoc/utils/file_watch.py +8 -2
  68. ripperdoc/utils/json_utils.py +2 -1
  69. ripperdoc/utils/mcp.py +11 -3
  70. ripperdoc/utils/memory.py +4 -2
  71. ripperdoc/utils/message_compaction.py +21 -7
  72. ripperdoc/utils/message_formatting.py +11 -7
  73. ripperdoc/utils/messages.py +105 -66
  74. ripperdoc/utils/path_ignore.py +38 -12
  75. ripperdoc/utils/permissions/path_validation_utils.py +2 -1
  76. ripperdoc/utils/permissions/shell_command_validation.py +427 -91
  77. ripperdoc/utils/safe_get_cwd.py +2 -1
  78. ripperdoc/utils/session_history.py +13 -6
  79. ripperdoc/utils/todo.py +2 -1
  80. ripperdoc/utils/token_estimation.py +6 -1
  81. {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.9.dist-info}/METADATA +24 -3
  82. ripperdoc-0.2.9.dist-info/RECORD +123 -0
  83. ripperdoc-0.2.7.dist-info/RECORD +0 -113
  84. {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.9.dist-info}/WHEEL +0 -0
  85. {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.9.dist-info}/entry_points.txt +0 -0
  86. {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.9.dist-info}/licenses/LICENSE +0 -0
  87. {ripperdoc-0.2.7.dist-info → ripperdoc-0.2.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,247 @@
1
+ """
2
+ Provider metadata used by interactive UI flows.
3
+
4
+ Each provider option represents exactly one protocol endpoint. Vendors that
5
+ offer multiple protocols (for example, DeepSeek exposing both OpenAI-style and
6
+ Anthropic-style APIs on different URLs) should be modeled as distinct provider
7
+ options so that protocol-specific defaults stay unambiguous.
8
+ """
9
+
10
+ from dataclasses import dataclass
11
+ from typing import Dict, List, Optional, Sequence, Tuple
12
+
13
+ from ripperdoc.core.config import ProviderType
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class ProviderOption:
18
+ """A single provider choice with protocol and UX defaults."""
19
+
20
+ key: str
21
+ protocol: ProviderType
22
+ default_model: str
23
+ model_suggestions: Tuple[str, ...] = ()
24
+ default_api_base: Optional[str] = None
25
+
26
+ @property
27
+ def label(self) -> str:
28
+ """Display label shown to the user."""
29
+ return self.key
30
+
31
+ def with_api_base(self, api_base: Optional[str]) -> "ProviderOption":
32
+ """Return a copy that overrides the default API base."""
33
+ return ProviderOption(
34
+ key=self.key,
35
+ protocol=self.protocol,
36
+ default_model=self.default_model,
37
+ model_suggestions=self.model_suggestions,
38
+ default_api_base=api_base if api_base else self.default_api_base,
39
+ )
40
+
41
+
42
+ class ProviderRegistry:
43
+ """Registry for known providers to keep wizard logic declarative."""
44
+
45
+ def __init__(self, providers: Sequence[ProviderOption], default_key: str) -> None:
46
+ if not providers:
47
+ raise ValueError("Provider registry cannot be empty")
48
+ self._providers: List[ProviderOption] = list(providers)
49
+ self._index: Dict[str, ProviderOption] = {p.key: p for p in providers}
50
+ if default_key not in self._index:
51
+ raise ValueError(f"Default provider '{default_key}' not found in registry")
52
+ self._default_key = default_key
53
+
54
+ @property
55
+ def providers(self) -> List[ProviderOption]:
56
+ """Return providers in display order."""
57
+ return list(self._providers)
58
+
59
+ @property
60
+ def default_choice(self) -> ProviderOption:
61
+ """Return the default provider selection."""
62
+ return self._index[self._default_key]
63
+
64
+ def get(self, key: str) -> Optional[ProviderOption]:
65
+ """Look up a provider option by key."""
66
+ return self._index.get(key)
67
+
68
+ def keys(self) -> List[str]:
69
+ """Return provider keys in display order."""
70
+ return [p.key for p in self._providers]
71
+
72
+
73
+ def default_model_for_protocol(protocol: ProviderType) -> str:
74
+ """Reasonable default model per protocol family."""
75
+ if protocol == ProviderType.ANTHROPIC:
76
+ return "claude-3-5-sonnet-20241022"
77
+ if protocol == ProviderType.GEMINI:
78
+ return "gemini-1.5-pro"
79
+ return "gpt-4o-mini"
80
+
81
+
82
+ KNOWN_PROVIDERS = ProviderRegistry(
83
+ providers=[
84
+ ProviderOption(
85
+ key="deepseek",
86
+ protocol=ProviderType.OPENAI_COMPATIBLE,
87
+ default_model="deepseek-chat",
88
+ model_suggestions=("deepseek-chat", "deepseek-reasoner"),
89
+ default_api_base="https://api.deepseek.com/v1",
90
+ ),
91
+ ProviderOption(
92
+ key="openai",
93
+ protocol=ProviderType.OPENAI_COMPATIBLE,
94
+ default_model="gpt-4o-mini",
95
+ model_suggestions=(
96
+ "gpt-5.1",
97
+ "gpt-5.1-chat",
98
+ "gpt-5.1-codex",
99
+ "gpt-4o",
100
+ "gpt-4-turbo",
101
+ "o1-preview",
102
+ "o1-mini",
103
+ ),
104
+ default_api_base="https://api.openai.com/v1",
105
+ ),
106
+ ProviderOption(
107
+ key="openrouter",
108
+ protocol=ProviderType.OPENAI_COMPATIBLE,
109
+ default_model="openai/gpt-4o-mini",
110
+ model_suggestions=(
111
+ "openai/gpt-4o-mini",
112
+ "meta-llama/llama-3.1-8b-instruct",
113
+ "google/gemini-flash-1.5",
114
+ ),
115
+ default_api_base="https://openrouter.ai/api/v1",
116
+ ),
117
+ ProviderOption(
118
+ key="anthropic",
119
+ protocol=ProviderType.ANTHROPIC,
120
+ default_model="claude-3-5-sonnet-20241022",
121
+ model_suggestions=(
122
+ "claude-3-5-sonnet-20241022",
123
+ "claude-3-5-haiku-20241022",
124
+ "claude-3-opus-20240229",
125
+ "claude-3-sonnet-20240229",
126
+ "claude-3-haiku-20240307",
127
+ ),
128
+ default_api_base=None,
129
+ ),
130
+ ProviderOption(
131
+ key="openai_compatible",
132
+ protocol=ProviderType.OPENAI_COMPATIBLE,
133
+ default_model="gpt-4o-mini",
134
+ model_suggestions=(
135
+ "gpt-4o-mini",
136
+ "gpt-4o",
137
+ "gpt-3.5-turbo",
138
+ ),
139
+ default_api_base=None,
140
+ ),
141
+ ProviderOption(
142
+ key="mistralai",
143
+ protocol=ProviderType.OPENAI_COMPATIBLE,
144
+ default_model="mistral-small-creative",
145
+ model_suggestions=(
146
+ "mistral-small-creative",
147
+ "mistral-large-latest",
148
+ "mistral-small-latest",
149
+ "devstral-2512",
150
+ "ministral-14b-2512",
151
+ "ministral-8b-2512",
152
+ "codestral-latest",
153
+ "pixtral-large-latest",
154
+ ),
155
+ default_api_base="https://api.mistral.ai/v1",
156
+ ),
157
+ ProviderOption(
158
+ key="google",
159
+ protocol=ProviderType.GEMINI,
160
+ default_model="gemini-1.5-pro",
161
+ model_suggestions=(
162
+ "gemini-2.5-pro",
163
+ "gemini-2.5-flash-lite",
164
+ "gemini-2.5-flash",
165
+ "gemini-3-pro-preview",
166
+ "gemini-3-flash-preview",
167
+ ),
168
+ default_api_base="https://generativelanguage.googleapis.com/v1beta",
169
+ ),
170
+ ProviderOption(
171
+ key="moonshot",
172
+ protocol=ProviderType.OPENAI_COMPATIBLE,
173
+ default_model="kimi-k2-turbo-preview",
174
+ model_suggestions=(
175
+ "kimi-k2-0905-preview",
176
+ "kimi-k2-0711-preview",
177
+ "kimi-k2-turbo-preview",
178
+ "kimi-k2-thinking",
179
+ "kimi-k2-thinking-turbo",
180
+ ),
181
+ default_api_base="https://api.moonshot.cn/v1",
182
+ ),
183
+ ProviderOption(
184
+ key="qwen",
185
+ protocol=ProviderType.OPENAI_COMPATIBLE,
186
+ default_model="qwen-turbo",
187
+ model_suggestions=(
188
+ "qwen-turbo",
189
+ "qwen-plus",
190
+ "qwen-max",
191
+ "qwen2.5-32b",
192
+ "qwen2.5-coder-32b",
193
+ ),
194
+ default_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
195
+ ),
196
+ ProviderOption(
197
+ key="zhipu",
198
+ protocol=ProviderType.OPENAI_COMPATIBLE,
199
+ default_model="glm-4-flash",
200
+ model_suggestions=(
201
+ "glm-4-plus",
202
+ "glm-4-air-250414",
203
+ "glm-4-airx",
204
+ "glm-4-long",
205
+ "glm-4-flashx",
206
+ "glm-4-flash-250414",
207
+ "glm-4.6",
208
+ "glm-4.5",
209
+ "glm-4.5-air",
210
+ "glm-4.5-airx",
211
+ "glm-4.5-x",
212
+ "glm-4.5-flash",
213
+ ),
214
+ default_api_base="https://open.bigmodel.cn/api/paas/v4",
215
+ ),
216
+ ProviderOption(
217
+ key="minimax",
218
+ protocol=ProviderType.OPENAI_COMPATIBLE,
219
+ default_model="MiniMax-M2",
220
+ model_suggestions=("MiniMax-M2",),
221
+ default_api_base="https://api.minimax.chat/v1",
222
+ ),
223
+ ProviderOption(
224
+ key="siliconflow",
225
+ protocol=ProviderType.OPENAI_COMPATIBLE,
226
+ default_model="deepseek-ai/DeepSeek-V3.2",
227
+ model_suggestions=(
228
+ "deepseek-ai/DeepSeek-V3.2",
229
+ "Qwen/Qwen2.5-32B-Instruct",
230
+ "Qwen/Qwen3-Coder-480B-A35B-Instruct",
231
+ "zai-org/GLM-4.6",
232
+ "moonshotai/Kimi-K2-Thinking",
233
+ "MiniMaxAI/MiniMax-M2",
234
+ ),
235
+ default_api_base="https://api.siliconflow.cn/v1",
236
+ ),
237
+ ],
238
+ default_key="deepseek",
239
+ )
240
+
241
+
242
+ __all__ = [
243
+ "KNOWN_PROVIDERS",
244
+ "ProviderOption",
245
+ "ProviderRegistry",
246
+ "default_model_for_protocol",
247
+ ]