autopilot-code 0.0.27 → 0.1.0

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.
@@ -30,5 +30,6 @@
30
30
  "autoResolveConflicts": true,
31
31
  "conflictResolutionMaxAttempts": 3,
32
32
  "autoFixChecks": true,
33
- "autoFixChecksMaxAttempts": 3
33
+ "autoFixChecksMaxAttempts": 3,
34
+ "autoUpdate": true
34
35
  }
package/dist/cli.js CHANGED
@@ -347,7 +347,8 @@ async function initCommand() {
347
347
  priorityLabels: ["p0", "p1", "p2"],
348
348
  maxParallel: 1,
349
349
  branchPrefix: "autopilot/",
350
- allowedBaseBranch: "main"
350
+ allowedBaseBranch: "main",
351
+ autoUpdate: true
351
352
  };
352
353
  }
353
354
  template.repo = repoName;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autopilot-code",
3
- "version": "0.0.27",
3
+ "version": "0.1.0",
4
4
  "private": false,
5
5
  "description": "Repo-issue–driven autopilot runner",
6
6
  "license": "MIT",
@@ -14,7 +14,9 @@ if (process.env.CI || process.env.GITHUB_ACTIONS) {
14
14
  }
15
15
 
16
16
  // Skip if running in an autopilot worktree (prevents killing the running service)
17
- if (process.cwd().includes('/tmp/autopilot-issue-') || process.env.AUTOPILOT_WORKTREE) {
17
+ // INIT_CWD is set by npm to the directory where npm install was run
18
+ const initCwd = process.env.INIT_CWD || process.cwd();
19
+ if (initCwd.includes('/tmp/autopilot-issue-') || process.env.AUTOPILOT_WORKTREE) {
18
20
  console.log('Autopilot: skipping auto-install (running in worktree).');
19
21
  process.exit(0);
20
22
  }
@@ -84,6 +84,7 @@ class RepoConfig:
84
84
  conflict_resolution_max_attempts: int
85
85
  auto_fix_checks: bool
86
86
  auto_fix_checks_max_attempts: int
87
+ auto_update: bool
87
88
 
88
89
 
89
90
  def load_config(repo_root: Path) -> RepoConfig | None:
@@ -132,6 +133,7 @@ def load_config(repo_root: Path) -> RepoConfig | None:
132
133
  conflict_resolution_max_attempts=conflict_resolution_max_attempts,
133
134
  auto_fix_checks=auto_fix_checks,
134
135
  auto_fix_checks_max_attempts=auto_fix_checks_max_attempts,
136
+ auto_update=data.get("autoUpdate", False),
135
137
  )
136
138
 
137
139
 
@@ -245,6 +247,68 @@ def write_state(repo_root: Path, state: dict[str, Any]) -> None:
245
247
  p.write_text(json.dumps(state, indent=2, sort_keys=True) + "\n", encoding="utf-8")
246
248
 
247
249
 
250
+ def load_global_state() -> dict[str, Any]:
251
+ p = GLOBAL_STATE_FILE
252
+ if not p.exists():
253
+ GLOBAL_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
254
+ return {}
255
+ try:
256
+ return json.loads(p.read_text(encoding="utf-8"))
257
+ except Exception:
258
+ return {}
259
+
260
+
261
+ def write_global_state(state: dict[str, Any]) -> None:
262
+ GLOBAL_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
263
+ GLOBAL_STATE_FILE.write_text(json.dumps(state, indent=2, sort_keys=True) + "\n", encoding="utf-8")
264
+
265
+
266
+ def flag_autopilot_needs_update() -> None:
267
+ """Flag that autopilot needs to update itself."""
268
+ state = load_global_state()
269
+ state["needsUpdate"] = True
270
+ write_global_state(state)
271
+
272
+
273
+ def check_autopilot_needs_update() -> bool:
274
+ """Check if autopilot is flagged for update."""
275
+ state = load_global_state()
276
+ return state.get("needsUpdate", False)
277
+
278
+
279
+ def clear_autopilot_update_flag() -> None:
280
+ """Clear the update flag."""
281
+ state = load_global_state()
282
+ if "needsUpdate" in state:
283
+ del state["needsUpdate"]
284
+ write_global_state(state)
285
+
286
+
287
+ def is_autopilot_repo(repo: str) -> bool:
288
+ """Check if the repo is the autopilot repository."""
289
+ return repo in ("bakkensoftware/autopilot", "anomalyco/autopilot")
290
+
291
+
292
+ def update_autopilot() -> bool:
293
+ """Update autopilot globally and restart service."""
294
+ print("[autopilot] Updating autopilot-code...", flush=True)
295
+
296
+ try:
297
+ sh(["npm", "install", "-g", "autopilot-code"], check=True)
298
+ print("[autopilot] Successfully installed updated autopilot-code", flush=True)
299
+ except Exception as e:
300
+ print(f"[autopilot] Failed to install autopilot-code: {e}", flush=True)
301
+ return False
302
+
303
+ try:
304
+ sh(["systemctl", "--user", "restart", "autopilot"], check=True)
305
+ print("[autopilot] Restarted autopilot service", flush=True)
306
+ return True
307
+ except Exception as e:
308
+ print(f"[autopilot] Failed to restart service: {e}", flush=True)
309
+ return False
310
+
311
+
248
312
  def touch_heartbeat(cfg: RepoConfig, issue_number: int) -> None:
249
313
  """Update durable local heartbeat state for the repo.
250
314
 
@@ -585,6 +649,11 @@ def try_merge_pr(cfg: RepoConfig, issue_number: int, pr: dict[str, Any]) -> bool
585
649
  "--add-label", cfg.label_done, "--remove-label", cfg.label_in_progress])
586
650
  sh(["gh", "issue", "close", str(issue_number), "--repo", cfg.repo])
587
651
 
652
+ # Flag autopilot for update if we merged our own repo
653
+ if is_autopilot_repo(cfg.repo):
654
+ print(f"[{cfg.repo}] Merged PR to autopilot repo, flagging for self-update", flush=True)
655
+ flag_autopilot_needs_update()
656
+
588
657
  return True
589
658
  except Exception as e:
590
659
  print(f"[{cfg.repo}] Failed to merge PR #{pr_number}: {e}", flush=True)
@@ -747,6 +816,24 @@ def run_cycle(
747
816
  ]
748
817
  )
749
818
 
819
+ # Check if autopilot needs to update
820
+ if not dry_run and check_autopilot_needs_update():
821
+ print("[autopilot] Detected need for self-update", flush=True)
822
+
823
+ # Check if any repo has auto_update enabled
824
+ any_auto_update = any(cfg.auto_update for cfg in all_configs)
825
+
826
+ if any_auto_update:
827
+ print("[autopilot] Performing self-update...", flush=True)
828
+ if update_autopilot():
829
+ clear_autopilot_update_flag()
830
+ print("[autopilot] Self-update completed, service restarted", flush=True)
831
+ else:
832
+ print("[autopilot] Self-update failed, flag preserved for next cycle", flush=True)
833
+ else:
834
+ print("[autopilot] auto_update is disabled for all repos, skipping self-update", flush=True)
835
+ clear_autopilot_update_flag()
836
+
750
837
  return claimed_count
751
838
 
752
839
 
@@ -18,5 +18,6 @@
18
18
  "autoResolveConflicts": true,
19
19
  "conflictResolutionMaxAttempts": 3,
20
20
  "autoFixChecks": true,
21
- "autoFixChecksMaxAttempts": 3
21
+ "autoFixChecksMaxAttempts": 3,
22
+ "autoUpdate": true
22
23
  }