Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
## 2025-02-14 - [ASCII Fallback for Tables]
**Learning:** Using Unicode box drawing characters enhances the CLI experience, but a robust ASCII fallback is crucial for CI environments and piped outputs.
**Action:** Always implement a fallback mechanism (like checking `sys.stderr.isatty()`) when using rich text or Unicode symbols.

## 2025-02-28 - [Interactive Restart]

Check notice

Code scanning / Remark-lint (reported by Codacy)

Warn when references to undefined definitions are found. Note

[no-undefined-references] Found reference to undefined definition

Check notice

Code scanning / Remark-lint (reported by Codacy)

Warn when shortcut reference links are used. Note

[no-shortcut-reference-link] Use the trailing [] on reference links
**Learning:** Reconstructing command arguments manually for process restarts is brittle and breaks forward compatibility.
**Action:** When restarting a CLI tool with modified flags (e.g., removing `--dry-run`), filter `sys.argv` instead of rebuilding the argument list from parsed args.
51 changes: 51 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2355,6 +2355,53 @@ def _fetch_if_valid(url: str):
# --------------------------------------------------------------------------- #
# 5. Entry-point
# --------------------------------------------------------------------------- #
def prompt_for_interactive_restart(profile_ids: List[str]) -> None:
"""
Prompts the user to restart the script in live mode (after a successful dry run).

If the user confirms, the script restarts itself using os.execv, preserving
all original arguments (except --dry-run) and environment variables.

This function only runs if sys.stdin is a TTY (interactive session).
"""
if not sys.stdin.isatty():
return

try:
if USE_COLORS:
prompt = f"\n{Colors.BOLD}πŸš€ Ready to launch? {Colors.ENDC}Press [Enter] to run now (or Ctrl+C to cancel)..."
else:
prompt = "\nπŸš€ Ready to launch? Press [Enter] to run now (or Ctrl+C to cancel)..."

# Flush stderr to ensure prompt is visible
sys.stderr.flush()
input(prompt)

# Prepare environment for the new process
# Pass the current token to avoid re-prompting if it was entered interactively
if TOKEN:
os.environ["TOKEN"] = TOKEN

# Construct command arguments
# Use sys.argv filtering to preserve all user-provided flags (even future ones)
# while removing --dry-run to switch to live mode.
clean_argv = [arg for arg in sys.argv[1:] if arg != "--dry-run"]
new_argv = [sys.executable, sys.argv[0]] + clean_argv

# If --profiles wasn't in original args (meaning it came from env/input),
# inject it explicitly so the user doesn't have to re-enter it.
if "--profiles" not in sys.argv and profile_ids:
new_argv.extend(["--profiles", ",".join(profile_ids)])

print(f"\n{Colors.GREEN}πŸ”„ Restarting in live mode...{Colors.ENDC}")
# Security: The input to execv is derived from trusted sys.argv and validated profile_ids.
# It restarts the same script with the same python interpreter.
os.execv(sys.executable, new_argv) # nosec B606

except (KeyboardInterrupt, EOFError):
print(f"\n{Colors.WARNING}⚠️ Cancelled.{Colors.ENDC}")


def print_summary_table(
sync_results: List[Dict[str, Any]], success_count: int, total: int, dry_run: bool
) -> None:
Expand Down Expand Up @@ -2758,6 +2805,10 @@ def make_col_separator(left, mid, right, horiz):
else:
print("πŸ‘‰ Ready to sync? Run the following command:")
print(f" {cmd_str}")

# Offer interactive restart if appropriate
prompt_for_interactive_restart(profile_ids)

else:
if USE_COLORS:
print(
Expand Down
Loading