aline-ai 0.5.4__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.
- {aline_ai-0.5.4.dist-info → aline_ai-0.5.5.dist-info}/METADATA +1 -1
- aline_ai-0.5.5.dist-info/RECORD +93 -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 +7 -0
- 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 +4 -4
- realign/dashboard/screens/create_event.py +3 -1
- realign/dashboard/screens/event_detail.py +14 -6
- 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 +3 -1
- realign/dashboard/widgets/header.py +1 -0
- realign/dashboard/widgets/search_panel.py +37 -27
- realign/dashboard/widgets/sessions_table.py +24 -15
- realign/dashboard/widgets/terminal_panel.py +66 -22
- 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.5.dist-info}/WHEEL +0 -0
- {aline_ai-0.5.4.dist-info → aline_ai-0.5.5.dist-info}/entry_points.txt +0 -0
- {aline_ai-0.5.4.dist-info → aline_ai-0.5.5.dist-info}/licenses/LICENSE +0 -0
- {aline_ai-0.5.4.dist-info → aline_ai-0.5.5.dist-info}/top_level.txt +0 -0
realign/commands/upgrade.py
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|