@open330/oac 2026.4.3 → 2026.220.1

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +2 -2
  3. package/dist/{chunk-YWIB3TRI.js → chunk-6A37SKAJ.js} +15 -2
  4. package/dist/chunk-6A37SKAJ.js.map +1 -0
  5. package/dist/{chunk-ZRYAHZQJ.js → chunk-7C7SC4TZ.js} +1 -1
  6. package/dist/{chunk-XUW3XWTX.js → chunk-7Y4LZUDP.js} +89 -121
  7. package/dist/chunk-7Y4LZUDP.js.map +1 -0
  8. package/dist/{chunk-CJAJ4MBO.js → chunk-OS3XDHOJ.js} +57 -18
  9. package/dist/chunk-OS3XDHOJ.js.map +1 -0
  10. package/dist/{chunk-HDMLNOND.js → chunk-OTPXGXO7.js} +44 -18
  11. package/dist/chunk-OTPXGXO7.js.map +1 -0
  12. package/dist/{chunk-7FWC3Z4W.js → chunk-QPVNC7S4.js} +479 -196
  13. package/dist/chunk-QPVNC7S4.js.map +1 -0
  14. package/dist/cli/cli.js +6 -6
  15. package/dist/cli/index.js +6 -6
  16. package/dist/completion/index.js +4 -8
  17. package/dist/completion/index.js.map +1 -1
  18. package/dist/core/index.d.ts +16 -1
  19. package/dist/core/index.js +8 -4
  20. package/dist/dashboard/index.js +33 -24
  21. package/dist/dashboard/index.js.map +1 -1
  22. package/dist/discovery/index.d.ts +18 -2
  23. package/dist/discovery/index.js +4 -2
  24. package/dist/execution/index.d.ts +45 -1
  25. package/dist/execution/index.js +7 -3
  26. package/dist/repo/index.d.ts +2 -2
  27. package/dist/repo/index.js +1 -1
  28. package/dist/{types-CYCwgojB.d.ts → types-3_IAAxh5.d.ts} +1 -0
  29. package/docs/config-reference.md +271 -0
  30. package/docs/multi-agent-support-technical-spec.md +312 -0
  31. package/package.json +23 -18
  32. package/dist/chunk-7FWC3Z4W.js.map +0 -1
  33. package/dist/chunk-CJAJ4MBO.js.map +0 -1
  34. package/dist/chunk-HDMLNOND.js.map +0 -1
  35. package/dist/chunk-XUW3XWTX.js.map +0 -1
  36. package/dist/chunk-YWIB3TRI.js.map +0 -1
  37. /package/dist/{chunk-ZRYAHZQJ.js.map → chunk-7C7SC4TZ.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  cloneRepo,
3
3
  resolveRepo
4
- } from "./chunk-CJAJ4MBO.js";
4
+ } from "./chunk-OS3XDHOJ.js";
5
5
  import {
6
6
  CompositeScanner,
7
7
  GitHubIssuesScanner,
@@ -9,6 +9,7 @@ import {
9
9
  TestGapScanner,
10
10
  TodoScanner,
11
11
  analyzeCodebase,
12
+ buildScanners,
12
13
  createBacklog,
13
14
  getPendingEpics,
14
15
  groupFindingsIntoEpics,
@@ -19,7 +20,7 @@ import {
19
20
  persistContext,
20
21
  rankTasks,
21
22
  updateBacklog
22
- } from "./chunk-HDMLNOND.js";
23
+ } from "./chunk-OTPXGXO7.js";
23
24
  import {
24
25
  buildEpicExecutionPlan,
25
26
  buildExecutionPlan,
@@ -27,17 +28,20 @@ import {
27
28
  estimateTokens
28
29
  } from "./chunk-5GAUWC3L.js";
29
30
  import {
30
- ClaudeCodeAdapter,
31
- CodexAdapter,
31
+ adapterRegistry,
32
32
  createSandbox,
33
33
  epicAsTask,
34
34
  executeTask
35
- } from "./chunk-7FWC3Z4W.js";
35
+ } from "./chunk-QPVNC7S4.js";
36
36
  import {
37
37
  UNLIMITED_BUDGET,
38
38
  createEventBus,
39
39
  loadConfig
40
- } from "./chunk-ZRYAHZQJ.js";
40
+ } from "./chunk-7C7SC4TZ.js";
41
+ import {
42
+ isRecord,
43
+ truncate
44
+ } from "./chunk-6A37SKAJ.js";
41
45
  import {
42
46
  contributionLogSchema,
43
47
  writeContributionLog
@@ -51,7 +55,7 @@ import Table from "cli-table3";
51
55
  import { Command as Command2 } from "commander";
52
56
 
53
57
  // src/cli/github-auth.ts
54
- import { execFileSync } from "child_process";
58
+ import { execFileSync, spawnSync } from "child_process";
55
59
  function ensureGitHubAuth() {
56
60
  const githubToken = process.env.GITHUB_TOKEN?.trim();
57
61
  if (githubToken) {
@@ -79,24 +83,12 @@ function ensureGitHubAuth() {
79
83
  }
80
84
  function checkGitHubScopes(required = ["repo"]) {
81
85
  try {
82
- const output = execFileSync("gh", ["auth", "status"], {
86
+ const result = spawnSync("gh", ["auth", "status"], {
83
87
  timeout: 5e3,
84
88
  encoding: "utf-8",
85
- // Merge stderr into stdout so we can read scope info
86
89
  stdio: ["ignore", "pipe", "pipe"]
87
90
  });
88
- let combined = output;
89
- if (!combined.includes("Token scopes")) {
90
- try {
91
- combined = execFileSync("sh", ["-c", "gh auth status 2>&1"], {
92
- timeout: 5e3,
93
- encoding: "utf-8",
94
- stdio: ["ignore", "pipe", "ignore"]
95
- });
96
- } catch {
97
- return [];
98
- }
99
- }
91
+ const combined = `${result.stdout ?? ""}${result.stderr ?? ""}`;
100
92
  const scopeLine = combined.match(/Token scopes:\s*(.+)/);
101
93
  if (!scopeLine) return [];
102
94
  const scopes = scopeLine[1].split(",").map((s) => s.trim().replace(/^'|'$/g, ""));
@@ -110,14 +102,15 @@ function checkGitHubScopes(required = ["repo"]) {
110
102
  import chalk, { Chalk } from "chalk";
111
103
  import "commander";
112
104
  import ora from "ora";
105
+ import PQueue from "p-queue";
113
106
 
114
107
  // src/cli/config-loader.ts
115
108
  import { constants as fsConstants } from "fs";
116
109
  import { access, readFile } from "fs/promises";
117
110
  import { resolve } from "path";
118
111
  import { pathToFileURL } from "url";
119
- var LEGACY_DEFINE_CONFIG_IMPORT = /@(?:open330\/oac-core|oac\/core)/;
120
- var LEGACY_DEFINE_CONFIG_IMPORT_LINE = /^\s*import\s*\{\s*defineConfig\s*\}\s*from\s*["']@(?:open330\/oac-core|oac\/core)["'];\s*$/m;
112
+ var DEFINE_CONFIG_IMPORT = /@(?:open330\/oac(?:-core)?|oac\/core)/;
113
+ var DEFINE_CONFIG_IMPORT_LINE = /^\s*import\s*\{\s*defineConfig\s*\}\s*from\s*["']@(?:open330\/oac(?:-core)?|oac\/core)["'];\s*$/m;
121
114
  var LEGACY_DEFINE_CONFIG_EXPORT = /export\s+default\s+defineConfig\s*\(/;
122
115
  async function loadOptionalConfigFile(configPath, options = {}) {
123
116
  const absolutePath = resolve(options.cwd ?? process.cwd(), configPath);
@@ -161,16 +154,16 @@ function shouldTryLegacyDefineConfigFallback(error) {
161
154
  if (!(error instanceof Error)) {
162
155
  return false;
163
156
  }
164
- return LEGACY_DEFINE_CONFIG_IMPORT.test(error.message);
157
+ return DEFINE_CONFIG_IMPORT.test(error.message);
165
158
  }
166
159
  function transformLegacyDefineConfigSource(source) {
167
- if (!LEGACY_DEFINE_CONFIG_IMPORT_LINE.test(source)) {
160
+ if (!DEFINE_CONFIG_IMPORT_LINE.test(source)) {
168
161
  return null;
169
162
  }
170
163
  if (!LEGACY_DEFINE_CONFIG_EXPORT.test(source)) {
171
164
  return null;
172
165
  }
173
- return source.replace(LEGACY_DEFINE_CONFIG_IMPORT_LINE, "").replace(LEGACY_DEFINE_CONFIG_EXPORT, "export default (");
166
+ return source.replace(DEFINE_CONFIG_IMPORT_LINE, "").replace(LEGACY_DEFINE_CONFIG_EXPORT, "export default (");
174
167
  }
175
168
  async function importCandidate(moduleSpecifier) {
176
169
  const imported = await import(moduleSpecifier);
@@ -217,12 +210,6 @@ function parseInteger(value) {
217
210
  function formatInteger(value) {
218
211
  return new Intl.NumberFormat("en-US").format(value);
219
212
  }
220
- function truncate(value, maxLength) {
221
- if (value.length <= maxLength) {
222
- return value;
223
- }
224
- return `${value.slice(0, Math.max(0, maxLength - 3))}...`;
225
- }
226
213
  async function loadOptionalConfig(configPath, verbose, ui) {
227
214
  return loadOptionalConfigFile(configPath, {
228
215
  onWarning: verbose ? (message) => {
@@ -263,13 +250,16 @@ function resolveBudget(tokensOption, config) {
263
250
  async function estimateTaskMap(tasks, providerId, onProgress) {
264
251
  let completed = 0;
265
252
  const total = tasks.length;
253
+ const queue = new PQueue({ concurrency: 10 });
266
254
  const entries = await Promise.all(
267
- tasks.map(async (task) => {
268
- const estimate = await estimateTokens(task, providerId);
269
- completed += 1;
270
- onProgress?.(completed, total);
271
- return [task.id, estimate];
272
- })
255
+ tasks.map(
256
+ (task) => queue.add(async () => {
257
+ const estimate = await estimateTokens(task, providerId);
258
+ completed += 1;
259
+ onProgress?.(completed, total);
260
+ return [task.id, estimate];
261
+ })
262
+ )
273
263
  );
274
264
  return new Map(entries);
275
265
  }
@@ -382,14 +372,7 @@ function normalizeOutputFormat(value) {
382
372
  throw new Error(`Unsupported --format value "${value}". Use "table" or "json".`);
383
373
  }
384
374
  function buildScannerList(config, hasGitHubAuth) {
385
- const scanners = [];
386
- const lint = config?.discovery.scanners.lint ?? true;
387
- const todo = config?.discovery.scanners.todo ?? true;
388
- if (lint) scanners.push(new LintScanner());
389
- if (todo) scanners.push(new TodoScanner());
390
- scanners.push(new TestGapScanner());
391
- if (hasGitHubAuth) scanners.push(new GitHubIssuesScanner());
392
- return scanners;
375
+ return buildScanners(config, hasGitHubAuth).instances;
393
376
  }
394
377
 
395
378
  // src/cli/commands/completion.ts
@@ -598,6 +581,16 @@ async function runDoctorChecks() {
598
581
  status: codexResult.ok ? "pass" : "fail",
599
582
  message: codexResult.ok ? void 0 : explainCommandFailure("codex", codexResult)
600
583
  });
584
+ const opencodeResult = await runCommand("opencode", ["--version"]);
585
+ const opencodeVersion = extractVersion(opencodeResult.stdout) ?? "--";
586
+ checks.push({
587
+ id: "opencode",
588
+ name: "OpenCode CLI",
589
+ requirement: "installed",
590
+ value: opencodeVersion,
591
+ status: opencodeResult.ok ? "pass" : "fail",
592
+ message: opencodeResult.ok ? void 0 : explainCommandFailure("opencode", opencodeResult)
593
+ });
601
594
  return checks;
602
595
  }
603
596
  async function checkGithubAuth() {
@@ -709,7 +702,7 @@ async function runCommand(command, args) {
709
702
  });
710
703
  return {
711
704
  ok: result.exitCode === 0,
712
- exitCode: result.exitCode,
705
+ exitCode: result.exitCode ?? null,
713
706
  stdout: result.stdout,
714
707
  stderr: result.stderr
715
708
  };
@@ -780,15 +773,15 @@ function createExplainCommand() {
780
773
  console.log(` ${ui.blue("Scope:")} ${epic.scope}`);
781
774
  console.log(` ${ui.blue("Priority:")} ${epic.priority}`);
782
775
  console.log(` ${ui.blue("Status:")} ${epic.status}`);
783
- console.log(` ${ui.blue("Tasks:")} ${epic.taskIds.length}`);
776
+ console.log(` ${ui.blue("Tasks:")} ${epic.subtasks.length}`);
784
777
  console.log("");
785
778
  console.log(ui.dim("Description:"));
786
779
  console.log(` ${epic.description}`);
787
- if (epic.taskIds.length > 0) {
780
+ if (epic.subtasks.length > 0) {
788
781
  console.log("");
789
782
  console.log(ui.dim("Task IDs:"));
790
- for (const taskId of epic.taskIds) {
791
- console.log(` - ${taskId}`);
783
+ for (const subtask of epic.subtasks) {
784
+ console.log(` - ${subtask.id}`);
792
785
  }
793
786
  }
794
787
  }
@@ -854,7 +847,7 @@ function printAvailableIds(ui, context, backlog) {
854
847
 
855
848
  // src/cli/commands/init.ts
856
849
  import { constants as fsConstants2 } from "fs";
857
- import { access as access2, mkdir, writeFile } from "fs/promises";
850
+ import { access as access2, mkdir, readFile as readFile2, writeFile } from "fs/promises";
858
851
  import { resolve as resolve3 } from "path";
859
852
  import { checkbox, confirm, input } from "@inquirer/prompts";
860
853
  import { Command as Command6 } from "commander";
@@ -919,6 +912,7 @@ async function runMinimalInit(options, globalOptions, ui) {
919
912
  });
920
913
  await writeFile(configPath, configContent, "utf8");
921
914
  await mkdir(trackingDirectory, { recursive: true });
915
+ await ensureGitignoreEntry(process.cwd(), ".oac/");
922
916
  const summary = {
923
917
  configPath,
924
918
  trackingDirectory,
@@ -947,7 +941,7 @@ async function runInteractiveInit(globalOptions, ui) {
947
941
  choices: [
948
942
  { name: "Claude Code", value: "claude-code", checked: true },
949
943
  { name: "Codex CLI", value: "codex" },
950
- { name: "OpenCode (coming soon)", value: "opencode", disabled: true }
944
+ { name: "OpenCode", value: "opencode" }
951
945
  ],
952
946
  validate: (value) => value.length > 0 ? true : "Select at least one provider to continue."
953
947
  });
@@ -1007,6 +1001,7 @@ async function runInteractiveInit(globalOptions, ui) {
1007
1001
  });
1008
1002
  await writeFile(configPath, configContent, "utf8");
1009
1003
  await mkdir(trackingDirectory, { recursive: true });
1004
+ await ensureGitignoreEntry(process.cwd(), ".oac/");
1010
1005
  const summary = {
1011
1006
  configPath,
1012
1007
  trackingDirectory,
@@ -1082,9 +1077,23 @@ async function pathExists2(path) {
1082
1077
  return false;
1083
1078
  }
1084
1079
  }
1080
+ async function ensureGitignoreEntry(dir, entry) {
1081
+ const gitignorePath = resolve3(dir, ".gitignore");
1082
+ let content = "";
1083
+ try {
1084
+ content = await readFile2(gitignorePath, "utf8");
1085
+ } catch {
1086
+ }
1087
+ if (content.split("\n").some((line) => line.trim() === entry)) {
1088
+ return;
1089
+ }
1090
+ const separator = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
1091
+ await writeFile(gitignorePath, `${content}${separator}${entry}
1092
+ `, "utf8");
1093
+ }
1085
1094
 
1086
1095
  // src/cli/commands/leaderboard.ts
1087
- import { readFile as readFile2, readdir } from "fs/promises";
1096
+ import { readFile as readFile3, readdir } from "fs/promises";
1088
1097
  import { resolve as resolve4 } from "path";
1089
1098
  import Table2 from "cli-table3";
1090
1099
  import { Command as Command7 } from "commander";
@@ -1144,7 +1153,7 @@ Examples:
1144
1153
  async function loadLeaderboardEntries(repoPath) {
1145
1154
  const leaderboardPath = resolve4(repoPath, ".oac", "leaderboard.json");
1146
1155
  try {
1147
- const leaderboardRaw = await readFile2(leaderboardPath, "utf8");
1156
+ const leaderboardRaw = await readFile3(leaderboardPath, "utf8");
1148
1157
  const leaderboardPayload = JSON.parse(leaderboardRaw);
1149
1158
  return parseStoredLeaderboardEntries(leaderboardPayload);
1150
1159
  } catch (error) {
@@ -1204,7 +1213,7 @@ async function readContributionLogs(repoPath) {
1204
1213
  fileNames.map(async (fileName) => {
1205
1214
  const filePath = resolve4(contributionsPath, fileName);
1206
1215
  try {
1207
- const content = await readFile2(filePath, "utf8");
1216
+ const content = await readFile3(filePath, "utf8");
1208
1217
  const payload = JSON.parse(content);
1209
1218
  const parsed = contributionLogSchema.safeParse(payload);
1210
1219
  return parsed.success ? parsed.data : null;
@@ -1270,9 +1279,6 @@ function sortValue(entry, field) {
1270
1279
  }
1271
1280
  return entry.totalPRsCreated;
1272
1281
  }
1273
- function isRecord(value) {
1274
- return typeof value === "object" && value !== null;
1275
- }
1276
1282
  function isFileNotFoundError(error) {
1277
1283
  if (!isRecord(error)) {
1278
1284
  return false;
@@ -1281,7 +1287,7 @@ function isFileNotFoundError(error) {
1281
1287
  }
1282
1288
 
1283
1289
  // src/cli/commands/log.ts
1284
- import { readFile as readFile3, readdir as readdir2 } from "fs/promises";
1290
+ import { readFile as readFile4, readdir as readdir2 } from "fs/promises";
1285
1291
  import { resolve as resolve5 } from "path";
1286
1292
  import Table3 from "cli-table3";
1287
1293
  import { Command as Command8 } from "commander";
@@ -1357,7 +1363,7 @@ async function readContributionLogs2(repoPath) {
1357
1363
  files.map(async (fileName) => {
1358
1364
  const filePath = resolve5(contributionsPath, fileName);
1359
1365
  try {
1360
- const content = await readFile3(filePath, "utf8");
1366
+ const content = await readFile4(filePath, "utf8");
1361
1367
  const payload = JSON.parse(content);
1362
1368
  const parsed = contributionLogSchema.safeParse(payload);
1363
1369
  return parsed.success ? parsed.data : null;
@@ -1547,7 +1553,7 @@ import { randomUUID } from "crypto";
1547
1553
 
1548
1554
  // src/cli/commands/run/epic.ts
1549
1555
  import Table6 from "cli-table3";
1550
- import PQueue2 from "p-queue";
1556
+ import PQueue3 from "p-queue";
1551
1557
 
1552
1558
  // src/cli/commands/run/pr.ts
1553
1559
  import { execa } from "execa";
@@ -1672,7 +1678,7 @@ async function createPullRequest(input2) {
1672
1678
  // src/cli/commands/run/task.ts
1673
1679
  import Table5 from "cli-table3";
1674
1680
  import { execa as execa2 } from "execa";
1675
- import PQueue from "p-queue";
1681
+ import PQueue2 from "p-queue";
1676
1682
  async function discoverTasks(ctx, options, config, ghToken, resolvedRepo) {
1677
1683
  const scannerSelection = selectScannersFromConfig2(config, Boolean(ghToken));
1678
1684
  const minPriority = config?.discovery.minPriority ?? 20;
@@ -1795,7 +1801,7 @@ async function executePlan(ctx, params) {
1795
1801
  `Executing ${plan.selectedTasks.length} planned task(s)...`
1796
1802
  );
1797
1803
  let completedCount = 0;
1798
- const taskQueue = new PQueue({ concurrency });
1804
+ const taskQueue = new PQueue2({ concurrency });
1799
1805
  const executedTasks = await Promise.all(
1800
1806
  plan.selectedTasks.map(
1801
1807
  (entry) => taskQueue.add(async () => {
@@ -1820,7 +1826,7 @@ async function executePlan(ctx, params) {
1820
1826
  );
1821
1827
  executionSpinner?.succeed("Execution stage finished");
1822
1828
  const completionSpinner = createSpinner(ctx.suppressOutput, "Completing task outputs...");
1823
- const completionQueue = new PQueue({ concurrency });
1829
+ const completionQueue = new PQueue2({ concurrency });
1824
1830
  const completedTasks = await Promise.all(
1825
1831
  executedTasks.map(
1826
1832
  (result) => completionQueue.add(async () => {
@@ -1891,33 +1897,8 @@ function printFinalSummary(ctx, params) {
1891
1897
  }
1892
1898
  }
1893
1899
  function selectScannersFromConfig2(config, hasGitHubAuth) {
1894
- const enabled = [];
1895
- if (config?.discovery.scanners.lint !== false) {
1896
- enabled.push("lint");
1897
- }
1898
- if (config?.discovery.scanners.todo !== false) {
1899
- enabled.push("todo");
1900
- }
1901
- if (config?.discovery.scanners.testGap !== false) {
1902
- enabled.push("test-gap");
1903
- }
1904
- if (hasGitHubAuth) {
1905
- enabled.push("github-issues");
1906
- }
1907
- if (enabled.length === 0) {
1908
- enabled.push("lint", "todo", "test-gap");
1909
- }
1910
- const uniqueEnabled = [...new Set(enabled)];
1911
- const scannerInstances = uniqueEnabled.map((scannerName) => {
1912
- if (scannerName === "lint") return new LintScanner();
1913
- if (scannerName === "github-issues") return new GitHubIssuesScanner();
1914
- if (scannerName === "test-gap") return new TestGapScanner();
1915
- return new TodoScanner();
1916
- });
1917
- return {
1918
- enabled: uniqueEnabled,
1919
- scanner: new CompositeScanner(scannerInstances)
1920
- };
1900
+ const { names, composite } = buildScanners(config, hasGitHubAuth);
1901
+ return { enabled: names, scanner: composite };
1921
1902
  }
1922
1903
  async function executeWithAgent(input2) {
1923
1904
  const startedAt = Date.now();
@@ -2000,15 +1981,12 @@ Automated contribution by OAC using Codex CLI.`],
2000
1981
  }
2001
1982
  }
2002
1983
  async function resolveAdapter(providerId) {
2003
- const normalizedId = providerId === "codex-cli" ? "codex" : providerId;
2004
- const adapters = {
2005
- codex: () => new CodexAdapter(),
2006
- "claude-code": () => new ClaudeCodeAdapter()
2007
- };
2008
- const factory = adapters[normalizedId];
1984
+ const normalizedId = adapterRegistry.resolveId(providerId);
1985
+ const factory = adapterRegistry.get(providerId);
2009
1986
  if (!factory) {
1987
+ const supported = adapterRegistry.registeredIds().join(", ");
2010
1988
  throw new Error(
2011
- `Unknown provider "${providerId}". Supported providers: codex, claude-code.
1989
+ `Unknown provider "${providerId}". Supported providers: ${supported}.
2012
1990
  Run \`oac doctor\` to check your environment setup.`
2013
1991
  );
2014
1992
  }
@@ -2016,7 +1994,7 @@ Run \`oac doctor\` to check your environment setup.`
2016
1994
  const availability = await adapter.checkAvailability();
2017
1995
  if (!availability.available) {
2018
1996
  throw new Error(
2019
- `Agent CLI "${normalizedId}" is not available: ${availability.reason ?? "unknown reason"}.
1997
+ `Agent CLI "${normalizedId}" is not available: ${availability.error ?? "unknown reason"}.
2020
1998
  Install the ${normalizedId} CLI or switch providers.
2021
1999
  Run \`oac doctor\` for setup instructions.`
2022
2000
  );
@@ -2254,14 +2232,7 @@ async function tryLoadOrAnalyzeEpics(ctx, params) {
2254
2232
  return getPendingEpics(backlog);
2255
2233
  }
2256
2234
  function buildScannerList2(config, hasGitHubAuth) {
2257
- const scanners = [];
2258
- if (config?.discovery.scanners.lint !== false) scanners.push(new LintScanner());
2259
- if (config?.discovery.scanners.todo !== false) scanners.push(new TodoScanner());
2260
- if (config?.discovery.scanners.testGap !== false) {
2261
- scanners.push(new TestGapScanner());
2262
- }
2263
- if (hasGitHubAuth) scanners.push(new GitHubIssuesScanner());
2264
- return scanners;
2235
+ return buildScanners(config, hasGitHubAuth).instances;
2265
2236
  }
2266
2237
  function makeStubEstimate(taskId, providerId, tokens) {
2267
2238
  return {
@@ -2348,7 +2319,7 @@ async function runEpicPipeline(ctx, params) {
2348
2319
  ctx.suppressOutput,
2349
2320
  `Executing ${epicTotal} epic(s)...`
2350
2321
  );
2351
- const epicQueue = new PQueue2({ concurrency });
2322
+ const epicQueue = new PQueue3({ concurrency });
2352
2323
  const allTaskResults = await Promise.all(
2353
2324
  epicPlan.selectedEpics.map(
2354
2325
  (entry) => epicQueue.add(async () => {
@@ -2496,7 +2467,7 @@ function renderEpicPlanTable(ui, plan, budget) {
2496
2467
  }
2497
2468
 
2498
2469
  // src/cli/commands/run/retry.ts
2499
- import { readFile as readFile4, readdir as readdir3 } from "fs/promises";
2470
+ import { readFile as readFile5, readdir as readdir3 } from "fs/promises";
2500
2471
  import { resolve as resolve6 } from "path";
2501
2472
  async function readMostRecentContributionLog(repoPath) {
2502
2473
  const contributionsPath = resolve6(repoPath, ".oac", "contributions");
@@ -2509,7 +2480,7 @@ async function readMostRecentContributionLog(repoPath) {
2509
2480
  }
2510
2481
  for (const fileName of entries) {
2511
2482
  try {
2512
- const content = await readFile4(resolve6(contributionsPath, fileName), "utf8");
2483
+ const content = await readFile5(resolve6(contributionsPath, fileName), "utf8");
2513
2484
  const parsed = contributionLogSchema.safeParse(JSON.parse(content));
2514
2485
  if (parsed.success) return parsed.data;
2515
2486
  } catch {
@@ -2967,7 +2938,7 @@ function parseCsv(value) {
2967
2938
  }
2968
2939
 
2969
2940
  // src/cli/commands/status.ts
2970
- import { readFile as readFile5 } from "fs/promises";
2941
+ import { readFile as readFile6 } from "fs/promises";
2971
2942
  import { resolve as resolve7 } from "path";
2972
2943
  import { Command as Command12 } from "commander";
2973
2944
  var WATCH_INTERVAL_MS = 2e3;
@@ -3009,7 +2980,7 @@ Examples:
3009
2980
  async function readRunStatus(repoPath) {
3010
2981
  const statusPath = resolve7(repoPath, ".oac", "status.json");
3011
2982
  try {
3012
- const raw = await readFile5(statusPath, "utf8");
2983
+ const raw = await readFile6(statusPath, "utf8");
3013
2984
  const payload = JSON.parse(raw);
3014
2985
  return parseRunStatus(payload);
3015
2986
  } catch (error) {
@@ -3020,7 +2991,7 @@ async function readRunStatus(repoPath) {
3020
2991
  }
3021
2992
  }
3022
2993
  function parseRunStatus(payload) {
3023
- if (!isRecord2(payload)) {
2994
+ if (!isRecord(payload)) {
3024
2995
  throw new Error("Invalid .oac/status.json format.");
3025
2996
  }
3026
2997
  const runId = payload.runId;
@@ -3038,7 +3009,7 @@ function parseRunStatus(payload) {
3038
3009
  };
3039
3010
  }
3040
3011
  function parseRunStatusTask(task, index) {
3041
- if (!isRecord2(task)) {
3012
+ if (!isRecord(task)) {
3042
3013
  throw new Error(`Invalid task at index ${String(index)} in .oac/status.json.`);
3043
3014
  }
3044
3015
  const taskId = task.taskId;
@@ -3126,11 +3097,8 @@ function formatTaskList(tasks) {
3126
3097
  }
3127
3098
  return tasks.map((task) => `${task.taskId} (${task.title})`).join(", ");
3128
3099
  }
3129
- function isRecord2(value) {
3130
- return typeof value === "object" && value !== null;
3131
- }
3132
3100
  function isFileNotFoundError3(error) {
3133
- if (!isRecord2(error)) {
3101
+ if (!isRecord(error)) {
3134
3102
  return false;
3135
3103
  }
3136
3104
  return error.code === "ENOENT";
@@ -3151,7 +3119,7 @@ function registerCommands(program) {
3151
3119
  program.addCommand(createExplainCommand());
3152
3120
  }
3153
3121
  async function createCliProgram() {
3154
- const version = true ? "2026.4.3" : "0.0.0";
3122
+ const version = true ? "2026.220.1" : "0.0.0";
3155
3123
  const program = new Command13();
3156
3124
  program.name("oac").description("Open Agent Contribution CLI").version(version).option("--config <path>", "Config file path", "oac.config.ts").option("--verbose", "Enable verbose logging", false).option("--quiet", "Suppress non-error output", false).option("--json", "Output machine-readable JSON", false).option("--no-color", "Disable ANSI colors");
3157
3125
  registerCommands(program);
@@ -3181,4 +3149,4 @@ export {
3181
3149
  createCliProgram,
3182
3150
  runCli
3183
3151
  };
3184
- //# sourceMappingURL=chunk-XUW3XWTX.js.map
3152
+ //# sourceMappingURL=chunk-7Y4LZUDP.js.map