Skip to content

Commit ba839a7

Browse files
authored
feat: --force-commit (#34)
1 parent bdecea3 commit ba839a7

File tree

4 files changed

+52
-0
lines changed

4 files changed

+52
-0
lines changed

src/cli.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ def create_parser(cls) -> argparse.ArgumentParser:
277277
action="store_true",
278278
help="Share agent session across runs (advanced)",
279279
)
280+
g_limits.add_argument(
281+
"--force-commit",
282+
action="store_true",
283+
help="Force a git commit in the workspace after agent finishes (if there are changes)",
284+
)
280285

281286
# Config, state & logs group
282287
g_state = parser.add_argument_group("Config, State & Logs")
@@ -1623,6 +1628,8 @@ async def run_orchestrator(self, args: argparse.Namespace) -> int:
16231628
] = args.max_parallel
16241629
if hasattr(args, "timeout") and args.timeout:
16251630
cli_config.setdefault("runner", {})["timeout"] = args.timeout
1631+
if hasattr(args, "force_commit") and args.force_commit:
1632+
cli_config.setdefault("runner", {})["force_commit"] = True
16261633
if args.model:
16271634
cli_config["model"] = args.model
16281635
if hasattr(args, "plugin") and args.plugin:
@@ -1965,6 +1972,7 @@ def _red(k, v):
19651972
),
19661973
default_docker_image=full_config.get("runner", {}).get("docker_image"),
19671974
default_agent_cli_args=_agent_cli_args or None,
1975+
force_commit=bool(full_config.get("runner", {}).get("force_commit", False)),
19681976
)
19691977

19701978
# Initialize orchestrator

src/instance_runner/api.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ async def run_instance(
5555
allow_overwrite_protected_refs: bool = False,
5656
allow_global_session_volume: bool = False,
5757
agent_cli_args: Optional[list[str]] = None,
58+
force_commit: bool = False,
5859
) -> InstanceResult:
5960
"""
6061
Execute a single AI coding instance in an isolated environment.
@@ -133,6 +134,7 @@ async def run_instance(
133134
allow_overwrite_protected_refs=allow_overwrite_protected_refs,
134135
allow_global_session_volume=allow_global_session_volume,
135136
agent_cli_args=agent_cli_args,
137+
force_commit=force_commit,
136138
)
137139

138140

src/instance_runner/runner.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ async def run_instance(
104104
allow_overwrite_protected_refs: bool = False,
105105
allow_global_session_volume: bool = False,
106106
agent_cli_args: Optional[list[str]] = None,
107+
force_commit: bool = False,
107108
) -> InstanceResult:
108109
"""
109110
Execute a single AI coding instance in Docker.
@@ -259,6 +260,7 @@ async def run_instance(
259260
allow_overwrite_protected_refs=allow_overwrite_protected_refs,
260261
allow_global_session_volume=allow_global_session_volume,
261262
agent_cli_args=agent_cli_args,
263+
force_commit=force_commit,
262264
)
263265

264266
# Success or non-retryable error
@@ -365,6 +367,7 @@ async def _run_instance_attempt(
365367
allow_overwrite_protected_refs: bool = False,
366368
allow_global_session_volume: bool = False,
367369
agent_cli_args: Optional[list[str]] = None,
370+
force_commit: bool = False,
368371
) -> InstanceResult:
369372
"""Single attempt at running an instance (internal helper for retry logic)."""
370373
start_time = time.time()
@@ -670,6 +673,40 @@ def emit_event(event_type: str, data: Dict[str, Any]) -> None:
670673
logger.info("Collecting results and importing branch")
671674
emit_event("instance.result_collection_started", {})
672675

676+
# Optional: force a commit if there are uncommitted changes
677+
if force_commit and workspace_dir:
678+
try:
679+
# Check for uncommitted changes
680+
status_cmd = [
681+
"git",
682+
"-C",
683+
str(workspace_dir),
684+
"status",
685+
"--porcelain",
686+
]
687+
rc, out = await git_ops._run_command(status_cmd) # type: ignore[attr-defined]
688+
if rc == 0 and (out or "").strip():
689+
# Stage all and commit
690+
await git_ops._run_command(["git", "-C", str(workspace_dir), "add", "-A"]) # type: ignore[attr-defined]
691+
msg = f"pitaya: force commit (run_id={run_id or ''} iid={instance_id})"
692+
commit_cmd = [
693+
"git",
694+
"-C",
695+
str(workspace_dir),
696+
"commit",
697+
"-m",
698+
msg,
699+
]
700+
rc2, out2 = await git_ops._run_command(commit_cmd) # type: ignore[attr-defined]
701+
if rc2 != 0:
702+
logger.debug(
703+
f"force-commit skipped (git commit failed): {out2}"
704+
)
705+
else:
706+
logger.info("force-commit created a commit in workspace")
707+
except Exception as e:
708+
logger.debug(f"force-commit error ignored: {e}")
709+
673710
# Import work from workspace to host repository according to policy
674711
import_info = await git_ops.import_branch(
675712
repo_path=repo_path,

src/orchestration/orchestrator.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def __init__(
7373
default_model_alias: str = "sonnet",
7474
default_docker_image: Optional[str] = None,
7575
default_agent_cli_args: Optional[List[str]] = None,
76+
force_commit: bool = False,
7677
):
7778
"""
7879
Initialize orchestrator.
@@ -104,6 +105,8 @@ def __init__(
104105
self.default_agent_cli_args: List[str] = list(default_agent_cli_args or [])
105106
except Exception:
106107
self.default_agent_cli_args = []
108+
# Runner behavior: force a commit if workspace has changes
109+
self.force_commit: bool = bool(force_commit)
107110
# Load model mapping checksum for handshake (single-process still validates equality)
108111
try:
109112
from ..utils.model_mapping import load_model_mapping
@@ -1748,6 +1751,7 @@ def _write_last_active():
17481751
allow_overwrite_protected_refs=self.allow_overwrite_protected_refs,
17491752
allow_global_session_volume=self.allow_global_session_volume,
17501753
agent_cli_args=(info.metadata or {}).get("agent_cli_args"),
1754+
force_commit=self.force_commit,
17511755
)
17521756
logger.info(
17531757
f"_execute_instance: run_instance finished iid={instance_id} success={result.success} status={getattr(result,'status',None)}"
@@ -2689,6 +2693,7 @@ async def _run_instance_from_saved_state(self, instance_info) -> InstanceResult:
26892693
allow_overwrite_protected_refs=self.allow_overwrite_protected_refs,
26902694
allow_global_session_volume=self.allow_global_session_volume,
26912695
agent_cli_args=(instance_info.metadata or {}).get("agent_cli_args"),
2696+
force_commit=self.force_commit,
26922697
)
26932698

26942699
# Update state

0 commit comments

Comments
 (0)