autopilot-code 0.0.6 → 0.0.8

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 CHANGED
@@ -16,6 +16,26 @@ const GLOBAL_CONFIG_DIR = node_path_1.default.join(process.env.HOME || "", ".con
16
16
  const GLOBAL_CONFIG_FILE = node_path_1.default.join(GLOBAL_CONFIG_DIR, "config.json");
17
17
  const SYSTEM_DIR = "/etc/systemd/system";
18
18
  const USER_DIR = node_path_1.default.join(process.env.HOME || "", ".config", "systemd", "user");
19
+ function getRepoName(dir) {
20
+ try {
21
+ const res = (0, node_child_process_1.spawnSync)("git", ["remote", "get-url", "origin"], { cwd: dir, encoding: "utf8" });
22
+ if (res.status !== 0)
23
+ return null;
24
+ const url = res.stdout.trim();
25
+ // Handle SSH: git@github.com:owner/repo.git
26
+ if (url.includes("@github.com:")) {
27
+ return url.split("@github.com:")[1].replace(".git", "");
28
+ }
29
+ // Handle HTTPS: https://github.com/owner/repo.git
30
+ if (url.includes("github.com/")) {
31
+ return url.split("github.com/")[1].replace(".git", "");
32
+ }
33
+ return null;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
19
39
  function run(cmd, args) {
20
40
  const res = (0, node_child_process_1.spawnSync)(cmd, args, { stdio: "inherit" });
21
41
  if (res.error)
@@ -164,8 +184,8 @@ function installSystemdService() {
164
184
  const { unitPath, logPath, useSystem } = getSystemdPaths();
165
185
  const intervalSeconds = "60";
166
186
  if (!(0, node_fs_1.existsSync)(GLOBAL_CONFIG_FILE)) {
167
- console.error("Configuration not found. Run 'autopilot init' first.");
168
- process.exit(1);
187
+ console.log("Global configuration not found. Creating a basic one...");
188
+ saveGlobalConfig({ sourceFolders: [] });
169
189
  }
170
190
  if (!systemctl("--version", [], true)) {
171
191
  console.error("systemd is not available on this system.");
@@ -254,31 +274,75 @@ function statusSystemdService() {
254
274
  spawnSync("systemctl", ["status", "autopilot.service", ...daemonReloadArgs], { stdio: "inherit" });
255
275
  }
256
276
  async function initCommand() {
257
- console.log("🚀 Autopilot Setup\n");
258
- const existingConfig = loadGlobalConfig();
259
- if (existingConfig && existingConfig.sourceFolders.length > 0) {
260
- console.log("Existing configuration found:");
261
- console.log("Current source folders:");
262
- existingConfig.sourceFolders.forEach((folder, idx) => {
263
- const isGit = isGitRepo(folder);
264
- console.log(` ${idx + 1}. ${folder}${isGit ? " (git repo)" : ""}`);
265
- });
266
- console.log();
267
- const overwrite = await prompt("Do you want to replace this configuration? (y/N): ");
268
- if (overwrite.toLowerCase() !== "y") {
269
- console.log("Configuration unchanged.");
270
- return;
277
+ const cwd = process.cwd();
278
+ const validation = validatePath(cwd);
279
+ // 1. Ensure global config exists
280
+ let globalConfig = loadGlobalConfig();
281
+ if (!globalConfig) {
282
+ console.log("Creating new global configuration...");
283
+ globalConfig = { sourceFolders: [] };
284
+ saveGlobalConfig(globalConfig);
285
+ }
286
+ if (validation.isGit) {
287
+ // REPO MODE
288
+ console.log("🚀 Initializing Autopilot in this repository...");
289
+ // a) Add to global scan list if not already there
290
+ if (!globalConfig.sourceFolders.includes(cwd)) {
291
+ globalConfig.sourceFolders.push(cwd);
292
+ saveGlobalConfig(globalConfig);
293
+ }
294
+ // b) Create .autopilot/autopilot.json
295
+ const autopilotDir = node_path_1.default.join(cwd, ".autopilot");
296
+ const autopilotFile = node_path_1.default.join(autopilotDir, "autopilot.json");
297
+ if (!(0, node_fs_1.existsSync)(autopilotDir))
298
+ (0, node_fs_1.mkdirSync)(autopilotDir, { recursive: true });
299
+ if ((0, node_fs_1.existsSync)(autopilotFile)) {
300
+ console.log("⚠️ Autopilot config already exists in this repo.");
301
+ }
302
+ else {
303
+ const repoName = getRepoName(cwd) || "owner/repo";
304
+ const templatePath = node_path_1.default.join(repoRoot, "templates", "autopilot.json");
305
+ let template;
306
+ if ((0, node_fs_1.existsSync)(templatePath)) {
307
+ template = JSON.parse((0, node_fs_1.readFileSync)(templatePath, "utf8"));
308
+ }
309
+ else {
310
+ // Fallback internal default
311
+ template = {
312
+ enabled: true,
313
+ repo: repoName,
314
+ agent: "opencode",
315
+ issueLabels: {
316
+ queue: ["autopilot:todo"],
317
+ blocked: "autopilot:blocked",
318
+ inProgress: "autopilot:in-progress",
319
+ done: "autopilot:done"
320
+ },
321
+ priorityLabels: ["p0", "p1", "p2"],
322
+ maxParallel: 1,
323
+ branchPrefix: "autopilot/",
324
+ allowedBaseBranch: "main"
325
+ };
326
+ }
327
+ template.repo = repoName;
328
+ (0, node_fs_1.writeFileSync)(autopilotFile, JSON.stringify(template, null, 2) + "\n", "utf8");
329
+ console.log(`✅ Created .autopilot/autopilot.json (repo: ${repoName})`);
271
330
  }
272
331
  }
273
- const sourceFolders = await collectSourceFolders();
274
- const config = {
275
- sourceFolders,
276
- };
277
- saveGlobalConfig(config);
278
- console.log("\n✅ Configuration saved to:", GLOBAL_CONFIG_FILE);
279
- console.log("\nYou can now run:");
280
- console.log(" autopilot scan # Scan repos without claiming issues");
281
- console.log(" autopilot run-once # Claim and work on one issue");
332
+ else {
333
+ // FOLDER MODE
334
+ console.log(`🚀 Adding directory to Autopilot scan list: ${cwd}`);
335
+ if (!globalConfig.sourceFolders.includes(cwd)) {
336
+ globalConfig.sourceFolders.push(cwd);
337
+ saveGlobalConfig(globalConfig);
338
+ console.log(" Added to global scan folders.");
339
+ }
340
+ else {
341
+ console.log("ℹ️ This folder is already in the scan list.");
342
+ }
343
+ console.log("\nNote: Autopilot will now scan all sub-folders of this directory for git repos.");
344
+ console.log("You must still run 'autopilot init' inside each repo you want to activate (unless it already has a config).");
345
+ }
282
346
  }
283
347
  const runnerPath = node_path_1.default.join(repoRoot, "scripts", "run_autopilot.py");
284
348
  const program = new commander_1.Command();
@@ -309,19 +373,30 @@ program
309
373
  .description("Discover autopilot-enabled repos + show next issue candidate (dry-run)")
310
374
  .option("--root <paths...>", "Root folder(s) that contain git repos (space-separated)")
311
375
  .option("--max-depth <number>", "Maximum depth for recursive repo discovery", "5")
376
+ .option("--min-priority <label>", "Minimum priority label to work (e.g. p0, p1)")
377
+ .option("--ignore-labels <labels...>", "Ignore issues with these labels (space-separated)")
312
378
  .action((opts) => {
313
379
  let rootPaths = opts.root;
314
380
  if (!rootPaths || rootPaths.length === 0) {
315
- const config = loadGlobalConfig();
316
- if (!config || config.sourceFolders.length === 0) {
317
- console.error("No source folders configured. Run 'autopilot init' first.");
318
- process.exit(1);
381
+ let config = loadGlobalConfig();
382
+ if (!config) {
383
+ config = { sourceFolders: [] };
384
+ saveGlobalConfig(config);
319
385
  }
320
386
  rootPaths = config.sourceFolders;
321
387
  }
388
+ if (!rootPaths || rootPaths.length === 0) {
389
+ console.log("No source folders configured. Run 'autopilot init' to add some.");
390
+ return;
391
+ }
322
392
  const args = [runnerPath, "--root", ...rootPaths];
323
393
  if (opts.maxDepth)
324
394
  args.push("--max-depth", opts.maxDepth);
395
+ if (opts.minPriority)
396
+ args.push("--min-priority", opts.minPriority);
397
+ if (opts.ignoreLabels && opts.ignoreLabels.length > 0) {
398
+ args.push("--ignore-labels", ...opts.ignoreLabels);
399
+ }
325
400
  args.push("--dry-run");
326
401
  run("python3", args);
327
402
  });
@@ -330,19 +405,30 @@ program
330
405
  .description("Claim exactly one issue and post a progress comment")
331
406
  .option("--root <paths...>", "Root folder(s) that contain git repos (space-separated)")
332
407
  .option("--max-depth <number>", "Maximum depth for recursive repo discovery", "5")
408
+ .option("--min-priority <label>", "Minimum priority label to work (e.g. p0, p1)")
409
+ .option("--ignore-labels <labels...>", "Ignore issues with these labels (space-separated)")
333
410
  .action((opts) => {
334
411
  let rootPaths = opts.root;
335
412
  if (!rootPaths || rootPaths.length === 0) {
336
- const config = loadGlobalConfig();
337
- if (!config || config.sourceFolders.length === 0) {
338
- console.error("No source folders configured. Run 'autopilot init' first.");
339
- process.exit(1);
413
+ let config = loadGlobalConfig();
414
+ if (!config) {
415
+ config = { sourceFolders: [] };
416
+ saveGlobalConfig(config);
340
417
  }
341
418
  rootPaths = config.sourceFolders;
342
419
  }
420
+ if (!rootPaths || rootPaths.length === 0) {
421
+ console.log("No source folders configured. Run 'autopilot init' to add some.");
422
+ return;
423
+ }
343
424
  const args = [runnerPath, "--root", ...rootPaths];
344
425
  if (opts.maxDepth)
345
426
  args.push("--max-depth", opts.maxDepth);
427
+ if (opts.minPriority)
428
+ args.push("--min-priority", opts.minPriority);
429
+ if (opts.ignoreLabels && opts.ignoreLabels.length > 0) {
430
+ args.push("--ignore-labels", ...opts.ignoreLabels);
431
+ }
346
432
  run("python3", args);
347
433
  });
348
434
  program
@@ -352,19 +438,30 @@ program
352
438
  .option("--interval-seconds <number>", "Interval between cycles in seconds", "60")
353
439
  .option("--root <paths...>", "Root folder(s) that contain git repos (space-separated)")
354
440
  .option("--max-depth <number>", "Maximum depth for recursive repo discovery", "5")
441
+ .option("--min-priority <label>", "Minimum priority label to work (e.g. p0, p1)")
442
+ .option("--ignore-labels <labels...>", "Ignore issues with these labels (space-separated)")
355
443
  .action((opts) => {
356
444
  let rootPaths = opts.root;
357
445
  if (!rootPaths || rootPaths.length === 0) {
358
- const config = loadGlobalConfig();
359
- if (!config || config.sourceFolders.length === 0) {
360
- console.error("No source folders configured. Run 'autopilot init' first.");
361
- process.exit(1);
446
+ let config = loadGlobalConfig();
447
+ if (!config) {
448
+ config = { sourceFolders: [] };
449
+ saveGlobalConfig(config);
362
450
  }
363
451
  rootPaths = config.sourceFolders;
364
452
  }
453
+ if (!rootPaths || rootPaths.length === 0) {
454
+ console.log("No source folders configured. Run 'autopilot init' to add some.");
455
+ return;
456
+ }
365
457
  const args = [runnerPath, "--root", ...rootPaths];
366
458
  if (opts.maxDepth)
367
459
  args.push("--max-depth", opts.maxDepth);
460
+ if (opts.minPriority)
461
+ args.push("--min-priority", opts.minPriority);
462
+ if (opts.ignoreLabels && opts.ignoreLabels.length > 0) {
463
+ args.push("--ignore-labels", ...opts.ignoreLabels);
464
+ }
368
465
  if (opts.foreground) {
369
466
  const interval = opts.intervalSeconds || "60";
370
467
  args.push("--interval-seconds", interval);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autopilot-code",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "private": false,
5
5
  "description": "Repo-issue–driven autopilot runner",
6
6
  "license": "MIT",
@@ -433,6 +433,8 @@ def main() -> int:
433
433
  default=None,
434
434
  help="Run in loop mode with this interval between cycles (for foreground service mode)",
435
435
  )
436
+ ap.add_argument("--min-priority", help="Override minPriority for all discovered repos")
437
+ ap.add_argument("--ignore-labels", nargs="+", help="Override ignoreIssueLabels for all discovered repos")
436
438
  args = ap.parse_args()
437
439
 
438
440
  all_configs: list[RepoConfig] = []
@@ -445,6 +447,14 @@ def main() -> int:
445
447
  print(f"Warning: root path {root} is not a directory, skipping")
446
448
  continue
447
449
  configs = discover_repos(root, max_depth=args.max_depth)
450
+
451
+ # Apply overrides
452
+ for cfg in configs:
453
+ if args.min_priority:
454
+ cfg.min_priority = args.min_priority
455
+ if args.ignore_labels:
456
+ cfg.ignore_issue_labels = args.ignore_labels
457
+
448
458
  all_configs.extend(configs)
449
459
 
450
460
  if not all_configs: