kweaver-dolphin 0.1.0__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 (199) hide show
  1. DolphinLanguageSDK/__init__.py +58 -0
  2. dolphin/__init__.py +62 -0
  3. dolphin/cli/__init__.py +20 -0
  4. dolphin/cli/args/__init__.py +9 -0
  5. dolphin/cli/args/parser.py +567 -0
  6. dolphin/cli/builtin_agents/__init__.py +22 -0
  7. dolphin/cli/commands/__init__.py +4 -0
  8. dolphin/cli/interrupt/__init__.py +8 -0
  9. dolphin/cli/interrupt/handler.py +205 -0
  10. dolphin/cli/interrupt/keyboard.py +82 -0
  11. dolphin/cli/main.py +49 -0
  12. dolphin/cli/multimodal/__init__.py +34 -0
  13. dolphin/cli/multimodal/clipboard.py +327 -0
  14. dolphin/cli/multimodal/handler.py +249 -0
  15. dolphin/cli/multimodal/image_processor.py +214 -0
  16. dolphin/cli/multimodal/input_parser.py +149 -0
  17. dolphin/cli/runner/__init__.py +8 -0
  18. dolphin/cli/runner/runner.py +989 -0
  19. dolphin/cli/ui/__init__.py +10 -0
  20. dolphin/cli/ui/console.py +2795 -0
  21. dolphin/cli/ui/input.py +340 -0
  22. dolphin/cli/ui/layout.py +425 -0
  23. dolphin/cli/ui/stream_renderer.py +302 -0
  24. dolphin/cli/utils/__init__.py +8 -0
  25. dolphin/cli/utils/helpers.py +135 -0
  26. dolphin/cli/utils/version.py +49 -0
  27. dolphin/core/__init__.py +107 -0
  28. dolphin/core/agent/__init__.py +10 -0
  29. dolphin/core/agent/agent_state.py +69 -0
  30. dolphin/core/agent/base_agent.py +970 -0
  31. dolphin/core/code_block/__init__.py +0 -0
  32. dolphin/core/code_block/agent_init_block.py +0 -0
  33. dolphin/core/code_block/assign_block.py +98 -0
  34. dolphin/core/code_block/basic_code_block.py +1865 -0
  35. dolphin/core/code_block/explore_block.py +1327 -0
  36. dolphin/core/code_block/explore_block_v2.py +712 -0
  37. dolphin/core/code_block/explore_strategy.py +672 -0
  38. dolphin/core/code_block/judge_block.py +220 -0
  39. dolphin/core/code_block/prompt_block.py +32 -0
  40. dolphin/core/code_block/skill_call_deduplicator.py +291 -0
  41. dolphin/core/code_block/tool_block.py +129 -0
  42. dolphin/core/common/__init__.py +17 -0
  43. dolphin/core/common/constants.py +176 -0
  44. dolphin/core/common/enums.py +1173 -0
  45. dolphin/core/common/exceptions.py +133 -0
  46. dolphin/core/common/multimodal.py +539 -0
  47. dolphin/core/common/object_type.py +165 -0
  48. dolphin/core/common/output_format.py +432 -0
  49. dolphin/core/common/types.py +36 -0
  50. dolphin/core/config/__init__.py +16 -0
  51. dolphin/core/config/global_config.py +1289 -0
  52. dolphin/core/config/ontology_config.py +133 -0
  53. dolphin/core/context/__init__.py +12 -0
  54. dolphin/core/context/context.py +1580 -0
  55. dolphin/core/context/context_manager.py +161 -0
  56. dolphin/core/context/var_output.py +82 -0
  57. dolphin/core/context/variable_pool.py +356 -0
  58. dolphin/core/context_engineer/__init__.py +41 -0
  59. dolphin/core/context_engineer/config/__init__.py +5 -0
  60. dolphin/core/context_engineer/config/settings.py +402 -0
  61. dolphin/core/context_engineer/core/__init__.py +7 -0
  62. dolphin/core/context_engineer/core/budget_manager.py +327 -0
  63. dolphin/core/context_engineer/core/context_assembler.py +583 -0
  64. dolphin/core/context_engineer/core/context_manager.py +637 -0
  65. dolphin/core/context_engineer/core/tokenizer_service.py +260 -0
  66. dolphin/core/context_engineer/example/incremental_example.py +267 -0
  67. dolphin/core/context_engineer/example/traditional_example.py +334 -0
  68. dolphin/core/context_engineer/services/__init__.py +5 -0
  69. dolphin/core/context_engineer/services/compressor.py +399 -0
  70. dolphin/core/context_engineer/utils/__init__.py +6 -0
  71. dolphin/core/context_engineer/utils/context_utils.py +441 -0
  72. dolphin/core/context_engineer/utils/message_formatter.py +270 -0
  73. dolphin/core/context_engineer/utils/token_utils.py +139 -0
  74. dolphin/core/coroutine/__init__.py +15 -0
  75. dolphin/core/coroutine/context_snapshot.py +154 -0
  76. dolphin/core/coroutine/context_snapshot_profile.py +922 -0
  77. dolphin/core/coroutine/context_snapshot_store.py +268 -0
  78. dolphin/core/coroutine/execution_frame.py +145 -0
  79. dolphin/core/coroutine/execution_state_registry.py +161 -0
  80. dolphin/core/coroutine/resume_handle.py +101 -0
  81. dolphin/core/coroutine/step_result.py +101 -0
  82. dolphin/core/executor/__init__.py +18 -0
  83. dolphin/core/executor/debug_controller.py +630 -0
  84. dolphin/core/executor/dolphin_executor.py +1063 -0
  85. dolphin/core/executor/executor.py +624 -0
  86. dolphin/core/flags/__init__.py +27 -0
  87. dolphin/core/flags/definitions.py +49 -0
  88. dolphin/core/flags/manager.py +113 -0
  89. dolphin/core/hook/__init__.py +95 -0
  90. dolphin/core/hook/expression_evaluator.py +499 -0
  91. dolphin/core/hook/hook_dispatcher.py +380 -0
  92. dolphin/core/hook/hook_types.py +248 -0
  93. dolphin/core/hook/isolated_variable_pool.py +284 -0
  94. dolphin/core/interfaces.py +53 -0
  95. dolphin/core/llm/__init__.py +0 -0
  96. dolphin/core/llm/llm.py +495 -0
  97. dolphin/core/llm/llm_call.py +100 -0
  98. dolphin/core/llm/llm_client.py +1285 -0
  99. dolphin/core/llm/message_sanitizer.py +120 -0
  100. dolphin/core/logging/__init__.py +20 -0
  101. dolphin/core/logging/logger.py +526 -0
  102. dolphin/core/message/__init__.py +8 -0
  103. dolphin/core/message/compressor.py +749 -0
  104. dolphin/core/parser/__init__.py +8 -0
  105. dolphin/core/parser/parser.py +405 -0
  106. dolphin/core/runtime/__init__.py +10 -0
  107. dolphin/core/runtime/runtime_graph.py +926 -0
  108. dolphin/core/runtime/runtime_instance.py +446 -0
  109. dolphin/core/skill/__init__.py +14 -0
  110. dolphin/core/skill/context_retention.py +157 -0
  111. dolphin/core/skill/skill_function.py +686 -0
  112. dolphin/core/skill/skill_matcher.py +282 -0
  113. dolphin/core/skill/skillkit.py +700 -0
  114. dolphin/core/skill/skillset.py +72 -0
  115. dolphin/core/trajectory/__init__.py +10 -0
  116. dolphin/core/trajectory/recorder.py +189 -0
  117. dolphin/core/trajectory/trajectory.py +522 -0
  118. dolphin/core/utils/__init__.py +9 -0
  119. dolphin/core/utils/cache_kv.py +212 -0
  120. dolphin/core/utils/tools.py +340 -0
  121. dolphin/lib/__init__.py +93 -0
  122. dolphin/lib/debug/__init__.py +8 -0
  123. dolphin/lib/debug/visualizer.py +409 -0
  124. dolphin/lib/memory/__init__.py +28 -0
  125. dolphin/lib/memory/async_processor.py +220 -0
  126. dolphin/lib/memory/llm_calls.py +195 -0
  127. dolphin/lib/memory/manager.py +78 -0
  128. dolphin/lib/memory/sandbox.py +46 -0
  129. dolphin/lib/memory/storage.py +245 -0
  130. dolphin/lib/memory/utils.py +51 -0
  131. dolphin/lib/ontology/__init__.py +12 -0
  132. dolphin/lib/ontology/basic/__init__.py +0 -0
  133. dolphin/lib/ontology/basic/base.py +102 -0
  134. dolphin/lib/ontology/basic/concept.py +130 -0
  135. dolphin/lib/ontology/basic/object.py +11 -0
  136. dolphin/lib/ontology/basic/relation.py +63 -0
  137. dolphin/lib/ontology/datasource/__init__.py +27 -0
  138. dolphin/lib/ontology/datasource/datasource.py +66 -0
  139. dolphin/lib/ontology/datasource/oracle_datasource.py +338 -0
  140. dolphin/lib/ontology/datasource/sql.py +845 -0
  141. dolphin/lib/ontology/mapping.py +177 -0
  142. dolphin/lib/ontology/ontology.py +733 -0
  143. dolphin/lib/ontology/ontology_context.py +16 -0
  144. dolphin/lib/ontology/ontology_manager.py +107 -0
  145. dolphin/lib/skill_results/__init__.py +31 -0
  146. dolphin/lib/skill_results/cache_backend.py +559 -0
  147. dolphin/lib/skill_results/result_processor.py +181 -0
  148. dolphin/lib/skill_results/result_reference.py +179 -0
  149. dolphin/lib/skill_results/skillkit_hook.py +324 -0
  150. dolphin/lib/skill_results/strategies.py +328 -0
  151. dolphin/lib/skill_results/strategy_registry.py +150 -0
  152. dolphin/lib/skillkits/__init__.py +44 -0
  153. dolphin/lib/skillkits/agent_skillkit.py +155 -0
  154. dolphin/lib/skillkits/cognitive_skillkit.py +82 -0
  155. dolphin/lib/skillkits/env_skillkit.py +250 -0
  156. dolphin/lib/skillkits/mcp_adapter.py +616 -0
  157. dolphin/lib/skillkits/mcp_skillkit.py +771 -0
  158. dolphin/lib/skillkits/memory_skillkit.py +650 -0
  159. dolphin/lib/skillkits/noop_skillkit.py +31 -0
  160. dolphin/lib/skillkits/ontology_skillkit.py +89 -0
  161. dolphin/lib/skillkits/plan_act_skillkit.py +452 -0
  162. dolphin/lib/skillkits/resource/__init__.py +52 -0
  163. dolphin/lib/skillkits/resource/models/__init__.py +6 -0
  164. dolphin/lib/skillkits/resource/models/skill_config.py +109 -0
  165. dolphin/lib/skillkits/resource/models/skill_meta.py +127 -0
  166. dolphin/lib/skillkits/resource/resource_skillkit.py +393 -0
  167. dolphin/lib/skillkits/resource/skill_cache.py +215 -0
  168. dolphin/lib/skillkits/resource/skill_loader.py +395 -0
  169. dolphin/lib/skillkits/resource/skill_validator.py +406 -0
  170. dolphin/lib/skillkits/resource_skillkit.py +11 -0
  171. dolphin/lib/skillkits/search_skillkit.py +163 -0
  172. dolphin/lib/skillkits/sql_skillkit.py +274 -0
  173. dolphin/lib/skillkits/system_skillkit.py +509 -0
  174. dolphin/lib/skillkits/vm_skillkit.py +65 -0
  175. dolphin/lib/utils/__init__.py +9 -0
  176. dolphin/lib/utils/data_process.py +207 -0
  177. dolphin/lib/utils/handle_progress.py +178 -0
  178. dolphin/lib/utils/security.py +139 -0
  179. dolphin/lib/utils/text_retrieval.py +462 -0
  180. dolphin/lib/vm/__init__.py +11 -0
  181. dolphin/lib/vm/env_executor.py +895 -0
  182. dolphin/lib/vm/python_session_manager.py +453 -0
  183. dolphin/lib/vm/vm.py +610 -0
  184. dolphin/sdk/__init__.py +60 -0
  185. dolphin/sdk/agent/__init__.py +12 -0
  186. dolphin/sdk/agent/agent_factory.py +236 -0
  187. dolphin/sdk/agent/dolphin_agent.py +1106 -0
  188. dolphin/sdk/api/__init__.py +4 -0
  189. dolphin/sdk/runtime/__init__.py +8 -0
  190. dolphin/sdk/runtime/env.py +363 -0
  191. dolphin/sdk/skill/__init__.py +10 -0
  192. dolphin/sdk/skill/global_skills.py +706 -0
  193. dolphin/sdk/skill/traditional_toolkit.py +260 -0
  194. kweaver_dolphin-0.1.0.dist-info/METADATA +521 -0
  195. kweaver_dolphin-0.1.0.dist-info/RECORD +199 -0
  196. kweaver_dolphin-0.1.0.dist-info/WHEEL +5 -0
  197. kweaver_dolphin-0.1.0.dist-info/entry_points.txt +27 -0
  198. kweaver_dolphin-0.1.0.dist-info/licenses/LICENSE.txt +201 -0
  199. kweaver_dolphin-0.1.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,425 @@
1
+ """
2
+ Layout Manager - Terminal layout management with fixed bottom status area.
3
+
4
+ This module provides the LayoutManager class which manages terminal layouts
5
+ with a fixed bottom status area and scrollable content region.
6
+
7
+ Architecture:
8
+ ┌──────────────────────────────────────────────────────┐
9
+ │ [Scrollable Content Region] │ ← Lines 1 to (height - 3)
10
+ │ ✓ Tool output, logs, responses, user input │
11
+ │ > User input appears here in scroll region │
12
+ │ ... │
13
+ └──────────────────────────────────────────────────────┘
14
+ ──────────────────────────────────────────────────────── ← Fixed separator at height-2
15
+ ⠋ Status Bar (animated spinner + timer) ← Fixed at height-1
16
+
17
+ Features:
18
+ - ANSI scroll region for content (lines 1 to N-3)
19
+ - Fixed separator line between content and status
20
+ - Fixed status bar at bottom with spinner animation
21
+ - Input prompt appears INSIDE the scroll region (not fixed)
22
+ """
23
+
24
+ import signal
25
+ import os
26
+ import sys
27
+ from typing import Optional
28
+
29
+ from dolphin.cli.ui.console import StatusBar, Theme, set_active_status_bar
30
+
31
+
32
+ def _should_enable_layout() -> bool:
33
+ """Multi-check to ensure layout is only enabled in correct environments.
34
+
35
+ Returns:
36
+ True if the terminal supports advanced layout features
37
+ """
38
+ # Not a TTY
39
+ if not sys.stdout.isatty():
40
+ return False
41
+
42
+ # No TERM environment variable
43
+ if not os.environ.get('TERM'):
44
+ return False
45
+
46
+ # Running in Jupyter
47
+ if 'ipykernel' in sys.modules:
48
+ return False
49
+
50
+ # Running in pytest
51
+ if 'pytest' in sys.modules:
52
+ return False
53
+
54
+ # Dumb terminal
55
+ if os.environ.get('TERM') == 'dumb':
56
+ return False
57
+
58
+ return True
59
+
60
+
61
+ class LayoutManager:
62
+ """Manages terminal layout with fixed bottom status area.
63
+
64
+ Provides a modern CLI experience with:
65
+ - Scrollable content region at top (including user input)
66
+ - Fixed separator line
67
+ - Fixed status bar at bottom
68
+
69
+ The layout uses ANSI escape sequences to create scroll regions.
70
+ User input happens INSIDE the scroll region, not in a fixed area.
71
+
72
+ Usage:
73
+ layout = LayoutManager(enabled=True)
74
+ layout.start_session("Interactive", "my_agent")
75
+
76
+ # During execution
77
+ layout.show_status("Processing your request...")
78
+
79
+ # Content prints normally and scrolls
80
+ print("Some output...")
81
+
82
+ # End session
83
+ layout.end_session()
84
+
85
+ Attributes:
86
+ enabled: Whether layout features are active
87
+ _status_bar: Active StatusBar instance
88
+ _terminal_height: Cached terminal height
89
+ _terminal_width: Cached terminal width
90
+ """
91
+
92
+ # Reserve lines at bottom: separator (1) + status bar (1) + buffer (1)
93
+ BOTTOM_RESERVE = 3
94
+
95
+ def __init__(self, enabled: bool = True):
96
+ """Initialize layout manager.
97
+
98
+ Args:
99
+ enabled: Enable layout features (auto-disabled if terminal unsupported)
100
+ """
101
+ self.enabled = enabled and _should_enable_layout()
102
+ self._status_bar: Optional[StatusBar] = None
103
+ self._terminal_height = 24
104
+ self._terminal_width = 80
105
+ self._scroll_region_active = False
106
+ self._session_active = False
107
+ self._original_sigwinch_handler = None
108
+
109
+ def _get_terminal_size(self) -> tuple:
110
+ """Get terminal dimensions.
111
+
112
+ Returns:
113
+ Tuple of (height, width)
114
+ """
115
+ try:
116
+ import shutil
117
+ size = shutil.get_terminal_size()
118
+ return size.lines, size.columns
119
+ except Exception:
120
+ return 24, 80
121
+
122
+ def _handle_resize(self, signum, frame):
123
+ """Handle terminal resize event."""
124
+ if not self.enabled:
125
+ return
126
+
127
+ # Get new size
128
+ try:
129
+ height, width = self._get_terminal_size()
130
+ except:
131
+ return
132
+
133
+ if height == self._terminal_height and width == self._terminal_width:
134
+ return
135
+
136
+ old_height = self._terminal_height
137
+
138
+ # Update dimensions
139
+ self._terminal_height = height
140
+ self._terminal_width = width
141
+
142
+ # Re-setup scroll region
143
+ try:
144
+ scroll_bottom = height - self.BOTTOM_RESERVE
145
+ if scroll_bottom >= 5:
146
+ sys.stdout.write(f"\033[1;{scroll_bottom}r")
147
+ self._scroll_region_active = True
148
+ else:
149
+ sys.stdout.write("\033[r")
150
+ self._scroll_region_active = False
151
+ except:
152
+ pass
153
+
154
+ # Update Status Bar if active
155
+ if self._status_bar:
156
+ self._status_bar.fixed_row = height - 1
157
+
158
+ # Redraw Separator
159
+ if self._scroll_region_active:
160
+ self._draw_separator()
161
+
162
+ sys.stdout.flush()
163
+
164
+ def _setup_scroll_region(self) -> None:
165
+ """Setup ANSI scroll region (top portion of screen)."""
166
+ if not self.enabled:
167
+ return
168
+
169
+ self._terminal_height, self._terminal_width = self._get_terminal_size()
170
+ scroll_bottom = self._terminal_height - self.BOTTOM_RESERVE
171
+
172
+ if scroll_bottom < 5:
173
+ # Terminal too small, disable layout
174
+ self.enabled = False
175
+ return
176
+
177
+ # Push existing content up to prevent overlap with fixed region
178
+ sys.stdout.write("\n" * self.BOTTOM_RESERVE)
179
+
180
+ # Set scroll region: ESC[<top>;<bottom>r
181
+ sys.stdout.write(f"\033[1;{scroll_bottom}r")
182
+ # Move cursor to top of scroll region
183
+ sys.stdout.write("\033[1;1H")
184
+ sys.stdout.flush()
185
+ self._scroll_region_active = True
186
+
187
+ def _reset_scroll_region(self) -> None:
188
+ """Reset scroll region to full screen.
189
+
190
+ This method:
191
+ 1. Resets the scroll region to cover the entire terminal
192
+ 2. Clears the fixed separator and status bar lines (they are now stale)
193
+ 3. Positions cursor at a reasonable location for subsequent output
194
+ """
195
+ if self._scroll_region_active:
196
+ height = self._terminal_height
197
+
198
+ # Build a single atomic output sequence
199
+ output_parts = [
200
+ "\033[r", # Reset scroll region to full screen
201
+ "\033[?25h", # Show cursor
202
+ ]
203
+
204
+ # Clear the fixed separator line (was at height-2)
205
+ sep_line = height - 2
206
+ if sep_line > 0:
207
+ output_parts.append(f"\033[{sep_line};1H\033[K")
208
+
209
+ # Clear the fixed status bar line (was at height-1)
210
+ status_line = height - 1
211
+ if status_line > 0:
212
+ output_parts.append(f"\033[{status_line};1H\033[K")
213
+
214
+ # Clear the bottom line too (height)
215
+ output_parts.append(f"\033[{height};1H\033[K")
216
+
217
+ # Position cursor at what was the scroll region bottom + 1
218
+ # This is where new output should appear after session ends
219
+ scroll_bottom = height - self.BOTTOM_RESERVE
220
+ cursor_row = scroll_bottom + 1
221
+ if cursor_row > height:
222
+ cursor_row = height
223
+ output_parts.append(f"\033[{cursor_row};1H")
224
+
225
+ sys.stdout.write("".join(output_parts))
226
+ sys.stdout.flush()
227
+ self._scroll_region_active = False
228
+
229
+ def _draw_separator(self) -> None:
230
+ """Draw separator line between content and status area."""
231
+ if not self.enabled:
232
+ return
233
+
234
+ height, width = self._get_terminal_size()
235
+ sep_line = height - 2 # Separator at height-2
236
+
237
+ # Draw separator with atomic ANSI sequence
238
+ output = (
239
+ f"\0337" # Save cursor (DEC)
240
+ f"\033[{sep_line};1H" # Move to separator line
241
+ f"\033[K{Theme.BORDER}{'─' * (width)}{Theme.RESET}" # Clear & Draw
242
+ f"\0338" # Restore cursor (DEC)
243
+ )
244
+ sys.stdout.write(output)
245
+ sys.stdout.flush()
246
+
247
+ def start_session(self, mode: str, agent_name: str) -> None:
248
+ """Start a new session with the layout.
249
+
250
+ This displays the session banner and initializes the layout.
251
+
252
+ Args:
253
+ mode: Session mode (e.g., "Interactive", "Execution")
254
+ agent_name: Name of the agent being run
255
+ """
256
+ self._session_active = True
257
+
258
+ if self.enabled:
259
+ # Register resize handler
260
+ if hasattr(signal, 'SIGWINCH'):
261
+ self._original_sigwinch_handler = signal.signal(signal.SIGWINCH, self._handle_resize)
262
+
263
+ self._setup_scroll_region()
264
+ # Initial separator
265
+ self._draw_separator()
266
+
267
+ def end_session(self) -> None:
268
+ """End the current session and cleanup."""
269
+ self._session_active = False
270
+
271
+ # Restore original signal handler
272
+ if hasattr(signal, 'SIGWINCH') and self._original_sigwinch_handler:
273
+ signal.signal(signal.SIGWINCH, self._original_sigwinch_handler)
274
+ self._original_sigwinch_handler = None
275
+
276
+ # Stop status bar if running
277
+ self.hide_status()
278
+
279
+ # Reset terminal state
280
+ self._reset_scroll_region()
281
+
282
+ # Note: Removed the final print() here - it caused extra blank lines
283
+ # The _reset_scroll_region already positions cursor properly
284
+
285
+ def show_status(
286
+ self,
287
+ message: str = "Processing",
288
+ hint: str = "esc to interrupt"
289
+ ) -> StatusBar:
290
+ """Show animated status bar at fixed bottom position.
291
+
292
+ Args:
293
+ message: Status message to display
294
+ hint: Hint text (shown in parentheses)
295
+
296
+ Returns:
297
+ The StatusBar instance
298
+ """
299
+ # Stop existing status bar
300
+ if self._status_bar:
301
+ self._status_bar.stop(clear=True)
302
+
303
+ # Calculate fixed row for status bar
304
+ fixed_row = None
305
+ if self.enabled and self._scroll_region_active:
306
+ height, _ = self._get_terminal_size()
307
+ fixed_row = height - 1 # Status bar at height-1 (bottom)
308
+
309
+ StatusBar._debug_log(f"LayoutManager.show_status: enabled={self.enabled}, scroll_active={self._scroll_region_active}, fixed_row={fixed_row}")
310
+
311
+ self._status_bar = StatusBar(message=message, hint=hint, fixed_row=fixed_row)
312
+ self._status_bar.start()
313
+
314
+ # Register with global coordinator for LivePlanCard coordination
315
+ set_active_status_bar(self._status_bar)
316
+
317
+ return self._status_bar
318
+
319
+ def hide_status(self, clear: bool = True) -> None:
320
+ """Hide the status bar.
321
+
322
+ Args:
323
+ clear: Whether to clear the status bar line
324
+ """
325
+ if self._status_bar:
326
+ # Check if we were using fixed row
327
+ fixed_row = self._status_bar.fixed_row
328
+
329
+ self._status_bar.stop(clear=False)
330
+ self._status_bar = None
331
+
332
+ # Unregister from global coordinator
333
+ set_active_status_bar(None)
334
+
335
+ if clear and fixed_row is not None:
336
+ # Clear the status bar row
337
+ sys.stdout.write("\0337") # Save cursor
338
+ sys.stdout.write(f"\033[{fixed_row};1H\033[K")
339
+ sys.stdout.write("\0338") # Restore cursor
340
+ sys.stdout.flush()
341
+ elif clear:
342
+ # Fallback for inline status bar
343
+ sys.stdout.write("\r\033[K")
344
+ sys.stdout.flush()
345
+
346
+ def update_status(self, message: str) -> None:
347
+ """Update status bar message.
348
+
349
+ Args:
350
+ message: New status message
351
+ """
352
+ if self._status_bar:
353
+ self._status_bar.update_message(message)
354
+
355
+ def display_interrupt_prompt(self) -> None:
356
+ """Display the interrupt prompt UI.
357
+
358
+ Shows a formatted prompt indicating execution was interrupted
359
+ and user can provide new input.
360
+ """
361
+ print()
362
+ print(f"{Theme.WARNING}{'━' * 40}{Theme.RESET}")
363
+ print(f"{Theme.WARNING}🛑 Execution interrupted{Theme.RESET}")
364
+ print(f"{Theme.MUTED}Enter new instructions, or press Enter to continue{Theme.RESET}")
365
+ print(f"{Theme.WARNING}{'━' * 40}{Theme.RESET}")
366
+
367
+ def display_completion(self, message: str = "Completed") -> None:
368
+ """Display completion message.
369
+
370
+ Args:
371
+ message: Completion message to display
372
+ """
373
+ print(f"\n{Theme.SUCCESS}✓ {message}{Theme.RESET}")
374
+
375
+ def display_error(self, message: str) -> None:
376
+ """Display error message.
377
+
378
+ Args:
379
+ message: Error message to display
380
+ """
381
+ print(f"\n{Theme.ERROR}✗ {message}{Theme.RESET}")
382
+
383
+ def display_info(self, message: str) -> None:
384
+ """Display info message.
385
+
386
+ Args:
387
+ message: Info message to display
388
+ """
389
+ print(f"{Theme.PRIMARY}ℹ {message}{Theme.RESET}")
390
+
391
+ def display_warning(self, message: str) -> None:
392
+ """Display warning message.
393
+
394
+ Args:
395
+ message: Warning message to display
396
+ """
397
+ print(f"{Theme.WARNING}⚠ {message}{Theme.RESET}")
398
+
399
+ async def get_user_input(self, prompt: str = "> ") -> str:
400
+ """Get user input asynchronously.
401
+
402
+ This uses prompt_toolkit for async input with proper terminal handling.
403
+ Input happens INSIDE the scroll region, not in a fixed area.
404
+
405
+ Args:
406
+ prompt: Input prompt string
407
+
408
+ Returns:
409
+ User input string
410
+ """
411
+ from dolphin.cli.ui.input import prompt_conversation
412
+
413
+ # Hide status bar during input
414
+ if self._status_bar:
415
+ self._status_bar.stop(clear=True)
416
+
417
+ # Ensure cursor is visible for input
418
+ sys.stdout.write("\033[?25h")
419
+ sys.stdout.flush()
420
+
421
+ try:
422
+ return await prompt_conversation(prompt)
423
+ finally:
424
+ # If we are returning to a session, the caller will re-show/hide as needed
425
+ pass