synapse-cli-agent 0.1.13__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.
- synapse/__init__.py +13 -0
- synapse/__main__.py +6 -0
- synapse/app/__init__.py +1 -0
- synapse/app/agent.py +492 -0
- synapse/app/agent_md.py +107 -0
- synapse/cli.py +750 -0
- synapse/commands/__init__.py +1 -0
- synapse/commands/compression.py +573 -0
- synapse/commands/helpers.py +22 -0
- synapse/commands/mcp.py +406 -0
- synapse/commands/model.py +173 -0
- synapse/commands/result.py +34 -0
- synapse/commands/sessions.py +443 -0
- synapse/commands/slash_cmds.py +521 -0
- synapse/commands/slash_complete.py +816 -0
- synapse/commands/theme.py +99 -0
- synapse/config.py +27 -0
- synapse/content/__init__.py +1 -0
- synapse/content/input_history.py +122 -0
- synapse/content/multimodal.py +733 -0
- synapse/content/prompts.py +249 -0
- synapse/content/skills_catalog.py +128 -0
- synapse/integrations/__init__.py +1 -0
- synapse/integrations/checkpoint_seed.py +281 -0
- synapse/integrations/codex_history.py +375 -0
- synapse/integrations/codex_import.py +393 -0
- synapse/integrations/codex_sessions.py +629 -0
- synapse/integrations/describe_image.py +370 -0
- synapse/integrations/http_clients.py +199 -0
- synapse/integrations/llm_openai_compat.py +90 -0
- synapse/integrations/llm_openai_websocket.py +187 -0
- synapse/integrations/mcp_client.py +646 -0
- synapse/integrations/vision_middleware.py +62 -0
- synapse/models/__init__.py +5 -0
- synapse/models/config.py +240 -0
- synapse/models/helpers.py +206 -0
- synapse/models/profile.py +59 -0
- synapse/models/registry.py +722 -0
- synapse/models_registry.py +7 -0
- synapse/observability/__init__.py +1 -0
- synapse/observability/startup_trace.py +127 -0
- synapse/runtime/__init__.py +1 -0
- synapse/runtime/async_runtime.py +176 -0
- synapse/runtime/backends.py +458 -0
- synapse/runtime/context_compact.py +249 -0
- synapse/runtime/execute_capture.py +48 -0
- synapse/runtime/fs_permissions.py +79 -0
- synapse/runtime/harness.py +57 -0
- synapse/runtime/hitl.py +197 -0
- synapse/runtime/interaction_ledger.py +82 -0
- synapse/runtime/middleware.py +802 -0
- synapse/runtime/model_request_compression_middleware.py +745 -0
- synapse/runtime/pathing.py +146 -0
- synapse/runtime/safety.py +184 -0
- synapse/runtime/steer.py +240 -0
- synapse/runtime/subagents.py +207 -0
- synapse/runtime/tool_ignore.py +221 -0
- synapse/runtime/tool_output_eval.py +118 -0
- synapse/runtime/tool_output_middleware.py +585 -0
- synapse/runtime/tool_output_usage_middleware.py +60 -0
- synapse/sessions/__init__.py +31 -0
- synapse/sessions/cancel_repair.py +208 -0
- synapse/sessions/session_recap.py +174 -0
- synapse/sessions/store.py +695 -0
- synapse/sessions/transcript.py +754 -0
- synapse/settings/__init__.py +5 -0
- synapse/settings/config_paths.py +184 -0
- synapse/settings/schema.py +464 -0
- synapse/tool_output/__init__.py +59 -0
- synapse/tool_output/detection.py +170 -0
- synapse/tool_output/metrics.py +32 -0
- synapse/tool_output/models.py +173 -0
- synapse/tool_output/pipeline.py +330 -0
- synapse/tool_output/repository.py +721 -0
- synapse/tool_output/transformers.py +648 -0
- synapse/tools/__init__.py +5 -0
- synapse/tools/session_tools.py +204 -0
- synapse/ui/__init__.py +10 -0
- synapse/ui/bottombar/__init__.py +73 -0
- synapse/ui/bottombar/components/__init__.py +143 -0
- synapse/ui/bottombar/components/key_hints.py +30 -0
- synapse/ui/bottombar/components/mcp.py +64 -0
- synapse/ui/bottombar/components/mode.py +24 -0
- synapse/ui/bottombar/components/model.py +28 -0
- synapse/ui/bottombar/components/thread.py +29 -0
- synapse/ui/bottombar/context.py +36 -0
- synapse/ui/bottombar/core.py +74 -0
- synapse/ui/dialogs/__init__.py +25 -0
- synapse/ui/dialogs/base.py +362 -0
- synapse/ui/dialogs/codex_session_list.py +84 -0
- synapse/ui/dialogs/compression_diagnostics.py +210 -0
- synapse/ui/dialogs/git_explore.py +702 -0
- synapse/ui/dialogs/mcp_panel.py +407 -0
- synapse/ui/dialogs/model_picker.py +128 -0
- synapse/ui/dialogs/safety_panel.py +63 -0
- synapse/ui/dialogs/session_list.py +98 -0
- synapse/ui/dialogs/theme_designer.py +863 -0
- synapse/ui/dialogs/theme_picker.py +113 -0
- synapse/ui/git_explore/__init__.py +31 -0
- synapse/ui/git_explore/engine.py +82 -0
- synapse/ui/git_explore/provider.py +242 -0
- synapse/ui/git_explore/unified.py +85 -0
- synapse/ui/rendering.py +350 -0
- synapse/ui/sink.py +70 -0
- synapse/ui/steer_widget.py +367 -0
- synapse/ui/stream.py +1207 -0
- synapse/ui/stream_events.py +421 -0
- synapse/ui/stream_runtime.py +252 -0
- synapse/ui/theme.py +1154 -0
- synapse/ui/timeline.py +621 -0
- synapse/ui/topbar/__init__.py +97 -0
- synapse/ui/topbar/components/__init__.py +150 -0
- synapse/ui/topbar/components/branch.py +41 -0
- synapse/ui/topbar/components/title.py +24 -0
- synapse/ui/topbar/components/tool_output.py +24 -0
- synapse/ui/topbar/components/usage.py +24 -0
- synapse/ui/topbar/components/workspace.py +32 -0
- synapse/ui/topbar/context.py +32 -0
- synapse/ui/topbar/core.py +979 -0
- synapse/ui/topbar/git_changes_popover.py +178 -0
- synapse/ui/topbar/git_chrome.py +475 -0
- synapse/ui/topbar/tool_output_popover.py +84 -0
- synapse/ui/topbar/widget.py +474 -0
- synapse/ui/tui.py +5717 -0
- synapse/ui/turn_rail.py +71 -0
- synapse/ui/user_turn.py +83 -0
- synapse/ui/welcome.py +261 -0
- synapse_cli_agent-0.1.13.dist-info/METADATA +412 -0
- synapse_cli_agent-0.1.13.dist-info/RECORD +131 -0
- synapse_cli_agent-0.1.13.dist-info/WHEEL +4 -0
- synapse_cli_agent-0.1.13.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"""Steer queue panel — compact OptionRow-style chrome (model-picker language).
|
|
2
|
+
|
|
3
|
+
Layout (narrow, not full-width)::
|
|
4
|
+
|
|
5
|
+
+-- 排队 · 2 ----------------------------------+
|
|
6
|
+
| * first note… x |
|
|
7
|
+
| o second… x |
|
|
8
|
+
+----------------------------------------------+
|
|
9
|
+
|
|
10
|
+
- Pending notes, plus notes already applied during the active turn.
|
|
11
|
+
- Click row body or x drops that note.
|
|
12
|
+
- Header right "清空" clears all; left chevron toggles collapse.
|
|
13
|
+
- Minimal copy: no English essay.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from rich.text import Text
|
|
21
|
+
from textual.app import ComposeResult
|
|
22
|
+
from textual.containers import Vertical
|
|
23
|
+
from textual.events import Click
|
|
24
|
+
from textual.message import Message
|
|
25
|
+
from textual.reactive import reactive
|
|
26
|
+
from textual.widgets import Static
|
|
27
|
+
|
|
28
|
+
# Hardcoded fallbacks for DEFAULT_CSS (widget CSS cannot resolve $theme-*).
|
|
29
|
+
# App stylesheet in tui.py overrides with $theme-* at runtime.
|
|
30
|
+
_C_FG = "#e8eaed"
|
|
31
|
+
_C_DIM = "#9aa0a6"
|
|
32
|
+
_C_MUTED = "#5f6368"
|
|
33
|
+
_C_ORANGE = "#f4b183"
|
|
34
|
+
_C_USER = "#8ab4f8"
|
|
35
|
+
_C_BAR = "#2b2d31"
|
|
36
|
+
_C_BG = "#1a1b1e"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _sync_theme_colors(theme: object | None = None) -> None:
|
|
40
|
+
global _C_FG, _C_DIM, _C_MUTED, _C_ORANGE, _C_USER, _C_BAR, _C_BG
|
|
41
|
+
try:
|
|
42
|
+
from synapse.ui.theme import get_theme
|
|
43
|
+
|
|
44
|
+
t = theme or get_theme()
|
|
45
|
+
except Exception: # noqa: BLE001
|
|
46
|
+
return
|
|
47
|
+
_C_FG = str(getattr(t, "fg", _C_FG))
|
|
48
|
+
_C_DIM = str(getattr(t, "dim", _C_DIM))
|
|
49
|
+
_C_MUTED = str(getattr(t, "muted", _C_MUTED))
|
|
50
|
+
_C_ORANGE = str(getattr(t, "orange", _C_ORANGE))
|
|
51
|
+
_C_USER = str(getattr(t, "user", _C_USER))
|
|
52
|
+
_C_BAR = str(getattr(t, "bar", _C_BAR))
|
|
53
|
+
_C_BG = str(getattr(t, "bg", _C_BG))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
from synapse.ui.theme import on_theme_change
|
|
58
|
+
|
|
59
|
+
on_theme_change(_sync_theme_colors)
|
|
60
|
+
_sync_theme_colors()
|
|
61
|
+
except Exception: # noqa: BLE001
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _preview(text: str, *, max_len: int = 40) -> str:
|
|
66
|
+
one = " ".join((text or "").split())
|
|
67
|
+
if len(one) > max_len:
|
|
68
|
+
one = one[: max(0, max_len - 1)] + "…"
|
|
69
|
+
return one
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _display_width(text: str) -> int:
|
|
73
|
+
total = 0
|
|
74
|
+
for ch in text or "":
|
|
75
|
+
o = ord(ch)
|
|
76
|
+
if (
|
|
77
|
+
0x1100 <= o <= 0x115F
|
|
78
|
+
or 0x2E80 <= o <= 0xA4CF
|
|
79
|
+
or 0xAC00 <= o <= 0xD7A3
|
|
80
|
+
or 0xF900 <= o <= 0xFAFF
|
|
81
|
+
or 0xFE10 <= o <= 0xFE19
|
|
82
|
+
or 0xFE30 <= o <= 0xFE6F
|
|
83
|
+
or 0xFF00 <= o <= 0xFF60
|
|
84
|
+
or 0xFFE0 <= o <= 0xFFE6
|
|
85
|
+
or 0x1F300 <= o <= 0x1FAFF
|
|
86
|
+
):
|
|
87
|
+
total += 2
|
|
88
|
+
else:
|
|
89
|
+
total += 1
|
|
90
|
+
return total
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _truncate(text: str, max_w: int) -> str:
|
|
94
|
+
if max_w <= 0:
|
|
95
|
+
return ""
|
|
96
|
+
if _display_width(text) <= max_w:
|
|
97
|
+
return text
|
|
98
|
+
if max_w == 1:
|
|
99
|
+
return "…"
|
|
100
|
+
out: list[str] = []
|
|
101
|
+
used = 0
|
|
102
|
+
limit = max_w - 1
|
|
103
|
+
for ch in text:
|
|
104
|
+
cw = _display_width(ch)
|
|
105
|
+
if used + cw > limit:
|
|
106
|
+
break
|
|
107
|
+
out.append(ch)
|
|
108
|
+
used += cw
|
|
109
|
+
return "".join(out) + "…"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class SteerDrop(Message):
|
|
113
|
+
"""Drop one pending note by index."""
|
|
114
|
+
|
|
115
|
+
def __init__(self, index: int) -> None:
|
|
116
|
+
super().__init__()
|
|
117
|
+
self.index = int(index)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class SteerClear(Message):
|
|
121
|
+
"""Clear the entire pending queue."""
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class SteerRow(Static):
|
|
125
|
+
"""One pending note — OptionRow language: o/* bullet + body + x."""
|
|
126
|
+
|
|
127
|
+
DEFAULT_CSS = """
|
|
128
|
+
SteerRow {
|
|
129
|
+
height: 1;
|
|
130
|
+
width: 1fr;
|
|
131
|
+
color: #9aa0a6;
|
|
132
|
+
padding: 0 1;
|
|
133
|
+
background: #1a1b1e;
|
|
134
|
+
overflow: hidden;
|
|
135
|
+
text-overflow: ellipsis;
|
|
136
|
+
}
|
|
137
|
+
SteerRow.-next {
|
|
138
|
+
color: #8ab4f8;
|
|
139
|
+
background: #2b2d31;
|
|
140
|
+
text-style: bold;
|
|
141
|
+
}
|
|
142
|
+
SteerRow:hover {
|
|
143
|
+
background: #2b2d31;
|
|
144
|
+
}
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
def __init__(self, index: int, text: str, *, is_next: bool = False) -> None:
|
|
148
|
+
super().__init__(classes="-next" if is_next else "")
|
|
149
|
+
self.index = int(index)
|
|
150
|
+
self.note = text or ""
|
|
151
|
+
self.is_next = bool(is_next)
|
|
152
|
+
self._paint()
|
|
153
|
+
|
|
154
|
+
def _paint(self) -> None:
|
|
155
|
+
w = int(getattr(self.size, "width", 0) or 0)
|
|
156
|
+
if w <= 0:
|
|
157
|
+
try:
|
|
158
|
+
w = int(getattr(self.app.size, "width", 0) or 48) - 8
|
|
159
|
+
except Exception: # noqa: BLE001
|
|
160
|
+
w = 44
|
|
161
|
+
usable = max(16, w - 2)
|
|
162
|
+
bullet = "●" if self.is_next else "○"
|
|
163
|
+
drop = "×"
|
|
164
|
+
fixed = _display_width(f"{bullet} ") + 2 + _display_width(drop)
|
|
165
|
+
body_w = max(4, usable - fixed)
|
|
166
|
+
body = _truncate(_preview(self.note, max_len=80), body_w)
|
|
167
|
+
pad = max(1, usable - _display_width(f"{bullet} {body}") - _display_width(drop))
|
|
168
|
+
|
|
169
|
+
fg = _C_USER if self.is_next else _C_DIM
|
|
170
|
+
style = f"bold {fg}" if self.is_next else fg
|
|
171
|
+
line = Text()
|
|
172
|
+
line.append(f"{bullet} ", style=style)
|
|
173
|
+
line.append(body, style=style)
|
|
174
|
+
line.append(" " * pad, style="")
|
|
175
|
+
line.append(drop, style=_C_MUTED)
|
|
176
|
+
self.update(line)
|
|
177
|
+
|
|
178
|
+
def on_resize(self) -> None:
|
|
179
|
+
self._paint()
|
|
180
|
+
|
|
181
|
+
def on_click(self, event: Click) -> None:
|
|
182
|
+
event.stop()
|
|
183
|
+
# Whole row drops this unapplied note (including × zone).
|
|
184
|
+
self.post_message(SteerDrop(self.index))
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class SteerHeader(Static):
|
|
188
|
+
"""Compact title: 排队 · N 清空."""
|
|
189
|
+
|
|
190
|
+
DEFAULT_CSS = """
|
|
191
|
+
SteerHeader {
|
|
192
|
+
height: 1;
|
|
193
|
+
width: 1fr;
|
|
194
|
+
color: #f4b183;
|
|
195
|
+
text-style: bold;
|
|
196
|
+
padding: 0 1;
|
|
197
|
+
background: #1a1b1e;
|
|
198
|
+
}
|
|
199
|
+
SteerHeader:hover {
|
|
200
|
+
background: #2b2d31;
|
|
201
|
+
}
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
def __init__(self) -> None:
|
|
205
|
+
super().__init__()
|
|
206
|
+
self._n = 0
|
|
207
|
+
self._collapsed = False
|
|
208
|
+
self._paint()
|
|
209
|
+
|
|
210
|
+
def set_state(self, n: int, *, collapsed: bool) -> None:
|
|
211
|
+
self._n = int(n)
|
|
212
|
+
self._collapsed = bool(collapsed)
|
|
213
|
+
self._paint()
|
|
214
|
+
|
|
215
|
+
def _paint(self) -> None:
|
|
216
|
+
w = int(getattr(self.size, "width", 0) or 0)
|
|
217
|
+
if w <= 0:
|
|
218
|
+
w = 48
|
|
219
|
+
usable = max(12, w - 2)
|
|
220
|
+
mark = "▸" if self._collapsed else "▾"
|
|
221
|
+
left = f"{mark} 排队"
|
|
222
|
+
if self._n:
|
|
223
|
+
left = f"{left} · {self._n}"
|
|
224
|
+
right = "清空"
|
|
225
|
+
pad = max(1, usable - _display_width(left) - _display_width(right))
|
|
226
|
+
line = Text()
|
|
227
|
+
line.append(left, style=f"bold {_C_ORANGE}")
|
|
228
|
+
line.append(" " * pad, style="")
|
|
229
|
+
line.append(right, style=_C_MUTED)
|
|
230
|
+
self.update(line)
|
|
231
|
+
|
|
232
|
+
def on_resize(self) -> None:
|
|
233
|
+
self._paint()
|
|
234
|
+
|
|
235
|
+
def on_click(self, event: Click) -> None:
|
|
236
|
+
event.stop()
|
|
237
|
+
w = int(getattr(self.size, "width", 0) or 48)
|
|
238
|
+
x = int(getattr(event, "x", 0) or 0)
|
|
239
|
+
if x >= max(0, w - 8):
|
|
240
|
+
self.post_message(SteerClear())
|
|
241
|
+
return
|
|
242
|
+
parent = self.parent
|
|
243
|
+
toggle = getattr(parent, "toggle", None)
|
|
244
|
+
if callable(toggle):
|
|
245
|
+
toggle()
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class SteerQueueWidget(Vertical):
|
|
249
|
+
"""Compact mid-run guidance float (unapplied only)."""
|
|
250
|
+
|
|
251
|
+
DEFAULT_CSS = """
|
|
252
|
+
SteerQueueWidget {
|
|
253
|
+
height: auto;
|
|
254
|
+
max-height: 12;
|
|
255
|
+
width: 48;
|
|
256
|
+
max-width: 56;
|
|
257
|
+
min-width: 28;
|
|
258
|
+
margin: 0 1 0 1;
|
|
259
|
+
padding: 0;
|
|
260
|
+
display: none;
|
|
261
|
+
background: #1a1b1e;
|
|
262
|
+
border: round #8ab4f8;
|
|
263
|
+
overflow-y: auto;
|
|
264
|
+
scrollbar-size: 0 0;
|
|
265
|
+
}
|
|
266
|
+
SteerQueueWidget.active {
|
|
267
|
+
display: block;
|
|
268
|
+
}
|
|
269
|
+
SteerQueueWidget.-collapsed {
|
|
270
|
+
max-height: 3;
|
|
271
|
+
}
|
|
272
|
+
SteerQueueWidget > #steer-rows {
|
|
273
|
+
height: auto;
|
|
274
|
+
width: 1fr;
|
|
275
|
+
layout: vertical;
|
|
276
|
+
padding: 0;
|
|
277
|
+
}
|
|
278
|
+
SteerQueueWidget.-collapsed > #steer-rows {
|
|
279
|
+
display: none;
|
|
280
|
+
}
|
|
281
|
+
"""
|
|
282
|
+
|
|
283
|
+
collapsed: reactive[bool] = reactive(False)
|
|
284
|
+
|
|
285
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
286
|
+
super().__init__(**kwargs)
|
|
287
|
+
self._items: list[str] = []
|
|
288
|
+
|
|
289
|
+
@property
|
|
290
|
+
def count(self) -> int:
|
|
291
|
+
return len(self._items)
|
|
292
|
+
|
|
293
|
+
def compose(self) -> ComposeResult:
|
|
294
|
+
yield SteerHeader()
|
|
295
|
+
yield Vertical(id="steer-rows")
|
|
296
|
+
|
|
297
|
+
def on_mount(self) -> None:
|
|
298
|
+
self._paint()
|
|
299
|
+
|
|
300
|
+
def set_items(self, items: list[str] | None) -> None:
|
|
301
|
+
self._items = [str(x).strip() for x in (items or []) if str(x).strip()]
|
|
302
|
+
if not self._items:
|
|
303
|
+
self.collapsed = False
|
|
304
|
+
self._paint()
|
|
305
|
+
|
|
306
|
+
def toggle(self) -> None:
|
|
307
|
+
if not self._items:
|
|
308
|
+
return
|
|
309
|
+
self.collapsed = not self.collapsed
|
|
310
|
+
self._paint()
|
|
311
|
+
|
|
312
|
+
def _paint_block(self) -> None:
|
|
313
|
+
"""Compat alias used by theme refresh paths in tui."""
|
|
314
|
+
self._paint()
|
|
315
|
+
|
|
316
|
+
def _paint(self) -> None:
|
|
317
|
+
if not self.is_mounted:
|
|
318
|
+
return
|
|
319
|
+
if not self._items:
|
|
320
|
+
self.remove_class("active")
|
|
321
|
+
self.remove_class("-collapsed")
|
|
322
|
+
try:
|
|
323
|
+
self.query_one(SteerHeader).set_state(0, collapsed=False)
|
|
324
|
+
rows = self.query_one("#steer-rows", Vertical)
|
|
325
|
+
rows.remove_children()
|
|
326
|
+
except Exception: # noqa: BLE001
|
|
327
|
+
pass
|
|
328
|
+
return
|
|
329
|
+
|
|
330
|
+
self.add_class("active")
|
|
331
|
+
if self.collapsed:
|
|
332
|
+
self.add_class("-collapsed")
|
|
333
|
+
else:
|
|
334
|
+
self.remove_class("-collapsed")
|
|
335
|
+
|
|
336
|
+
try:
|
|
337
|
+
self.query_one(SteerHeader).set_state(
|
|
338
|
+
len(self._items), collapsed=self.collapsed
|
|
339
|
+
)
|
|
340
|
+
except Exception: # noqa: BLE001
|
|
341
|
+
pass
|
|
342
|
+
|
|
343
|
+
try:
|
|
344
|
+
rows = self.query_one("#steer-rows", Vertical)
|
|
345
|
+
except Exception: # noqa: BLE001
|
|
346
|
+
return
|
|
347
|
+
try:
|
|
348
|
+
rows.remove_children()
|
|
349
|
+
except Exception: # noqa: BLE001
|
|
350
|
+
for child in list(rows.children):
|
|
351
|
+
child.remove()
|
|
352
|
+
if self.collapsed:
|
|
353
|
+
return
|
|
354
|
+
for i, body in enumerate(self._items):
|
|
355
|
+
rows.mount(SteerRow(i, body, is_next=(i == 0)))
|
|
356
|
+
|
|
357
|
+
def on_steer_drop(self, event: SteerDrop) -> None:
|
|
358
|
+
event.stop()
|
|
359
|
+
drop = getattr(self.app, "drop_steer_at", None)
|
|
360
|
+
if callable(drop):
|
|
361
|
+
drop(event.index)
|
|
362
|
+
|
|
363
|
+
def on_steer_clear(self, event: SteerClear) -> None:
|
|
364
|
+
event.stop()
|
|
365
|
+
clear = getattr(self.app, "clear_steer_queue", None)
|
|
366
|
+
if callable(clear):
|
|
367
|
+
clear()
|