diff --git a/src/auto_commit_service/tray/local_agent.py b/src/auto_commit_service/tray/local_agent.py index 2d30520..15b0975 100644 --- a/src/auto_commit_service/tray/local_agent.py +++ b/src/auto_commit_service/tray/local_agent.py @@ -80,11 +80,15 @@ class LocalCommitAgent: cycle_seconds: int = 300, co_author: str = "Lilith Autocommit ", recovery_state_path: Path | None = None, + dry_run: bool = False, + max_diff_bytes: int = 131072, ): self.acs_url = acs_url.rstrip("/") self.repos_paths = repos_paths self.cycle_seconds = cycle_seconds self.co_author = co_author + self.dry_run = dry_run + self.max_diff_bytes = max_diff_bytes self._client = httpx.Client(base_url=self.acs_url, timeout=30.0) self._running = False @@ -263,11 +267,13 @@ class LocalCommitAgent: # stage denied secret paths too). _git(repo_path, "add", "--", *allowed) - # Get the diff of staged changes + # Get the diff of staged changes. Size cap comes from self.max_diff_bytes; + # the 6000-byte stage-time cap is a sub-cap before the prefilter-level cap. + stage_cap = min(6000, self.max_diff_bytes) raw_diff = _git(repo_path, "diff", "--cached", "--stat") + "\n" + _git( - repo_path, "diff", "--cached", max_bytes=6000 + repo_path, "diff", "--cached", max_bytes=stage_cap ) - diff, was_truncated = truncate_diff(raw_diff) + diff, was_truncated = truncate_diff(raw_diff, max_bytes=self.max_diff_bytes) if was_truncated: logger.debug(f"{_repo_display_name(repo_path)}: diff truncated for transmission") if not diff.strip(): @@ -299,6 +305,15 @@ class LocalCommitAgent: _git(repo_path, "reset", "HEAD") return False + # Dry-run gate — log intent, unstage, do not commit or push + if self.dry_run: + logger.info( + f"[DRY-RUN] {repo_name} ({branch}) would commit {len(allowed)} file(s) " + f"with message: {message.splitlines()[0] if message else '(empty)'}" + ) + _git(repo_path, "reset", "HEAD") + return False + # Commit full_message = f"{message}\n\nCo-Authored-By: {self.co_author}" _git(repo_path, "commit", "-m", full_message)