superqode 0.1.5__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 (288) hide show
  1. superqode/__init__.py +33 -0
  2. superqode/acp/__init__.py +23 -0
  3. superqode/acp/client.py +913 -0
  4. superqode/acp/permission_screen.py +457 -0
  5. superqode/acp/types.py +480 -0
  6. superqode/acp_discovery.py +856 -0
  7. superqode/agent/__init__.py +22 -0
  8. superqode/agent/edit_strategies.py +334 -0
  9. superqode/agent/loop.py +892 -0
  10. superqode/agent/qe_report_templates.py +39 -0
  11. superqode/agent/system_prompts.py +353 -0
  12. superqode/agent_output.py +721 -0
  13. superqode/agent_stream.py +953 -0
  14. superqode/agents/__init__.py +59 -0
  15. superqode/agents/acp_registry.py +305 -0
  16. superqode/agents/client.py +249 -0
  17. superqode/agents/data/augmentcode.com.toml +51 -0
  18. superqode/agents/data/cagent.dev.toml +51 -0
  19. superqode/agents/data/claude.com.toml +60 -0
  20. superqode/agents/data/codeassistant.dev.toml +51 -0
  21. superqode/agents/data/codex.openai.com.toml +57 -0
  22. superqode/agents/data/fastagent.ai.toml +66 -0
  23. superqode/agents/data/geminicli.com.toml +77 -0
  24. superqode/agents/data/goose.block.xyz.toml +54 -0
  25. superqode/agents/data/junie.jetbrains.com.toml +56 -0
  26. superqode/agents/data/kimi.moonshot.cn.toml +57 -0
  27. superqode/agents/data/llmlingagent.dev.toml +51 -0
  28. superqode/agents/data/molt.bot.toml +49 -0
  29. superqode/agents/data/opencode.ai.toml +60 -0
  30. superqode/agents/data/stakpak.dev.toml +51 -0
  31. superqode/agents/data/vtcode.dev.toml +51 -0
  32. superqode/agents/discovery.py +266 -0
  33. superqode/agents/messaging.py +160 -0
  34. superqode/agents/persona.py +166 -0
  35. superqode/agents/registry.py +421 -0
  36. superqode/agents/schema.py +72 -0
  37. superqode/agents/unified.py +367 -0
  38. superqode/app/__init__.py +111 -0
  39. superqode/app/constants.py +314 -0
  40. superqode/app/css.py +366 -0
  41. superqode/app/models.py +118 -0
  42. superqode/app/suggester.py +125 -0
  43. superqode/app/widgets.py +1591 -0
  44. superqode/app_enhanced.py +399 -0
  45. superqode/app_main.py +17187 -0
  46. superqode/approval.py +312 -0
  47. superqode/atomic.py +296 -0
  48. superqode/commands/__init__.py +1 -0
  49. superqode/commands/acp.py +965 -0
  50. superqode/commands/agents.py +180 -0
  51. superqode/commands/auth.py +278 -0
  52. superqode/commands/config.py +374 -0
  53. superqode/commands/init.py +826 -0
  54. superqode/commands/providers.py +819 -0
  55. superqode/commands/qe.py +1145 -0
  56. superqode/commands/roles.py +380 -0
  57. superqode/commands/serve.py +172 -0
  58. superqode/commands/suggestions.py +127 -0
  59. superqode/commands/superqe.py +460 -0
  60. superqode/config/__init__.py +51 -0
  61. superqode/config/loader.py +812 -0
  62. superqode/config/schema.py +498 -0
  63. superqode/core/__init__.py +111 -0
  64. superqode/core/roles.py +281 -0
  65. superqode/danger.py +386 -0
  66. superqode/data/superqode-template.yaml +1522 -0
  67. superqode/design_system.py +1080 -0
  68. superqode/dialogs/__init__.py +6 -0
  69. superqode/dialogs/base.py +39 -0
  70. superqode/dialogs/model.py +130 -0
  71. superqode/dialogs/provider.py +870 -0
  72. superqode/diff_view.py +919 -0
  73. superqode/enterprise.py +21 -0
  74. superqode/evaluation/__init__.py +25 -0
  75. superqode/evaluation/adapters.py +93 -0
  76. superqode/evaluation/behaviors.py +89 -0
  77. superqode/evaluation/engine.py +209 -0
  78. superqode/evaluation/scenarios.py +96 -0
  79. superqode/execution/__init__.py +36 -0
  80. superqode/execution/linter.py +538 -0
  81. superqode/execution/modes.py +347 -0
  82. superqode/execution/resolver.py +283 -0
  83. superqode/execution/runner.py +642 -0
  84. superqode/file_explorer.py +811 -0
  85. superqode/file_viewer.py +471 -0
  86. superqode/flash.py +183 -0
  87. superqode/guidance/__init__.py +58 -0
  88. superqode/guidance/config.py +203 -0
  89. superqode/guidance/prompts.py +71 -0
  90. superqode/harness/__init__.py +54 -0
  91. superqode/harness/accelerator.py +291 -0
  92. superqode/harness/config.py +319 -0
  93. superqode/harness/validator.py +147 -0
  94. superqode/history.py +279 -0
  95. superqode/integrations/superopt_runner.py +124 -0
  96. superqode/logging/__init__.py +49 -0
  97. superqode/logging/adapters.py +219 -0
  98. superqode/logging/formatter.py +923 -0
  99. superqode/logging/integration.py +341 -0
  100. superqode/logging/sinks.py +170 -0
  101. superqode/logging/unified_log.py +417 -0
  102. superqode/lsp/__init__.py +26 -0
  103. superqode/lsp/client.py +544 -0
  104. superqode/main.py +1069 -0
  105. superqode/mcp/__init__.py +89 -0
  106. superqode/mcp/auth_storage.py +380 -0
  107. superqode/mcp/client.py +1236 -0
  108. superqode/mcp/config.py +319 -0
  109. superqode/mcp/integration.py +337 -0
  110. superqode/mcp/oauth.py +436 -0
  111. superqode/mcp/oauth_callback.py +385 -0
  112. superqode/mcp/types.py +290 -0
  113. superqode/memory/__init__.py +31 -0
  114. superqode/memory/feedback.py +342 -0
  115. superqode/memory/store.py +522 -0
  116. superqode/notifications.py +369 -0
  117. superqode/optimization/__init__.py +5 -0
  118. superqode/optimization/config.py +33 -0
  119. superqode/permissions/__init__.py +25 -0
  120. superqode/permissions/rules.py +488 -0
  121. superqode/plan.py +323 -0
  122. superqode/providers/__init__.py +33 -0
  123. superqode/providers/gateway/__init__.py +165 -0
  124. superqode/providers/gateway/base.py +228 -0
  125. superqode/providers/gateway/litellm_gateway.py +1170 -0
  126. superqode/providers/gateway/openresponses_gateway.py +436 -0
  127. superqode/providers/health.py +297 -0
  128. superqode/providers/huggingface/__init__.py +74 -0
  129. superqode/providers/huggingface/downloader.py +472 -0
  130. superqode/providers/huggingface/endpoints.py +442 -0
  131. superqode/providers/huggingface/hub.py +531 -0
  132. superqode/providers/huggingface/inference.py +394 -0
  133. superqode/providers/huggingface/transformers_runner.py +516 -0
  134. superqode/providers/local/__init__.py +100 -0
  135. superqode/providers/local/base.py +438 -0
  136. superqode/providers/local/discovery.py +418 -0
  137. superqode/providers/local/lmstudio.py +256 -0
  138. superqode/providers/local/mlx.py +457 -0
  139. superqode/providers/local/ollama.py +486 -0
  140. superqode/providers/local/sglang.py +268 -0
  141. superqode/providers/local/tgi.py +260 -0
  142. superqode/providers/local/tool_support.py +477 -0
  143. superqode/providers/local/vllm.py +258 -0
  144. superqode/providers/manager.py +1338 -0
  145. superqode/providers/models.py +1016 -0
  146. superqode/providers/models_dev.py +578 -0
  147. superqode/providers/openresponses/__init__.py +87 -0
  148. superqode/providers/openresponses/converters/__init__.py +17 -0
  149. superqode/providers/openresponses/converters/messages.py +343 -0
  150. superqode/providers/openresponses/converters/tools.py +268 -0
  151. superqode/providers/openresponses/schema/__init__.py +56 -0
  152. superqode/providers/openresponses/schema/models.py +585 -0
  153. superqode/providers/openresponses/streaming/__init__.py +5 -0
  154. superqode/providers/openresponses/streaming/parser.py +338 -0
  155. superqode/providers/openresponses/tools/__init__.py +21 -0
  156. superqode/providers/openresponses/tools/apply_patch.py +352 -0
  157. superqode/providers/openresponses/tools/code_interpreter.py +290 -0
  158. superqode/providers/openresponses/tools/file_search.py +333 -0
  159. superqode/providers/openresponses/tools/mcp_adapter.py +252 -0
  160. superqode/providers/registry.py +716 -0
  161. superqode/providers/usage.py +332 -0
  162. superqode/pure_mode.py +384 -0
  163. superqode/qr/__init__.py +23 -0
  164. superqode/qr/dashboard.py +781 -0
  165. superqode/qr/generator.py +1018 -0
  166. superqode/qr/templates.py +135 -0
  167. superqode/safety/__init__.py +41 -0
  168. superqode/safety/sandbox.py +413 -0
  169. superqode/safety/warnings.py +256 -0
  170. superqode/server/__init__.py +33 -0
  171. superqode/server/lsp_server.py +775 -0
  172. superqode/server/web.py +250 -0
  173. superqode/session/__init__.py +25 -0
  174. superqode/session/persistence.py +580 -0
  175. superqode/session/sharing.py +477 -0
  176. superqode/session.py +475 -0
  177. superqode/sidebar.py +2991 -0
  178. superqode/stream_view.py +648 -0
  179. superqode/styles/__init__.py +3 -0
  180. superqode/superqe/__init__.py +184 -0
  181. superqode/superqe/acp_runner.py +1064 -0
  182. superqode/superqe/constitution/__init__.py +62 -0
  183. superqode/superqe/constitution/evaluator.py +308 -0
  184. superqode/superqe/constitution/loader.py +432 -0
  185. superqode/superqe/constitution/schema.py +250 -0
  186. superqode/superqe/events.py +591 -0
  187. superqode/superqe/frameworks/__init__.py +65 -0
  188. superqode/superqe/frameworks/base.py +234 -0
  189. superqode/superqe/frameworks/e2e.py +263 -0
  190. superqode/superqe/frameworks/executor.py +237 -0
  191. superqode/superqe/frameworks/javascript.py +409 -0
  192. superqode/superqe/frameworks/python.py +373 -0
  193. superqode/superqe/frameworks/registry.py +92 -0
  194. superqode/superqe/mcp_tools/__init__.py +47 -0
  195. superqode/superqe/mcp_tools/core_tools.py +418 -0
  196. superqode/superqe/mcp_tools/registry.py +230 -0
  197. superqode/superqe/mcp_tools/testing_tools.py +167 -0
  198. superqode/superqe/noise.py +89 -0
  199. superqode/superqe/orchestrator.py +778 -0
  200. superqode/superqe/roles.py +609 -0
  201. superqode/superqe/session.py +713 -0
  202. superqode/superqe/skills/__init__.py +57 -0
  203. superqode/superqe/skills/base.py +106 -0
  204. superqode/superqe/skills/core_skills.py +899 -0
  205. superqode/superqe/skills/registry.py +90 -0
  206. superqode/superqe/verifier.py +101 -0
  207. superqode/superqe_cli.py +76 -0
  208. superqode/tool_call.py +358 -0
  209. superqode/tools/__init__.py +93 -0
  210. superqode/tools/agent_tools.py +496 -0
  211. superqode/tools/base.py +324 -0
  212. superqode/tools/batch_tool.py +133 -0
  213. superqode/tools/diagnostics.py +311 -0
  214. superqode/tools/edit_tools.py +653 -0
  215. superqode/tools/enhanced_base.py +515 -0
  216. superqode/tools/file_tools.py +269 -0
  217. superqode/tools/file_tracking.py +45 -0
  218. superqode/tools/lsp_tools.py +610 -0
  219. superqode/tools/network_tools.py +350 -0
  220. superqode/tools/permissions.py +400 -0
  221. superqode/tools/question_tool.py +324 -0
  222. superqode/tools/search_tools.py +598 -0
  223. superqode/tools/shell_tools.py +259 -0
  224. superqode/tools/todo_tools.py +121 -0
  225. superqode/tools/validation.py +80 -0
  226. superqode/tools/web_tools.py +639 -0
  227. superqode/tui.py +1152 -0
  228. superqode/tui_integration.py +875 -0
  229. superqode/tui_widgets/__init__.py +27 -0
  230. superqode/tui_widgets/widgets/__init__.py +18 -0
  231. superqode/tui_widgets/widgets/progress.py +185 -0
  232. superqode/tui_widgets/widgets/tool_display.py +188 -0
  233. superqode/undo_manager.py +574 -0
  234. superqode/utils/__init__.py +5 -0
  235. superqode/utils/error_handling.py +323 -0
  236. superqode/utils/fuzzy.py +257 -0
  237. superqode/widgets/__init__.py +477 -0
  238. superqode/widgets/agent_collab.py +390 -0
  239. superqode/widgets/agent_store.py +936 -0
  240. superqode/widgets/agent_switcher.py +395 -0
  241. superqode/widgets/animation_manager.py +284 -0
  242. superqode/widgets/code_context.py +356 -0
  243. superqode/widgets/command_palette.py +412 -0
  244. superqode/widgets/connection_status.py +537 -0
  245. superqode/widgets/conversation_history.py +470 -0
  246. superqode/widgets/diff_indicator.py +155 -0
  247. superqode/widgets/enhanced_status_bar.py +385 -0
  248. superqode/widgets/enhanced_toast.py +476 -0
  249. superqode/widgets/file_browser.py +809 -0
  250. superqode/widgets/file_reference.py +585 -0
  251. superqode/widgets/issue_timeline.py +340 -0
  252. superqode/widgets/leader_key.py +264 -0
  253. superqode/widgets/mode_switcher.py +445 -0
  254. superqode/widgets/model_picker.py +234 -0
  255. superqode/widgets/permission_preview.py +1205 -0
  256. superqode/widgets/prompt.py +358 -0
  257. superqode/widgets/provider_connect.py +725 -0
  258. superqode/widgets/pty_shell.py +587 -0
  259. superqode/widgets/qe_dashboard.py +321 -0
  260. superqode/widgets/resizable_sidebar.py +377 -0
  261. superqode/widgets/response_changes.py +218 -0
  262. superqode/widgets/response_display.py +528 -0
  263. superqode/widgets/rich_tool_display.py +613 -0
  264. superqode/widgets/sidebar_panels.py +1180 -0
  265. superqode/widgets/slash_complete.py +356 -0
  266. superqode/widgets/split_view.py +612 -0
  267. superqode/widgets/status_bar.py +273 -0
  268. superqode/widgets/superqode_display.py +786 -0
  269. superqode/widgets/thinking_display.py +815 -0
  270. superqode/widgets/throbber.py +87 -0
  271. superqode/widgets/toast.py +206 -0
  272. superqode/widgets/unified_output.py +1073 -0
  273. superqode/workspace/__init__.py +75 -0
  274. superqode/workspace/artifacts.py +472 -0
  275. superqode/workspace/coordinator.py +353 -0
  276. superqode/workspace/diff_tracker.py +429 -0
  277. superqode/workspace/git_guard.py +373 -0
  278. superqode/workspace/git_snapshot.py +526 -0
  279. superqode/workspace/manager.py +750 -0
  280. superqode/workspace/snapshot.py +357 -0
  281. superqode/workspace/watcher.py +535 -0
  282. superqode/workspace/worktree.py +440 -0
  283. superqode-0.1.5.dist-info/METADATA +204 -0
  284. superqode-0.1.5.dist-info/RECORD +288 -0
  285. superqode-0.1.5.dist-info/WHEEL +5 -0
  286. superqode-0.1.5.dist-info/entry_points.txt +3 -0
  287. superqode-0.1.5.dist-info/licenses/LICENSE +648 -0
  288. superqode-0.1.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,385 @@
1
+ """
2
+ Enhanced Status Bar - Comprehensive Information Display.
3
+
4
+ A beautiful, information-rich status bar showing:
5
+ - Connection status (ACP/BYOK)
6
+ - Model and provider info
7
+ - Token usage and cost
8
+ - Tool call progress
9
+ - Thinking indicator
10
+ - Mode indicator
11
+ - Conversation count
12
+ - Latency/performance
13
+
14
+ Brings together all status information in one place.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import asyncio
20
+ from dataclasses import dataclass, field
21
+ from datetime import datetime
22
+ from enum import Enum
23
+ from typing import Any, Callable, Dict, List, Optional
24
+
25
+ from rich.console import RenderableType
26
+ from rich.text import Text
27
+ from textual.reactive import reactive
28
+ from textual.widgets import Static
29
+ from textual.containers import Horizontal
30
+ from textual.timer import Timer
31
+ from textual import events
32
+
33
+
34
+ class AgentStatus(Enum):
35
+ """Status of the agent."""
36
+
37
+ IDLE = "idle"
38
+ CONNECTING = "connecting"
39
+ THINKING = "thinking"
40
+ STREAMING = "streaming"
41
+ TOOL_CALL = "tool_call"
42
+ WAITING = "waiting"
43
+ ERROR = "error"
44
+
45
+
46
+ @dataclass
47
+ class StatusBarState:
48
+ """State for the enhanced status bar."""
49
+
50
+ # Connection
51
+ connected: bool = False
52
+ connection_type: str = "" # "acp", "byok", "local"
53
+
54
+ # Agent/Model
55
+ agent_name: str = ""
56
+ model_name: str = ""
57
+ provider: str = ""
58
+
59
+ # Status
60
+ status: AgentStatus = AgentStatus.IDLE
61
+ status_message: str = ""
62
+
63
+ # Progress
64
+ tool_count: int = 0
65
+ tools_running: int = 0
66
+ tools_complete: int = 0
67
+ tools_error: int = 0
68
+
69
+ # Tokens
70
+ prompt_tokens: int = 0
71
+ completion_tokens: int = 0
72
+ total_cost: float = 0.0
73
+
74
+ # Conversation
75
+ message_count: int = 0
76
+
77
+ # Mode
78
+ mode: str = "home"
79
+
80
+ # Performance
81
+ latency_ms: Optional[float] = None
82
+ last_response_time: Optional[float] = None
83
+
84
+
85
+ # Status styling
86
+ STATUS_STYLES = {
87
+ AgentStatus.IDLE: {"icon": "○", "color": "#52525b", "animate": False},
88
+ AgentStatus.CONNECTING: {"icon": "◐", "color": "#fbbf24", "animate": True},
89
+ AgentStatus.THINKING: {"icon": "💭", "color": "#ec4899", "animate": True},
90
+ AgentStatus.STREAMING: {"icon": "●", "color": "#22c55e", "animate": True},
91
+ AgentStatus.TOOL_CALL: {"icon": "🔧", "color": "#f59e0b", "animate": True},
92
+ AgentStatus.WAITING: {"icon": "⏳", "color": "#3b82f6", "animate": False},
93
+ AgentStatus.ERROR: {"icon": "✗", "color": "#ef4444", "animate": False},
94
+ }
95
+
96
+ PROVIDER_ICONS = {
97
+ "anthropic": "🧠",
98
+ "openai": "🤖",
99
+ "google": "🔮",
100
+ "mistral": "🌊",
101
+ "groq": "⚡",
102
+ "ollama": "🦙",
103
+ "opencode": "💻",
104
+ "local": "💻",
105
+ }
106
+
107
+
108
+ class EnhancedStatusBar(Static):
109
+ """
110
+ Enhanced status bar with comprehensive information.
111
+
112
+ Displays all key information in a compact, beautiful format.
113
+ """
114
+
115
+ DEFAULT_CSS = """
116
+ EnhancedStatusBar {
117
+ height: 1;
118
+ background: #0f0f0f;
119
+ border-top: solid #27272a;
120
+ padding: 0 1;
121
+ }
122
+
123
+ EnhancedStatusBar.error {
124
+ background: #1a0f0f;
125
+ }
126
+
127
+ EnhancedStatusBar.active {
128
+ background: #0f1a0f;
129
+ }
130
+ """
131
+
132
+ def __init__(self, **kwargs):
133
+ super().__init__(**kwargs)
134
+ self._state = StatusBarState()
135
+ self._frame = 0
136
+ self._timer: Optional[Timer] = None
137
+
138
+ def on_mount(self) -> None:
139
+ """Start animation timer."""
140
+ self._timer = self.set_interval(0.25, self._tick)
141
+
142
+ def _tick(self) -> None:
143
+ """Animation tick."""
144
+ self._frame += 1
145
+ status_style = STATUS_STYLES.get(self._state.status, STATUS_STYLES[AgentStatus.IDLE])
146
+ if status_style["animate"]:
147
+ self.refresh()
148
+
149
+ def update_state(self, **kwargs) -> None:
150
+ """Update status bar state."""
151
+ for key, value in kwargs.items():
152
+ if hasattr(self._state, key):
153
+ setattr(self._state, key, value)
154
+
155
+ # Update CSS classes
156
+ self.remove_class("error", "active")
157
+ if self._state.status == AgentStatus.ERROR:
158
+ self.add_class("error")
159
+ elif self._state.status in (
160
+ AgentStatus.STREAMING,
161
+ AgentStatus.THINKING,
162
+ AgentStatus.TOOL_CALL,
163
+ ):
164
+ self.add_class("active")
165
+
166
+ self.refresh()
167
+
168
+ def set_status(self, status: AgentStatus, message: str = "") -> None:
169
+ """Set the current status."""
170
+ self.update_state(status=status, status_message=message)
171
+
172
+ def _get_animated_icon(self) -> str:
173
+ """Get animated status icon."""
174
+ status_style = STATUS_STYLES.get(self._state.status, STATUS_STYLES[AgentStatus.IDLE])
175
+
176
+ if not status_style["animate"]:
177
+ return status_style["icon"]
178
+
179
+ if self._state.status == AgentStatus.THINKING:
180
+ frames = ["💭", "💬", "💭", "💬"]
181
+ return frames[self._frame % len(frames)]
182
+ elif self._state.status == AgentStatus.STREAMING:
183
+ frames = ["●", "◐", "○", "◑"]
184
+ return frames[self._frame % len(frames)]
185
+ elif self._state.status == AgentStatus.TOOL_CALL:
186
+ frames = ["🔧", "⚙️", "🔧", "⚙️"]
187
+ return frames[self._frame % len(frames)]
188
+ else:
189
+ frames = ["◐", "◓", "◑", "◒"]
190
+ return frames[self._frame % len(frames)]
191
+
192
+ def render(self) -> Text:
193
+ state = self._state
194
+ result = Text()
195
+
196
+ # ═══════════════════════════════════════════════════════════════════
197
+ # LEFT SECTION - Connection & Model
198
+ # ═══════════════════════════════════════════════════════════════════
199
+
200
+ # Connection indicator
201
+ if state.connected:
202
+ result.append("● ", style="bold #22c55e")
203
+ else:
204
+ result.append("○ ", style="#52525b")
205
+
206
+ # Connection type badge
207
+ if state.connection_type:
208
+ type_label = state.connection_type.upper()
209
+ result.append(f"[{type_label}] ", style="#6b7280")
210
+
211
+ # Provider/Agent icon and name
212
+ provider_icon = PROVIDER_ICONS.get(state.provider.lower(), "🤖")
213
+ if state.agent_name:
214
+ result.append(f"{provider_icon} ", style="#a855f7")
215
+ result.append(state.agent_name, style="#a855f7")
216
+ elif state.model_name:
217
+ result.append(f"{provider_icon} ", style="#6b7280")
218
+ # Truncate long model names
219
+ model_display = state.model_name
220
+ if len(model_display) > 20:
221
+ model_display = model_display[:17] + "..."
222
+ result.append(model_display, style="#a1a1aa")
223
+ else:
224
+ result.append("No agent", style="#52525b")
225
+
226
+ result.append(" │ ", style="#27272a")
227
+
228
+ # ═══════════════════════════════════════════════════════════════════
229
+ # CENTER SECTION - Status
230
+ # ═══════════════════════════════════════════════════════════════════
231
+
232
+ status_style = STATUS_STYLES.get(state.status, STATUS_STYLES[AgentStatus.IDLE])
233
+ status_icon = self._get_animated_icon()
234
+
235
+ result.append(f"{status_icon} ", style=f"bold {status_style['color']}")
236
+
237
+ # Status text
238
+ if state.status_message:
239
+ result.append(state.status_message[:30], style=status_style["color"])
240
+ else:
241
+ result.append(state.status.value.replace("_", " ").title(), style=status_style["color"])
242
+
243
+ result.append(" │ ", style="#27272a")
244
+
245
+ # ═══════════════════════════════════════════════════════════════════
246
+ # TOOL PROGRESS
247
+ # ═══════════════════════════════════════════════════════════════════
248
+
249
+ if state.tool_count > 0 or state.tools_running > 0:
250
+ result.append("🔧 ", style="#f59e0b")
251
+
252
+ if state.tools_running > 0:
253
+ result.append(f"◐{state.tools_running} ", style="bold #fbbf24")
254
+ if state.tools_complete > 0:
255
+ result.append(f"✓{state.tools_complete} ", style="#22c55e")
256
+ if state.tools_error > 0:
257
+ result.append(f"✗{state.tools_error} ", style="#ef4444")
258
+
259
+ result.append(" │ ", style="#27272a")
260
+
261
+ # ═══════════════════════════════════════════════════════════════════
262
+ # RIGHT SECTION - Stats
263
+ # ═══════════════════════════════════════════════════════════════════
264
+
265
+ # Token usage
266
+ total_tokens = state.prompt_tokens + state.completion_tokens
267
+ if total_tokens > 0:
268
+ result.append("📊 ", style="#6b7280")
269
+ result.append(f"{total_tokens:,}", style="#a1a1aa")
270
+ result.append(" ", style="")
271
+
272
+ # Cost
273
+ if state.total_cost > 0:
274
+ result.append("💰 ", style="#6b7280")
275
+ result.append(f"${state.total_cost:.3f}", style="#fbbf24")
276
+ result.append(" ", style="")
277
+
278
+ # Message count
279
+ if state.message_count > 0:
280
+ result.append("💬 ", style="#6b7280")
281
+ result.append(f"{state.message_count}", style="#a1a1aa")
282
+ result.append(" ", style="")
283
+
284
+ # Latency
285
+ if state.latency_ms is not None:
286
+ latency_color = (
287
+ "#22c55e"
288
+ if state.latency_ms < 200
289
+ else "#f59e0b"
290
+ if state.latency_ms < 500
291
+ else "#ef4444"
292
+ )
293
+ result.append("📶 ", style="#6b7280")
294
+ result.append(f"{state.latency_ms:.0f}ms", style=latency_color)
295
+ result.append(" ", style="")
296
+
297
+ # Mode indicator
298
+ result.append("│ ", style="#27272a")
299
+ mode_icons = {
300
+ "home": "🏠",
301
+ "qe": "🔍",
302
+ "agent": "🤖",
303
+ "chat": "💬",
304
+ "review": "📝",
305
+ }
306
+ mode_icon = mode_icons.get(state.mode.lower(), "📌")
307
+ result.append(f"{mode_icon} ", style="#3b82f6")
308
+ result.append(state.mode.upper(), style="bold #3b82f6")
309
+
310
+ return result
311
+
312
+
313
+ class MiniStatusIndicator(Static):
314
+ """
315
+ Mini status indicator for compact displays.
316
+
317
+ Shows essential status in minimal space.
318
+ """
319
+
320
+ DEFAULT_CSS = """
321
+ MiniStatusIndicator {
322
+ width: auto;
323
+ height: 1;
324
+ }
325
+ """
326
+
327
+ def __init__(self, **kwargs):
328
+ super().__init__(**kwargs)
329
+ self._connected = False
330
+ self._status = AgentStatus.IDLE
331
+ self._model = ""
332
+ self._frame = 0
333
+
334
+ def update(
335
+ self,
336
+ connected: bool = None,
337
+ status: AgentStatus = None,
338
+ model: str = None,
339
+ ) -> None:
340
+ """Update the indicator."""
341
+ if connected is not None:
342
+ self._connected = connected
343
+ if status is not None:
344
+ self._status = status
345
+ if model is not None:
346
+ self._model = model
347
+ self.refresh()
348
+
349
+ def animate(self) -> None:
350
+ """Advance animation frame."""
351
+ self._frame += 1
352
+ self.refresh()
353
+
354
+ def render(self) -> Text:
355
+ result = Text()
356
+
357
+ # Connection dot
358
+ if self._connected:
359
+ result.append("● ", style="bold #22c55e")
360
+ else:
361
+ result.append("○ ", style="#52525b")
362
+
363
+ # Status icon
364
+ status_style = STATUS_STYLES.get(self._status, STATUS_STYLES[AgentStatus.IDLE])
365
+ if status_style["animate"]:
366
+ frames = ["◐", "◓", "◑", "◒"]
367
+ icon = frames[self._frame % len(frames)]
368
+ else:
369
+ icon = status_style["icon"]
370
+
371
+ result.append(f"{icon} ", style=status_style["color"])
372
+
373
+ # Model name (short)
374
+ if self._model:
375
+ model_short = self._model[:15] + "..." if len(self._model) > 15 else self._model
376
+ result.append(model_short, style="#6b7280")
377
+
378
+ return result
379
+
380
+
381
+ def create_default_status_bar() -> EnhancedStatusBar:
382
+ """Create a default enhanced status bar."""
383
+ bar = EnhancedStatusBar()
384
+ bar.update_state(mode="home")
385
+ return bar