aline-ai 0.5.4__py3-none-any.whl → 0.5.6__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.4.dist-info → aline_ai-0.5.6.dist-info}/METADATA +1 -1
- aline_ai-0.5.6.dist-info/RECORD +95 -0
- realign/__init__.py +1 -1
- realign/adapters/antigravity.py +28 -20
- realign/adapters/base.py +46 -50
- realign/adapters/claude.py +14 -14
- realign/adapters/codex.py +7 -7
- realign/adapters/gemini.py +11 -11
- realign/adapters/registry.py +14 -10
- realign/claude_detector.py +2 -2
- realign/claude_hooks/__init__.py +3 -3
- realign/claude_hooks/permission_request_hook_installer.py +31 -32
- realign/claude_hooks/stop_hook.py +4 -1
- realign/claude_hooks/stop_hook_installer.py +30 -31
- realign/cli.py +23 -4
- realign/codex_detector.py +11 -11
- realign/commands/add.py +88 -65
- realign/commands/config.py +3 -12
- realign/commands/context.py +3 -1
- realign/commands/export_shares.py +86 -127
- realign/commands/import_shares.py +145 -155
- realign/commands/init.py +166 -30
- realign/commands/restore.py +18 -6
- realign/commands/search.py +14 -42
- realign/commands/upgrade.py +155 -11
- realign/commands/watcher.py +98 -219
- realign/commands/worker.py +29 -6
- realign/config.py +25 -20
- realign/context.py +1 -3
- realign/dashboard/app.py +34 -24
- realign/dashboard/screens/__init__.py +10 -1
- realign/dashboard/screens/create_agent.py +244 -0
- realign/dashboard/screens/create_event.py +3 -1
- realign/dashboard/screens/event_detail.py +14 -6
- realign/dashboard/screens/help_screen.py +114 -0
- realign/dashboard/screens/session_detail.py +3 -1
- realign/dashboard/screens/share_import.py +7 -3
- realign/dashboard/tmux_manager.py +54 -9
- realign/dashboard/widgets/config_panel.py +85 -1
- realign/dashboard/widgets/events_table.py +314 -70
- realign/dashboard/widgets/header.py +2 -1
- realign/dashboard/widgets/search_panel.py +37 -27
- realign/dashboard/widgets/sessions_table.py +404 -85
- realign/dashboard/widgets/terminal_panel.py +155 -175
- realign/dashboard/widgets/watcher_panel.py +6 -2
- realign/dashboard/widgets/worker_panel.py +10 -1
- realign/db/__init__.py +1 -1
- realign/db/base.py +5 -15
- realign/db/locks.py +0 -1
- realign/db/migration.py +82 -76
- realign/db/schema.py +2 -6
- realign/db/sqlite_db.py +23 -41
- realign/events/__init__.py +0 -1
- realign/events/event_summarizer.py +27 -15
- realign/events/session_summarizer.py +29 -15
- realign/file_lock.py +1 -0
- realign/hooks.py +150 -60
- realign/logging_config.py +12 -15
- realign/mcp_server.py +30 -51
- realign/mcp_watcher.py +0 -1
- realign/models/event.py +29 -20
- realign/prompts/__init__.py +7 -7
- realign/prompts/presets.py +15 -11
- realign/redactor.py +99 -59
- realign/triggers/__init__.py +9 -9
- realign/triggers/antigravity_trigger.py +30 -28
- realign/triggers/base.py +4 -3
- realign/triggers/claude_trigger.py +104 -85
- realign/triggers/codex_trigger.py +15 -5
- realign/triggers/gemini_trigger.py +57 -47
- realign/triggers/next_turn_trigger.py +3 -1
- realign/triggers/registry.py +6 -2
- realign/triggers/turn_status.py +3 -1
- realign/watcher_core.py +306 -131
- realign/watcher_daemon.py +8 -8
- realign/worker_core.py +3 -1
- realign/worker_daemon.py +3 -1
- aline_ai-0.5.4.dist-info/RECORD +0 -93
- {aline_ai-0.5.4.dist-info → aline_ai-0.5.6.dist-info}/WHEEL +0 -0
- {aline_ai-0.5.4.dist-info → aline_ai-0.5.6.dist-info}/entry_points.txt +0 -0
- {aline_ai-0.5.4.dist-info → aline_ai-0.5.6.dist-info}/licenses/LICENSE +0 -0
- {aline_ai-0.5.4.dist-info → aline_ai-0.5.6.dist-info}/top_level.txt +0 -0
realign/commands/watcher.py
CHANGED
|
@@ -72,9 +72,7 @@ def detect_watcher_process() -> tuple[bool, int | None, str]:
|
|
|
72
72
|
# Then check for orphaned daemon process (PID file missing)
|
|
73
73
|
limited_detection = False
|
|
74
74
|
try:
|
|
75
|
-
ps_output = subprocess.run(
|
|
76
|
-
["ps", "aux"], capture_output=True, text=True, timeout=2
|
|
77
|
-
)
|
|
75
|
+
ps_output = subprocess.run(["ps", "aux"], capture_output=True, text=True, timeout=2)
|
|
78
76
|
if ps_output.returncode == 0:
|
|
79
77
|
for line in ps_output.stdout.split("\n"):
|
|
80
78
|
if "watcher_daemon.py" in line and "grep" not in line:
|
|
@@ -118,9 +116,7 @@ def detect_all_watcher_processes() -> list[tuple[int, str]]:
|
|
|
118
116
|
|
|
119
117
|
try:
|
|
120
118
|
# Use ps to find all watcher_daemon.py processes
|
|
121
|
-
ps_output = subprocess.run(
|
|
122
|
-
["ps", "aux"], capture_output=True, text=True, timeout=2
|
|
123
|
-
)
|
|
119
|
+
ps_output = subprocess.run(["ps", "aux"], capture_output=True, text=True, timeout=2)
|
|
124
120
|
|
|
125
121
|
if ps_output.returncode == 0:
|
|
126
122
|
for line in ps_output.stdout.split("\n"):
|
|
@@ -303,10 +299,7 @@ def _count_claude_turns(session_file: Path) -> int:
|
|
|
303
299
|
is_tool_result = False
|
|
304
300
|
if isinstance(content, list):
|
|
305
301
|
for item in content:
|
|
306
|
-
if (
|
|
307
|
-
isinstance(item, dict)
|
|
308
|
-
and item.get("type") == "tool_result"
|
|
309
|
-
):
|
|
302
|
+
if isinstance(item, dict) and item.get("type") == "tool_result":
|
|
310
303
|
is_tool_result = True
|
|
311
304
|
break
|
|
312
305
|
|
|
@@ -417,9 +410,7 @@ def get_all_tracked_sessions() -> List[Dict]:
|
|
|
417
410
|
session_details.append(details)
|
|
418
411
|
|
|
419
412
|
# Sort by mtime (most recent first)
|
|
420
|
-
session_details.sort(
|
|
421
|
-
key=lambda x: x["mtime"] if x["mtime"] else datetime.min, reverse=True
|
|
422
|
-
)
|
|
413
|
+
session_details.sort(key=lambda x: x["mtime"] if x["mtime"] else datetime.min, reverse=True)
|
|
423
414
|
|
|
424
415
|
return session_details
|
|
425
416
|
except Exception as e:
|
|
@@ -461,9 +452,7 @@ def watcher_status_command(verbose: bool = False) -> int:
|
|
|
461
452
|
console.print(f"Mode: Standalone (SQLite)")
|
|
462
453
|
|
|
463
454
|
# Active Sessions (New!)
|
|
464
|
-
console.print(
|
|
465
|
-
f"\n[bold cyan]Active Sessions (Currently Monitoring)[/bold cyan]"
|
|
466
|
-
)
|
|
455
|
+
console.print(f"\n[bold cyan]Active Sessions (Currently Monitoring)[/bold cyan]")
|
|
467
456
|
try:
|
|
468
457
|
from ..hooks import find_all_active_sessions
|
|
469
458
|
from ..adapters import get_adapter_registry
|
|
@@ -475,9 +464,7 @@ def watcher_status_command(verbose: bool = False) -> int:
|
|
|
475
464
|
for s in active_sessions[:5]: # Show top 5
|
|
476
465
|
adapter = registry.auto_detect_adapter(s)
|
|
477
466
|
source = adapter.name.capitalize() if adapter else "Unknown"
|
|
478
|
-
mtime = datetime.fromtimestamp(s.stat().st_mtime).strftime(
|
|
479
|
-
"%Y-%m-%d %H:%M:%S"
|
|
480
|
-
)
|
|
467
|
+
mtime = datetime.fromtimestamp(s.stat().st_mtime).strftime("%Y-%m-%d %H:%M:%S")
|
|
481
468
|
|
|
482
469
|
# Try to get project name
|
|
483
470
|
project_name = "-"
|
|
@@ -512,12 +499,14 @@ def watcher_status_command(verbose: bool = False) -> int:
|
|
|
512
499
|
# Recent Sessions (3)
|
|
513
500
|
console.print(f"\n[bold]Recent Sessions[/bold]")
|
|
514
501
|
sessions = list(
|
|
515
|
-
conn.execute(
|
|
502
|
+
conn.execute(
|
|
503
|
+
"""
|
|
516
504
|
SELECT id, session_type, workspace_path, last_activity_at
|
|
517
505
|
FROM sessions
|
|
518
506
|
ORDER BY last_activity_at DESC
|
|
519
507
|
LIMIT 3
|
|
520
|
-
"""
|
|
508
|
+
"""
|
|
509
|
+
)
|
|
521
510
|
)
|
|
522
511
|
|
|
523
512
|
if sessions:
|
|
@@ -555,23 +544,23 @@ def watcher_status_command(verbose: bool = False) -> int:
|
|
|
555
544
|
except:
|
|
556
545
|
pass
|
|
557
546
|
|
|
558
|
-
console.print(
|
|
559
|
-
f" {session_name} | {source} | {workspace} | {last_activity}"
|
|
560
|
-
)
|
|
547
|
+
console.print(f" {session_name} | {source} | {workspace} | {last_activity}")
|
|
561
548
|
else:
|
|
562
549
|
console.print(f" [dim](no sessions yet)[/dim]")
|
|
563
550
|
|
|
564
551
|
# Recent Conversations (5)
|
|
565
552
|
console.print(f"\n[bold]Recent Conversations[/bold]")
|
|
566
553
|
turns = list(
|
|
567
|
-
conn.execute(
|
|
554
|
+
conn.execute(
|
|
555
|
+
"""
|
|
568
556
|
SELECT t.turn_number, t.llm_title, t.timestamp,
|
|
569
557
|
s.id, s.session_type, s.workspace_path
|
|
570
558
|
FROM turns t
|
|
571
559
|
JOIN sessions s ON t.session_id = s.id
|
|
572
560
|
ORDER BY t.timestamp DESC
|
|
573
561
|
LIMIT 5
|
|
574
|
-
"""
|
|
562
|
+
"""
|
|
563
|
+
)
|
|
575
564
|
)
|
|
576
565
|
|
|
577
566
|
if turns:
|
|
@@ -647,9 +636,7 @@ def watcher_status_command(verbose: bool = False) -> int:
|
|
|
647
636
|
|
|
648
637
|
# Suggestions
|
|
649
638
|
if status == "Stopped":
|
|
650
|
-
console.print(
|
|
651
|
-
f"\n[dim]Run 'aline watcher start' to start the watcher[/dim]"
|
|
652
|
-
)
|
|
639
|
+
console.print(f"\n[dim]Run 'aline watcher start' to start the watcher[/dim]")
|
|
653
640
|
|
|
654
641
|
console.print()
|
|
655
642
|
return 0
|
|
@@ -675,9 +662,7 @@ def watcher_start_command() -> int:
|
|
|
675
662
|
is_running, pid, mode = detect_watcher_process()
|
|
676
663
|
|
|
677
664
|
if is_running:
|
|
678
|
-
console.print(
|
|
679
|
-
f"[yellow]Watcher is already running (PID: {pid}, mode: {mode})[/yellow]"
|
|
680
|
-
)
|
|
665
|
+
console.print(f"[yellow]Watcher is already running (PID: {pid}, mode: {mode})[/yellow]")
|
|
681
666
|
console.print(f"[dim]Use 'aline watcher stop' to stop it first[/dim]")
|
|
682
667
|
return 0
|
|
683
668
|
|
|
@@ -724,9 +709,7 @@ def watcher_start_command() -> int:
|
|
|
724
709
|
|
|
725
710
|
if is_running:
|
|
726
711
|
console.print(f"[green]✓ Watcher started successfully (PID: {pid})[/green]")
|
|
727
|
-
console.print(
|
|
728
|
-
f"[dim]Logs: {log_dir}/watcher_*.log, {log_dir}/watcher_core.log[/dim]"
|
|
729
|
-
)
|
|
712
|
+
console.print(f"[dim]Logs: {log_dir}/watcher_*.log, {log_dir}/watcher_core.log[/dim]")
|
|
730
713
|
|
|
731
714
|
# Ensure worker is running (turn/session summaries are processed by the worker).
|
|
732
715
|
try:
|
|
@@ -769,9 +752,7 @@ def watcher_stop_command() -> int:
|
|
|
769
752
|
# Display all processes that will be stopped
|
|
770
753
|
if len(all_processes) == 1:
|
|
771
754
|
pid, mode = all_processes[0]
|
|
772
|
-
console.print(
|
|
773
|
-
f"[cyan]Stopping watcher (PID: {pid}, mode: {mode})...[/cyan]"
|
|
774
|
-
)
|
|
755
|
+
console.print(f"[cyan]Stopping watcher (PID: {pid}, mode: {mode})...[/cyan]")
|
|
775
756
|
else:
|
|
776
757
|
console.print(
|
|
777
758
|
f"[cyan]Found {len(all_processes)} watcher processes, stopping all...[/cyan]"
|
|
@@ -854,9 +835,7 @@ def watcher_fresh_command() -> int:
|
|
|
854
835
|
|
|
855
836
|
# If stop failed, don't try to start
|
|
856
837
|
if stop_exit_code != 0:
|
|
857
|
-
console.print(
|
|
858
|
-
f"\n[red]✗ Failed to stop watcher, aborting restart[/red]"
|
|
859
|
-
)
|
|
838
|
+
console.print(f"\n[red]✗ Failed to stop watcher, aborting restart[/red]")
|
|
860
839
|
return stop_exit_code
|
|
861
840
|
|
|
862
841
|
console.print() # Add blank line for readability
|
|
@@ -959,9 +938,7 @@ def _get_imported_sessions(db, exclude_session_ids: set) -> list:
|
|
|
959
938
|
# Only include sessions that are imported via import_shares command
|
|
960
939
|
# Check for: 1) metadata.source == 'share_import' OR 2) session_type == 'imported'
|
|
961
940
|
# AND file_path is '.' (from Path(''))
|
|
962
|
-
file_path_str = (
|
|
963
|
-
str(session.session_file_path) if session.session_file_path else ""
|
|
964
|
-
)
|
|
941
|
+
file_path_str = str(session.session_file_path) if session.session_file_path else ""
|
|
965
942
|
|
|
966
943
|
# Check if file path indicates imported session
|
|
967
944
|
has_no_file = not session.session_file_path or file_path_str in ("", ".")
|
|
@@ -1026,9 +1003,9 @@ def _get_imported_sessions(db, exclude_session_ids: set) -> list:
|
|
|
1026
1003
|
"session_id": session.id,
|
|
1027
1004
|
"source": session.session_type or "imported",
|
|
1028
1005
|
"project_name": project_name,
|
|
1029
|
-
"project_path":
|
|
1030
|
-
|
|
1031
|
-
|
|
1006
|
+
"project_path": (
|
|
1007
|
+
Path(session.workspace_path) if session.workspace_path else None
|
|
1008
|
+
),
|
|
1032
1009
|
"progress_source": "db",
|
|
1033
1010
|
"created_at": session.created_at, # Use import time, not original session start time
|
|
1034
1011
|
"last_activity": session.last_activity_at,
|
|
@@ -1114,9 +1091,7 @@ def _get_session_tracking_status_batch(
|
|
|
1114
1091
|
stat = session_file.stat()
|
|
1115
1092
|
mtime = stat.st_mtime
|
|
1116
1093
|
last_activity = datetime.fromtimestamp(stat.st_mtime)
|
|
1117
|
-
created_at = datetime.fromtimestamp(
|
|
1118
|
-
getattr(stat, "st_birthtime", stat.st_ctime)
|
|
1119
|
-
)
|
|
1094
|
+
created_at = datetime.fromtimestamp(getattr(stat, "st_birthtime", stat.st_ctime))
|
|
1120
1095
|
except Exception:
|
|
1121
1096
|
mtime = None
|
|
1122
1097
|
last_activity = datetime.now()
|
|
@@ -1266,9 +1241,7 @@ def _get_session_tracking_status_batch(
|
|
|
1266
1241
|
return session_infos
|
|
1267
1242
|
|
|
1268
1243
|
|
|
1269
|
-
def _get_session_tracking_status(
|
|
1270
|
-
session_file: Path, config: ReAlignConfig, db=None
|
|
1271
|
-
) -> dict:
|
|
1244
|
+
def _get_session_tracking_status(session_file: Path, config: ReAlignConfig, db=None) -> dict:
|
|
1272
1245
|
"""
|
|
1273
1246
|
Get tracking status for a session file.
|
|
1274
1247
|
|
|
@@ -1335,9 +1308,7 @@ def _get_session_tracking_status(
|
|
|
1335
1308
|
stat = session_file.stat()
|
|
1336
1309
|
last_activity = datetime.fromtimestamp(stat.st_mtime)
|
|
1337
1310
|
# Use birthtime on macOS, fallback to ctime
|
|
1338
|
-
created_at = datetime.fromtimestamp(
|
|
1339
|
-
getattr(stat, "st_birthtime", stat.st_ctime)
|
|
1340
|
-
)
|
|
1311
|
+
created_at = datetime.fromtimestamp(getattr(stat, "st_birthtime", stat.st_ctime))
|
|
1341
1312
|
except Exception:
|
|
1342
1313
|
last_activity = datetime.now()
|
|
1343
1314
|
created_at = datetime.now()
|
|
@@ -1357,9 +1328,7 @@ def _get_session_tracking_status(
|
|
|
1357
1328
|
}
|
|
1358
1329
|
|
|
1359
1330
|
|
|
1360
|
-
def _get_sorted_session_infos(
|
|
1361
|
-
detect_turns: bool = False, include_empty: bool = True
|
|
1362
|
-
) -> List[dict]:
|
|
1331
|
+
def _get_sorted_session_infos(detect_turns: bool = False, include_empty: bool = True) -> List[dict]:
|
|
1363
1332
|
"""
|
|
1364
1333
|
Get sorted session infos list - shared logic between session list and event generate.
|
|
1365
1334
|
|
|
@@ -1382,9 +1351,7 @@ def _get_sorted_session_infos(
|
|
|
1382
1351
|
# Get status for each session (DB is optional; if missing, treat as empty).
|
|
1383
1352
|
db = None
|
|
1384
1353
|
try:
|
|
1385
|
-
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv(
|
|
1386
|
-
"REALIGN_DB_PATH"
|
|
1387
|
-
)
|
|
1354
|
+
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv("REALIGN_DB_PATH")
|
|
1388
1355
|
resolved_db_path = Path(env_db_path or config.sqlite_db_path).expanduser()
|
|
1389
1356
|
if resolved_db_path.exists():
|
|
1390
1357
|
from ..db import get_database
|
|
@@ -1484,9 +1451,7 @@ def watcher_session_list_command(
|
|
|
1484
1451
|
if records:
|
|
1485
1452
|
try:
|
|
1486
1453
|
config = ReAlignConfig.load()
|
|
1487
|
-
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv(
|
|
1488
|
-
"REALIGN_DB_PATH"
|
|
1489
|
-
)
|
|
1454
|
+
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv("REALIGN_DB_PATH")
|
|
1490
1455
|
resolved_db_path = Path(env_db_path or config.sqlite_db_path).expanduser()
|
|
1491
1456
|
if resolved_db_path.exists():
|
|
1492
1457
|
from ..db import get_database
|
|
@@ -1562,24 +1527,18 @@ def watcher_session_list_command(
|
|
|
1562
1527
|
"session_title": info.get("session_title"),
|
|
1563
1528
|
"session_summary": info.get("session_summary"),
|
|
1564
1529
|
"creator_name": info.get("creator_name"),
|
|
1565
|
-
"session_file":
|
|
1566
|
-
|
|
1567
|
-
|
|
1530
|
+
"session_file": (
|
|
1531
|
+
str(info.get("session_file")) if info.get("session_file") else None
|
|
1532
|
+
),
|
|
1568
1533
|
}
|
|
1569
1534
|
# Add turn records if requested
|
|
1570
1535
|
if records:
|
|
1571
|
-
session_data["turns"] = session_turns_map.get(
|
|
1572
|
-
info["session_id"], []
|
|
1573
|
-
)
|
|
1536
|
+
session_data["turns"] = session_turns_map.get(info["session_id"], [])
|
|
1574
1537
|
json_sessions.append(session_data)
|
|
1575
1538
|
|
|
1576
1539
|
# Count by status
|
|
1577
|
-
tracked_count = sum(
|
|
1578
|
-
|
|
1579
|
-
)
|
|
1580
|
-
partial_count = sum(
|
|
1581
|
-
1 for info in session_infos if info["status"] == "partial"
|
|
1582
|
-
)
|
|
1540
|
+
tracked_count = sum(1 for info in session_infos if info["status"] == "tracked")
|
|
1541
|
+
partial_count = sum(1 for info in session_infos if info["status"] == "partial")
|
|
1583
1542
|
new_count = sum(1 for info in session_infos if info["status"] == "new")
|
|
1584
1543
|
|
|
1585
1544
|
output = {
|
|
@@ -1600,17 +1559,13 @@ def watcher_session_list_command(
|
|
|
1600
1559
|
partial_count = sum(1 for info in session_infos if info["status"] == "partial")
|
|
1601
1560
|
new_count = sum(1 for info in session_infos if info["status"] == "new")
|
|
1602
1561
|
|
|
1603
|
-
console.print(
|
|
1604
|
-
f"\n[bold]Discovered Sessions ({len(session_infos)} total):[/bold]"
|
|
1605
|
-
)
|
|
1562
|
+
console.print(f"\n[bold]Discovered Sessions ({len(session_infos)} total):[/bold]")
|
|
1606
1563
|
if detect_turns:
|
|
1607
1564
|
console.print(
|
|
1608
1565
|
f" [green]{tracked_count} tracked[/green], [yellow]{partial_count} partial[/yellow], [dim]{new_count} new[/dim]\n"
|
|
1609
1566
|
)
|
|
1610
1567
|
else:
|
|
1611
|
-
console.print(
|
|
1612
|
-
f" [green]{tracked_count} tracked[/green], [dim]{new_count} new[/dim]\n"
|
|
1613
|
-
)
|
|
1568
|
+
console.print(f" [green]{tracked_count} tracked[/green], [dim]{new_count} new[/dim]\n")
|
|
1614
1569
|
|
|
1615
1570
|
import math
|
|
1616
1571
|
|
|
@@ -1622,9 +1577,7 @@ def watcher_session_list_command(
|
|
|
1622
1577
|
|
|
1623
1578
|
start_index = (page - 1) * per_page
|
|
1624
1579
|
if start_index >= total_sessions:
|
|
1625
|
-
console.print(
|
|
1626
|
-
f"[red]Error: page {page} is out of range (1-{total_pages})[/red]"
|
|
1627
|
-
)
|
|
1580
|
+
console.print(f"[red]Error: page {page} is out of range (1-{total_pages})[/red]")
|
|
1628
1581
|
console.print("[dim]Tip: use --page 1 to start from the beginning[/dim]")
|
|
1629
1582
|
return 1
|
|
1630
1583
|
|
|
@@ -1656,9 +1609,7 @@ def watcher_session_list_command(
|
|
|
1656
1609
|
"new": "[dim]new[/dim]",
|
|
1657
1610
|
}.get(info["status"], info["status"])
|
|
1658
1611
|
|
|
1659
|
-
created_str = info["created_at"].strftime(
|
|
1660
|
-
"%m-%d %H:%M"
|
|
1661
|
-
) # Shorter date format
|
|
1612
|
+
created_str = info["created_at"].strftime("%m-%d %H:%M") # Shorter date format
|
|
1662
1613
|
activity_str = _format_relative_time(info["last_activity"])
|
|
1663
1614
|
|
|
1664
1615
|
# Truncate session ID if too long (show enough for UUID matching)
|
|
@@ -1736,24 +1687,14 @@ def watcher_session_list_command(
|
|
|
1736
1687
|
)
|
|
1737
1688
|
if total_pages > 1:
|
|
1738
1689
|
if page > 1:
|
|
1739
|
-
console.print(
|
|
1740
|
-
f"[dim]Prev page: aline watcher session list --page {page - 1}[/dim]"
|
|
1741
|
-
)
|
|
1690
|
+
console.print(f"[dim]Prev page: aline watcher session list --page {page - 1}[/dim]")
|
|
1742
1691
|
if page < total_pages:
|
|
1743
|
-
console.print(
|
|
1744
|
-
f"[dim]Next page: aline watcher session list --page {page + 1}[/dim]"
|
|
1745
|
-
)
|
|
1692
|
+
console.print(f"[dim]Next page: aline watcher session list --page {page + 1}[/dim]")
|
|
1746
1693
|
console.print("[dim]Tip: adjust page size with --per-page[/dim]")
|
|
1747
1694
|
|
|
1748
|
-
console.print(
|
|
1749
|
-
|
|
1750
|
-
)
|
|
1751
|
-
console.print(
|
|
1752
|
-
"[dim] aline watcher session import 1-10 (range)[/dim]"
|
|
1753
|
-
)
|
|
1754
|
-
console.print(
|
|
1755
|
-
"[dim] aline watcher session import <id> (by session ID)[/dim]"
|
|
1756
|
-
)
|
|
1695
|
+
console.print("[dim]Import: aline watcher session import 1 (by number)[/dim]")
|
|
1696
|
+
console.print("[dim] aline watcher session import 1-10 (range)[/dim]")
|
|
1697
|
+
console.print("[dim] aline watcher session import <id> (by session ID)[/dim]")
|
|
1757
1698
|
console.print()
|
|
1758
1699
|
|
|
1759
1700
|
return 0
|
|
@@ -1764,9 +1705,7 @@ def watcher_session_list_command(
|
|
|
1764
1705
|
return 1
|
|
1765
1706
|
|
|
1766
1707
|
|
|
1767
|
-
def watcher_event_generate_command(
|
|
1768
|
-
session_selector: str, show_sessions: bool = False
|
|
1769
|
-
) -> int:
|
|
1708
|
+
def watcher_event_generate_command(session_selector: str, show_sessions: bool = False) -> int:
|
|
1770
1709
|
"""
|
|
1771
1710
|
Generate an event from selected sessions.
|
|
1772
1711
|
|
|
@@ -1801,16 +1740,12 @@ def watcher_event_generate_command(
|
|
|
1801
1740
|
session_infos = _get_sorted_session_infos(detect_turns=False)
|
|
1802
1741
|
if not session_infos:
|
|
1803
1742
|
console.print("[yellow]No sessions discovered.[/yellow]")
|
|
1804
|
-
console.print(
|
|
1805
|
-
"[dim]Use 'aline watcher session import' to import sessions first.[/dim]"
|
|
1806
|
-
)
|
|
1743
|
+
console.print("[dim]Use 'aline watcher session import' to import sessions first.[/dim]")
|
|
1807
1744
|
return 1
|
|
1808
1745
|
|
|
1809
1746
|
# If selector is "list", show available sessions
|
|
1810
1747
|
if session_selector.lower() == "list" or show_sessions:
|
|
1811
|
-
console.print(
|
|
1812
|
-
f"\n[bold]Sessions ({len(session_infos)} available):[/bold]\n"
|
|
1813
|
-
)
|
|
1748
|
+
console.print(f"\n[bold]Sessions ({len(session_infos)} available):[/bold]\n")
|
|
1814
1749
|
table = Table(show_header=True, header_style="bold", box=None)
|
|
1815
1750
|
table.add_column("#", justify="right", style="cyan", no_wrap=True)
|
|
1816
1751
|
table.add_column("SESSION ID", no_wrap=True)
|
|
@@ -1823,7 +1758,9 @@ def watcher_event_generate_command(
|
|
|
1823
1758
|
sid = info["session_id"]
|
|
1824
1759
|
session_id_display = sid[:16] + "..." if len(sid) > 16 else sid
|
|
1825
1760
|
status = info["status"]
|
|
1826
|
-
status_style = {"tracked": "green", "partial": "yellow", "new": "dim"}.get(
|
|
1761
|
+
status_style = {"tracked": "green", "partial": "yellow", "new": "dim"}.get(
|
|
1762
|
+
status, ""
|
|
1763
|
+
)
|
|
1827
1764
|
title = info.get("session_title") or "-"
|
|
1828
1765
|
if len(title) > 50:
|
|
1829
1766
|
title = title[:47] + "..."
|
|
@@ -1840,7 +1777,9 @@ def watcher_event_generate_command(
|
|
|
1840
1777
|
console.print()
|
|
1841
1778
|
console.print("[dim]Usage: aline watcher event generate <selector>[/dim]")
|
|
1842
1779
|
console.print("[dim]Examples: 1-3, abc123de, abc123de,def456gh[/dim]")
|
|
1843
|
-
console.print(
|
|
1780
|
+
console.print(
|
|
1781
|
+
"[dim]Note: Only 'tracked' sessions can be used to generate events.[/dim]"
|
|
1782
|
+
)
|
|
1844
1783
|
return 0
|
|
1845
1784
|
|
|
1846
1785
|
# Check if selector is a UUID (or UUID prefix) for sessions
|
|
@@ -1851,9 +1790,7 @@ def watcher_event_generate_command(
|
|
|
1851
1790
|
|
|
1852
1791
|
if not indices:
|
|
1853
1792
|
console.print(f"[red]Invalid session selector: {session_selector}[/red]")
|
|
1854
|
-
console.print(
|
|
1855
|
-
f"[dim]Valid range: 1-{len(session_infos)}, or session UUID/prefix[/dim]"
|
|
1856
|
-
)
|
|
1793
|
+
console.print(f"[dim]Valid range: 1-{len(session_infos)}, or session UUID/prefix[/dim]")
|
|
1857
1794
|
return 1
|
|
1858
1795
|
|
|
1859
1796
|
# Validate indices
|
|
@@ -1872,7 +1809,9 @@ def watcher_event_generate_command(
|
|
|
1872
1809
|
console.print("[red]Cannot generate event: some sessions are not tracked.[/red]")
|
|
1873
1810
|
for info in non_tracked:
|
|
1874
1811
|
console.print(f" • {info['session_id'][:16]}... (status: new)")
|
|
1875
|
-
console.print(
|
|
1812
|
+
console.print(
|
|
1813
|
+
"[dim]Use 'aline watcher session import' to import these sessions first.[/dim]"
|
|
1814
|
+
)
|
|
1876
1815
|
return 1
|
|
1877
1816
|
|
|
1878
1817
|
# Get SessionRecord objects from database for the selected sessions
|
|
@@ -1883,9 +1822,7 @@ def watcher_event_generate_command(
|
|
|
1883
1822
|
console.print("[red]Failed to retrieve session details from database.[/red]")
|
|
1884
1823
|
return 1
|
|
1885
1824
|
|
|
1886
|
-
console.print(
|
|
1887
|
-
f"\n[bold]Creating event from {len(selected_sessions)} session(s):[/bold]"
|
|
1888
|
-
)
|
|
1825
|
+
console.print(f"\n[bold]Creating event from {len(selected_sessions)} session(s):[/bold]")
|
|
1889
1826
|
for s in selected_sessions:
|
|
1890
1827
|
title = s.session_title or s.id[:16]
|
|
1891
1828
|
console.print(f" • {title}")
|
|
@@ -1900,9 +1837,7 @@ def watcher_event_generate_command(
|
|
|
1900
1837
|
|
|
1901
1838
|
# Calculate time range from sessions
|
|
1902
1839
|
start_times = [s.started_at for s in selected_sessions if s.started_at]
|
|
1903
|
-
end_times = [
|
|
1904
|
-
s.last_activity_at for s in selected_sessions if s.last_activity_at
|
|
1905
|
-
]
|
|
1840
|
+
end_times = [s.last_activity_at for s in selected_sessions if s.last_activity_at]
|
|
1906
1841
|
|
|
1907
1842
|
event = EventRecord(
|
|
1908
1843
|
id=event_id,
|
|
@@ -1971,9 +1906,7 @@ def watcher_event_delete_command(event_selector: str) -> int:
|
|
|
1971
1906
|
|
|
1972
1907
|
# Handle "all" selector
|
|
1973
1908
|
if event_selector.lower() == "all":
|
|
1974
|
-
confirm = (
|
|
1975
|
-
input(f"Delete ALL {len(all_events)} events? [y/N]: ").strip().lower()
|
|
1976
|
-
)
|
|
1909
|
+
confirm = input(f"Delete ALL {len(all_events)} events? [y/N]: ").strip().lower()
|
|
1977
1910
|
if confirm != "y":
|
|
1978
1911
|
console.print("Cancelled.")
|
|
1979
1912
|
return 0
|
|
@@ -1987,9 +1920,7 @@ def watcher_event_delete_command(event_selector: str) -> int:
|
|
|
1987
1920
|
|
|
1988
1921
|
if not indices:
|
|
1989
1922
|
console.print(f"[red]Invalid event selector: {event_selector}[/red]")
|
|
1990
|
-
console.print(
|
|
1991
|
-
f"[dim]Valid range: 1-{len(all_events)}, or event UUID/prefix[/dim]"
|
|
1992
|
-
)
|
|
1923
|
+
console.print(f"[dim]Valid range: 1-{len(all_events)}, or event UUID/prefix[/dim]")
|
|
1993
1924
|
return 1
|
|
1994
1925
|
|
|
1995
1926
|
# Validate indices
|
|
@@ -2001,9 +1932,7 @@ def watcher_event_delete_command(event_selector: str) -> int:
|
|
|
2001
1932
|
|
|
2002
1933
|
# Delete events
|
|
2003
1934
|
deleted_count = 0
|
|
2004
|
-
for idx in sorted(
|
|
2005
|
-
indices, reverse=True
|
|
2006
|
-
): # Delete from end to avoid index shift
|
|
1935
|
+
for idx in sorted(indices, reverse=True): # Delete from end to avoid index shift
|
|
2007
1936
|
event = all_events[idx - 1]
|
|
2008
1937
|
if db.delete_event(event.id):
|
|
2009
1938
|
deleted_count += 1
|
|
@@ -2049,12 +1978,8 @@ def watcher_event_show_command(event_selector: str) -> int:
|
|
|
2049
1978
|
|
|
2050
1979
|
if not indices:
|
|
2051
1980
|
console.print(f"[red]Invalid event selector: {event_selector}[/red]")
|
|
2052
|
-
console.print(
|
|
2053
|
-
|
|
2054
|
-
)
|
|
2055
|
-
console.print(
|
|
2056
|
-
"[dim]Use 'aline watcher event list' to see available events[/dim]"
|
|
2057
|
-
)
|
|
1981
|
+
console.print(f"[dim]Valid range: 1-{len(all_events)}, or event UUID/prefix[/dim]")
|
|
1982
|
+
console.print("[dim]Use 'aline watcher event list' to see available events[/dim]")
|
|
2058
1983
|
return 1
|
|
2059
1984
|
|
|
2060
1985
|
if len(indices) > 1:
|
|
@@ -2081,12 +2006,8 @@ def watcher_event_show_command(event_selector: str) -> int:
|
|
|
2081
2006
|
console.print(f" [bold]ID:[/bold] {event.id}")
|
|
2082
2007
|
console.print(f" [bold]Title:[/bold] {event.title}")
|
|
2083
2008
|
console.print(f" [bold]Generated by:[/bold] {generated_by_display}")
|
|
2084
|
-
console.print(
|
|
2085
|
-
|
|
2086
|
-
)
|
|
2087
|
-
console.print(
|
|
2088
|
-
f" [bold]Updated:[/bold] {event.updated_at.strftime('%Y-%m-%d %H:%M:%S')}"
|
|
2089
|
-
)
|
|
2009
|
+
console.print(f" [bold]Created:[/bold] {event.created_at.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
2010
|
+
console.print(f" [bold]Updated:[/bold] {event.updated_at.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
2090
2011
|
|
|
2091
2012
|
if event.description:
|
|
2092
2013
|
console.print(f"\n[bold]Description:[/bold]")
|
|
@@ -2116,9 +2037,7 @@ def watcher_event_show_command(event_selector: str) -> int:
|
|
|
2116
2037
|
# Get turn count
|
|
2117
2038
|
turns = db.get_turns_for_session(s.id)
|
|
2118
2039
|
turn_count = len(turns) if turns else 0
|
|
2119
|
-
activity = (
|
|
2120
|
-
_format_relative_time(s.last_activity_at) if s.last_activity_at else "-"
|
|
2121
|
-
)
|
|
2040
|
+
activity = _format_relative_time(s.last_activity_at) if s.last_activity_at else "-"
|
|
2122
2041
|
|
|
2123
2042
|
console.print(
|
|
2124
2043
|
f"\n[bold cyan]Session #{idx}[/bold cyan] [dim]({s.session_type or '-'}, {turn_count} turns, {activity})[/dim]"
|
|
@@ -2276,9 +2195,7 @@ def watcher_event_list_command(
|
|
|
2276
2195
|
|
|
2277
2196
|
console.print(table)
|
|
2278
2197
|
console.print()
|
|
2279
|
-
console.print(
|
|
2280
|
-
"[dim]Create events: aline watcher event generate <sessions>[/dim]"
|
|
2281
|
-
)
|
|
2198
|
+
console.print("[dim]Create events: aline watcher event generate <sessions>[/dim]")
|
|
2282
2199
|
console.print()
|
|
2283
2200
|
|
|
2284
2201
|
return 0
|
|
@@ -2342,9 +2259,7 @@ def watcher_event_revise_slack_command(
|
|
|
2342
2259
|
prompt_path = Path.home() / ".aline" / "prompts" / "slack_share_revise.md"
|
|
2343
2260
|
if not prompt_path.exists():
|
|
2344
2261
|
# Fallback to example file
|
|
2345
|
-
prompt_path = (
|
|
2346
|
-
Path.home() / ".aline" / "prompts" / "slack_share_revise.md.example"
|
|
2347
|
-
)
|
|
2262
|
+
prompt_path = Path.home() / ".aline" / "prompts" / "slack_share_revise.md.example"
|
|
2348
2263
|
|
|
2349
2264
|
if not prompt_path.exists():
|
|
2350
2265
|
if not json_output:
|
|
@@ -2691,11 +2606,7 @@ def _create_debug_callback(debug_file: Path) -> Callable[[Dict[str, Any]], None]
|
|
|
2691
2606
|
payload_with_ts = {"timestamp": datetime.now().isoformat(), **payload}
|
|
2692
2607
|
with open(debug_file, "a", encoding="utf-8") as f:
|
|
2693
2608
|
# Pretty-print JSON for readability
|
|
2694
|
-
f.write(
|
|
2695
|
-
json.dumps(
|
|
2696
|
-
payload_with_ts, ensure_ascii=False, default=str, indent=2
|
|
2697
|
-
)
|
|
2698
|
-
)
|
|
2609
|
+
f.write(json.dumps(payload_with_ts, ensure_ascii=False, default=str, indent=2))
|
|
2699
2610
|
f.write("\n---\n") # Separator between events
|
|
2700
2611
|
except Exception as e:
|
|
2701
2612
|
logger.debug(f"Debug callback error: {e}")
|
|
@@ -2731,9 +2642,7 @@ def _import_single_session(
|
|
|
2731
2642
|
|
|
2732
2643
|
if show_header:
|
|
2733
2644
|
console.print(f"\n[bold]Importing: {session_file.name}[/bold]")
|
|
2734
|
-
console.print(
|
|
2735
|
-
f" Source: {status_info['source']}, Project: {status_info['project_name']}"
|
|
2736
|
-
)
|
|
2645
|
+
console.print(f" Source: {status_info['source']}, Project: {status_info['project_name']}")
|
|
2737
2646
|
|
|
2738
2647
|
watcher = DialogueWatcher()
|
|
2739
2648
|
project_path = watcher._extract_project_path(session_file)
|
|
@@ -2899,12 +2808,8 @@ def watcher_session_import_command(
|
|
|
2899
2808
|
|
|
2900
2809
|
if not indices:
|
|
2901
2810
|
console.print(f"[red]Session not found: {session_id}[/red]")
|
|
2902
|
-
console.print(
|
|
2903
|
-
|
|
2904
|
-
)
|
|
2905
|
-
console.print(
|
|
2906
|
-
"[dim]Use 'aline watcher session list' to see available sessions[/dim]"
|
|
2907
|
-
)
|
|
2811
|
+
console.print(f"[dim]Valid range: 1-{len(session_infos)}, or session UUID/prefix[/dim]")
|
|
2812
|
+
console.print("[dim]Use 'aline watcher session list' to see available sessions[/dim]")
|
|
2908
2813
|
return 1
|
|
2909
2814
|
|
|
2910
2815
|
# Import selected sessions
|
|
@@ -2923,9 +2828,7 @@ def watcher_session_import_command(
|
|
|
2923
2828
|
)
|
|
2924
2829
|
continue
|
|
2925
2830
|
|
|
2926
|
-
console.print(
|
|
2927
|
-
f"\n[cyan]({i}/{len(indices)})[/cyan] #{idx} {session_file.name}"
|
|
2928
|
-
)
|
|
2831
|
+
console.print(f"\n[cyan]({i}/{len(indices)})[/cyan] #{idx} {session_file.name}")
|
|
2929
2832
|
|
|
2930
2833
|
if _import_single_session(
|
|
2931
2834
|
session_file,
|
|
@@ -3079,9 +2982,7 @@ def watcher_session_refresh_command(session_selector: str) -> int:
|
|
|
3079
2982
|
# Get database connection
|
|
3080
2983
|
db = None
|
|
3081
2984
|
try:
|
|
3082
|
-
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv(
|
|
3083
|
-
"REALIGN_DB_PATH"
|
|
3084
|
-
)
|
|
2985
|
+
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv("REALIGN_DB_PATH")
|
|
3085
2986
|
resolved_db_path = Path(env_db_path or config.sqlite_db_path).expanduser()
|
|
3086
2987
|
if resolved_db_path.exists():
|
|
3087
2988
|
from ..db import get_database
|
|
@@ -3127,9 +3028,7 @@ def watcher_session_refresh_command(session_selector: str) -> int:
|
|
|
3127
3028
|
|
|
3128
3029
|
if not indices:
|
|
3129
3030
|
console.print(f"[red]Invalid session selector: {session_selector}[/red]")
|
|
3130
|
-
console.print(
|
|
3131
|
-
f"[dim]Valid range: 1-{len(session_infos)}, or session UUID/prefix[/dim]"
|
|
3132
|
-
)
|
|
3031
|
+
console.print(f"[dim]Valid range: 1-{len(session_infos)}, or session UUID/prefix[/dim]")
|
|
3133
3032
|
console.print("[dim]Examples: 1, 1-5, 1,3,5-7, abc123de, abc123de,def456gh[/dim]")
|
|
3134
3033
|
return 1
|
|
3135
3034
|
|
|
@@ -3196,9 +3095,7 @@ def watcher_session_show_command(
|
|
|
3196
3095
|
# Get database connection
|
|
3197
3096
|
db = None
|
|
3198
3097
|
try:
|
|
3199
|
-
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv(
|
|
3200
|
-
"REALIGN_DB_PATH"
|
|
3201
|
-
)
|
|
3098
|
+
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv("REALIGN_DB_PATH")
|
|
3202
3099
|
resolved_db_path = Path(env_db_path or config.sqlite_db_path).expanduser()
|
|
3203
3100
|
if resolved_db_path.exists():
|
|
3204
3101
|
from ..db import get_database
|
|
@@ -3247,12 +3144,8 @@ def watcher_session_show_command(
|
|
|
3247
3144
|
|
|
3248
3145
|
if not indices:
|
|
3249
3146
|
console.print(f"[red]Invalid session selector: {session_selector}[/red]")
|
|
3250
|
-
console.print(
|
|
3251
|
-
|
|
3252
|
-
)
|
|
3253
|
-
console.print(
|
|
3254
|
-
"[dim]Use 'aline watcher session list' to see available sessions[/dim]"
|
|
3255
|
-
)
|
|
3147
|
+
console.print(f"[dim]Valid range: 1-{len(session_infos)}, or session UUID/prefix[/dim]")
|
|
3148
|
+
console.print("[dim]Use 'aline watcher session list' to see available sessions[/dim]")
|
|
3256
3149
|
return 1
|
|
3257
3150
|
|
|
3258
3151
|
if len(indices) > 1:
|
|
@@ -3333,8 +3226,12 @@ def watcher_session_show_command(
|
|
|
3333
3226
|
"title": title,
|
|
3334
3227
|
"temp_title": temp_title or "",
|
|
3335
3228
|
"timestamp": time_str,
|
|
3336
|
-
"user_message": (t["user_message"] if "user_message" in keys else t[3])
|
|
3337
|
-
|
|
3229
|
+
"user_message": (t["user_message"] if "user_message" in keys else t[3])
|
|
3230
|
+
or "",
|
|
3231
|
+
"assistant_summary": (
|
|
3232
|
+
t["assistant_summary"] if "assistant_summary" in keys else t[4]
|
|
3233
|
+
)
|
|
3234
|
+
or "",
|
|
3338
3235
|
}
|
|
3339
3236
|
)
|
|
3340
3237
|
|
|
@@ -3348,15 +3245,11 @@ def watcher_session_show_command(
|
|
|
3348
3245
|
"last_activity": info["last_activity"].isoformat(),
|
|
3349
3246
|
"total_turns": info["total_turns"],
|
|
3350
3247
|
"committed_turns": info["committed_turns"],
|
|
3351
|
-
"session_title": session_record.session_title
|
|
3352
|
-
if session_record
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
else None,
|
|
3357
|
-
"summary_status": getattr(session_record, "summary_status", None)
|
|
3358
|
-
if session_record
|
|
3359
|
-
else None,
|
|
3248
|
+
"session_title": session_record.session_title if session_record else None,
|
|
3249
|
+
"session_summary": session_record.session_summary if session_record else None,
|
|
3250
|
+
"summary_status": (
|
|
3251
|
+
getattr(session_record, "summary_status", None) if session_record else None
|
|
3252
|
+
),
|
|
3360
3253
|
"turns": turns_data,
|
|
3361
3254
|
}
|
|
3362
3255
|
|
|
@@ -3369,9 +3262,7 @@ def watcher_session_show_command(
|
|
|
3369
3262
|
console.print(f" Source: {info['source']}")
|
|
3370
3263
|
console.print(f" Project: {info['project_name']}")
|
|
3371
3264
|
console.print(f" Created: {info['created_at'].strftime('%Y-%m-%d %H:%M:%S')}")
|
|
3372
|
-
console.print(
|
|
3373
|
-
f" Last Activity: {info['last_activity'].strftime('%Y-%m-%d %H:%M:%S')}"
|
|
3374
|
-
)
|
|
3265
|
+
console.print(f" Last Activity: {info['last_activity'].strftime('%Y-%m-%d %H:%M:%S')}")
|
|
3375
3266
|
|
|
3376
3267
|
if session_record:
|
|
3377
3268
|
summary_status = getattr(session_record, "summary_status", None)
|
|
@@ -3390,9 +3281,7 @@ def watcher_session_show_command(
|
|
|
3390
3281
|
console.print(f" Summary: {session_record.session_summary}")
|
|
3391
3282
|
|
|
3392
3283
|
if not turns:
|
|
3393
|
-
console.print(
|
|
3394
|
-
f"\n[yellow]No turns found for this session in database.[/yellow]"
|
|
3395
|
-
)
|
|
3284
|
+
console.print(f"\n[yellow]No turns found for this session in database.[/yellow]")
|
|
3396
3285
|
console.print(
|
|
3397
3286
|
f"[dim]Total turns in file: {info['total_turns']}, Committed: {info['committed_turns']}[/dim]"
|
|
3398
3287
|
)
|
|
@@ -3497,9 +3386,7 @@ def watcher_llm_command(
|
|
|
3497
3386
|
|
|
3498
3387
|
# Header
|
|
3499
3388
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
3500
|
-
console.print(
|
|
3501
|
-
f"\n[bold cyan]Lock Operations Monitor[/bold cyan] - {timestamp}"
|
|
3502
|
-
)
|
|
3389
|
+
console.print(f"\n[bold cyan]Lock Operations Monitor[/bold cyan] - {timestamp}")
|
|
3503
3390
|
console.print(f"[dim]Log file: {log_file}[/dim]\n")
|
|
3504
3391
|
|
|
3505
3392
|
# Check if log file exists
|
|
@@ -3575,9 +3462,7 @@ def watcher_llm_command(
|
|
|
3575
3462
|
|
|
3576
3463
|
# Extract time only from timestamp (HH:MM:SS)
|
|
3577
3464
|
time_only = (
|
|
3578
|
-
timestamp_str.split()[-1]
|
|
3579
|
-
if " " in timestamp_str
|
|
3580
|
-
else timestamp_str
|
|
3465
|
+
timestamp_str.split()[-1] if " " in timestamp_str else timestamp_str
|
|
3581
3466
|
)
|
|
3582
3467
|
|
|
3583
3468
|
# Format and print line
|
|
@@ -3701,9 +3586,7 @@ def watcher_session_delete_command(
|
|
|
3701
3586
|
# Get database connection
|
|
3702
3587
|
db = None
|
|
3703
3588
|
try:
|
|
3704
|
-
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv(
|
|
3705
|
-
"REALIGN_DB_PATH"
|
|
3706
|
-
)
|
|
3589
|
+
env_db_path = os.getenv("REALIGN_SQLITE_DB_PATH") or os.getenv("REALIGN_DB_PATH")
|
|
3707
3590
|
resolved_db_path = Path(env_db_path or config.sqlite_db_path).expanduser()
|
|
3708
3591
|
if resolved_db_path.exists():
|
|
3709
3592
|
from ..db import get_database
|
|
@@ -3751,12 +3634,8 @@ def watcher_session_delete_command(
|
|
|
3751
3634
|
|
|
3752
3635
|
if not indices:
|
|
3753
3636
|
console.print(f"[red]Invalid session selector: {session_selector}[/red]")
|
|
3754
|
-
console.print(
|
|
3755
|
-
|
|
3756
|
-
)
|
|
3757
|
-
console.print(
|
|
3758
|
-
"[dim]Use 'aline watcher session list' to see available sessions[/dim]"
|
|
3759
|
-
)
|
|
3637
|
+
console.print(f"[dim]Valid range: 1-{len(session_infos)}, or session UUID/prefix[/dim]")
|
|
3638
|
+
console.print("[dim]Use 'aline watcher session list' to see available sessions[/dim]")
|
|
3760
3639
|
return 1
|
|
3761
3640
|
|
|
3762
3641
|
if len(indices) > 1:
|