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.
Files changed (131) hide show
  1. synapse/__init__.py +13 -0
  2. synapse/__main__.py +6 -0
  3. synapse/app/__init__.py +1 -0
  4. synapse/app/agent.py +492 -0
  5. synapse/app/agent_md.py +107 -0
  6. synapse/cli.py +750 -0
  7. synapse/commands/__init__.py +1 -0
  8. synapse/commands/compression.py +573 -0
  9. synapse/commands/helpers.py +22 -0
  10. synapse/commands/mcp.py +406 -0
  11. synapse/commands/model.py +173 -0
  12. synapse/commands/result.py +34 -0
  13. synapse/commands/sessions.py +443 -0
  14. synapse/commands/slash_cmds.py +521 -0
  15. synapse/commands/slash_complete.py +816 -0
  16. synapse/commands/theme.py +99 -0
  17. synapse/config.py +27 -0
  18. synapse/content/__init__.py +1 -0
  19. synapse/content/input_history.py +122 -0
  20. synapse/content/multimodal.py +733 -0
  21. synapse/content/prompts.py +249 -0
  22. synapse/content/skills_catalog.py +128 -0
  23. synapse/integrations/__init__.py +1 -0
  24. synapse/integrations/checkpoint_seed.py +281 -0
  25. synapse/integrations/codex_history.py +375 -0
  26. synapse/integrations/codex_import.py +393 -0
  27. synapse/integrations/codex_sessions.py +629 -0
  28. synapse/integrations/describe_image.py +370 -0
  29. synapse/integrations/http_clients.py +199 -0
  30. synapse/integrations/llm_openai_compat.py +90 -0
  31. synapse/integrations/llm_openai_websocket.py +187 -0
  32. synapse/integrations/mcp_client.py +646 -0
  33. synapse/integrations/vision_middleware.py +62 -0
  34. synapse/models/__init__.py +5 -0
  35. synapse/models/config.py +240 -0
  36. synapse/models/helpers.py +206 -0
  37. synapse/models/profile.py +59 -0
  38. synapse/models/registry.py +722 -0
  39. synapse/models_registry.py +7 -0
  40. synapse/observability/__init__.py +1 -0
  41. synapse/observability/startup_trace.py +127 -0
  42. synapse/runtime/__init__.py +1 -0
  43. synapse/runtime/async_runtime.py +176 -0
  44. synapse/runtime/backends.py +458 -0
  45. synapse/runtime/context_compact.py +249 -0
  46. synapse/runtime/execute_capture.py +48 -0
  47. synapse/runtime/fs_permissions.py +79 -0
  48. synapse/runtime/harness.py +57 -0
  49. synapse/runtime/hitl.py +197 -0
  50. synapse/runtime/interaction_ledger.py +82 -0
  51. synapse/runtime/middleware.py +802 -0
  52. synapse/runtime/model_request_compression_middleware.py +745 -0
  53. synapse/runtime/pathing.py +146 -0
  54. synapse/runtime/safety.py +184 -0
  55. synapse/runtime/steer.py +240 -0
  56. synapse/runtime/subagents.py +207 -0
  57. synapse/runtime/tool_ignore.py +221 -0
  58. synapse/runtime/tool_output_eval.py +118 -0
  59. synapse/runtime/tool_output_middleware.py +585 -0
  60. synapse/runtime/tool_output_usage_middleware.py +60 -0
  61. synapse/sessions/__init__.py +31 -0
  62. synapse/sessions/cancel_repair.py +208 -0
  63. synapse/sessions/session_recap.py +174 -0
  64. synapse/sessions/store.py +695 -0
  65. synapse/sessions/transcript.py +754 -0
  66. synapse/settings/__init__.py +5 -0
  67. synapse/settings/config_paths.py +184 -0
  68. synapse/settings/schema.py +464 -0
  69. synapse/tool_output/__init__.py +59 -0
  70. synapse/tool_output/detection.py +170 -0
  71. synapse/tool_output/metrics.py +32 -0
  72. synapse/tool_output/models.py +173 -0
  73. synapse/tool_output/pipeline.py +330 -0
  74. synapse/tool_output/repository.py +721 -0
  75. synapse/tool_output/transformers.py +648 -0
  76. synapse/tools/__init__.py +5 -0
  77. synapse/tools/session_tools.py +204 -0
  78. synapse/ui/__init__.py +10 -0
  79. synapse/ui/bottombar/__init__.py +73 -0
  80. synapse/ui/bottombar/components/__init__.py +143 -0
  81. synapse/ui/bottombar/components/key_hints.py +30 -0
  82. synapse/ui/bottombar/components/mcp.py +64 -0
  83. synapse/ui/bottombar/components/mode.py +24 -0
  84. synapse/ui/bottombar/components/model.py +28 -0
  85. synapse/ui/bottombar/components/thread.py +29 -0
  86. synapse/ui/bottombar/context.py +36 -0
  87. synapse/ui/bottombar/core.py +74 -0
  88. synapse/ui/dialogs/__init__.py +25 -0
  89. synapse/ui/dialogs/base.py +362 -0
  90. synapse/ui/dialogs/codex_session_list.py +84 -0
  91. synapse/ui/dialogs/compression_diagnostics.py +210 -0
  92. synapse/ui/dialogs/git_explore.py +702 -0
  93. synapse/ui/dialogs/mcp_panel.py +407 -0
  94. synapse/ui/dialogs/model_picker.py +128 -0
  95. synapse/ui/dialogs/safety_panel.py +63 -0
  96. synapse/ui/dialogs/session_list.py +98 -0
  97. synapse/ui/dialogs/theme_designer.py +863 -0
  98. synapse/ui/dialogs/theme_picker.py +113 -0
  99. synapse/ui/git_explore/__init__.py +31 -0
  100. synapse/ui/git_explore/engine.py +82 -0
  101. synapse/ui/git_explore/provider.py +242 -0
  102. synapse/ui/git_explore/unified.py +85 -0
  103. synapse/ui/rendering.py +350 -0
  104. synapse/ui/sink.py +70 -0
  105. synapse/ui/steer_widget.py +367 -0
  106. synapse/ui/stream.py +1207 -0
  107. synapse/ui/stream_events.py +421 -0
  108. synapse/ui/stream_runtime.py +252 -0
  109. synapse/ui/theme.py +1154 -0
  110. synapse/ui/timeline.py +621 -0
  111. synapse/ui/topbar/__init__.py +97 -0
  112. synapse/ui/topbar/components/__init__.py +150 -0
  113. synapse/ui/topbar/components/branch.py +41 -0
  114. synapse/ui/topbar/components/title.py +24 -0
  115. synapse/ui/topbar/components/tool_output.py +24 -0
  116. synapse/ui/topbar/components/usage.py +24 -0
  117. synapse/ui/topbar/components/workspace.py +32 -0
  118. synapse/ui/topbar/context.py +32 -0
  119. synapse/ui/topbar/core.py +979 -0
  120. synapse/ui/topbar/git_changes_popover.py +178 -0
  121. synapse/ui/topbar/git_chrome.py +475 -0
  122. synapse/ui/topbar/tool_output_popover.py +84 -0
  123. synapse/ui/topbar/widget.py +474 -0
  124. synapse/ui/tui.py +5717 -0
  125. synapse/ui/turn_rail.py +71 -0
  126. synapse/ui/user_turn.py +83 -0
  127. synapse/ui/welcome.py +261 -0
  128. synapse_cli_agent-0.1.13.dist-info/METADATA +412 -0
  129. synapse_cli_agent-0.1.13.dist-info/RECORD +131 -0
  130. synapse_cli_agent-0.1.13.dist-info/WHEEL +4 -0
  131. 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()