ripperdoc 0.2.10__py3-none-any.whl → 0.3.1__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 +164 -57
- ripperdoc/cli/commands/__init__.py +4 -0
- ripperdoc/cli/commands/agents_cmd.py +3 -7
- ripperdoc/cli/commands/doctor_cmd.py +29 -0
- ripperdoc/cli/commands/memory_cmd.py +2 -1
- ripperdoc/cli/commands/models_cmd.py +61 -5
- ripperdoc/cli/commands/resume_cmd.py +1 -0
- ripperdoc/cli/commands/skills_cmd.py +103 -0
- ripperdoc/cli/commands/stats_cmd.py +4 -4
- ripperdoc/cli/commands/status_cmd.py +10 -0
- ripperdoc/cli/commands/tasks_cmd.py +6 -3
- ripperdoc/cli/commands/themes_cmd.py +139 -0
- ripperdoc/cli/ui/file_mention_completer.py +63 -13
- ripperdoc/cli/ui/helpers.py +6 -3
- ripperdoc/cli/ui/interrupt_listener.py +233 -0
- ripperdoc/cli/ui/message_display.py +7 -0
- ripperdoc/cli/ui/panels.py +13 -8
- ripperdoc/cli/ui/rich_ui.py +513 -84
- ripperdoc/cli/ui/spinner.py +68 -5
- ripperdoc/cli/ui/tool_renderers.py +10 -9
- ripperdoc/cli/ui/wizard.py +18 -11
- ripperdoc/core/agents.py +4 -0
- ripperdoc/core/config.py +235 -0
- ripperdoc/core/default_tools.py +1 -0
- ripperdoc/core/hooks/llm_callback.py +0 -1
- ripperdoc/core/hooks/manager.py +6 -0
- ripperdoc/core/permissions.py +123 -39
- ripperdoc/core/providers/openai.py +55 -9
- ripperdoc/core/query.py +349 -108
- ripperdoc/core/query_utils.py +17 -14
- ripperdoc/core/skills.py +1 -0
- ripperdoc/core/theme.py +298 -0
- ripperdoc/core/tool.py +8 -3
- ripperdoc/protocol/__init__.py +14 -0
- ripperdoc/protocol/models.py +300 -0
- ripperdoc/protocol/stdio.py +1453 -0
- ripperdoc/tools/background_shell.py +49 -5
- ripperdoc/tools/bash_tool.py +75 -9
- ripperdoc/tools/file_edit_tool.py +98 -29
- ripperdoc/tools/file_read_tool.py +139 -8
- ripperdoc/tools/file_write_tool.py +46 -3
- ripperdoc/tools/grep_tool.py +98 -8
- ripperdoc/tools/lsp_tool.py +9 -15
- ripperdoc/tools/multi_edit_tool.py +26 -3
- ripperdoc/tools/skill_tool.py +52 -1
- ripperdoc/tools/task_tool.py +33 -8
- ripperdoc/utils/file_watch.py +12 -6
- ripperdoc/utils/image_utils.py +125 -0
- ripperdoc/utils/log.py +30 -3
- ripperdoc/utils/lsp.py +9 -3
- ripperdoc/utils/mcp.py +80 -18
- ripperdoc/utils/message_formatting.py +2 -2
- ripperdoc/utils/messages.py +177 -32
- ripperdoc/utils/pending_messages.py +50 -0
- ripperdoc/utils/permissions/shell_command_validation.py +3 -3
- ripperdoc/utils/permissions/tool_permission_utils.py +9 -3
- ripperdoc/utils/platform.py +198 -0
- ripperdoc/utils/session_heatmap.py +1 -3
- ripperdoc/utils/session_history.py +2 -2
- ripperdoc/utils/session_stats.py +1 -0
- ripperdoc/utils/shell_utils.py +8 -5
- ripperdoc/utils/todo.py +0 -6
- {ripperdoc-0.2.10.dist-info → ripperdoc-0.3.1.dist-info}/METADATA +49 -17
- ripperdoc-0.3.1.dist-info/RECORD +136 -0
- {ripperdoc-0.2.10.dist-info → ripperdoc-0.3.1.dist-info}/WHEEL +1 -1
- ripperdoc/cli/ui/interrupt_handler.py +0 -174
- ripperdoc/sdk/__init__.py +0 -9
- ripperdoc/sdk/client.py +0 -408
- ripperdoc-0.2.10.dist-info/RECORD +0 -129
- {ripperdoc-0.2.10.dist-info → ripperdoc-0.3.1.dist-info}/entry_points.txt +0 -0
- {ripperdoc-0.2.10.dist-info → ripperdoc-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {ripperdoc-0.2.10.dist-info → ripperdoc-0.3.1.dist-info}/top_level.txt +0 -0
ripperdoc/utils/shell_utils.py
CHANGED
|
@@ -9,15 +9,16 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
import os
|
|
11
11
|
import shutil
|
|
12
|
+
from pathlib import PureWindowsPath
|
|
12
13
|
from typing import Iterable, List
|
|
13
14
|
|
|
14
15
|
from ripperdoc.utils.log import get_logger
|
|
16
|
+
from ripperdoc.utils.platform import is_windows
|
|
15
17
|
|
|
16
18
|
logger = get_logger()
|
|
17
19
|
|
|
18
20
|
# Common locations to probe if shutil.which misses an otherwise standard path.
|
|
19
21
|
_COMMON_BIN_DIRS: tuple[str, ...] = ("/bin", "/usr/bin", "/usr/local/bin", "/opt/homebrew/bin")
|
|
20
|
-
_IS_WINDOWS = os.name == "nt"
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
def _is_executable(path: str) -> bool:
|
|
@@ -93,7 +94,7 @@ def find_suitable_shell() -> str:
|
|
|
93
94
|
current_is_bash = "bash" in current_shell
|
|
94
95
|
current_is_zsh = "zsh" in current_shell
|
|
95
96
|
|
|
96
|
-
if not
|
|
97
|
+
if not is_windows():
|
|
97
98
|
if (current_is_bash or current_is_zsh) and _is_executable(current_shell):
|
|
98
99
|
logger.debug("Using SHELL from environment: %s", current_shell)
|
|
99
100
|
return current_shell
|
|
@@ -149,9 +150,11 @@ def build_shell_command(shell_path: str, command: str) -> List[str]:
|
|
|
149
150
|
For bash/zsh (including Git Bash), use -lc to run as login shell.
|
|
150
151
|
For cmd.exe fallback, use /d /s /c.
|
|
151
152
|
"""
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
# Use PureWindowsPath to correctly extract the shell name from the path.
|
|
154
|
+
# This handles both Windows-style (C:\\Windows\\System32\\cmd.exe) and Unix-style
|
|
155
|
+
# (/usr/bin/bash) paths, as well as simple names (cmd, bash) on any platform.
|
|
156
|
+
shell_name = PureWindowsPath(shell_path).name.lower()
|
|
157
|
+
if shell_name in ("cmd", "cmd.exe"):
|
|
155
158
|
return [shell_path, "/d", "/s", "/c", command]
|
|
156
159
|
return [shell_path, "-lc", command]
|
|
157
160
|
|
ripperdoc/utils/todo.py
CHANGED
|
@@ -185,12 +185,6 @@ def format_todo_summary(todos: Sequence[TodoItem]) -> str:
|
|
|
185
185
|
f"{stats['by_status']['completed']} completed)."
|
|
186
186
|
)
|
|
187
187
|
|
|
188
|
-
next_item = get_next_actionable(todos)
|
|
189
|
-
if next_item:
|
|
190
|
-
summary += f" Next to tackle: {next_item.content} (id: {next_item.id}, status: {next_item.status})."
|
|
191
|
-
elif stats["total"] == 0:
|
|
192
|
-
summary += " No todos stored yet."
|
|
193
|
-
|
|
194
188
|
return summary
|
|
195
189
|
|
|
196
190
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ripperdoc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: AI-powered terminal assistant for coding tasks
|
|
5
5
|
Author: Ripperdoc Team
|
|
6
6
|
License: Apache-2.0
|
|
@@ -23,10 +23,11 @@ Requires-Dist: python-dotenv>=1.0.0
|
|
|
23
23
|
Requires-Dist: aiofiles>=23.0.0
|
|
24
24
|
Requires-Dist: prompt-toolkit>=3.0.0
|
|
25
25
|
Requires-Dist: PyYAML>=6.0.0
|
|
26
|
-
Requires-Dist: mcp[cli]>=1.
|
|
26
|
+
Requires-Dist: mcp[cli]>=1.25.0
|
|
27
27
|
Requires-Dist: json_repair>=0.54.2
|
|
28
28
|
Requires-Dist: tiktoken>=0.7.0
|
|
29
29
|
Requires-Dist: google-genai>=0.3.0
|
|
30
|
+
Requires-Dist: charset-normalizer>=3.0.0
|
|
30
31
|
Provides-Extra: dev
|
|
31
32
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
32
33
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -99,27 +100,22 @@ pip install git+https://github.com/quantmew/ripperdoc.git
|
|
|
99
100
|
Or install from source:
|
|
100
101
|
```bash
|
|
101
102
|
# Clone the repository
|
|
102
|
-
git clone
|
|
103
|
-
cd
|
|
103
|
+
git clone https://github.com/quantmew/ripperdoc.git
|
|
104
|
+
cd ripperdoc
|
|
104
105
|
|
|
105
106
|
# Install from source
|
|
106
107
|
pip install -e .
|
|
107
108
|
```
|
|
108
109
|
|
|
109
|
-
### Configuration
|
|
110
110
|
|
|
111
|
-
Set your API key as an environment variable:
|
|
112
|
-
```bash
|
|
113
|
-
export OPENAI_API_KEY="your-api-key-here"
|
|
114
|
-
# or for Anthropic Claude
|
|
115
|
-
export ANTHROPIC_API_KEY="your-api-key-here"
|
|
116
|
-
```
|
|
117
111
|
|
|
118
112
|
## Usage
|
|
119
113
|
|
|
120
114
|
### Interactive Mode (Recommended)
|
|
121
115
|
```bash
|
|
122
116
|
ripperdoc
|
|
117
|
+
# or use the short alias
|
|
118
|
+
rd
|
|
123
119
|
```
|
|
124
120
|
|
|
125
121
|
This launches an interactive session where you can:
|
|
@@ -128,6 +124,13 @@ This launches an interactive session where you can:
|
|
|
128
124
|
- Execute commands
|
|
129
125
|
- Navigate and explore files
|
|
130
126
|
|
|
127
|
+
**Options:**
|
|
128
|
+
- `--yolo` - Skip permission prompts (safe mode is on by default)
|
|
129
|
+
- `--model <model_name>` - Specify a model (e.g., `claude-sonnet-4-20250514`, `gpt-4o`)
|
|
130
|
+
- `--tools <tool_list>` - Filter available tools (comma-separated, or "" for none)
|
|
131
|
+
- `--no-mcp` - Disable MCP server integration
|
|
132
|
+
- `--verbose` - Enable verbose logging
|
|
133
|
+
|
|
131
134
|
### Python SDK (headless)
|
|
132
135
|
|
|
133
136
|
Use Ripperdoc without the terminal UI via the new Python SDK. See [docs/SDK_USAGE.md](docs/SDK_USAGE.md) for examples of the one-shot `query` helper and the session-based `RipperdocClient`. 中文指南见 [docs/SDK_USAGE_CN.md](docs/SDK_USAGE_CN.md)。
|
|
@@ -143,38 +146,67 @@ See the [examples/](examples/) directory for complete SDK usage examples.
|
|
|
143
146
|
|
|
144
147
|
### Safe Mode Permissions
|
|
145
148
|
|
|
146
|
-
Safe mode is
|
|
149
|
+
Safe mode is enabled by default. When prompted:
|
|
150
|
+
- Type `y` or `yes` to allow a single operation
|
|
151
|
+
- Type `a` or `always` to allow all operations of that type for the session
|
|
152
|
+
- Type `n` or `no` to deny the operation
|
|
153
|
+
|
|
154
|
+
Use `--yolo` flag to skip all permission prompts:
|
|
155
|
+
```bash
|
|
156
|
+
ripperdoc --yolo
|
|
157
|
+
```
|
|
147
158
|
|
|
148
159
|
### Agent Skills
|
|
149
160
|
|
|
150
161
|
Extend Ripperdoc with reusable Skill bundles:
|
|
151
162
|
|
|
152
|
-
- Personal skills
|
|
153
|
-
- Project skills
|
|
154
|
-
- Each `SKILL.md` starts with YAML frontmatter
|
|
155
|
-
-
|
|
156
|
-
-
|
|
163
|
+
- **Personal skills**: `~/.ripperdoc/skills/<skill-name>/SKILL.md`
|
|
164
|
+
- **Project skills**: `.ripperdoc/skills/<skill-name>/SKILL.md` (can be checked into git)
|
|
165
|
+
- Each `SKILL.md` starts with YAML frontmatter:
|
|
166
|
+
- `name` - Skill identifier
|
|
167
|
+
- `description` - What the skill does
|
|
168
|
+
- `allowed-tools` (optional) - Restrict which tools the skill can use
|
|
169
|
+
- `model` (optional) - Suggest a specific model for this skill
|
|
170
|
+
- `max-thinking-tokens` (optional) - Control thinking budget
|
|
171
|
+
- `disable-model-invocation` (optional) - Use skill without calling the model
|
|
172
|
+
- Add supporting files alongside `SKILL.md` as needed
|
|
173
|
+
- Skills are auto-discovered and loaded on demand via the `Skill` tool
|
|
174
|
+
|
|
175
|
+
**Built-in skills:** PDF manipulation (`pdf`), PowerPoint (`pptx`), Excel (`xlsx`)
|
|
157
176
|
|
|
158
177
|
## Examples
|
|
159
178
|
|
|
160
179
|
### Code Analysis
|
|
161
180
|
```
|
|
162
181
|
> Can you explain what this function does?
|
|
182
|
+
> Find all references to the `parse_config` function
|
|
163
183
|
```
|
|
164
184
|
|
|
165
185
|
### File Operations
|
|
166
186
|
```
|
|
167
187
|
> Read the main.py file and suggest improvements
|
|
188
|
+
> Create a new component called UserProfile.tsx
|
|
189
|
+
> Update all imports to use the new package structure
|
|
168
190
|
```
|
|
169
191
|
|
|
170
192
|
### Code Generation
|
|
171
193
|
```
|
|
172
194
|
> Create a new Python script that implements a REST API client
|
|
195
|
+
> Generate unit tests for the auth module
|
|
196
|
+
> Add error handling to the database connection code
|
|
173
197
|
```
|
|
174
198
|
|
|
175
199
|
### Project Navigation
|
|
176
200
|
```
|
|
177
201
|
> Show me all the Python files in the project
|
|
202
|
+
> Find where the user authentication logic is implemented
|
|
203
|
+
> List all API endpoints in the project
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### MCP Integration
|
|
207
|
+
```
|
|
208
|
+
> What MCP servers are available?
|
|
209
|
+
> Query the context7 documentation for React hooks
|
|
178
210
|
```
|
|
179
211
|
|
|
180
212
|
## Development
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
ripperdoc/__init__.py,sha256=WpPS91f5Gza7_d_r4nyqaZ8bJMFXt486w-h3D1Ha9qk,66
|
|
2
|
+
ripperdoc/__main__.py,sha256=1Avq2MceBfwUlNsfasC8n4dqVL_V56Bl3DRsnY4_Nxk,370
|
|
3
|
+
ripperdoc/cli/__init__.py,sha256=03wf6gXBcEgXJrDJS-W_5BEG_DdJ_ep7CxQFPML-73g,35
|
|
4
|
+
ripperdoc/cli/cli.py,sha256=OZgN803jYmzdKxynHWG7VNwd7dQhM1KdYakXDyMlZT8,21826
|
|
5
|
+
ripperdoc/cli/commands/__init__.py,sha256=Up-tTlq3lhxDt-YEdiOoHwfRyIdb8nlL5waECzRg-xY,4858
|
|
6
|
+
ripperdoc/cli/commands/agents_cmd.py,sha256=agDTXwZWSr-fmtp_afuD1kMTA1NalMHtoKQ3eVtJMFs,15699
|
|
7
|
+
ripperdoc/cli/commands/base.py,sha256=4KUjxCM04MwbSMUKVNEBph_jeAKPI8b5MHsUFoz7l5g,386
|
|
8
|
+
ripperdoc/cli/commands/clear_cmd.py,sha256=iyOLWtgYwJKNjG-el2mwFRA3VWGIXrNNLl32Xdwpq9o,584
|
|
9
|
+
ripperdoc/cli/commands/compact_cmd.py,sha256=uR_nB1OX7cUL1TOJoefwdO31Qfyjd0nZSSttErqUxbA,473
|
|
10
|
+
ripperdoc/cli/commands/config_cmd.py,sha256=QcFYOOmNFSHmw6K2vY_wfKrYXi8PSzz6koJFREJoF_c,884
|
|
11
|
+
ripperdoc/cli/commands/context_cmd.py,sha256=tM8o2ZfX-axFYaFLsWOTSER_Yevk3ANr2numHfuh2UE,5232
|
|
12
|
+
ripperdoc/cli/commands/cost_cmd.py,sha256=yD9LSqgxVvYNTDPnEHxugjyLWcmbtH5dXim7DIW9zXc,2822
|
|
13
|
+
ripperdoc/cli/commands/doctor_cmd.py,sha256=w-AVph1fvmlnbuTeUdAL19zikj4MmNRxmXlhcvR2SXQ,8188
|
|
14
|
+
ripperdoc/cli/commands/exit_cmd.py,sha256=lEGLMVozoOM2Ea_Yw-sbaIvAbfb_Nx3UTpC49ga-MZ8,376
|
|
15
|
+
ripperdoc/cli/commands/help_cmd.py,sha256=jyK6U2bsGEIwFpu08slVHKfxRyS3oblnRXdqSgU_W4w,978
|
|
16
|
+
ripperdoc/cli/commands/hooks_cmd.py,sha256=-ixQhKb1CX2c7_2zDdAqXV9ThnMf31UH3a9UBERD9mw,21026
|
|
17
|
+
ripperdoc/cli/commands/mcp_cmd.py,sha256=ZCnswx0TIiaiUUsIX7NpHaLZLZtvlUhBnN12s_ZtPCA,2424
|
|
18
|
+
ripperdoc/cli/commands/memory_cmd.py,sha256=BsYYUosmnIs92mwgHH1e3DdzOj83iJ5_AJ8kBeSkRCw,6594
|
|
19
|
+
ripperdoc/cli/commands/models_cmd.py,sha256=LYebi7s9kv6xxlSqX3Pb1AsWY9S-xp0ikdtPVECinvo,18635
|
|
20
|
+
ripperdoc/cli/commands/permissions_cmd.py,sha256=aIMIvmt78nB2Q-Qa5ojqClUOsPRcoyeDIuhOJX8xg2k,11559
|
|
21
|
+
ripperdoc/cli/commands/resume_cmd.py,sha256=Pil2gJIkjf9fIFrxTyVXTwS7kzsg14CVg1SNQPZYAmw,4295
|
|
22
|
+
ripperdoc/cli/commands/skills_cmd.py,sha256=OFDLy2g_o_GDzdatk18E-Xv4bhVG80MQUr_PQLmTveQ,3496
|
|
23
|
+
ripperdoc/cli/commands/stats_cmd.py,sha256=I6nFZndBy_VRcUAxXAjplSjIzA-5UqRK4HlQJbpHydg,7857
|
|
24
|
+
ripperdoc/cli/commands/status_cmd.py,sha256=9pI_GF4mxR9cQXF-HEURZb0qO6GWp2hcy3rzaVW98II,5962
|
|
25
|
+
ripperdoc/cli/commands/tasks_cmd.py,sha256=tghFKy0ENeJ9Mf0h5Waceq8l9JXP5xTLsJHP4ZkibbQ,9044
|
|
26
|
+
ripperdoc/cli/commands/themes_cmd.py,sha256=b3Ti-KmRF9XVk1jtS7bkz5F8317yu1fyp1I89SSpfqI,4019
|
|
27
|
+
ripperdoc/cli/commands/todos_cmd.py,sha256=7Q0B1NVqGtB3R29ndbn4m0VQQm-YQ7d4Wlk7vJ7dLQI,1848
|
|
28
|
+
ripperdoc/cli/commands/tools_cmd.py,sha256=3cMi0vN4mAUhpKqJtRgNvZfcKzRPaMs_pkYYXlyvSSU,384
|
|
29
|
+
ripperdoc/cli/ui/__init__.py,sha256=TxSzTYdITlrYmYVfins_w_jzPqqWRpqky5u1ikwvmtM,43
|
|
30
|
+
ripperdoc/cli/ui/context_display.py,sha256=3ezdtHVwltkPQ5etYwfqUh-fjnpPu8B3P81UzrdHxZs,10020
|
|
31
|
+
ripperdoc/cli/ui/file_mention_completer.py,sha256=ysNqZieQVlUb7DC4CP_FMKNeTG8AIqKLmJgl6HJBURo,13649
|
|
32
|
+
ripperdoc/cli/ui/helpers.py,sha256=iM7kMb-fMTO6n4_MDVrESE1P-Y7w8PXiIhCCLp5yyA4,2618
|
|
33
|
+
ripperdoc/cli/ui/interrupt_listener.py,sha256=m9NeyOSJ3f-zuLE4YzUUEoKuuxo7oBKuvY5Z1WabjoE,7223
|
|
34
|
+
ripperdoc/cli/ui/message_display.py,sha256=eaS80PBo9QfgWT-MX4jfQOjbt0vwQ4w1MDGKBWPrQOs,10856
|
|
35
|
+
ripperdoc/cli/ui/panels.py,sha256=kaf3sDG2AIcrdrqbASnqGYHySfSeMNozGFhqvZ4bTJs,2207
|
|
36
|
+
ripperdoc/cli/ui/provider_options.py,sha256=Ic30K1ev8w2oEcha4IjDYSoxw1tyCVB4hLoQpS_Y_5E,8369
|
|
37
|
+
ripperdoc/cli/ui/rich_ui.py,sha256=LkE22XdNE4sooX-SyVUec7qX_XDTHjExFTwhqj1MPY4,76870
|
|
38
|
+
ripperdoc/cli/ui/spinner.py,sha256=IlmMgyk-eA6Bk4fXDjbWs3AFL2iFPeWmnS0q28tWOgU,5175
|
|
39
|
+
ripperdoc/cli/ui/thinking_spinner.py,sha256=3zmxj3vd-1njdiHF2Afsm7RGiRl7645AEc7fTLKgAbU,2805
|
|
40
|
+
ripperdoc/cli/ui/tool_renderers.py,sha256=7ACcZoKU91kvFsk3YdP2TzibfI-W_F1dv-Ksr68rrYE,11280
|
|
41
|
+
ripperdoc/cli/ui/wizard.py,sha256=bFKJeQStJ2Opq_ih9tgchkJP14bMvI-PX-zHVwzMiy8,7423
|
|
42
|
+
ripperdoc/core/__init__.py,sha256=UemJCA-Y8df1466AX-YbRFj071zKajmqO1mi40YVW2g,40
|
|
43
|
+
ripperdoc/core/agents.py,sha256=Xl1HEJz8v-xIEhzgObeysgrz-SQBYbxYVRI4CvRl-w8,20539
|
|
44
|
+
ripperdoc/core/commands.py,sha256=NXCkljYbAP4dDoRy-_3semFNWxG4YAk9q82u8FTKH60,835
|
|
45
|
+
ripperdoc/core/config.py,sha256=4KvaGKG4bf9wX6haPvxJllokdpPbJVvfTIMfsC0maag,29936
|
|
46
|
+
ripperdoc/core/custom_commands.py,sha256=2BMYiBq15FDjl3aOa3styN6nARyfU7xFAb4ly2Vsp-w,14254
|
|
47
|
+
ripperdoc/core/default_tools.py,sha256=mpb9mqmrAjMqgcmpRU_uQF1G6vpYbp8nkiwrh71KQyM,5250
|
|
48
|
+
ripperdoc/core/permissions.py,sha256=7Fj44HB4yJj5bm54T_c85sdzjMFWWg_5kXm3CZqklI4,18424
|
|
49
|
+
ripperdoc/core/query.py,sha256=dC_sW2D2bPLI6nPM3VxFpTBA4fYYHHRNmE6zvy93pus,62057
|
|
50
|
+
ripperdoc/core/query_utils.py,sha256=2OQYeobFD-24NG0CZnnm3D5HCJ7r8AOB08I-wpQhH1A,24888
|
|
51
|
+
ripperdoc/core/skills.py,sha256=NGP_QFzL2SBkz8wZBGxNA_6Gt8qkRIZtJDnPs_DayxE,10511
|
|
52
|
+
ripperdoc/core/system_prompt.py,sha256=d3GNCsJ_mdIojpWg1Wc0gRDC_gzRDI5G4tQN_gxhRdo,26752
|
|
53
|
+
ripperdoc/core/theme.py,sha256=cQ0LTDxP2whFEsTRi421p1Rs7Epe9rlv-HgFirvIxzM,8427
|
|
54
|
+
ripperdoc/core/tool.py,sha256=0ihPcsgr0Dz5kl9-8hCU-xaRui5_WCjIOnVTpshc8k0,8529
|
|
55
|
+
ripperdoc/core/hooks/__init__.py,sha256=xw7VJQu1ZB0ENHVqL5xtruBnP3d0FNgrBH6NTL2xYgg,2735
|
|
56
|
+
ripperdoc/core/hooks/config.py,sha256=wE_eMHDZu9-yHGyJ45ySL1_l2yx7B8i4jiThs78W6Zc,10085
|
|
57
|
+
ripperdoc/core/hooks/events.py,sha256=UGBDdec52abi2e6ox8ncsLeDo3t9ZJesymKaPwxNDAE,18403
|
|
58
|
+
ripperdoc/core/hooks/executor.py,sha256=3MdiCdc4Bn2xHcTlRT72BajrgAZ5roKck0NBnO4Re0c,16781
|
|
59
|
+
ripperdoc/core/hooks/integration.py,sha256=IzkOSpaMjC397zKdKO1jTR0uyzOet-eCwPLuXwTYOts,11082
|
|
60
|
+
ripperdoc/core/hooks/llm_callback.py,sha256=TsttZ8Q7c8-36ebbI8nTyYcKbA7Kr9rmY5UO2gzuL-c,1733
|
|
61
|
+
ripperdoc/core/hooks/manager.py,sha256=dfHhB8f5US8ZN2a0JbzD5bQZHsnBS6Zs8xVZ2IcSsrg,25092
|
|
62
|
+
ripperdoc/core/providers/__init__.py,sha256=yevsHF0AUI4b6Wiq_401NXewJ3dqe8LUUtQm0TLPPNQ,1911
|
|
63
|
+
ripperdoc/core/providers/anthropic.py,sha256=B967szN1Thc0K1Iv8TvKWcVKktCevBmShftupVag8pk,28551
|
|
64
|
+
ripperdoc/core/providers/base.py,sha256=HNOa3_XWszu6DbI8BYixxV0hnZb9qZ_FU4uinFVRHjU,9271
|
|
65
|
+
ripperdoc/core/providers/gemini.py,sha256=Fs-dShsmIVBFfz-jg4fBjvQyrxVnZ5yx4ALcES-l5Sg,27089
|
|
66
|
+
ripperdoc/core/providers/openai.py,sha256=BhvDvkDjeYJMbvI4mbswQXbjdab53oJduku-Yja1zmQ,25561
|
|
67
|
+
ripperdoc/protocol/__init__.py,sha256=rSYu_Y2acRfsAE8gUTG82VnyrK3AFrIfwuJBf2cjHjs,325
|
|
68
|
+
ripperdoc/protocol/models.py,sha256=goNurNKI0eGZeCGmr7KqMPkZMvMOABXWsb-8un0LDlc,7468
|
|
69
|
+
ripperdoc/protocol/stdio.py,sha256=jia8cca3offyOc8kego-MnJfXsZkFwQw0cZZzfeFQqs,58933
|
|
70
|
+
ripperdoc/tools/__init__.py,sha256=RBFz0DDnztDXMqv_zRxFHVY-ez2HYcncx8zh_y-BX6w,42
|
|
71
|
+
ripperdoc/tools/ask_user_question_tool.py,sha256=ZWg5xAdeaRoR98KvvPuKmJH4L2dgzH87VXM4dxKcqBE,15478
|
|
72
|
+
ripperdoc/tools/background_shell.py,sha256=VMJd0G7s1l7qSRvlkRaIbgWmj4N0U_sr0kLzBzVLO2A,21263
|
|
73
|
+
ripperdoc/tools/bash_output_tool.py,sha256=cC5dDmKYmkOTsLCXCcTYgc0loVWtmRobPn0C-I6qO-o,3379
|
|
74
|
+
ripperdoc/tools/bash_tool.py,sha256=m3jfukBBOSQUYJbntekTGGk3FIn1GKaZVvcqMWwLBYE,47598
|
|
75
|
+
ripperdoc/tools/dynamic_mcp_tool.py,sha256=kxxWhp6pP9N8fK3ubu5fHQYQv7aSwxcnaa3C9ZsBbOU,15879
|
|
76
|
+
ripperdoc/tools/enter_plan_mode_tool.py,sha256=LNQv43uWkohiQTYQdsrKbpAfQSJNE_FJ9Y6AM_ckjng,7976
|
|
77
|
+
ripperdoc/tools/exit_plan_mode_tool.py,sha256=XxhEih5EUrcscvkRA9lel54XoVIhl_cCL2xcvMJjtVA,5756
|
|
78
|
+
ripperdoc/tools/file_edit_tool.py,sha256=IHgaWbzR7NKpLJ5XOjxU24c5-RyseVJw-p3QFGtcKJQ,22190
|
|
79
|
+
ripperdoc/tools/file_read_tool.py,sha256=TXEt_Q7RSaTx4qdx3_mOYP704UU6qRccL5_AqPlNFrY,13735
|
|
80
|
+
ripperdoc/tools/file_write_tool.py,sha256=HqOkFYedacNsPatKxVhth0kI5fGh83tm2VxdD_pO-V0,8570
|
|
81
|
+
ripperdoc/tools/glob_tool.py,sha256=eZG4fzahjJsSM8NdmTiVl5nBfDQK7egPg6P7cqOM_1Y,5948
|
|
82
|
+
ripperdoc/tools/grep_tool.py,sha256=bqrliI6e-9cNKIOfxdCv6mBwHr_1BSLwAPSTbOTc4B4,18239
|
|
83
|
+
ripperdoc/tools/kill_bash_tool.py,sha256=_jwnJVCPe8uXZTJd7myh4hWCD-eBuB2XDaYwRCmNSsI,4625
|
|
84
|
+
ripperdoc/tools/ls_tool.py,sha256=JWQucgNOLjrGZwM7imu3GWe5YFwXxdXGoaBr50wDZCQ,15367
|
|
85
|
+
ripperdoc/tools/lsp_tool.py,sha256=atpaaMqf3jld7SyNXtfdM6NkxYrp3KbYZ91oC4EqQlU,21315
|
|
86
|
+
ripperdoc/tools/mcp_tools.py,sha256=BVz8MJhijNnHq1J2LLkZS89wp_pwwnOytH1HYcfkFqQ,23085
|
|
87
|
+
ripperdoc/tools/multi_edit_tool.py,sha256=s9gN3oRPqeYjQxdsfnkfHSIMTrBs09ihV_TYuVqaey8,18446
|
|
88
|
+
ripperdoc/tools/notebook_edit_tool.py,sha256=Y2XkQB4WDbSWeCsO3Ybnsrbcxki99aOv3o23jZ5D1Hw,14445
|
|
89
|
+
ripperdoc/tools/skill_tool.py,sha256=8TcmNxpSGiBXd-ipgoD9BIopKkR13-3U56rkzozazhY,9763
|
|
90
|
+
ripperdoc/tools/task_tool.py,sha256=SQW2yLM0yectI0dVBoaDF0Tp5T4yOYqvHpsFWapOE44,33979
|
|
91
|
+
ripperdoc/tools/todo_tool.py,sha256=eIwF-s1117DrXJ4yXUMwkNs1gfKYNF2OlWzkJAXDzmk,20001
|
|
92
|
+
ripperdoc/tools/tool_search_tool.py,sha256=AeY-tFtWr2IAHTCEnG9kvsRRBqrBd-PJ96oUnFKa3Vs,13890
|
|
93
|
+
ripperdoc/utils/__init__.py,sha256=gdso60znB2hsYZ_YZBKVcuOY3QVfoqD2wHQ4pvr5lSw,37
|
|
94
|
+
ripperdoc/utils/bash_constants.py,sha256=KNn8bzB6nVU5jid9jvjiH4FAu8pP3DZONJ-OknJypAQ,1641
|
|
95
|
+
ripperdoc/utils/bash_output_utils.py,sha256=3Cf5wKJzRbUesmCNy5HtXIBtv0Z2BxklTfFHJ9q1T3w,1210
|
|
96
|
+
ripperdoc/utils/coerce.py,sha256=KOPb4KR4p32nwHWG_6GsGHeVZunJyYc2YhC5DLmEZO8,1015
|
|
97
|
+
ripperdoc/utils/context_length_errors.py,sha256=oyDVr_ME_6j97TLwVZ8bDMb6ISGQx6wEHrY7ckc0GuA,7714
|
|
98
|
+
ripperdoc/utils/conversation_compaction.py,sha256=mbOYwQXXsAqiJ7mBQ25195bXtH3tb5GSU0HUNsvnl1g,18345
|
|
99
|
+
ripperdoc/utils/exit_code_handlers.py,sha256=QtO1iDxVAb8Xp03D6_QixPoJC-RQlcp3ssIo_rm4two,7973
|
|
100
|
+
ripperdoc/utils/file_watch.py,sha256=Oqx5elgE3_z6CSAKdTbIPna_E4SePBqDujpqqANcw9U,11823
|
|
101
|
+
ripperdoc/utils/git_utils.py,sha256=Hq-Zx-KPyX4lp_i8ozhic15LyYdX_IfCRm-EyoFu59A,9047
|
|
102
|
+
ripperdoc/utils/image_utils.py,sha256=52YRLN0NwPEHnL3-smYktx2T8Oh002W0nvZsxI-WFdo,3380
|
|
103
|
+
ripperdoc/utils/json_utils.py,sha256=Bx1pHHu5r7GtvCqFHM3K9EoknFAtYOaCqTn9RN-5qBA,757
|
|
104
|
+
ripperdoc/utils/log.py,sha256=niCsP__DSbgSAJfitmrsSkh3UjPw7NdYHURrx7DLRuU,7197
|
|
105
|
+
ripperdoc/utils/lsp.py,sha256=4_zw1ZzbvMe16kn6U5EHyMyACX-m0Hr0AjoFXi1xsEQ,26844
|
|
106
|
+
ripperdoc/utils/mcp.py,sha256=-8yZD6gc43BqiFmG3intZcyfVhAYusaXgoI8rJUSdGA,22621
|
|
107
|
+
ripperdoc/utils/memory.py,sha256=J_kucw1BBnHQ1qG2_ZzdNysKvS1lrpuMtB5wxJDmXZU,8033
|
|
108
|
+
ripperdoc/utils/message_compaction.py,sha256=FwYxjWc0B7IlzT1VPEyfhwEl8rXbDi37utbEbS5qGWw,22577
|
|
109
|
+
ripperdoc/utils/message_formatting.py,sha256=9uA7c3MMuWTIp0SQAXkvuRsofKlQ_r0xRHD7ln5lR8s,7820
|
|
110
|
+
ripperdoc/utils/messages.py,sha256=qX9vh81hZXQc3vHLTLfuiLrLwMkLc4XKpX7ZnTRzI7I,30987
|
|
111
|
+
ripperdoc/utils/output_utils.py,sha256=R3wqFh9Dko_GK00Exx7XI0DnnldRWMsxZypYX5y6SJo,7448
|
|
112
|
+
ripperdoc/utils/path_ignore.py,sha256=5VOk075Ef9Wz9LhAWjFQuXJfnypxTD0w9cZVoTGko2M,17882
|
|
113
|
+
ripperdoc/utils/path_utils.py,sha256=C45Q3OeXnj-0FVEtvf_tdG5922XB6HthUzlUCvfc17Y,1626
|
|
114
|
+
ripperdoc/utils/pending_messages.py,sha256=75DKO1SgVGMlzC_ycfKNJ_cktj_MFVFy60j4EXeRsM0,1683
|
|
115
|
+
ripperdoc/utils/platform.py,sha256=Q-2hp0ywegEiuxK3TzE5Pg9wuHJiY8tPp9eoEMCtx4Y,5024
|
|
116
|
+
ripperdoc/utils/prompt.py,sha256=zICNEsA_OtKx8t3zo9tHLXXu6G5K8rPO3jFLKz4j5tg,560
|
|
117
|
+
ripperdoc/utils/safe_get_cwd.py,sha256=lYxFJAN7lomoLwTAfMZtyOueotuvhC8TN84NtrPKj1E,827
|
|
118
|
+
ripperdoc/utils/sandbox_utils.py,sha256=G91P8dw2VFcCiCpjXZ4LvzbAPiO8REqMhw39eI5Z4dU,1123
|
|
119
|
+
ripperdoc/utils/session_heatmap.py,sha256=o88ZlL9tFizOEbo92r6RKcfe2hscghVv7wS_REltZIw,8436
|
|
120
|
+
ripperdoc/utils/session_history.py,sha256=S-z5TneMvyLvoITJG4bRKvr4bvh5LWp8rKIuekLaFA4,9716
|
|
121
|
+
ripperdoc/utils/session_stats.py,sha256=xf5KKhNlzocPxMAS5fRUF6YVDH9fpqObfx_ah_iAMqA,9101
|
|
122
|
+
ripperdoc/utils/session_usage.py,sha256=p8_s46zDTzV1qzP4HR4PuZmLeJvSfq9mG_Y5rCnRYyA,3213
|
|
123
|
+
ripperdoc/utils/shell_token_utils.py,sha256=SduoSU-RERJdM_7gBn0urr5UXtl4XOpPgydBd2fwzWg,2500
|
|
124
|
+
ripperdoc/utils/shell_utils.py,sha256=RQ0iMdvv0SQOs9vqDAaklLLOo0inC935DOjmy0iZKYc,5541
|
|
125
|
+
ripperdoc/utils/todo.py,sha256=t0DJMHtwRBGf_uEx9zzDwp2K0TOoOT0NEhFXWm_YoR0,6807
|
|
126
|
+
ripperdoc/utils/token_estimation.py,sha256=qPQbeUwVlafEjzsXw6qMo0hd4Vjb1gCUMAPBouYUASI,1066
|
|
127
|
+
ripperdoc/utils/permissions/__init__.py,sha256=33FfOaDLepxJSkp0RLvTdVu7qBXuEcnOoTHFbEtFOt0,653
|
|
128
|
+
ripperdoc/utils/permissions/path_validation_utils.py,sha256=KOegjWaph8tXU7aqwQXRAxFEzrmRuPvdLb36J1QIPDQ,5772
|
|
129
|
+
ripperdoc/utils/permissions/shell_command_validation.py,sha256=BRi-1OGzr-Wiuxa00Ye6oqPctoJUZBOoRoi6dUiAsfM,33256
|
|
130
|
+
ripperdoc/utils/permissions/tool_permission_utils.py,sha256=YqbYSXyR0RBbLibBtigYb9O9143mDRulsQCh_WwArvY,14653
|
|
131
|
+
ripperdoc-0.3.1.dist-info/licenses/LICENSE,sha256=bRv9UhBor6GhnQDj12RciDcRfu0R7sB-lqCy1sWF75c,9242
|
|
132
|
+
ripperdoc-0.3.1.dist-info/METADATA,sha256=QawsGroIo9Rs4CodXPVMBNbiFmPZrnJE8nMgqNNDEyQ,8651
|
|
133
|
+
ripperdoc-0.3.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
134
|
+
ripperdoc-0.3.1.dist-info/entry_points.txt,sha256=79aohFxFPJmrQ3-Mhain04vb3EWpuc0EyzvDDUnwAu4,81
|
|
135
|
+
ripperdoc-0.3.1.dist-info/top_level.txt,sha256=u8LbdTr1a-laHgCO0Utl_R3QGFUhLxWelCDnP2ZgpCU,10
|
|
136
|
+
ripperdoc-0.3.1.dist-info/RECORD,,
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
"""Interrupt handling for RichUI.
|
|
2
|
-
|
|
3
|
-
This module handles ESC/Ctrl+C key detection during query execution,
|
|
4
|
-
including terminal raw mode management.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import asyncio
|
|
8
|
-
import contextlib
|
|
9
|
-
import sys
|
|
10
|
-
from typing import Any, Optional, Set
|
|
11
|
-
|
|
12
|
-
from ripperdoc.utils.log import get_logger
|
|
13
|
-
|
|
14
|
-
logger = get_logger()
|
|
15
|
-
|
|
16
|
-
# Keys that trigger interrupt
|
|
17
|
-
INTERRUPT_KEYS: Set[str] = {"\x1b", "\x03"} # ESC, Ctrl+C
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class InterruptHandler:
|
|
21
|
-
"""Handles keyboard interrupt detection during async operations."""
|
|
22
|
-
|
|
23
|
-
def __init__(self) -> None:
|
|
24
|
-
"""Initialize the interrupt handler."""
|
|
25
|
-
self._query_interrupted: bool = False
|
|
26
|
-
self._esc_listener_active: bool = False
|
|
27
|
-
self._esc_listener_paused: bool = False
|
|
28
|
-
self._stdin_fd: Optional[int] = None
|
|
29
|
-
self._stdin_old_settings: Optional[list] = None
|
|
30
|
-
self._stdin_in_raw_mode: bool = False
|
|
31
|
-
self._abort_callback: Optional[Any] = None
|
|
32
|
-
|
|
33
|
-
def set_abort_callback(self, callback: Any) -> None:
|
|
34
|
-
"""Set the callback to trigger when interrupt is detected."""
|
|
35
|
-
self._abort_callback = callback
|
|
36
|
-
|
|
37
|
-
@property
|
|
38
|
-
def was_interrupted(self) -> bool:
|
|
39
|
-
"""Check if the last query was interrupted."""
|
|
40
|
-
return self._query_interrupted
|
|
41
|
-
|
|
42
|
-
def pause_listener(self) -> bool:
|
|
43
|
-
"""Pause ESC listener and restore cooked terminal mode if we own raw mode.
|
|
44
|
-
|
|
45
|
-
Returns:
|
|
46
|
-
Previous paused state for later restoration.
|
|
47
|
-
"""
|
|
48
|
-
prev = self._esc_listener_paused
|
|
49
|
-
self._esc_listener_paused = True
|
|
50
|
-
try:
|
|
51
|
-
import termios
|
|
52
|
-
except ImportError:
|
|
53
|
-
return prev
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
self._stdin_fd is not None
|
|
57
|
-
and self._stdin_old_settings is not None
|
|
58
|
-
and self._stdin_in_raw_mode
|
|
59
|
-
):
|
|
60
|
-
with contextlib.suppress(OSError, termios.error, ValueError):
|
|
61
|
-
termios.tcsetattr(self._stdin_fd, termios.TCSADRAIN, self._stdin_old_settings)
|
|
62
|
-
self._stdin_in_raw_mode = False
|
|
63
|
-
return prev
|
|
64
|
-
|
|
65
|
-
def resume_listener(self, previous_state: bool) -> None:
|
|
66
|
-
"""Restore paused state to what it was before a blocking prompt."""
|
|
67
|
-
self._esc_listener_paused = previous_state
|
|
68
|
-
|
|
69
|
-
async def _listen_for_interrupt_key(self) -> bool:
|
|
70
|
-
"""Listen for interrupt keys (ESC/Ctrl+C) during query execution.
|
|
71
|
-
|
|
72
|
-
Uses raw terminal mode for immediate key detection without waiting
|
|
73
|
-
for escape sequences to complete.
|
|
74
|
-
|
|
75
|
-
Returns:
|
|
76
|
-
True if an interrupt key was pressed.
|
|
77
|
-
"""
|
|
78
|
-
import select
|
|
79
|
-
import termios
|
|
80
|
-
import tty
|
|
81
|
-
|
|
82
|
-
try:
|
|
83
|
-
fd = sys.stdin.fileno()
|
|
84
|
-
old_settings = termios.tcgetattr(fd)
|
|
85
|
-
except (OSError, termios.error, ValueError):
|
|
86
|
-
return False
|
|
87
|
-
|
|
88
|
-
self._stdin_fd = fd
|
|
89
|
-
self._stdin_old_settings = old_settings
|
|
90
|
-
raw_enabled = False
|
|
91
|
-
try:
|
|
92
|
-
while self._esc_listener_active:
|
|
93
|
-
if self._esc_listener_paused:
|
|
94
|
-
if raw_enabled:
|
|
95
|
-
with contextlib.suppress(OSError, termios.error, ValueError):
|
|
96
|
-
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
97
|
-
raw_enabled = False
|
|
98
|
-
self._stdin_in_raw_mode = False
|
|
99
|
-
await asyncio.sleep(0.05)
|
|
100
|
-
continue
|
|
101
|
-
|
|
102
|
-
if not raw_enabled:
|
|
103
|
-
tty.setraw(fd)
|
|
104
|
-
raw_enabled = True
|
|
105
|
-
self._stdin_in_raw_mode = True
|
|
106
|
-
|
|
107
|
-
await asyncio.sleep(0.02)
|
|
108
|
-
if select.select([sys.stdin], [], [], 0)[0]:
|
|
109
|
-
if sys.stdin.read(1) in INTERRUPT_KEYS:
|
|
110
|
-
return True
|
|
111
|
-
except (OSError, ValueError):
|
|
112
|
-
pass
|
|
113
|
-
finally:
|
|
114
|
-
self._stdin_in_raw_mode = False
|
|
115
|
-
with contextlib.suppress(OSError, termios.error, ValueError):
|
|
116
|
-
if raw_enabled:
|
|
117
|
-
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
118
|
-
self._stdin_fd = None
|
|
119
|
-
self._stdin_old_settings = None
|
|
120
|
-
|
|
121
|
-
return False
|
|
122
|
-
|
|
123
|
-
async def _cancel_task(self, task: asyncio.Task) -> None:
|
|
124
|
-
"""Cancel a task and wait for it to finish."""
|
|
125
|
-
if not task.done():
|
|
126
|
-
task.cancel()
|
|
127
|
-
with contextlib.suppress(asyncio.CancelledError):
|
|
128
|
-
await task
|
|
129
|
-
|
|
130
|
-
def _trigger_abort(self) -> None:
|
|
131
|
-
"""Signal the query to abort via callback."""
|
|
132
|
-
if self._abort_callback is not None:
|
|
133
|
-
self._abort_callback()
|
|
134
|
-
|
|
135
|
-
async def run_with_interrupt(self, query_coro: Any) -> bool:
|
|
136
|
-
"""Run a coroutine with ESC key interrupt support.
|
|
137
|
-
|
|
138
|
-
Args:
|
|
139
|
-
query_coro: The coroutine to run with interrupt support.
|
|
140
|
-
|
|
141
|
-
Returns:
|
|
142
|
-
True if interrupted, False if completed normally.
|
|
143
|
-
"""
|
|
144
|
-
self._query_interrupted = False
|
|
145
|
-
self._esc_listener_active = True
|
|
146
|
-
|
|
147
|
-
query_task = asyncio.create_task(query_coro)
|
|
148
|
-
interrupt_task = asyncio.create_task(self._listen_for_interrupt_key())
|
|
149
|
-
|
|
150
|
-
try:
|
|
151
|
-
done, _ = await asyncio.wait(
|
|
152
|
-
{query_task, interrupt_task}, return_when=asyncio.FIRST_COMPLETED
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
# Check if interrupted
|
|
156
|
-
if interrupt_task in done and interrupt_task.result():
|
|
157
|
-
self._query_interrupted = True
|
|
158
|
-
self._trigger_abort()
|
|
159
|
-
await self._cancel_task(query_task)
|
|
160
|
-
return True
|
|
161
|
-
|
|
162
|
-
# Query completed normally
|
|
163
|
-
if query_task in done:
|
|
164
|
-
await self._cancel_task(interrupt_task)
|
|
165
|
-
with contextlib.suppress(Exception):
|
|
166
|
-
query_task.result()
|
|
167
|
-
return False
|
|
168
|
-
|
|
169
|
-
return False
|
|
170
|
-
|
|
171
|
-
finally:
|
|
172
|
-
self._esc_listener_active = False
|
|
173
|
-
await self._cancel_task(query_task)
|
|
174
|
-
await self._cancel_task(interrupt_task)
|