aline-ai 0.5.7__py3-none-any.whl → 0.5.8__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.
- {aline_ai-0.5.7.dist-info → aline_ai-0.5.8.dist-info}/METADATA +1 -1
- {aline_ai-0.5.7.dist-info → aline_ai-0.5.8.dist-info}/RECORD +12 -12
- realign/__init__.py +1 -1
- realign/cli.py +24 -6
- realign/commands/search.py +30 -0
- realign/dashboard/app.py +49 -25
- realign/dashboard/widgets/sessions_table.py +19 -7
- realign/dashboard/widgets/terminal_panel.py +24 -14
- {aline_ai-0.5.7.dist-info → aline_ai-0.5.8.dist-info}/WHEEL +0 -0
- {aline_ai-0.5.7.dist-info → aline_ai-0.5.8.dist-info}/entry_points.txt +0 -0
- {aline_ai-0.5.7.dist-info → aline_ai-0.5.8.dist-info}/licenses/LICENSE +0 -0
- {aline_ai-0.5.7.dist-info → aline_ai-0.5.8.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
aline_ai-0.5.
|
|
2
|
-
realign/__init__.py,sha256=
|
|
1
|
+
aline_ai-0.5.8.dist-info/licenses/LICENSE,sha256=H8wTqV5IF1oHw_HbBtS1PSDU8G_q81yblEIL_JfV8Vo,1077
|
|
2
|
+
realign/__init__.py,sha256=r_zeipazrpik0MPgEERMIzrPFCcbvLypS_erc6wytjc,1623
|
|
3
3
|
realign/claude_detector.py,sha256=ZLSJacMo6zzQclXByABKA70UNpstxqIv3fPGqdpA934,2792
|
|
4
|
-
realign/cli.py,sha256=
|
|
4
|
+
realign/cli.py,sha256=9VS3WbysZ78NRK5EvkJVg8s6Uh2TQjsGX1E9Pl81pHc,31234
|
|
5
5
|
realign/codex_detector.py,sha256=N9ulgMgvTzDfXE4s4vLd6OoS0hT7R6h2bDFFXWa-2hE,4183
|
|
6
6
|
realign/config.py,sha256=lIKZqeOwYc_gHo760lYYX6PnapuKrCWGqT5SA8-PbeA,12044
|
|
7
7
|
realign/context.py,sha256=S1YEUn5HWSDTerDDMsSsRV871IZxoaxDjPTPI2z6-Xs,9976
|
|
@@ -39,12 +39,12 @@ realign/commands/export_shares.py,sha256=Djy1aO7MoU1_ewzn6CZ43oNhSEEonV3sTkSQbHg
|
|
|
39
39
|
realign/commands/import_shares.py,sha256=ukX8huvLvEM5g0qEIoqrV1-imz1g-r0Jj2FqD-ojrIA,25297
|
|
40
40
|
realign/commands/init.py,sha256=ef-q3Qz5D_0Eqld8qjtX26X2QrovBSYcva3uAjiJuwk,33015
|
|
41
41
|
realign/commands/restore.py,sha256=s2BxQZHxQw9r12NzRVsK20KlGafy5AIoSjWMo5PcnHY,11173
|
|
42
|
-
realign/commands/search.py,sha256=
|
|
42
|
+
realign/commands/search.py,sha256=QJrC0hln9sCDFxXbpo0nPGMHXrud18qA5QfRyD0z6fQ,25926
|
|
43
43
|
realign/commands/upgrade.py,sha256=L3PLOUIN5qAQTbkfoVtSsIbbzEezA_xjjk9F1GMVfjw,12781
|
|
44
44
|
realign/commands/watcher.py,sha256=fWL3kaRkqE03-NtFLaXlx93hJAQrAuNPSoYhOyQZfq8,136273
|
|
45
45
|
realign/commands/worker.py,sha256=K1DG1uZ--ebKwklHCyIFdN_axoLjL9Onx8Naq-DOZBs,23078
|
|
46
46
|
realign/dashboard/__init__.py,sha256=QZkHTsGityH8UkF8rmvA3xW7dMXNe0swEWr443qfgCM,128
|
|
47
|
-
realign/dashboard/app.py,sha256=
|
|
47
|
+
realign/dashboard/app.py,sha256=jyW6mqmItTy253CPSqInxctkWzkrGEikdy-ikuShQ14,13299
|
|
48
48
|
realign/dashboard/tmux_manager.py,sha256=DdCiumQ7YQZnje5VfOQ60585C0X6Va_AhBQi_zmhE0Y,24035
|
|
49
49
|
realign/dashboard/screens/__init__.py,sha256=US6sAmQs5VVkH2tFkH_z0WDT4H8cVhLL-JckfSR1yQY,446
|
|
50
50
|
realign/dashboard/screens/create_agent.py,sha256=ugEs3IHrT7FsbuMEwyrqY3eoylp_pbftw42_Fu07tF4,7419
|
|
@@ -60,8 +60,8 @@ realign/dashboard/widgets/events_table.py,sha256=OG9RjwU4c50-RUMmdhXzmIMnYrt6_mC
|
|
|
60
60
|
realign/dashboard/widgets/header.py,sha256=0HHCFXX7F3C6HII-WDwOJwWkJrajmKPWmdoMWyOkn9E,1587
|
|
61
61
|
realign/dashboard/widgets/openable_table.py,sha256=GeJPDEYp0kRHShqvmPMzAePpYXRZHUNqcWNnxqsqxjA,1963
|
|
62
62
|
realign/dashboard/widgets/search_panel.py,sha256=ZNJDfwDSxUFnCeltYQYsQsPJ6t4HDeNWpENoTOoBdVM,8951
|
|
63
|
-
realign/dashboard/widgets/sessions_table.py,sha256=
|
|
64
|
-
realign/dashboard/widgets/terminal_panel.py,sha256=
|
|
63
|
+
realign/dashboard/widgets/sessions_table.py,sha256=PohOkg-ESLBa-Sq0PdLPhV-YzVXOGpUo5ETs0MYO4u8,33415
|
|
64
|
+
realign/dashboard/widgets/terminal_panel.py,sha256=S4UUMlFaBWDKZB_MR0jhBNvdwdGvPuRNHNxweFGDfks,28751
|
|
65
65
|
realign/dashboard/widgets/watcher_panel.py,sha256=O_mdDacgc87xA-5KEfta53Ik_Xsk_B2OfwenMOTtGw8,19722
|
|
66
66
|
realign/dashboard/widgets/worker_panel.py,sha256=F_jKWABuCNmjQgeeuCr4KnFRKdY4CLTNcEXMYwsNaSk,18691
|
|
67
67
|
realign/db/__init__.py,sha256=-1d-Zc4IOUVokbdTXi3R-bIwlkFEPAz_qTHAdcsdp6g,1870
|
|
@@ -88,8 +88,8 @@ realign/triggers/next_turn_trigger.py,sha256=BpP0PWn4mU1MZd6mv89jWcjs8Jtv0zEWapW
|
|
|
88
88
|
realign/triggers/registry.py,sha256=cb-AVLbYB2pqwfWL3q1DQxLv4kOw7g7m-GshTdfFESc,3827
|
|
89
89
|
realign/triggers/turn_status.py,sha256=wAZEhXDAmDoX5F-ohWfSnZZ0eA6DAJ9svSPiSv_f6sg,6041
|
|
90
90
|
realign/triggers/turn_summary.py,sha256=f3hEUshgv9skJ9AbfWpoYs417lsv_HK2A_vpPjgryO4,4467
|
|
91
|
-
aline_ai-0.5.
|
|
92
|
-
aline_ai-0.5.
|
|
93
|
-
aline_ai-0.5.
|
|
94
|
-
aline_ai-0.5.
|
|
95
|
-
aline_ai-0.5.
|
|
91
|
+
aline_ai-0.5.8.dist-info/METADATA,sha256=S2cnGF2C84A28xQzAGz7nszWbBKErn4LazeX6KhAiBA,1597
|
|
92
|
+
aline_ai-0.5.8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
93
|
+
aline_ai-0.5.8.dist-info/entry_points.txt,sha256=TvYELpMoWsUTcQdMV8tBHxCbEf_LbK4sESqK3r8PM6Y,78
|
|
94
|
+
aline_ai-0.5.8.dist-info/top_level.txt,sha256=yIL3s2xv9nf1GwD5n71Aq_JEIV4AfzCIDNKBzewuRm4,8
|
|
95
|
+
aline_ai-0.5.8.dist-info/RECORD,,
|
realign/__init__.py
CHANGED
realign/cli.py
CHANGED
|
@@ -819,18 +819,36 @@ def version():
|
|
|
819
819
|
def dashboard(
|
|
820
820
|
ctx: typer.Context,
|
|
821
821
|
dev: bool = typer.Option(False, "--dev", help="Enable developer mode (shows Watcher and Worker tabs)"),
|
|
822
|
+
debug: bool = typer.Option(False, "--debug", help="Enable debug logging to ~/.aline/.logs/dashboard.log"),
|
|
822
823
|
):
|
|
823
824
|
"""Open the interactive TUI dashboard."""
|
|
825
|
+
import os
|
|
826
|
+
import traceback
|
|
827
|
+
|
|
828
|
+
# Set debug log level if requested
|
|
829
|
+
if debug:
|
|
830
|
+
os.environ["REALIGN_LOG_LEVEL"] = "DEBUG"
|
|
831
|
+
|
|
824
832
|
from .dashboard.tmux_manager import bootstrap_dashboard_into_tmux
|
|
833
|
+
from .logging_config import setup_logger
|
|
834
|
+
|
|
835
|
+
# Initialize logger before dashboard
|
|
836
|
+
logger = setup_logger("realign.dashboard", "dashboard.log")
|
|
837
|
+
logger.info(f"Dashboard command invoked (dev={dev}, debug={debug})")
|
|
825
838
|
|
|
826
|
-
|
|
839
|
+
try:
|
|
840
|
+
bootstrap_dashboard_into_tmux()
|
|
827
841
|
|
|
828
|
-
|
|
842
|
+
from .dashboard.app import AlineDashboard
|
|
829
843
|
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
844
|
+
# Use dev flag from this command or inherit from parent context
|
|
845
|
+
dev_mode = dev or (ctx.obj.get("dev", False) if ctx.obj else False)
|
|
846
|
+
dash = AlineDashboard(dev_mode=dev_mode)
|
|
847
|
+
dash.run()
|
|
848
|
+
except Exception as e:
|
|
849
|
+
logger.error(f"Dashboard crashed: {e}\n{traceback.format_exc()}")
|
|
850
|
+
# Re-raise so user sees the error
|
|
851
|
+
raise
|
|
834
852
|
|
|
835
853
|
|
|
836
854
|
# Restore command group
|
realign/commands/search.py
CHANGED
|
@@ -528,6 +528,19 @@ def search_command(
|
|
|
528
528
|
|
|
529
529
|
console.print(f"[dim]Found {', '.join(summary_parts)}.[/dim]")
|
|
530
530
|
|
|
531
|
+
# Check if any result count hits the limit - suggest increasing limit
|
|
532
|
+
hit_limit = (
|
|
533
|
+
event_count == limit
|
|
534
|
+
or turn_count == limit
|
|
535
|
+
or session_count == limit
|
|
536
|
+
or (type == "content" and len(results.get("content", [])) == limit)
|
|
537
|
+
)
|
|
538
|
+
if hit_limit:
|
|
539
|
+
console.print(
|
|
540
|
+
f"[yellow]Results may be truncated (limit={limit}). "
|
|
541
|
+
f"Use --limit N to see more results.[/yellow]"
|
|
542
|
+
)
|
|
543
|
+
|
|
531
544
|
# === Original structured output for non-regex mode ===
|
|
532
545
|
else:
|
|
533
546
|
if type == "all":
|
|
@@ -624,6 +637,23 @@ def search_command(
|
|
|
624
637
|
"\n[dim]Tip: Use --verbose to see Markdown previews, or --no-regex for exact keyword match.[/dim]"
|
|
625
638
|
)
|
|
626
639
|
|
|
640
|
+
# Check if any result count hits the limit - suggest increasing limit
|
|
641
|
+
event_count = len(results.get("events", []))
|
|
642
|
+
turn_count = len(results.get("turns", []))
|
|
643
|
+
session_count = len(results.get("sessions", []))
|
|
644
|
+
content_count = len(results.get("content", []))
|
|
645
|
+
hit_limit = (
|
|
646
|
+
event_count == limit
|
|
647
|
+
or turn_count == limit
|
|
648
|
+
or session_count == limit
|
|
649
|
+
or content_count == limit
|
|
650
|
+
)
|
|
651
|
+
if hit_limit:
|
|
652
|
+
console.print(
|
|
653
|
+
f"[yellow]Results may be truncated (limit={limit}). "
|
|
654
|
+
f"Use --limit N to see more results.[/yellow]"
|
|
655
|
+
)
|
|
656
|
+
|
|
627
657
|
return 0
|
|
628
658
|
|
|
629
659
|
except Exception as e:
|
realign/dashboard/app.py
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
import subprocess
|
|
4
4
|
import sys
|
|
5
5
|
import time
|
|
6
|
+
import traceback
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
from textual.app import App, ComposeResult
|
|
9
10
|
from textual.binding import Binding
|
|
10
11
|
from textual.widgets import Footer, TabbedContent, TabPane
|
|
11
12
|
|
|
13
|
+
from ..logging_config import setup_logger
|
|
12
14
|
from .widgets import (
|
|
13
15
|
AlineHeader,
|
|
14
16
|
WatcherPanel,
|
|
@@ -20,6 +22,9 @@ from .widgets import (
|
|
|
20
22
|
TerminalPanel,
|
|
21
23
|
)
|
|
22
24
|
|
|
25
|
+
# Set up dashboard logger - logs to ~/.aline/.logs/dashboard.log
|
|
26
|
+
logger = setup_logger("realign.dashboard", "dashboard.log")
|
|
27
|
+
|
|
23
28
|
|
|
24
29
|
def _detect_system_dark_mode() -> bool:
|
|
25
30
|
"""Detect if the system is in dark mode.
|
|
@@ -77,28 +82,35 @@ class AlineDashboard(App):
|
|
|
77
82
|
"""
|
|
78
83
|
super().__init__()
|
|
79
84
|
self.dev_mode = dev_mode
|
|
85
|
+
logger.info(f"AlineDashboard initialized (dev_mode={dev_mode})")
|
|
80
86
|
|
|
81
87
|
def compose(self) -> ComposeResult:
|
|
82
88
|
"""Compose the dashboard layout."""
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
logger.debug("compose() started")
|
|
90
|
+
try:
|
|
91
|
+
yield AlineHeader()
|
|
92
|
+
tab_ids = self._tab_ids()
|
|
93
|
+
with TabbedContent(initial=tab_ids[0] if tab_ids else "terminal"):
|
|
94
|
+
with TabPane("Agents", id="terminal"):
|
|
95
|
+
yield TerminalPanel()
|
|
96
|
+
if self.dev_mode:
|
|
97
|
+
with TabPane("Watcher", id="watcher"):
|
|
98
|
+
yield WatcherPanel()
|
|
99
|
+
with TabPane("Worker", id="worker"):
|
|
100
|
+
yield WorkerPanel()
|
|
101
|
+
with TabPane("Contexts", id="sessions"):
|
|
102
|
+
yield SessionsTable()
|
|
103
|
+
with TabPane("Share", id="events"):
|
|
104
|
+
yield EventsTable()
|
|
105
|
+
with TabPane("Config", id="config"):
|
|
106
|
+
yield ConfigPanel()
|
|
107
|
+
with TabPane("Search", id="search"):
|
|
108
|
+
yield SearchPanel()
|
|
109
|
+
yield Footer()
|
|
110
|
+
logger.debug("compose() completed successfully")
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.error(f"compose() failed: {e}\n{traceback.format_exc()}")
|
|
113
|
+
raise
|
|
102
114
|
|
|
103
115
|
def _tab_ids(self) -> list[str]:
|
|
104
116
|
if self.dev_mode:
|
|
@@ -107,10 +119,16 @@ class AlineDashboard(App):
|
|
|
107
119
|
|
|
108
120
|
def on_mount(self) -> None:
|
|
109
121
|
"""Apply theme based on system settings and watch for changes."""
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
122
|
+
logger.info("on_mount() started")
|
|
123
|
+
try:
|
|
124
|
+
self._sync_theme()
|
|
125
|
+
# Check for system theme changes every 2 seconds
|
|
126
|
+
self.set_interval(2, self._sync_theme)
|
|
127
|
+
self._quit_confirm_deadline: float | None = None
|
|
128
|
+
logger.info("on_mount() completed successfully")
|
|
129
|
+
except Exception as e:
|
|
130
|
+
logger.error(f"on_mount() failed: {e}\n{traceback.format_exc()}")
|
|
131
|
+
raise
|
|
114
132
|
|
|
115
133
|
def _sync_theme(self) -> None:
|
|
116
134
|
"""Sync app theme with system theme."""
|
|
@@ -341,8 +359,14 @@ class AlineDashboard(App):
|
|
|
341
359
|
|
|
342
360
|
def run_dashboard() -> None:
|
|
343
361
|
"""Run the Aline Dashboard."""
|
|
344
|
-
|
|
345
|
-
|
|
362
|
+
logger.info("Starting Aline Dashboard")
|
|
363
|
+
try:
|
|
364
|
+
app = AlineDashboard()
|
|
365
|
+
app.run()
|
|
366
|
+
logger.info("Aline Dashboard exited normally")
|
|
367
|
+
except Exception as e:
|
|
368
|
+
logger.error(f"Dashboard crashed: {e}\n{traceback.format_exc()}")
|
|
369
|
+
raise
|
|
346
370
|
|
|
347
371
|
|
|
348
372
|
if __name__ == "__main__":
|
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
import os
|
|
7
7
|
import shutil
|
|
8
8
|
import subprocess
|
|
9
|
+
import traceback
|
|
9
10
|
from datetime import datetime
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import List, Optional, Set
|
|
@@ -18,8 +19,11 @@ from textual.reactive import reactive
|
|
|
18
19
|
from textual.worker import Worker, WorkerState
|
|
19
20
|
from textual.widgets import Button, DataTable, Static
|
|
20
21
|
|
|
22
|
+
from ...logging_config import setup_logger
|
|
21
23
|
from .openable_table import OpenableDataTable
|
|
22
24
|
|
|
25
|
+
logger = setup_logger("realign.dashboard.sessions", "dashboard.log")
|
|
26
|
+
|
|
23
27
|
|
|
24
28
|
class SessionsListTable(OpenableDataTable):
|
|
25
29
|
"""Sessions list table with multi-select behavior."""
|
|
@@ -145,13 +149,19 @@ class SessionsTable(Container):
|
|
|
145
149
|
|
|
146
150
|
def on_mount(self) -> None:
|
|
147
151
|
"""Set up the table on mount."""
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
logger.debug("SessionsTable.on_mount() started")
|
|
153
|
+
try:
|
|
154
|
+
table = self.query_one("#sessions-table", SessionsListTable)
|
|
155
|
+
table.owner = self
|
|
150
156
|
|
|
151
|
-
|
|
157
|
+
self._setup_table_columns(table)
|
|
152
158
|
|
|
153
|
-
|
|
154
|
-
|
|
159
|
+
# Calculate initial rows per page
|
|
160
|
+
self._calculate_rows_per_page()
|
|
161
|
+
logger.debug("SessionsTable.on_mount() completed")
|
|
162
|
+
except Exception as e:
|
|
163
|
+
logger.error(f"SessionsTable.on_mount() failed: {e}\n{traceback.format_exc()}")
|
|
164
|
+
raise
|
|
155
165
|
|
|
156
166
|
def on_resize(self) -> None:
|
|
157
167
|
"""Handle window resize to adjust rows per page."""
|
|
@@ -793,6 +803,7 @@ class SessionsTable(Container):
|
|
|
793
803
|
}
|
|
794
804
|
|
|
795
805
|
# Get paginated sessions
|
|
806
|
+
# Use cached total_turns instead of subquery for performance
|
|
796
807
|
offset = (int(page) - 1) * int(rows_per_page)
|
|
797
808
|
rows = conn.execute(
|
|
798
809
|
"""
|
|
@@ -802,7 +813,7 @@ class SessionsTable(Container):
|
|
|
802
813
|
s.workspace_path,
|
|
803
814
|
s.session_title,
|
|
804
815
|
s.last_activity_at,
|
|
805
|
-
|
|
816
|
+
s.total_turns
|
|
806
817
|
FROM sessions s
|
|
807
818
|
ORDER BY s.last_activity_at DESC
|
|
808
819
|
LIMIT ? OFFSET ?
|
|
@@ -847,7 +858,8 @@ class SessionsTable(Container):
|
|
|
847
858
|
"last_activity": activity_str,
|
|
848
859
|
}
|
|
849
860
|
)
|
|
850
|
-
except Exception:
|
|
861
|
+
except Exception as e:
|
|
862
|
+
logger.error(f"_collect_snapshot failed: {e}\n{traceback.format_exc()}")
|
|
851
863
|
total_sessions = 0
|
|
852
864
|
stats = {}
|
|
853
865
|
sessions = []
|
|
@@ -11,6 +11,7 @@ import asyncio
|
|
|
11
11
|
import os
|
|
12
12
|
import re
|
|
13
13
|
import shlex
|
|
14
|
+
import traceback
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
from typing import Callable
|
|
16
17
|
|
|
@@ -21,6 +22,9 @@ from textual.widgets import Button, Static
|
|
|
21
22
|
from rich.text import Text
|
|
22
23
|
|
|
23
24
|
from .. import tmux_manager
|
|
25
|
+
from ...logging_config import setup_logger
|
|
26
|
+
|
|
27
|
+
logger = setup_logger("realign.dashboard.terminal", "dashboard.log")
|
|
24
28
|
|
|
25
29
|
|
|
26
30
|
# Signal directory for permission request notifications
|
|
@@ -291,21 +295,27 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
291
295
|
self._signal_watcher: _SignalFileWatcher | None = None
|
|
292
296
|
|
|
293
297
|
def compose(self) -> ComposeResult:
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if controls_enabled:
|
|
304
|
-
yield Static(
|
|
305
|
-
"No terminals yet. Click 'Create' to open a new agent terminal."
|
|
298
|
+
logger.debug("TerminalPanel.compose() started")
|
|
299
|
+
try:
|
|
300
|
+
controls_enabled = self.supported()
|
|
301
|
+
with Horizontal(classes="summary"):
|
|
302
|
+
yield Button(
|
|
303
|
+
"+ Create",
|
|
304
|
+
id="new-agent",
|
|
305
|
+
variant="primary",
|
|
306
|
+
disabled=not controls_enabled,
|
|
306
307
|
)
|
|
307
|
-
|
|
308
|
-
|
|
308
|
+
with Vertical(id="terminals", classes="list"):
|
|
309
|
+
if controls_enabled:
|
|
310
|
+
yield Static(
|
|
311
|
+
"No terminals yet. Click 'Create' to open a new agent terminal."
|
|
312
|
+
)
|
|
313
|
+
else:
|
|
314
|
+
yield Static(self._support_message())
|
|
315
|
+
logger.debug("TerminalPanel.compose() completed")
|
|
316
|
+
except Exception as e:
|
|
317
|
+
logger.error(f"TerminalPanel.compose() failed: {e}\n{traceback.format_exc()}")
|
|
318
|
+
raise
|
|
309
319
|
|
|
310
320
|
def on_show(self) -> None:
|
|
311
321
|
# Don't `await refresh_data()` directly here: Textual may do an initial layout pass with
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|