aline-ai 0.5.3__py3-none-any.whl → 0.5.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 (80) hide show
  1. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/METADATA +1 -1
  2. aline_ai-0.5.5.dist-info/RECORD +93 -0
  3. realign/__init__.py +1 -1
  4. realign/adapters/antigravity.py +28 -20
  5. realign/adapters/base.py +46 -50
  6. realign/adapters/claude.py +14 -14
  7. realign/adapters/codex.py +7 -7
  8. realign/adapters/gemini.py +11 -11
  9. realign/adapters/registry.py +14 -10
  10. realign/claude_detector.py +2 -2
  11. realign/claude_hooks/__init__.py +3 -3
  12. realign/claude_hooks/permission_request_hook.py +35 -0
  13. realign/claude_hooks/permission_request_hook_installer.py +31 -32
  14. realign/claude_hooks/stop_hook.py +4 -1
  15. realign/claude_hooks/stop_hook_installer.py +30 -31
  16. realign/cli.py +24 -0
  17. realign/codex_detector.py +11 -11
  18. realign/commands/add.py +361 -35
  19. realign/commands/config.py +3 -12
  20. realign/commands/context.py +3 -1
  21. realign/commands/export_shares.py +86 -127
  22. realign/commands/import_shares.py +145 -155
  23. realign/commands/init.py +166 -30
  24. realign/commands/restore.py +18 -6
  25. realign/commands/search.py +14 -42
  26. realign/commands/upgrade.py +155 -11
  27. realign/commands/watcher.py +98 -219
  28. realign/commands/worker.py +29 -6
  29. realign/config.py +25 -20
  30. realign/context.py +1 -3
  31. realign/dashboard/app.py +4 -4
  32. realign/dashboard/screens/create_event.py +3 -1
  33. realign/dashboard/screens/event_detail.py +14 -6
  34. realign/dashboard/screens/session_detail.py +3 -1
  35. realign/dashboard/screens/share_import.py +7 -3
  36. realign/dashboard/tmux_manager.py +91 -22
  37. realign/dashboard/widgets/config_panel.py +85 -1
  38. realign/dashboard/widgets/events_table.py +3 -1
  39. realign/dashboard/widgets/header.py +1 -0
  40. realign/dashboard/widgets/search_panel.py +37 -27
  41. realign/dashboard/widgets/sessions_table.py +24 -15
  42. realign/dashboard/widgets/terminal_panel.py +207 -17
  43. realign/dashboard/widgets/watcher_panel.py +6 -2
  44. realign/dashboard/widgets/worker_panel.py +10 -1
  45. realign/db/__init__.py +1 -1
  46. realign/db/base.py +5 -15
  47. realign/db/locks.py +0 -1
  48. realign/db/migration.py +82 -76
  49. realign/db/schema.py +2 -6
  50. realign/db/sqlite_db.py +23 -41
  51. realign/events/__init__.py +0 -1
  52. realign/events/event_summarizer.py +27 -15
  53. realign/events/session_summarizer.py +29 -15
  54. realign/file_lock.py +1 -0
  55. realign/hooks.py +150 -60
  56. realign/logging_config.py +12 -15
  57. realign/mcp_server.py +30 -51
  58. realign/mcp_watcher.py +0 -1
  59. realign/models/event.py +29 -20
  60. realign/prompts/__init__.py +7 -7
  61. realign/prompts/presets.py +15 -11
  62. realign/redactor.py +99 -59
  63. realign/triggers/__init__.py +9 -9
  64. realign/triggers/antigravity_trigger.py +30 -28
  65. realign/triggers/base.py +4 -3
  66. realign/triggers/claude_trigger.py +104 -85
  67. realign/triggers/codex_trigger.py +15 -5
  68. realign/triggers/gemini_trigger.py +57 -47
  69. realign/triggers/next_turn_trigger.py +3 -1
  70. realign/triggers/registry.py +6 -2
  71. realign/triggers/turn_status.py +3 -1
  72. realign/watcher_core.py +306 -131
  73. realign/watcher_daemon.py +8 -8
  74. realign/worker_core.py +3 -1
  75. realign/worker_daemon.py +3 -1
  76. aline_ai-0.5.3.dist-info/RECORD +0 -93
  77. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/WHEEL +0 -0
  78. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/entry_points.txt +0 -0
  79. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/licenses/LICENSE +0 -0
  80. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,11 @@
1
1
  """ReAlign upgrade command - Upgrade database schema to latest version."""
2
2
 
3
3
  from pathlib import Path
4
+ import subprocess
4
5
  import typer
5
6
  from rich.console import Console
6
7
  from rich.table import Table
8
+ from typing import Optional, Tuple
7
9
 
8
10
  from ..config import ReAlignConfig
9
11
  from ..db.schema import SCHEMA_VERSION, get_migration_scripts
@@ -11,6 +13,132 @@ from ..db.schema import SCHEMA_VERSION, get_migration_scripts
11
13
  console = Console()
12
14
 
13
15
 
16
+ def get_latest_pypi_version() -> Optional[str]:
17
+ """Fetch the latest version of aline-ai from PyPI.
18
+
19
+ Returns:
20
+ The latest version string, or None if unable to fetch.
21
+ """
22
+ import urllib.request
23
+ import json
24
+
25
+ try:
26
+ url = "https://pypi.org/pypi/aline-ai/json"
27
+ with urllib.request.urlopen(url, timeout=3) as response:
28
+ data = json.loads(response.read().decode())
29
+ return data.get("info", {}).get("version")
30
+ except Exception:
31
+ return None
32
+
33
+
34
+ def compare_versions(current: str, latest: str) -> int:
35
+ """Compare two version strings.
36
+
37
+ Returns:
38
+ -1 if current < latest (update available)
39
+ 0 if current == latest
40
+ 1 if current > latest
41
+ """
42
+ def parse_version(v: str) -> Tuple[int, ...]:
43
+ """Parse version string to tuple of integers."""
44
+ parts = []
45
+ for part in v.split("."):
46
+ # Handle pre-release versions like "0.5.5a1"
47
+ num_part = ""
48
+ for char in part:
49
+ if char.isdigit():
50
+ num_part += char
51
+ else:
52
+ break
53
+ if num_part:
54
+ parts.append(int(num_part))
55
+ else:
56
+ parts.append(0)
57
+ return tuple(parts)
58
+
59
+ current_tuple = parse_version(current)
60
+ latest_tuple = parse_version(latest)
61
+
62
+ # Pad shorter tuple with zeros
63
+ max_len = max(len(current_tuple), len(latest_tuple))
64
+ current_tuple = current_tuple + (0,) * (max_len - len(current_tuple))
65
+ latest_tuple = latest_tuple + (0,) * (max_len - len(latest_tuple))
66
+
67
+ if current_tuple < latest_tuple:
68
+ return -1
69
+ elif current_tuple > latest_tuple:
70
+ return 1
71
+ return 0
72
+
73
+
74
+ def check_and_prompt_update() -> bool:
75
+ """Check for updates and prompt user to update if available.
76
+
77
+ Returns:
78
+ True if update was performed (should restart), False otherwise.
79
+ """
80
+ from importlib.metadata import version
81
+
82
+ try:
83
+ current_version = version("aline-ai")
84
+ except Exception:
85
+ return False
86
+
87
+ latest_version = get_latest_pypi_version()
88
+ if latest_version is None:
89
+ return False
90
+
91
+ if compare_versions(current_version, latest_version) >= 0:
92
+ # Current version is up to date or newer
93
+ return False
94
+
95
+ # New version available - prompt user
96
+ console.print(
97
+ f"\n[bold yellow]⬆ Update available:[/bold yellow] "
98
+ f"[cyan]{current_version}[/cyan] → [green]{latest_version}[/green]"
99
+ )
100
+
101
+ try:
102
+ response = console.input(
103
+ "[dim]Do you want to update now? ([/dim][green]y[/green][dim]/[/dim][yellow]n[/yellow][dim]):[/dim] "
104
+ ).strip().lower()
105
+ except (EOFError, KeyboardInterrupt):
106
+ console.print("\n[dim]Update skipped.[/dim]\n")
107
+ return False
108
+
109
+ if response not in ("y", "yes"):
110
+ console.print("[dim]Update skipped.[/dim]\n")
111
+ return False
112
+
113
+ # Perform update using pipx
114
+ console.print("\n[bold]Updating aline-ai via pipx...[/bold]\n")
115
+
116
+ try:
117
+ result = subprocess.run(
118
+ ["pipx", "upgrade", "aline-ai"],
119
+ capture_output=False,
120
+ )
121
+
122
+ if result.returncode == 0:
123
+ console.print(
124
+ f"\n[bold green]✓ Successfully updated to {latest_version}![/bold green]"
125
+ )
126
+ console.print("[dim]Please restart 'aline' to use the new version.[/dim]\n")
127
+ return True
128
+ else:
129
+ console.print("\n[bold red]✗ Update failed.[/bold red]")
130
+ console.print("[dim]You can manually update with: pipx upgrade aline-ai[/dim]\n")
131
+ return False
132
+
133
+ except FileNotFoundError:
134
+ console.print("\n[bold red]✗ pipx not found.[/bold red]")
135
+ console.print("[dim]Please install with: pip install aline-ai --upgrade[/dim]\n")
136
+ return False
137
+ except Exception as e:
138
+ console.print(f"\n[bold red]✗ Update failed: {e}[/bold red]\n")
139
+ return False
140
+
141
+
14
142
  def get_current_db_version(db_path: Path) -> int:
15
143
  """Get current schema version from database without triggering migration."""
16
144
  import sqlite3
@@ -33,9 +161,7 @@ def upgrade_command(
33
161
  dry_run: bool = typer.Option(
34
162
  False, "--dry-run", "-n", help="Show what would be done without making changes"
35
163
  ),
36
- force: bool = typer.Option(
37
- False, "--force", "-f", help="Force upgrade even if versions match"
38
- ),
164
+ force: bool = typer.Option(False, "--force", "-f", help="Force upgrade even if versions match"),
39
165
  restart_watcher: bool = typer.Option(
40
166
  True, "--restart-watcher/--no-restart-watcher", help="Restart watcher after upgrade"
41
167
  ),
@@ -89,7 +215,9 @@ def upgrade_command(
89
215
  raise typer.Exit(0)
90
216
 
91
217
  if current_version == target_version and force:
92
- console.print("\n[yellow]Versions match, but --force specified. Re-running migrations...[/yellow]")
218
+ console.print(
219
+ "\n[yellow]Versions match, but --force specified. Re-running migrations...[/yellow]"
220
+ )
93
221
 
94
222
  # Get migration scripts
95
223
  migrations = get_migration_scripts(current_version, target_version)
@@ -102,7 +230,7 @@ def upgrade_command(
102
230
  console.print(f"\n[bold]Migrations to apply ({len(migrations)} scripts):[/bold]")
103
231
  for i, script in enumerate(migrations, 1):
104
232
  # Show truncated script preview
105
- preview = script.strip().replace('\n', ' ')[:60]
233
+ preview = script.strip().replace("\n", " ")[:60]
106
234
  if len(script.strip()) > 60:
107
235
  preview += "..."
108
236
  console.print(f" {i}. [dim]{preview}[/dim]")
@@ -120,6 +248,7 @@ def upgrade_command(
120
248
  if restart_watcher:
121
249
  try:
122
250
  from . import watcher as watcher_cmd
251
+
123
252
  watcher_was_running = watcher_cmd._is_watcher_running()
124
253
  if watcher_was_running:
125
254
  console.print("[dim]Stopping watcher for upgrade...[/dim]")
@@ -142,6 +271,7 @@ def upgrade_command(
142
271
 
143
272
  try:
144
273
  from ..db.sqlite_db import SQLiteDatabase
274
+
145
275
  db = SQLiteDatabase(str(db_path))
146
276
  db.initialize() # This handles migrations automatically
147
277
  db.close()
@@ -150,9 +280,13 @@ def upgrade_command(
150
280
  new_version = get_current_db_version(db_path)
151
281
 
152
282
  if new_version >= target_version:
153
- console.print(f"\n[bold green]✓ Upgrade successful![/bold green] V{current_version} → V{new_version}")
283
+ console.print(
284
+ f"\n[bold green]✓ Upgrade successful![/bold green] V{current_version} → V{new_version}"
285
+ )
154
286
  else:
155
- console.print(f"\n[yellow]⚠ Partial upgrade: V{current_version} → V{new_version} (target: V{target_version})[/yellow]")
287
+ console.print(
288
+ f"\n[yellow]⚠ Partial upgrade: V{current_version} → V{new_version} (target: V{target_version})[/yellow]"
289
+ )
156
290
 
157
291
  except Exception as e:
158
292
  console.print(f"\n[bold red]✗ Upgrade failed: {e}[/bold red]")
@@ -163,11 +297,14 @@ def upgrade_command(
163
297
  console.print("\n[dim]Restarting watcher...[/dim]")
164
298
  try:
165
299
  from . import watcher as watcher_cmd
300
+
166
301
  exit_code = watcher_cmd.watcher_start_command()
167
302
  if exit_code == 0:
168
303
  console.print("[green]✓ Watcher restarted[/green]")
169
304
  else:
170
- console.print("[yellow]⚠ Failed to restart watcher. Run 'aline watcher start' manually.[/yellow]")
305
+ console.print(
306
+ "[yellow]⚠ Failed to restart watcher. Run 'aline watcher start' manually.[/yellow]"
307
+ )
171
308
  except Exception as e:
172
309
  console.print(f"[yellow]⚠ Failed to restart watcher: {e}[/yellow]")
173
310
 
@@ -180,7 +317,9 @@ def upgrade_command(
180
317
  if exit_code == 0:
181
318
  console.print("[green]✓ Worker restarted[/green]")
182
319
  else:
183
- console.print("[yellow]⚠ Failed to restart worker. Run 'aline worker start' manually.[/yellow]")
320
+ console.print(
321
+ "[yellow]⚠ Failed to restart worker. Run 'aline worker start' manually.[/yellow]"
322
+ )
184
323
  except Exception as e:
185
324
  console.print(f"[yellow]⚠ Failed to restart worker: {e}[/yellow]")
186
325
 
@@ -194,6 +333,7 @@ def version_command():
194
333
  # Package version
195
334
  try:
196
335
  from importlib.metadata import version
336
+
197
337
  pkg_version = version("aline-ai")
198
338
  except Exception:
199
339
  pkg_version = "unknown"
@@ -218,7 +358,9 @@ def version_command():
218
358
  table.add_row("Schema version (db)", "[red]Not found[/red]")
219
359
  else:
220
360
  if current_version < SCHEMA_VERSION:
221
- table.add_row("Schema version (db)", f"[yellow]V{current_version}[/yellow] (upgrade available)")
361
+ table.add_row(
362
+ "Schema version (db)", f"[yellow]V{current_version}[/yellow] (upgrade available)"
363
+ )
222
364
  else:
223
365
  table.add_row("Schema version (db)", f"[green]V{current_version}[/green]")
224
366
 
@@ -227,7 +369,9 @@ def version_command():
227
369
  console.print(table)
228
370
 
229
371
  if current_version >= 0 and current_version < SCHEMA_VERSION:
230
- console.print(f"\n[yellow]Tip: Run 'aline upgrade' to update database schema V{current_version} → V{SCHEMA_VERSION}[/yellow]")
372
+ console.print(
373
+ f"\n[yellow]Tip: Run 'aline upgrade' to update database schema V{current_version} → V{SCHEMA_VERSION}[/yellow]"
374
+ )
231
375
 
232
376
  console.print("")
233
377