autopilot-code 0.0.12 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +3 -3
- package/package.json +1 -1
- package/scripts/run_autopilot.py +29 -29
package/dist/cli.js
CHANGED
|
@@ -385,7 +385,7 @@ program
|
|
|
385
385
|
.command("scan")
|
|
386
386
|
.description("Discover autopilot-enabled repos + show next issue candidate (dry-run)")
|
|
387
387
|
.option("--root <paths...>", "Root folder(s) that contain git repos (space-separated)")
|
|
388
|
-
.option("--max-depth <number>", "Maximum depth for recursive repo discovery", "
|
|
388
|
+
.option("--max-depth <number>", "Maximum depth for recursive repo discovery", "3")
|
|
389
389
|
.option("--min-priority <label>", "Minimum priority label to work (e.g. p0, p1)")
|
|
390
390
|
.option("--ignore-labels <labels...>", "Ignore issues with these labels (space-separated)")
|
|
391
391
|
.action((opts) => {
|
|
@@ -417,7 +417,7 @@ program
|
|
|
417
417
|
.command("run-once")
|
|
418
418
|
.description("Claim exactly one issue and post a progress comment")
|
|
419
419
|
.option("--root <paths...>", "Root folder(s) that contain git repos (space-separated)")
|
|
420
|
-
.option("--max-depth <number>", "Maximum depth for recursive repo discovery", "
|
|
420
|
+
.option("--max-depth <number>", "Maximum depth for recursive repo discovery", "3")
|
|
421
421
|
.option("--min-priority <label>", "Minimum priority label to work (e.g. p0, p1)")
|
|
422
422
|
.option("--ignore-labels <labels...>", "Ignore issues with these labels (space-separated)")
|
|
423
423
|
.action((opts) => {
|
|
@@ -450,7 +450,7 @@ program
|
|
|
450
450
|
.option("--foreground", "Run in foreground mode (log to stdout)")
|
|
451
451
|
.option("--interval-seconds <number>", "Interval between cycles in seconds", "60")
|
|
452
452
|
.option("--root <paths...>", "Root folder(s) that contain git repos (space-separated)")
|
|
453
|
-
.option("--max-depth <number>", "Maximum depth for recursive repo discovery", "
|
|
453
|
+
.option("--max-depth <number>", "Maximum depth for recursive repo discovery", "3")
|
|
454
454
|
.option("--min-priority <label>", "Minimum priority label to work (e.g. p0, p1)")
|
|
455
455
|
.option("--ignore-labels <labels...>", "Ignore issues with these labels (space-separated)")
|
|
456
456
|
.action((opts) => {
|
package/package.json
CHANGED
package/scripts/run_autopilot.py
CHANGED
|
@@ -28,7 +28,7 @@ from typing import Any
|
|
|
28
28
|
STATE_DIR = ".autopilot"
|
|
29
29
|
STATE_FILE = "state.json"
|
|
30
30
|
DEFAULT_HEARTBEAT_MAX_AGE_SECS = 60 * 60 # 1h
|
|
31
|
-
DEFAULT_MAX_DEPTH =
|
|
31
|
+
DEFAULT_MAX_DEPTH = 3
|
|
32
32
|
IGNORED_DIRS = {
|
|
33
33
|
"node_modules",
|
|
34
34
|
".venv",
|
|
@@ -100,7 +100,7 @@ def load_config(repo_root: Path) -> RepoConfig | None:
|
|
|
100
100
|
allowed_merge_users = list(data.get("allowedMergeUsers", []))
|
|
101
101
|
|
|
102
102
|
if auto_merge and not allowed_merge_users:
|
|
103
|
-
print(f"Warning: [{data.get('repo', 'unknown')}] autoMerge is enabled but allowedMergeUsers is empty. Disabling autoMerge for this repo.")
|
|
103
|
+
print(f"Warning: [{data.get('repo', 'unknown')}] autoMerge is enabled but allowedMergeUsers is empty. Disabling autoMerge for this repo.", flush=True)
|
|
104
104
|
auto_merge = False
|
|
105
105
|
|
|
106
106
|
auto_resolve_conflicts = data.get("autoResolveConflicts", True)
|
|
@@ -146,16 +146,16 @@ def _discover_repos_recursive(
|
|
|
146
146
|
if current_depth > max_depth:
|
|
147
147
|
return
|
|
148
148
|
|
|
149
|
-
# Check if current directory is a git repo
|
|
150
|
-
if (current_dir / ".git").exists()
|
|
151
|
-
current_dir / ".autopilot" / "autopilot.json"
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
149
|
+
# Check if current directory is a git repo
|
|
150
|
+
if (current_dir / ".git").exists():
|
|
151
|
+
if (current_dir / ".autopilot" / "autopilot.json").exists():
|
|
152
|
+
try:
|
|
153
|
+
cfg = load_config(current_dir)
|
|
154
|
+
if cfg:
|
|
155
|
+
out.append(cfg)
|
|
156
|
+
except Exception as e:
|
|
157
|
+
print(f"Error loading config in {current_dir}: {e}", flush=True)
|
|
158
|
+
# stop descending once we hit a git repo
|
|
159
159
|
return
|
|
160
160
|
|
|
161
161
|
# Recursively search subdirectories (depth-first)
|
|
@@ -163,7 +163,7 @@ def _discover_repos_recursive(
|
|
|
163
163
|
for child in sorted(current_dir.iterdir(), key=lambda p: p.name.lower()):
|
|
164
164
|
if not child.is_dir():
|
|
165
165
|
continue
|
|
166
|
-
if child.name in IGNORED_DIRS:
|
|
166
|
+
if child.name in IGNORED_DIRS or child.name.startswith("."):
|
|
167
167
|
continue
|
|
168
168
|
_discover_repos_recursive(child, current_depth + 1, max_depth, out)
|
|
169
169
|
except PermissionError:
|
|
@@ -357,7 +357,7 @@ def run_cycle(
|
|
|
357
357
|
claimed_count = 0
|
|
358
358
|
|
|
359
359
|
for cfg in all_configs:
|
|
360
|
-
print(f"[{cfg.repo}] Scanning for issues...")
|
|
360
|
+
print(f"[{cfg.repo}] Scanning for issues...", flush=True)
|
|
361
361
|
# 1) First, check any in-progress issues and mark blocked if stale.
|
|
362
362
|
inprog = list_in_progress_issues(cfg)
|
|
363
363
|
for it in inprog:
|
|
@@ -393,7 +393,7 @@ def run_cycle(
|
|
|
393
393
|
"(Durable tracking: this repo will maintain `.autopilot/state.json` as a heartbeat; "
|
|
394
394
|
"the runner does not inspect processes.)"
|
|
395
395
|
)
|
|
396
|
-
print(f"[{cfg.repo}] next issue: #{issue['number']} {issue['title']}")
|
|
396
|
+
print(f"[{cfg.repo}] next issue: #{issue['number']} {issue['title']}", flush=True)
|
|
397
397
|
if dry_run:
|
|
398
398
|
claimed_count += 1
|
|
399
399
|
continue
|
|
@@ -443,10 +443,10 @@ def main() -> int:
|
|
|
443
443
|
for root_str in args.root:
|
|
444
444
|
root = Path(root_str).resolve()
|
|
445
445
|
if not root.exists():
|
|
446
|
-
print(f"Warning: root path {root} does not exist, skipping")
|
|
446
|
+
print(f"Warning: root path {root} does not exist, skipping", flush=True)
|
|
447
447
|
continue
|
|
448
448
|
if not root.is_dir():
|
|
449
|
-
print(f"Warning: root path {root} is not a directory, skipping")
|
|
449
|
+
print(f"Warning: root path {root} is not a directory, skipping", flush=True)
|
|
450
450
|
continue
|
|
451
451
|
configs = discover_repos(root, max_depth=args.max_depth)
|
|
452
452
|
|
|
@@ -460,12 +460,12 @@ def main() -> int:
|
|
|
460
460
|
all_configs.extend(configs)
|
|
461
461
|
|
|
462
462
|
if not all_configs:
|
|
463
|
-
print("No autopilot-enabled repos found.")
|
|
463
|
+
print("No autopilot-enabled repos found.", flush=True)
|
|
464
464
|
return 0
|
|
465
465
|
|
|
466
|
-
print(f"Found {len(all_configs)} autopilot-enabled repo(s)")
|
|
466
|
+
print(f"Found {len(all_configs)} autopilot-enabled repo(s)", flush=True)
|
|
467
467
|
for cfg in all_configs:
|
|
468
|
-
print(f" - {cfg.repo} at {cfg.root}")
|
|
468
|
+
print(f" - {cfg.repo} at {cfg.root}", flush=True)
|
|
469
469
|
|
|
470
470
|
# Loop mode (for foreground service)
|
|
471
471
|
if args.interval_seconds is not None:
|
|
@@ -473,37 +473,37 @@ def main() -> int:
|
|
|
473
473
|
|
|
474
474
|
def signal_handler(signum: int, frame: Any) -> None:
|
|
475
475
|
nonlocal shutdown_requested
|
|
476
|
-
print("\nShutdown requested (Ctrl+C), finishing current cycle...")
|
|
476
|
+
print("\nShutdown requested (Ctrl+C), finishing current cycle...", flush=True)
|
|
477
477
|
shutdown_requested = True
|
|
478
478
|
|
|
479
479
|
signal.signal(signal.SIGINT, signal_handler)
|
|
480
480
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
481
481
|
|
|
482
|
-
print(f"Running in foreground mode with {args.interval_seconds}s interval")
|
|
483
|
-
print("Press Ctrl+C to shut down cleanly\n")
|
|
482
|
+
print(f"Running in foreground mode with {args.interval_seconds}s interval", flush=True)
|
|
483
|
+
print("Press Ctrl+C to shut down cleanly\n", flush=True)
|
|
484
484
|
|
|
485
485
|
cycle_num = 0
|
|
486
486
|
while not shutdown_requested:
|
|
487
487
|
cycle_num += 1
|
|
488
488
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S %Z")
|
|
489
|
-
print(f"\n=== Cycle {cycle_num} at {timestamp} ===")
|
|
489
|
+
print(f"\n=== Cycle {cycle_num} at {timestamp} ===", flush=True)
|
|
490
490
|
|
|
491
491
|
try:
|
|
492
492
|
claimed = run_cycle(all_configs, dry_run=args.dry_run)
|
|
493
493
|
if claimed == 0:
|
|
494
|
-
print("No issues claimed in this cycle")
|
|
494
|
+
print("No issues claimed in this cycle", flush=True)
|
|
495
495
|
else:
|
|
496
|
-
print(f"Claimed {claimed} issue(s) in this cycle")
|
|
496
|
+
print(f"Claimed {claimed} issue(s) in this cycle", flush=True)
|
|
497
497
|
except Exception as e:
|
|
498
|
-
print(f"Error in cycle {cycle_num}: {e}")
|
|
498
|
+
print(f"Error in cycle {cycle_num}: {e}", flush=True)
|
|
499
499
|
|
|
500
500
|
if shutdown_requested:
|
|
501
501
|
break
|
|
502
502
|
|
|
503
|
-
print(f"Sleeping for {args.interval_seconds}s...")
|
|
503
|
+
print(f"Sleeping for {args.interval_seconds}s...", flush=True)
|
|
504
504
|
time.sleep(args.interval_seconds)
|
|
505
505
|
|
|
506
|
-
print("\nShutdown complete")
|
|
506
|
+
print("\nShutdown complete", flush=True)
|
|
507
507
|
return 0
|
|
508
508
|
|
|
509
509
|
# Single-shot mode (run-once)
|