autopilot-code 0.0.11 → 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 +7 -7
- package/package.json +1 -1
- package/scripts/run_autopilot.py +30 -28
package/dist/cli.js
CHANGED
|
@@ -209,7 +209,7 @@ function installSystemdService() {
|
|
|
209
209
|
if (!systemctl("enable", ["autopilot.service", ...daemonReloadArgs])) {
|
|
210
210
|
process.exit(1);
|
|
211
211
|
}
|
|
212
|
-
if (!systemctl("
|
|
212
|
+
if (!systemctl("restart", ["autopilot.service", ...daemonReloadArgs])) {
|
|
213
213
|
process.exit(1);
|
|
214
214
|
}
|
|
215
215
|
console.log("✅ Autopilot service installed, enabled and started.");
|
|
@@ -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) => {
|
|
@@ -402,7 +402,7 @@ program
|
|
|
402
402
|
console.log("No source folders configured. Run 'autopilot init' to add some.");
|
|
403
403
|
return;
|
|
404
404
|
}
|
|
405
|
-
const args = [runnerPath, "--root", ...rootPaths];
|
|
405
|
+
const args = ["-u", runnerPath, "--root", ...rootPaths];
|
|
406
406
|
if (opts.maxDepth)
|
|
407
407
|
args.push("--max-depth", opts.maxDepth);
|
|
408
408
|
if (opts.minPriority)
|
|
@@ -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) => {
|
|
@@ -434,7 +434,7 @@ program
|
|
|
434
434
|
console.log("No source folders configured. Run 'autopilot init' to add some.");
|
|
435
435
|
return;
|
|
436
436
|
}
|
|
437
|
-
const args = [runnerPath, "--root", ...rootPaths];
|
|
437
|
+
const args = ["-u", runnerPath, "--root", ...rootPaths];
|
|
438
438
|
if (opts.maxDepth)
|
|
439
439
|
args.push("--max-depth", opts.maxDepth);
|
|
440
440
|
if (opts.minPriority)
|
|
@@ -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) => {
|
|
@@ -467,7 +467,7 @@ program
|
|
|
467
467
|
console.log("No source folders configured. Run 'autopilot init' to add some.");
|
|
468
468
|
return;
|
|
469
469
|
}
|
|
470
|
-
const args = [runnerPath, "--root", ...rootPaths];
|
|
470
|
+
const args = ["-u", runnerPath, "--root", ...rootPaths];
|
|
471
471
|
if (opts.maxDepth)
|
|
472
472
|
args.push("--max-depth", opts.maxDepth);
|
|
473
473
|
if (opts.minPriority)
|
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,10 +100,8 @@ 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
|
-
|
|
104
|
-
|
|
105
|
-
"Please specify at least one allowed GitHub username."
|
|
106
|
-
)
|
|
103
|
+
print(f"Warning: [{data.get('repo', 'unknown')}] autoMerge is enabled but allowedMergeUsers is empty. Disabling autoMerge for this repo.", flush=True)
|
|
104
|
+
auto_merge = False
|
|
107
105
|
|
|
108
106
|
auto_resolve_conflicts = data.get("autoResolveConflicts", True)
|
|
109
107
|
conflict_resolution_max_attempts = int(data.get("conflictResolutionMaxAttempts", 3))
|
|
@@ -148,13 +146,16 @@ def _discover_repos_recursive(
|
|
|
148
146
|
if current_depth > max_depth:
|
|
149
147
|
return
|
|
150
148
|
|
|
151
|
-
# Check if current directory is a git repo
|
|
152
|
-
if (current_dir / ".git").exists()
|
|
153
|
-
current_dir / ".autopilot" / "autopilot.json"
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
|
158
159
|
return
|
|
159
160
|
|
|
160
161
|
# Recursively search subdirectories (depth-first)
|
|
@@ -162,7 +163,7 @@ def _discover_repos_recursive(
|
|
|
162
163
|
for child in sorted(current_dir.iterdir(), key=lambda p: p.name.lower()):
|
|
163
164
|
if not child.is_dir():
|
|
164
165
|
continue
|
|
165
|
-
if child.name in IGNORED_DIRS:
|
|
166
|
+
if child.name in IGNORED_DIRS or child.name.startswith("."):
|
|
166
167
|
continue
|
|
167
168
|
_discover_repos_recursive(child, current_depth + 1, max_depth, out)
|
|
168
169
|
except PermissionError:
|
|
@@ -356,6 +357,7 @@ def run_cycle(
|
|
|
356
357
|
claimed_count = 0
|
|
357
358
|
|
|
358
359
|
for cfg in all_configs:
|
|
360
|
+
print(f"[{cfg.repo}] Scanning for issues...", flush=True)
|
|
359
361
|
# 1) First, check any in-progress issues and mark blocked if stale.
|
|
360
362
|
inprog = list_in_progress_issues(cfg)
|
|
361
363
|
for it in inprog:
|
|
@@ -391,7 +393,7 @@ def run_cycle(
|
|
|
391
393
|
"(Durable tracking: this repo will maintain `.autopilot/state.json` as a heartbeat; "
|
|
392
394
|
"the runner does not inspect processes.)"
|
|
393
395
|
)
|
|
394
|
-
print(f"[{cfg.repo}] next issue: #{issue['number']} {issue['title']}")
|
|
396
|
+
print(f"[{cfg.repo}] next issue: #{issue['number']} {issue['title']}", flush=True)
|
|
395
397
|
if dry_run:
|
|
396
398
|
claimed_count += 1
|
|
397
399
|
continue
|
|
@@ -441,10 +443,10 @@ def main() -> int:
|
|
|
441
443
|
for root_str in args.root:
|
|
442
444
|
root = Path(root_str).resolve()
|
|
443
445
|
if not root.exists():
|
|
444
|
-
print(f"Warning: root path {root} does not exist, skipping")
|
|
446
|
+
print(f"Warning: root path {root} does not exist, skipping", flush=True)
|
|
445
447
|
continue
|
|
446
448
|
if not root.is_dir():
|
|
447
|
-
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)
|
|
448
450
|
continue
|
|
449
451
|
configs = discover_repos(root, max_depth=args.max_depth)
|
|
450
452
|
|
|
@@ -458,12 +460,12 @@ def main() -> int:
|
|
|
458
460
|
all_configs.extend(configs)
|
|
459
461
|
|
|
460
462
|
if not all_configs:
|
|
461
|
-
print("No autopilot-enabled repos found.")
|
|
463
|
+
print("No autopilot-enabled repos found.", flush=True)
|
|
462
464
|
return 0
|
|
463
465
|
|
|
464
|
-
print(f"Found {len(all_configs)} autopilot-enabled repo(s)")
|
|
466
|
+
print(f"Found {len(all_configs)} autopilot-enabled repo(s)", flush=True)
|
|
465
467
|
for cfg in all_configs:
|
|
466
|
-
print(f" - {cfg.repo} at {cfg.root}")
|
|
468
|
+
print(f" - {cfg.repo} at {cfg.root}", flush=True)
|
|
467
469
|
|
|
468
470
|
# Loop mode (for foreground service)
|
|
469
471
|
if args.interval_seconds is not None:
|
|
@@ -471,37 +473,37 @@ def main() -> int:
|
|
|
471
473
|
|
|
472
474
|
def signal_handler(signum: int, frame: Any) -> None:
|
|
473
475
|
nonlocal shutdown_requested
|
|
474
|
-
print("\nShutdown requested (Ctrl+C), finishing current cycle...")
|
|
476
|
+
print("\nShutdown requested (Ctrl+C), finishing current cycle...", flush=True)
|
|
475
477
|
shutdown_requested = True
|
|
476
478
|
|
|
477
479
|
signal.signal(signal.SIGINT, signal_handler)
|
|
478
480
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
479
481
|
|
|
480
|
-
print(f"Running in foreground mode with {args.interval_seconds}s interval")
|
|
481
|
-
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)
|
|
482
484
|
|
|
483
485
|
cycle_num = 0
|
|
484
486
|
while not shutdown_requested:
|
|
485
487
|
cycle_num += 1
|
|
486
488
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S %Z")
|
|
487
|
-
print(f"\n=== Cycle {cycle_num} at {timestamp} ===")
|
|
489
|
+
print(f"\n=== Cycle {cycle_num} at {timestamp} ===", flush=True)
|
|
488
490
|
|
|
489
491
|
try:
|
|
490
492
|
claimed = run_cycle(all_configs, dry_run=args.dry_run)
|
|
491
493
|
if claimed == 0:
|
|
492
|
-
print("No issues claimed in this cycle")
|
|
494
|
+
print("No issues claimed in this cycle", flush=True)
|
|
493
495
|
else:
|
|
494
|
-
print(f"Claimed {claimed} issue(s) in this cycle")
|
|
496
|
+
print(f"Claimed {claimed} issue(s) in this cycle", flush=True)
|
|
495
497
|
except Exception as e:
|
|
496
|
-
print(f"Error in cycle {cycle_num}: {e}")
|
|
498
|
+
print(f"Error in cycle {cycle_num}: {e}", flush=True)
|
|
497
499
|
|
|
498
500
|
if shutdown_requested:
|
|
499
501
|
break
|
|
500
502
|
|
|
501
|
-
print(f"Sleeping for {args.interval_seconds}s...")
|
|
503
|
+
print(f"Sleeping for {args.interval_seconds}s...", flush=True)
|
|
502
504
|
time.sleep(args.interval_seconds)
|
|
503
505
|
|
|
504
|
-
print("\nShutdown complete")
|
|
506
|
+
print("\nShutdown complete", flush=True)
|
|
505
507
|
return 0
|
|
506
508
|
|
|
507
509
|
# Single-shot mode (run-once)
|