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/add.py
CHANGED
|
@@ -516,32 +516,49 @@ def add_tmux_command() -> int:
|
|
|
516
516
|
_source_aline_tmux_conf(tmux_conf)
|
|
517
517
|
|
|
518
518
|
console.print(f"[green]✓[/green] tmux installed and config ready: [cyan]{tmux_conf}[/cyan]")
|
|
519
|
-
console.print(
|
|
519
|
+
console.print(
|
|
520
|
+
"[dim]Tip: in the Aline dashboard tmux session, mouse drag will copy to clipboard.[/dim]"
|
|
521
|
+
)
|
|
520
522
|
return 0
|
|
521
523
|
|
|
522
524
|
|
|
523
|
-
def
|
|
524
|
-
"""
|
|
525
|
+
def _ensure_symlink(target_link: Path, source_file: Path, force: bool = False) -> bool:
|
|
526
|
+
"""Create a symlink at target_link pointing to source_file.
|
|
525
527
|
|
|
526
528
|
Args:
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
529
|
+
target_link: The path where the symlink should be created (e.g., ~/.claude/skills/aline/SKILL.md)
|
|
530
|
+
source_file: The actual file to link to (e.g., ~/.aline/skills/aline/SKILL.md)
|
|
531
|
+
force: Whether to overwrite existing files/links
|
|
530
532
|
|
|
531
533
|
Returns:
|
|
532
|
-
|
|
534
|
+
True if a new link was created or updated, False if skipped (already exists)
|
|
533
535
|
"""
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
536
|
+
if target_link.exists() or target_link.is_symlink():
|
|
537
|
+
if not force:
|
|
538
|
+
# Check if it already points to the right place
|
|
539
|
+
try:
|
|
540
|
+
if target_link.is_symlink() and target_link.resolve() == source_file.resolve():
|
|
541
|
+
return False # Already correct
|
|
542
|
+
except Exception:
|
|
543
|
+
pass
|
|
544
|
+
return False # Exists and not forced
|
|
545
|
+
|
|
546
|
+
# Force: remove existing
|
|
547
|
+
if target_link.is_dir() and not target_link.is_symlink():
|
|
548
|
+
shutil.rmtree(target_link)
|
|
549
|
+
else:
|
|
550
|
+
target_link.unlink()
|
|
551
|
+
|
|
552
|
+
target_link.parent.mkdir(parents=True, exist_ok=True)
|
|
553
|
+
target_link.symlink_to(source_file)
|
|
554
|
+
return True
|
|
539
555
|
|
|
540
556
|
|
|
541
557
|
def add_skills_command(force: bool = False) -> int:
|
|
542
|
-
"""Install Aline skills for Claude Code.
|
|
558
|
+
"""Install Aline skills for Claude Code and Codex.
|
|
543
559
|
|
|
544
|
-
|
|
560
|
+
1. Writes built-in skills to ~/.aline/skills/
|
|
561
|
+
2. Creates symlinks in ~/.claude/skills/ and ~/.codex/skills/
|
|
545
562
|
|
|
546
563
|
Args:
|
|
547
564
|
force: Overwrite existing skills if they exist
|
|
@@ -549,42 +566,54 @@ def add_skills_command(force: bool = False) -> int:
|
|
|
549
566
|
Returns:
|
|
550
567
|
Exit code (0 for success, 1 for failure)
|
|
551
568
|
"""
|
|
552
|
-
|
|
569
|
+
aline_skill_root = Path.home() / ".aline" / "skills"
|
|
570
|
+
targets = [
|
|
571
|
+
("Claude", Path.home() / ".claude" / "skills"),
|
|
572
|
+
("Codex", Path.home() / ".codex" / "skills"),
|
|
573
|
+
("OpenCode", Path.home() / ".config" / "opencode" / "skill"),
|
|
574
|
+
]
|
|
575
|
+
|
|
553
576
|
installed_skills: list[str] = []
|
|
554
577
|
skipped_skills: list[str] = []
|
|
555
578
|
failed_skills: list[tuple[str, str]] = []
|
|
556
579
|
|
|
557
580
|
for skill_name, skill_content in SKILLS_REGISTRY.items():
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
# Check if skill already exists
|
|
561
|
-
if skill_path.exists() and not force:
|
|
562
|
-
skipped_skills.append(skill_name)
|
|
563
|
-
continue
|
|
564
|
-
|
|
581
|
+
# 1. Update master copy in ~/.aline/skills
|
|
582
|
+
master_path = aline_skill_root / skill_name / "SKILL.md"
|
|
565
583
|
try:
|
|
566
|
-
|
|
567
|
-
|
|
584
|
+
master_path.parent.mkdir(parents=True, exist_ok=True)
|
|
585
|
+
master_path.write_text(skill_content, encoding="utf-8")
|
|
568
586
|
except Exception as e:
|
|
569
|
-
failed_skills.append((skill_name, str(e)))
|
|
587
|
+
failed_skills.append((f"{skill_name} (storage)", str(e)))
|
|
588
|
+
continue
|
|
589
|
+
|
|
590
|
+
# 2. Link to targets
|
|
591
|
+
for tool_name, tool_root in targets:
|
|
592
|
+
dest_path = tool_root / skill_name / "SKILL.md"
|
|
593
|
+
|
|
594
|
+
try:
|
|
595
|
+
updated = _ensure_symlink(dest_path, master_path, force)
|
|
596
|
+
if updated:
|
|
597
|
+
installed_skills.append(f"{tool_name}/{skill_name}")
|
|
598
|
+
else:
|
|
599
|
+
skipped_skills.append(f"{tool_name}/{skill_name}")
|
|
600
|
+
except Exception as e:
|
|
601
|
+
failed_skills.append((f"{tool_name}/{skill_name}", str(e)))
|
|
570
602
|
|
|
571
603
|
# Report results
|
|
572
|
-
for
|
|
573
|
-
|
|
574
|
-
console.print(f"[green]✓[/green] Installed: [cyan]{skill_path}[/cyan]")
|
|
604
|
+
for item in installed_skills:
|
|
605
|
+
console.print(f"[green]✓[/green] Installed: [cyan]{item}[/cyan]")
|
|
575
606
|
|
|
576
|
-
for
|
|
577
|
-
|
|
578
|
-
console.print(f"[yellow]⊘[/yellow] Already exists: [dim]{skill_path}[/dim]")
|
|
607
|
+
for item in skipped_skills:
|
|
608
|
+
console.print(f"[yellow]⊘[/yellow] Already exists: [dim]{item}[/dim]")
|
|
579
609
|
|
|
580
|
-
for
|
|
581
|
-
console.print(f"[red]✗[/red] Failed to install {
|
|
610
|
+
for item, error in failed_skills:
|
|
611
|
+
console.print(f"[red]✗[/red] Failed to install {item}: {error}")
|
|
582
612
|
|
|
583
613
|
if skipped_skills and not installed_skills:
|
|
584
614
|
console.print("[dim]Use --force to overwrite existing skills[/dim]")
|
|
585
615
|
elif installed_skills:
|
|
586
|
-
|
|
587
|
-
console.print(f"[dim]Restart Claude Code to activate: {skill_names}[/dim]")
|
|
616
|
+
console.print("[dim]Restart your AI tools to activate new skills[/dim]")
|
|
588
617
|
|
|
589
618
|
return 1 if failed_skills else 0
|
|
590
619
|
|
|
@@ -592,11 +621,7 @@ def add_skills_command(force: bool = False) -> int:
|
|
|
592
621
|
def add_skills_dev_command(force: bool = False) -> int:
|
|
593
622
|
"""Install developer skills from skill-dev/ directory.
|
|
594
623
|
|
|
595
|
-
|
|
596
|
-
and installs them to ~/.claude/skills/
|
|
597
|
-
|
|
598
|
-
This is for developer use only - skills in development that are not
|
|
599
|
-
yet bundled into the package.
|
|
624
|
+
Symlinks skills from ./skill-dev/ to ~/.claude/skills/ and ~/.codex/skills/
|
|
600
625
|
|
|
601
626
|
Args:
|
|
602
627
|
force: Overwrite existing skills if they exist
|
|
@@ -605,7 +630,6 @@ def add_skills_dev_command(force: bool = False) -> int:
|
|
|
605
630
|
Exit code (0 for success, 1 for failure)
|
|
606
631
|
"""
|
|
607
632
|
# Find skill-dev directory relative to this file's package location
|
|
608
|
-
# Go up from src/realign/commands/add.py to project root
|
|
609
633
|
package_root = Path(__file__).parent.parent.parent.parent
|
|
610
634
|
skill_dev_dir = package_root / "skill-dev"
|
|
611
635
|
|
|
@@ -614,7 +638,12 @@ def add_skills_dev_command(force: bool = False) -> int:
|
|
|
614
638
|
console.print("[dim]This command is for developer use only.[/dim]")
|
|
615
639
|
return 1
|
|
616
640
|
|
|
617
|
-
|
|
641
|
+
targets = [
|
|
642
|
+
("Claude", Path.home() / ".claude" / "skills"),
|
|
643
|
+
("Codex", Path.home() / ".codex" / "skills"),
|
|
644
|
+
("OpenCode", Path.home() / ".config" / "opencode" / "skill"),
|
|
645
|
+
]
|
|
646
|
+
|
|
618
647
|
installed_skills: list[str] = []
|
|
619
648
|
skipped_skills: list[str] = []
|
|
620
649
|
failed_skills: list[tuple[str, str]] = []
|
|
@@ -629,42 +658,36 @@ def add_skills_dev_command(force: bool = False) -> int:
|
|
|
629
658
|
continue
|
|
630
659
|
|
|
631
660
|
skill_name = skill_dir.name
|
|
632
|
-
dest_path = claude_skill_root / skill_name / "SKILL.md"
|
|
633
661
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
skipped_skills.append(skill_name)
|
|
637
|
-
continue
|
|
662
|
+
for tool_name, tool_root in targets:
|
|
663
|
+
dest_path = tool_root / skill_name / "SKILL.md"
|
|
638
664
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
665
|
+
try:
|
|
666
|
+
updated = _ensure_symlink(dest_path, skill_file, force)
|
|
667
|
+
if updated:
|
|
668
|
+
installed_skills.append(f"{tool_name}/{skill_name}")
|
|
669
|
+
else:
|
|
670
|
+
skipped_skills.append(f"{tool_name}/{skill_name}")
|
|
671
|
+
except Exception as e:
|
|
672
|
+
failed_skills.append((f"{tool_name}/{skill_name}", str(e)))
|
|
645
673
|
|
|
646
674
|
if not installed_skills and not skipped_skills and not failed_skills:
|
|
647
675
|
console.print("[yellow]No skills found in skill-dev/[/yellow]")
|
|
648
|
-
console.print("[dim]Each skill should be in its own directory with a SKILL.md file.[/dim]")
|
|
649
676
|
return 0
|
|
650
677
|
|
|
651
678
|
# Report results
|
|
652
|
-
for
|
|
653
|
-
|
|
654
|
-
console.print(f"[green]✓[/green] Installed: [cyan]{skill_path}[/cyan]")
|
|
679
|
+
for item in installed_skills:
|
|
680
|
+
console.print(f"[green]✓[/green] Linked: [cyan]{item}[/cyan]")
|
|
655
681
|
|
|
656
|
-
for
|
|
657
|
-
|
|
658
|
-
console.print(f"[yellow]⊘[/yellow] Already exists: [dim]{skill_path}[/dim]")
|
|
682
|
+
for item in skipped_skills:
|
|
683
|
+
console.print(f"[yellow]⊘[/yellow] Already exists: [dim]{item}[/dim]")
|
|
659
684
|
|
|
660
|
-
for
|
|
661
|
-
console.print(f"[red]✗[/red] Failed to install {
|
|
685
|
+
for item, error in failed_skills:
|
|
686
|
+
console.print(f"[red]✗[/red] Failed to install {item}: {error}")
|
|
662
687
|
|
|
663
688
|
if skipped_skills and not installed_skills:
|
|
664
689
|
console.print("[dim]Use --force to overwrite existing skills[/dim]")
|
|
665
690
|
elif installed_skills:
|
|
666
|
-
|
|
667
|
-
console.print(f"[dim]Restart Claude Code to activate: {skill_names}[/dim]")
|
|
691
|
+
console.print("[dim]Restart your AI tools to activate new skills[/dim]")
|
|
668
692
|
|
|
669
693
|
return 1 if failed_skills else 0
|
|
670
|
-
|
realign/commands/config.py
CHANGED
|
@@ -13,18 +13,9 @@ console = Console()
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def config_command(
|
|
16
|
-
action: str = typer.Argument(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
),
|
|
20
|
-
key: Optional[str] = typer.Argument(
|
|
21
|
-
None,
|
|
22
|
-
help="Configuration key (for get/set operations)"
|
|
23
|
-
),
|
|
24
|
-
value: Optional[str] = typer.Argument(
|
|
25
|
-
None,
|
|
26
|
-
help="Configuration value (for set operation)"
|
|
27
|
-
),
|
|
16
|
+
action: str = typer.Argument(..., help="Action to perform: 'get', 'set', or 'init'"),
|
|
17
|
+
key: Optional[str] = typer.Argument(None, help="Configuration key (for get/set operations)"),
|
|
18
|
+
value: Optional[str] = typer.Argument(None, help="Configuration value (for set operation)"),
|
|
28
19
|
):
|
|
29
20
|
"""
|
|
30
21
|
Manage ReAlign configuration.
|
realign/commands/context.py
CHANGED
|
@@ -146,7 +146,9 @@ def context_show_command(
|
|
|
146
146
|
console.print("[dim]No active context.[/dim]")
|
|
147
147
|
env_val = os.environ.get(CONTEXT_ID_ENV_VAR)
|
|
148
148
|
if env_val:
|
|
149
|
-
console.print(
|
|
149
|
+
console.print(
|
|
150
|
+
f"[dim]ALINE_CONTEXT_ID is set to '{env_val}' but no matching context found.[/dim]"
|
|
151
|
+
)
|
|
150
152
|
console.print("[dim]Searches will include all sessions/events.[/dim]")
|
|
151
153
|
return 0
|
|
152
154
|
|