Skip to content

Latest commit

 

History

History
209 lines (155 loc) · 10.4 KB

File metadata and controls

209 lines (155 loc) · 10.4 KB

AgentAutoFlow File Sync

Syncs the {base folder}/{scaffold_folder}/ rules/docs folders across multiple project directories safely and reproducibly. The utility compares modification times and copies the newest version of each file to older peers, with dry-run, timestamped backups, atomic writes, and live progress.

What this is

A small, focused app inside this repo to keep your {base folder}/{scaffold_folder}/ directory consistent across projects. Use the desktop GUI or the CLI:

  • GUI: python main_gui.py
  • CLI: python cli_sync.py
  • Core engine: utils_sync/sync_core.py

Key features

  • Multi-folder sync — select any number of folders; the engine syncs all {scaffold_folder}/ subdirectories across them using mtime-based conflict resolution (newest file wins).
  • Scan → preview → execute — an overwrite preview panel shows every planned copy before anything is written; confirm or cancel before committing.
  • Dry-run mode — preview changes without touching any files; toggle via the Settings window or config.txt.
  • Safe writes — atomic copies (temp file + rename) prevent partial overwrites; optional timestamped .bak backups are created before every overwrite.
  • Backup cleanup — one-click button removes all .bak files when they are no longer needed.
  • Favorite folder sets — save common project combinations via folders_faves in config and reload them instantly.
  • Ignore patterns — exclude specific files or subdirectories from sync.
  • Live progress — threaded worker streams progress events to the GUI so the interface stays responsive during long syncs.
  • Simple configuration — all settings live in a human-editable config.txt; no database, no registry.
  • Cross-platform — runs on Windows, macOS, and Linux.

How it works

The engine orchestrates a scan → plan → execute workflow:

  • Scan: SyncEngine.scan_folders() in utils_sync/sync_core.py builds an index of files under each folder's {base folder}/{scaffold_folder}/
  • Plan: SyncEngine.plan_actions() in utils_sync/sync_core.py decides copy operations using newest mtime as source
  • Execute: SyncEngine.execute_actions() in utils_sync/sync_core.py performs safe, atomic copies with optional backups

Main components

  • Engine: SyncEngine.__init__() in utils_sync/sync_core.py holds config and an event queue and emits progress
  • Worker: SyncWorker.run() in utils_sync/sync_worker.py coordinates scan/plan/execute on a background thread for the GUI
  • Events: EventType, ProgressEvent, and make_event() in utils_sync/progress_events.py standardize messages shown in the UI and CLI
  • Paths: file_path_utils.has_roo_dir() and file_path_utils.get_roo_relative_path() in utils_sync/file_path_utils.py ensure only real {base folder}/{scaffold_folder}/ directories are synced and compute relative paths
  • Config I/O: config_sync.save_config() in utils_sync/config_sync.py persists settings atomically; defaults are loaded automatically
  • Logging: logger.init_logger() and logger.log_event() in utils_sync/logger.py write a rolling JSONL log and a human-readable plan log

Installation

  1. Ensure Python 3.9+ is installed
  2. Clone this repo
  3. Optional but recommended: create and activate a virtual environment
  4. Install dependencies:
pip install -r requirements.txt

or

  py -m pip install -r requirements.txt 

Quick start

GUI

  • Launch:
    python main_gui.py
    
  • In the window, click Add Folder and select two or more project roots that each contain a {base folder}/{scaffold_folder}/ directory
  • Open Settings to adjust dry-run, backup mode, and ignore patterns
  • Click Start Sync to preview or apply changes

CLI

  • Run headless sync:
    python cli_sync.py <folder1> <folder2> [<folder3> ...]
    
  • Requirements:
    • At least two folders; each must contain a {base folder}/{scaffold_folder}/ directory or the tool exits with code 1
  • Exit codes:
    • 0: success
    • 1: argument/validation error
    • 2: runtime failure

Configuration

Config File Location

By default, the app reads settings from config.txt in the project root. You can override this in three ways:

  1. Environment variable via .env file:

    AgentAutoFlow_CONFIG=/path/to/custom-config.txt
    
  2. CLI flag:

    python cli_sync.py --config /path/to/custom-config.txt folder1 folder2
    
  3. Default fallback: config.txt in project root

Priority order: CLI flag > environment variable > default

Config File Format

Example config.txt:

window_width=800
window_height=600

# Comma-separated names to ignore anywhere under .roo folder.
ignore_patterns=.roo\commands\run-sync.md, .roo\docs, .roo\rules\02-database.md

# Backup behavior ("none" or "timestamped").
backup_mode=timestamped

# if true, keep source modified times (copy2 already preserves on most platforms)
preserve_mtime=true

# if true, collect and display actions but do not modify files
dry_run=false

# Root-level allowlist for files above .roo folder.
root_allowlist=.roomodes

# For use with "Load Favorites" button.
folders_faves=D:\Dropbox\Projects\_MediaShare\app, D:\Dropbox\Projects\2ndFoundation\app, D:\Dropbox\Projects\AgentAutoFlow

Behavior and guarantees

  • Scope: By default, only the {base folder}/{scaffold_folder}/ subtree of each folder is scanned and synced, but .roomodes will be included if .roomodes is present in root_allowlist in config.txt.
  • Default (root-level files): No root-level scanning occurs unless opted-in via root_allowlist.
  • Conflict resolution: The newest mtime wins; the latest copy becomes the source for all older peers.
  • Backups: If backup_mode=timestamped and a destination exists, it is renamed with an ISO timestamp suffix before copy.
  • Atomicity: Copies write to a temp file in the destination directory then rename into place to avoid partial writes.
  • Safety rails: only includes regular files (no symlinks), requires a real {base folder}/{scaffold_folder}/ folder, and always respect ignore_patterns.
  • Symlinks: A symlinked {base folder}/{scaffold_folder}/ is treated as absent by utils_sync/file_path_utils.has_roo_dir().
  • Non-destructive: The current implementation copies newer files to older ones and does not delete files.

Tips

  • Start with dry_run=true to verify actions.
  • Add private, noisy, or large folders to ignore_patterns.
  • Keep one canonical project (AgentAutoFlow) as your "source of truth" and run sync from it first.

Troubleshooting

  • Error: Folder does not contain {base folder}/{scaffold_folder}/ directory: Ensure each selected path has a {base folder}/{scaffold_folder}/ folder at its top level
  • Permission denied: On Windows, run the terminal as Administrator or move the projects to a writable location
  • Paths with spaces: Quotes are not required in the GUI; for CLI, wrap paths in quotes if your shell needs it
  • Nothing happens in non-dry runs: Check antivirus or file locks; the app uses atomic replace operations that can be blocked

Developing and tests

  • Core logic and unit tests live under utils_sync/ and tests/
  • Example: tests/test_sync_core.py verifies newest-wins planning
  • Contribute improvements by keeping modules small and functions documented
  • Run tests with pytest tests/

Root-Level File Allowlist

A short opt-in mechanism to allow syncing a small set of files from a project root in addition to the default {base folder}/{scaffold_folder}/ subtree.

  • Summary: preserve the default behavior of scanning only {base folder}/{scaffold_folder}/ (the safe, opt-in default). When enabled, an optional root-level allowlist can include specific filenames (for example, .roomodes) which will be appended to the index after the {base folder}/{scaffold_folder}/ scan and indexed under a synthetic relative key equal to the filename (example: .roomodes) so they do not collide with {base folder}/{scaffold_folder}/ keys.

  • Config key and example (see config.txt):

    • root_allowlist=.roomodes
  • Default behavior:

    • No scanning outside {base folder}/{scaffold_folder}/ occurs unless files are explicitly allowlisted.
  • Safety rails:

    • Require a real, non-symlink {base folder}/{scaffold_folder}/ folder for a project to be eligible for syncing.
    • Only include files that exist, are regular files (not directories), and are not symlinks.
    • Optional size cap recommended (e.g., 256 KB) to avoid very large files being pulled in.
    • Respect existing ignore patterns by name (files matching ignore_patterns are skipped).
  • Scan behavior summary:

    • The engine first scans the {base folder}/{scaffold_folder}/ subtree as before.
    • After {base folder}/{scaffold_folder}/ is scanned, any root files present in root_allowlist are appended to the index and assigned a synthetic relative key equal to the filename (for example: .roomodes) so they are indexed alongside {base folder}/{scaffold_folder}/ entries without colliding with {base folder}/{scaffold_folder}/ keys.
    • These allowlisted root entries participate in the normal plan → execute workflow.
  • Code references:

    • Implementation and config I/O: utils_sync/config_sync.py
    • Scan/append behavior: utils_sync/sync_core.py
  • Mermaid flow (validation → scan → append allowlisted → plan → execute):

flowchart LR
  validation --> scan
  scan --> append_allowlisted
  append_allowlisted --> plan
  plan --> execute
Loading
  • Short acceptance criteria:
    • This "Root-Level File Allowlist" section exists in README-file-sync.md.
    • The example config snippet above matches the new config.txt entry referenced at config.txt.
    • The README mentions the safety checks and the root_allowlist configuration.
    • The README includes the short mermaid flow showing: validation → scan → append allowlisted → plan → execute.

Related docs

  • High-level project readme: README.md
  • This module’s engine: utils_sync/sync_core.py
  • CLI wrapper: cli_sync.py
  • GUI app: main_gui.py

Prompt stem to assist in changing file-sync app

Typical user path through main_gui.py: Load Favorites -> Scan -> Execute -> Confirmation dialog -> "Synchronization completed successfully" dialog -> List of files updated in green with checkmarks -> Delete .bak files -> Confirmation dialog -> Yes -> Deleted x .bak files dialog -> OK -> [Continue here with what you want to add or change about the file-sync app.] and feed the prompt to coder-sr mode. If it's a big change, feed it to planner-a or architect to get a detailed plan created.