From 48d2455b9cb87350944061690f0b763507191bed Mon Sep 17 00:00:00 2001 From: Bendt Date: Fri, 19 Dec 2025 10:33:48 -0500 Subject: [PATCH] Make TUI the default mode for luk sync command - luk sync now launches interactive TUI dashboard by default - Add --once flag for single sync (non-interactive) - Add --daemon flag for background daemon mode - Keep 'luk sync run' as legacy subcommand for backwards compatibility - Move common options (org, vdir, notify, etc.) to group level --- src/cli/sync.py | 223 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 157 insertions(+), 66 deletions(-) diff --git a/src/cli/sync.py b/src/cli/sync.py index 8d6ec47..dc9ae00 100644 --- a/src/cli/sync.py +++ b/src/cli/sync.py @@ -588,10 +588,149 @@ async def _sync_outlook_data( click.echo("Sync complete.") -@click.group() -def sync(): - """Email and calendar synchronization.""" - pass +@click.group(invoke_without_command=True) +@click.option( + "--once", + is_flag=True, + help="Run a single sync and exit (non-interactive).", + default=False, +) +@click.option( + "--daemon", + is_flag=True, + help="Run in background daemon mode.", + default=False, +) +@click.option( + "--org", + help="Specify the organization name for the subfolder to store emails and calendar events", + default="corteva", +) +@click.option( + "--vdir", + help="Output calendar events in vdir format to the specified directory", + default="~/Calendar", +) +@click.option( + "--notify/--no-notify", + help="Send macOS notifications for new email messages", + default=True, +) +@click.option( + "--dry-run", + is_flag=True, + help="Run in dry-run mode without making changes.", + default=False, +) +@click.option( + "--demo", + is_flag=True, + help="Run with simulated sync (demo mode)", + default=False, +) +@click.option( + "--days-back", + type=int, + help="Number of days to look back for calendar events", + default=1, +) +@click.option( + "--days-forward", + type=int, + help="Number of days to look forward for calendar events", + default=30, +) +@click.option( + "--download-attachments", + is_flag=True, + help="Download email attachments", + default=False, +) +@click.option( + "--two-way-calendar", + is_flag=True, + help="Enable two-way calendar sync (sync local changes to server)", + default=False, +) +@click.pass_context +def sync( + ctx, + once, + daemon, + org, + vdir, + notify, + dry_run, + demo, + days_back, + days_forward, + download_attachments, + two_way_calendar, +): + """Email and calendar synchronization. + + By default, opens the interactive TUI dashboard. + Use --once for a single sync, or --daemon for background mode. + """ + # If a subcommand is invoked, let it handle everything + if ctx.invoked_subcommand is not None: + return + + # Handle the default behavior (no subcommand) + if daemon: + # Run in daemon mode + from .sync_daemon import create_daemon_config, SyncDaemon + + config = create_daemon_config( + dry_run=dry_run, + vdir=vdir, + icsfile=None, + org=org, + days_back=days_back, + days_forward=days_forward, + continue_iteration=False, + download_attachments=download_attachments, + two_way_calendar=two_way_calendar, + notify=notify, + ) + + daemon_instance = SyncDaemon(config) + daemon_instance.start() + elif once: + # Run a single sync (non-interactive) + asyncio.run( + _sync_outlook_data( + dry_run, + vdir, + None, # icsfile + org, + days_back, + days_forward, + False, # continue_iteration + download_attachments, + two_way_calendar, + notify, + ) + ) + else: + # Default: Launch interactive TUI dashboard + from .sync_dashboard import run_dashboard_sync + + sync_config = { + "org": org, + "vdir": vdir, + "notify": notify, + "dry_run": dry_run, + "days_back": days_back, + "days_forward": days_forward, + "download_attachments": download_attachments, + "two_way_calendar": two_way_calendar, + "continue_iteration": False, + "icsfile": None, + } + asyncio.run( + run_dashboard_sync(notify=notify, sync_config=sync_config, demo_mode=demo) + ) def daemonize(): @@ -682,18 +821,6 @@ def daemonize(): help="Enable two-way calendar sync (sync local changes to server)", default=False, ) -@click.option( - "--daemon", - is_flag=True, - help="Run in daemon mode.", - default=False, -) -@click.option( - "--dashboard", - is_flag=True, - help="Run with TUI dashboard.", - default=False, -) @click.option( "--notify", is_flag=True, @@ -710,59 +837,23 @@ def run( continue_iteration, download_attachments, two_way_calendar, - daemon, - dashboard, notify, ): - if dashboard: - from .sync_dashboard import run_dashboard_sync - - sync_config = { - "dry_run": dry_run, - "vdir": vdir, - "icsfile": icsfile, - "org": org, - "days_back": days_back, - "days_forward": days_forward, - "continue_iteration": continue_iteration, - "download_attachments": download_attachments, - "two_way_calendar": two_way_calendar, - "notify": notify, - } - asyncio.run(run_dashboard_sync(notify=notify, sync_config=sync_config)) - elif daemon: - from .sync_daemon import create_daemon_config, SyncDaemon - - config = create_daemon_config( - dry_run=dry_run, - vdir=vdir, - icsfile=icsfile, - org=org, - days_back=days_back, - days_forward=days_forward, - continue_iteration=continue_iteration, - download_attachments=download_attachments, - two_way_calendar=two_way_calendar, - notify=notify, - ) - - daemon_instance = SyncDaemon(config) - daemon_instance.start() - else: - asyncio.run( - _sync_outlook_data( - dry_run, - vdir, - icsfile, - org, - days_back, - days_forward, - continue_iteration, - download_attachments, - two_way_calendar, - notify, - ) + """Run a single sync operation (legacy command, prefer 'luk sync --once').""" + asyncio.run( + _sync_outlook_data( + dry_run, + vdir, + icsfile, + org, + days_back, + days_forward, + continue_iteration, + download_attachments, + two_way_calendar, + notify, ) + ) @sync.command()