@open330/oac 2026.221.2 → 2026.222.2

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 (38) hide show
  1. package/README.md +170 -1
  2. package/dist/budget/index.js +1 -1
  3. package/dist/{chunk-EYUQMPVO.js → chunk-27FEE5KS.js} +86 -34
  4. package/dist/chunk-27FEE5KS.js.map +1 -0
  5. package/dist/{chunk-5GAUWC3L.js → chunk-ALBVUNUY.js} +1 -1
  6. package/dist/chunk-ALBVUNUY.js.map +1 -0
  7. package/dist/{chunk-VK33A5L4.js → chunk-ATVWSG75.js} +480 -232
  8. package/dist/chunk-ATVWSG75.js.map +1 -0
  9. package/dist/{chunk-7C7SC4TZ.js → chunk-I3TKNT4M.js} +9 -2
  10. package/dist/chunk-I3TKNT4M.js.map +1 -0
  11. package/dist/{chunk-6A37SKAJ.js → chunk-JDFAJP45.js} +1 -1
  12. package/dist/{chunk-6A37SKAJ.js.map → chunk-JDFAJP45.js.map} +1 -1
  13. package/dist/{chunk-OS3XDHOJ.js → chunk-UCYK4Z6O.js} +1 -1
  14. package/dist/chunk-UCYK4Z6O.js.map +1 -0
  15. package/dist/{chunk-OCCMKAJI.js → chunk-ZJBLRKCV.js} +3 -3
  16. package/dist/chunk-ZJBLRKCV.js.map +1 -0
  17. package/dist/cli/cli.js +7 -7
  18. package/dist/cli/index.js +7 -7
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/completion/index.d.ts +1 -1
  21. package/dist/completion/index.js +2 -2
  22. package/dist/completion/index.js.map +1 -1
  23. package/dist/{config-DequKoFA.d.ts → config-DnzZ7w92.d.ts} +60 -1
  24. package/dist/core/index.d.ts +1 -1
  25. package/dist/core/index.js +4 -2
  26. package/dist/dashboard/index.js +72 -23
  27. package/dist/dashboard/index.js.map +1 -1
  28. package/dist/discovery/index.d.ts +1 -1
  29. package/dist/discovery/index.js +2 -2
  30. package/dist/execution/index.js +3 -3
  31. package/dist/repo/index.js +1 -1
  32. package/package.json +13 -15
  33. package/dist/chunk-5GAUWC3L.js.map +0 -1
  34. package/dist/chunk-7C7SC4TZ.js.map +0 -1
  35. package/dist/chunk-EYUQMPVO.js.map +0 -1
  36. package/dist/chunk-OCCMKAJI.js.map +0 -1
  37. package/dist/chunk-OS3XDHOJ.js.map +0 -1
  38. package/dist/chunk-VK33A5L4.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/discovery/scanners/todo-scanner.ts","../src/discovery/scanners/lint-scanner.ts","../src/discovery/scanners/test-gap-scanner.ts","../src/discovery/scanners/github-issues-scanner.ts","../src/discovery/scanner.ts","../src/discovery/scanner-factory.ts","../src/discovery/ranker.ts","../src/discovery/analyzer.ts","../src/discovery/epic-grouper.ts","../src/discovery/backlog.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { readFile, readdir } from \"node:fs/promises\";\nimport { relative, resolve, sep } from \"node:path\";\nimport { truncate } from \"../../core/utils.js\";\nimport type { Task, TaskComplexity } from \"../../core/index.js\";\nimport type { ScanOptions, Scanner } from \"../types.js\";\n\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst TODO_GROUPING_WINDOW = 10;\nconst TODO_RG_PATTERN = \"\\\\b(TODO|FIXME|HACK|XXX)\\\\b\";\nconst TODO_KEYWORD_PATTERN = /\\b(TODO|FIXME|HACK|XXX)\\b/i;\nconst TODO_TEXT_PATTERN = /\\b(TODO|FIXME|HACK|XXX)\\b[:\\s-]?(.*)$/i;\nconst COMMENT_CONTINUATION_PATTERN = /^\\s*(?:\\/\\/|\\/\\*+|\\*|#|--)/;\nconst MAX_FUNCTION_LOOKBACK_LINES = 80;\nconst DEFAULT_EXCLUDES = [\".git\", \"node_modules\", \"dist\", \"build\", \"coverage\"];\n\nconst FUNCTION_PATTERNS = [\n /^\\s*(?:export\\s+)?(?:async\\s+)?function\\s+([A-Za-z_$][\\w$]*)\\s*\\(/,\n /^\\s*(?:export\\s+)?(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*(?:async\\s*)?(?:\\([^)]*\\)|[A-Za-z_$][\\w$]*)\\s*=>/,\n /^\\s*(?:public|private|protected|static|readonly|\\s)*(?:async\\s+)?([A-Za-z_$][\\w$]*)\\s*\\([^)]*\\)\\s*[:{]/,\n /^\\s*def\\s+([A-Za-z_]\\w*)\\s*\\(/,\n] as const;\n\ninterface TodoMatch {\n filePath: string;\n line: number;\n column: number;\n keyword: string;\n text: string;\n}\n\ninterface TodoCluster {\n filePath: string;\n matches: TodoMatch[];\n}\n\ninterface CommandResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n signal: NodeJS.Signals | null;\n timedOut: boolean;\n}\n\ninterface CommandOptions {\n cwd: string;\n timeoutMs: number;\n signal?: AbortSignal;\n}\n\n/**\n * Scanner that converts TODO-like markers into actionable tasks.\n */\nexport class TodoScanner implements Scanner {\n public readonly id = \"todo\";\n public readonly name = \"TODO Scanner\";\n\n public async scan(repoPath: string, options: ScanOptions = {}): Promise<Task[]> {\n const matches = await this.findTodoMatches(repoPath, options);\n if (matches.length === 0) {\n return [];\n }\n\n const grouped = groupTodoMatches(matches, TODO_GROUPING_WINDOW);\n const fileCache = new Map<string, string[]>();\n const now = new Date().toISOString();\n\n const tasks: Task[] = [];\n\n for (const cluster of grouped) {\n const fileLines = await getFileLines(repoPath, cluster.filePath, fileCache);\n const task = buildTodoTask(cluster, fileLines, now);\n tasks.push(task);\n }\n\n if (typeof options.maxTasks === \"number\" && options.maxTasks >= 0) {\n return tasks.slice(0, options.maxTasks);\n }\n\n return tasks;\n }\n\n private async findTodoMatches(repoPath: string, options: ScanOptions): Promise<TodoMatch[]> {\n try {\n return await findTodoMatchesWithRipgrep(repoPath, options);\n } catch (error) {\n if (isCommandNotFound(error)) {\n return findTodoMatchesWithFsFallback(repoPath, options);\n }\n throw error;\n }\n }\n}\n\nasync function findTodoMatchesWithRipgrep(\n repoPath: string,\n options: ScanOptions,\n): Promise<TodoMatch[]> {\n const args = [\"--json\", \"--line-number\", \"--column\"];\n if (options.includeHidden) {\n args.push(\"--hidden\");\n }\n\n const excludes = mergeExcludes(options.exclude);\n for (const pattern of excludes) {\n args.push(\"--glob\", toRgExclude(pattern));\n }\n\n args.push(\"-e\", TODO_RG_PATTERN, \".\");\n\n const result = await runCommand(\"rg\", args, {\n cwd: repoPath,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options.signal,\n });\n\n if (result.timedOut) {\n throw new Error(`TODO scanner timed out after ${options.timeoutMs ?? DEFAULT_TIMEOUT_MS}ms`);\n }\n\n if (result.exitCode === 1 && result.stdout.trim().length === 0) {\n return [];\n }\n\n if (result.exitCode !== 0 && result.exitCode !== 1) {\n throw new Error(`ripgrep failed: ${result.stderr || result.stdout}`);\n }\n\n return parseRipgrepJson(result.stdout);\n}\n\nfunction parseRipgrepJson(output: string): TodoMatch[] {\n const matches: TodoMatch[] = [];\n\n for (const line of output.split(/\\r?\\n/)) {\n if (line.trim().length === 0) {\n continue;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n continue;\n }\n\n const record = toRecord(parsed);\n if (record.type !== \"match\") {\n continue;\n }\n\n const data = toRecord(record.data);\n const pathRecord = toRecord(data.path);\n const linesRecord = toRecord(data.lines);\n\n const rawFilePath = asString(pathRecord.text);\n const rawText = asString(linesRecord.text);\n const filePath = rawFilePath ? normalizeRelativePath(rawFilePath) : undefined;\n const lineNumber = asNumber(data.line_number);\n const text = rawText ? sanitizeLine(rawText) : undefined;\n const submatches = asArray(data.submatches);\n const firstSubmatch = toRecord(submatches.at(0));\n const column = (asNumber(firstSubmatch.start) ?? 0) + 1;\n\n if (!filePath || !lineNumber || !text) {\n continue;\n }\n\n const keyword = extractTodoKeyword(text) ?? \"TODO\";\n\n matches.push({\n filePath,\n line: lineNumber,\n column,\n keyword,\n text,\n });\n }\n\n return matches;\n}\n\nasync function findTodoMatchesWithFsFallback(\n repoPath: string,\n options: ScanOptions,\n): Promise<TodoMatch[]> {\n const excludes = mergeExcludes(options.exclude);\n const files = await collectFiles(repoPath, excludes);\n const matches: TodoMatch[] = [];\n\n for (const filePath of files) {\n const absolutePath = resolve(repoPath, filePath);\n let content = \"\";\n try {\n content = await readFile(absolutePath, \"utf8\");\n } catch {\n continue;\n }\n\n const lines = content.split(/\\r?\\n/);\n for (let index = 0; index < lines.length; index += 1) {\n const lineText = lines[index] ?? \"\";\n if (!TODO_KEYWORD_PATTERN.test(lineText)) {\n continue;\n }\n\n const keyword = extractTodoKeyword(lineText) ?? \"TODO\";\n const columnIndex = lineText.search(TODO_KEYWORD_PATTERN);\n\n matches.push({\n filePath,\n line: index + 1,\n column: columnIndex >= 0 ? columnIndex + 1 : 1,\n keyword,\n text: sanitizeLine(lineText),\n });\n }\n }\n\n return matches;\n}\n\nfunction groupTodoMatches(matches: TodoMatch[], lineWindow: number): TodoCluster[] {\n const sorted = [...matches].sort((left, right) => {\n const byFile = left.filePath.localeCompare(right.filePath);\n if (byFile !== 0) {\n return byFile;\n }\n return left.line - right.line;\n });\n\n const groups: TodoCluster[] = [];\n let active: TodoCluster | undefined;\n\n for (const match of sorted) {\n if (!active) {\n active = { filePath: match.filePath, matches: [match] };\n groups.push(active);\n continue;\n }\n\n const last = active.matches[active.matches.length - 1];\n const sameFile = active.filePath === match.filePath;\n if (sameFile && last && match.line - last.line <= lineWindow) {\n active.matches.push(match);\n continue;\n }\n\n active = { filePath: match.filePath, matches: [match] };\n groups.push(active);\n }\n\n return groups;\n}\n\nasync function getFileLines(\n repoPath: string,\n filePath: string,\n cache: Map<string, string[]>,\n): Promise<string[]> {\n const cached = cache.get(filePath);\n if (cached) {\n return cached;\n }\n\n try {\n const text = await readFile(resolve(repoPath, filePath), \"utf8\");\n const lines = text.split(/\\r?\\n/);\n cache.set(filePath, lines);\n return lines;\n } catch {\n const empty: string[] = [];\n cache.set(filePath, empty);\n return empty;\n }\n}\n\nfunction buildTodoTask(cluster: TodoCluster, fileLines: string[], discoveredAt: string): Task {\n const first = cluster.matches[0];\n const last = cluster.matches[cluster.matches.length - 1];\n\n const functionName = first ? findNearestFunctionName(fileLines, first.line) : undefined;\n const isMultiLine = cluster.matches.some((match) => isMultiLineTodo(match, fileLines));\n const complexity: TaskComplexity =\n cluster.matches.length > 1 || isMultiLine ? \"simple\" : \"trivial\";\n\n const title = first\n ? `Address TODO comments in ${cluster.filePath}:${first.line}`\n : `Address TODO comments in ${cluster.filePath}`;\n\n const todoSummary = cluster.matches\n .map((match) => `- ${match.keyword} at line ${match.line}: ${truncate(match.text, 140)}`)\n .join(\"\\n\");\n\n const descriptionParts = [\n `Resolve TODO-style markers in \\`${cluster.filePath}\\`.`,\n functionName ? `Nearest function context: \\`${functionName}\\`.` : undefined,\n \"Markers discovered:\",\n todoSummary,\n ].filter((part): part is string => Boolean(part));\n\n const description = descriptionParts.join(\"\\n\\n\");\n const uniqueKeywords = Array.from(\n new Set(cluster.matches.map((match) => match.keyword.toUpperCase())),\n );\n const stableHashInput = [\n cluster.filePath,\n String(first?.line ?? 0),\n String(last?.line ?? 0),\n uniqueKeywords.join(\",\"),\n cluster.matches.map((match) => match.text).join(\"\\n\"),\n ].join(\"::\");\n\n const task: Task = {\n id: createTaskId(\"todo\", [cluster.filePath], title, stableHashInput),\n source: \"todo\",\n title,\n description,\n targetFiles: [cluster.filePath],\n priority: 0,\n complexity,\n executionMode: \"new-pr\",\n metadata: {\n scannerId: \"todo\",\n filePath: cluster.filePath,\n startLine: first?.line ?? null,\n endLine: last?.line ?? null,\n functionName: functionName ?? null,\n keywordSet: uniqueKeywords,\n matchCount: cluster.matches.length,\n matches: cluster.matches.map((match) => ({\n line: match.line,\n column: match.column,\n keyword: match.keyword,\n text: match.text,\n })),\n },\n discoveredAt,\n };\n\n return task;\n}\n\nfunction findNearestFunctionName(fileLines: string[], lineNumber: number): string | undefined {\n if (lineNumber <= 0 || fileLines.length === 0) {\n return undefined;\n }\n\n const startIndex = Math.max(0, lineNumber - 1 - MAX_FUNCTION_LOOKBACK_LINES);\n for (let index = lineNumber - 1; index >= startIndex; index -= 1) {\n const candidate = fileLines[index]?.trim();\n if (!candidate || candidate.startsWith(\"//\")) {\n continue;\n }\n\n for (const pattern of FUNCTION_PATTERNS) {\n const match = candidate.match(pattern);\n if (match?.[1]) {\n return match[1];\n }\n }\n }\n\n return undefined;\n}\n\nfunction isMultiLineTodo(match: TodoMatch, fileLines: string[]): boolean {\n const baseIndex = match.line - 1;\n const line = fileLines[baseIndex + 1];\n if (line === undefined) {\n return false;\n }\n\n const trimmed = line.trim();\n if (trimmed.length === 0 || TODO_KEYWORD_PATTERN.test(trimmed)) {\n return false;\n }\n\n if (COMMENT_CONTINUATION_PATTERN.test(trimmed)) {\n return true;\n }\n\n return false;\n}\n\nfunction extractTodoKeyword(lineText: string): string | undefined {\n const match = lineText.match(TODO_TEXT_PATTERN);\n if (!match?.[1]) {\n return undefined;\n }\n\n return match[1].toUpperCase();\n}\n\n\n\nfunction createTaskId(\n source: string,\n targetFiles: string[],\n title: string,\n suffix: string,\n): string {\n const base = [source, [...targetFiles].sort().join(\",\"), title, suffix].join(\"::\");\n return createHash(\"sha256\").update(base).digest(\"hex\").slice(0, 16);\n}\n\nfunction mergeExcludes(exclude: string[] | undefined): string[] {\n return Array.from(new Set([...DEFAULT_EXCLUDES, ...(exclude ?? [])].filter(Boolean)));\n}\n\nfunction toRgExclude(pattern: string): string {\n const trimmed = pattern.trim();\n if (trimmed.startsWith(\"!\")) {\n return trimmed;\n }\n return `!${trimmed}`;\n}\n\nasync function collectFiles(rootDir: string, excludes: string[]): Promise<string[]> {\n const files: string[] = [];\n const compiledExcludes = excludes.map(compileGlobMatcher);\n\n async function walk(relativeDir: string): Promise<void> {\n const absoluteDir = resolve(rootDir, relativeDir);\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await readdir(absoluteDir, { withFileTypes: true, encoding: \"utf8\" });\n } catch {\n return;\n }\n\n const subdirs: Promise<void>[] = [];\n for (const entry of entries) {\n const entryName = String(entry.name);\n const relPath = normalizeRelativePath(\n relativeDir ? `${relativeDir}/${entryName}` : entryName,\n );\n if (compiledExcludes.some((matches) => matches(relPath))) {\n continue;\n }\n\n if (entry.isDirectory()) {\n subdirs.push(walk(relPath));\n continue;\n }\n\n if (entry.isFile()) {\n files.push(relPath);\n }\n }\n await Promise.all(subdirs);\n }\n\n await walk(\"\");\n return files;\n}\n\nfunction compileGlobMatcher(pattern: string): (filePath: string) => boolean {\n const normalized = normalizeRelativePath(pattern.replace(/^!+/, \"\").trim());\n if (!normalized) {\n return () => false;\n }\n\n if (!normalized.includes(\"*\")) {\n const prefix = normalized.endsWith(\"/\") ? normalized : `${normalized}/`;\n return (filePath: string) =>\n filePath === normalized || filePath.startsWith(prefix) || filePath.endsWith(`/${normalized}`);\n }\n\n const escaped = normalized\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*/g, \"__DOUBLE_STAR__\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/__DOUBLE_STAR__/g, \".*\");\n\n const regex = new RegExp(`^${escaped}$`);\n return (filePath: string) => regex.test(filePath);\n}\n\nfunction normalizeRelativePath(filePath: string): string {\n return filePath.split(sep).join(\"/\");\n}\n\nfunction sanitizeLine(line: string): string {\n return line.replace(/\\r?\\n/g, \"\").trim();\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n if (value && typeof value === \"object\") {\n return value as Record<string, unknown>;\n }\n return {};\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction asArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction isCommandNotFound(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n\n const maybeNodeError = error as NodeJS.ErrnoException;\n return maybeNodeError.code === \"ENOENT\";\n}\n\nfunction runCommand(\n command: string,\n args: string[],\n options: CommandOptions,\n): Promise<CommandResult> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n signal: options.signal,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n let timedOut = false;\n let killHandle: NodeJS.Timeout | undefined;\n\n child.stdout.on(\"data\", (chunk: Buffer | string) => {\n stdout += chunk.toString();\n });\n\n child.stderr.on(\"data\", (chunk: Buffer | string) => {\n stderr += chunk.toString();\n });\n\n const timeoutHandle = setTimeout(() => {\n timedOut = true;\n child.kill(\"SIGTERM\");\n killHandle = setTimeout(() => child.kill(\"SIGKILL\"), 2_000);\n }, options.timeoutMs);\n\n child.on(\"error\", (error) => {\n clearTimeout(timeoutHandle);\n if (killHandle) {\n clearTimeout(killHandle);\n }\n rejectPromise(error);\n });\n\n child.on(\"close\", (exitCode, signal) => {\n clearTimeout(timeoutHandle);\n if (killHandle) {\n clearTimeout(killHandle);\n }\n\n resolvePromise({\n stdout,\n stderr,\n exitCode,\n signal,\n timedOut,\n });\n });\n });\n}\n","import { spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { access, readFile } from \"node:fs/promises\";\nimport { relative, resolve, sep } from \"node:path\";\nimport type { Task, TaskComplexity } from \"../../core/index.js\";\nimport type { ScanOptions, Scanner } from \"../types.js\";\n\nconst DEFAULT_TIMEOUT_MS = 60_000;\n\ntype PackageManager = \"pnpm\" | \"npm\" | \"yarn\" | \"bun\";\ntype LinterKind = \"eslint\" | \"biome\" | \"none\";\n\ninterface LinterDetection {\n kind: LinterKind;\n packageManager: PackageManager;\n}\n\ninterface LintFinding {\n filePath: string;\n line?: number;\n column?: number;\n ruleId: string;\n message: string;\n fixable: boolean;\n severity?: number;\n}\n\ninterface CommandResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n signal: NodeJS.Signals | null;\n timedOut: boolean;\n}\n\ninterface CommandOptions {\n cwd: string;\n timeoutMs: number;\n signal?: AbortSignal;\n}\n\n/**\n * Scanner that runs repo-native lint tooling and maps findings to tasks.\n */\nexport class LintScanner implements Scanner {\n public readonly id = \"lint\";\n public readonly name = \"Lint Scanner\";\n\n public async scan(repoPath: string, options: ScanOptions = {}): Promise<Task[]> {\n const detection = await detectLinter(repoPath);\n if (detection.kind === \"none\") {\n return [];\n }\n\n const result = await runLinter(repoPath, detection, options);\n const findings =\n detection.kind === \"eslint\"\n ? parseEslintFindings(result.stdout, repoPath)\n : parseBiomeFindings(result.stdout, repoPath);\n\n if (findings.length === 0) {\n return [];\n }\n\n const tasks = buildLintTasks(findings, detection.kind);\n if (typeof options.maxTasks === \"number\" && options.maxTasks >= 0) {\n return tasks.slice(0, options.maxTasks);\n }\n\n return tasks;\n }\n}\n\nasync function detectLinter(repoPath: string): Promise<LinterDetection> {\n const packageManager = await detectPackageManager(repoPath);\n const packageJson = await readPackageJson(repoPath);\n\n const scriptLint = asString(toRecord(packageJson.scripts).lint)?.toLowerCase() ?? \"\";\n const dependencies = collectDependencyNames(packageJson);\n\n if (scriptLint.includes(\"biome\")) {\n return { kind: \"biome\", packageManager };\n }\n if (scriptLint.includes(\"eslint\")) {\n return { kind: \"eslint\", packageManager };\n }\n\n if (dependencies.has(\"eslint\") || (await hasAnyFile(repoPath, ESLINT_CONFIG_FILES))) {\n return { kind: \"eslint\", packageManager };\n }\n if (dependencies.has(\"@biomejs/biome\") || (await hasAnyFile(repoPath, BIOME_CONFIG_FILES))) {\n return { kind: \"biome\", packageManager };\n }\n\n return { kind: \"none\", packageManager };\n}\n\nconst ESLINT_CONFIG_FILES = [\n \".eslintrc\",\n \".eslintrc.json\",\n \".eslintrc.cjs\",\n \".eslintrc.js\",\n \"eslint.config.js\",\n \"eslint.config.mjs\",\n \"eslint.config.cjs\",\n] as const;\n\nconst BIOME_CONFIG_FILES = [\"biome.json\", \"biome.jsonc\"] as const;\n\nasync function detectPackageManager(repoPath: string): Promise<PackageManager> {\n const checks: Array<{ file: string; manager: PackageManager }> = [\n { file: \"pnpm-lock.yaml\", manager: \"pnpm\" },\n { file: \"bun.lockb\", manager: \"bun\" },\n { file: \"bun.lock\", manager: \"bun\" },\n { file: \"yarn.lock\", manager: \"yarn\" },\n { file: \"package-lock.json\", manager: \"npm\" },\n ];\n\n for (const check of checks) {\n if (await fileExists(resolve(repoPath, check.file))) {\n return check.manager;\n }\n }\n\n return \"npm\";\n}\n\nasync function runLinter(\n repoPath: string,\n detection: LinterDetection,\n options: ScanOptions,\n): Promise<CommandResult> {\n const command = buildLintCommand(detection, options);\n const result = await runCommand(command.command, command.args, {\n cwd: repoPath,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options.signal,\n });\n\n if (result.timedOut) {\n throw new Error(`Lint scanner timed out after ${options.timeoutMs ?? DEFAULT_TIMEOUT_MS}ms`);\n }\n\n const output = result.stdout.trim();\n\n // ESLint and Biome both return non-zero exit codes when lint violations exist.\n if (result.exitCode !== 0 && output.length === 0) {\n return {\n ...result,\n stdout: normalizeJsonText(result.stderr),\n };\n }\n\n return {\n ...result,\n stdout: normalizeJsonText(result.stdout),\n };\n}\n\nfunction buildLintCommand(\n detection: LinterDetection,\n options: ScanOptions,\n): { command: string; args: string[] } {\n const excludes = options.exclude ?? [];\n\n if (detection.kind === \"eslint\") {\n const eslintArgs = [\"eslint\", \".\", \"--format\", \"json\", \"--no-error-on-unmatched-pattern\"];\n for (const pattern of excludes) {\n eslintArgs.push(\"--ignore-pattern\", pattern);\n }\n return withPackageManagerRunner(detection.packageManager, eslintArgs);\n }\n\n const biomeArgs = [\"biome\", \"check\", \".\", \"--reporter=json\"];\n return withPackageManagerRunner(detection.packageManager, biomeArgs);\n}\n\nfunction withPackageManagerRunner(\n packageManager: PackageManager,\n commandArgs: string[],\n): { command: string; args: string[] } {\n if (packageManager === \"pnpm\") {\n return { command: \"pnpm\", args: [\"exec\", ...commandArgs] };\n }\n\n if (packageManager === \"yarn\") {\n return { command: \"yarn\", args: commandArgs };\n }\n\n if (packageManager === \"bun\") {\n return { command: \"bunx\", args: commandArgs };\n }\n\n return { command: \"npx\", args: [\"--no-install\", ...commandArgs] };\n}\n\nfunction parseEslintFindings(output: string, repoPath: string): LintFinding[] {\n const parsed = parseJson(output);\n if (!Array.isArray(parsed)) {\n return [];\n }\n\n const findings: LintFinding[] = [];\n for (const result of parsed) {\n const resultRecord = toRecord(result);\n const filePathValue = asString(resultRecord.filePath);\n const filePath = normalizeFilePath(filePathValue, repoPath);\n if (!filePath) {\n continue;\n }\n\n const messages = asArray(resultRecord.messages);\n for (const message of messages) {\n const messageRecord = toRecord(message);\n const ruleId = asString(messageRecord.ruleId) ?? \"unknown\";\n const text = asString(messageRecord.message);\n if (!text) {\n continue;\n }\n\n findings.push({\n filePath,\n line: asNumber(messageRecord.line),\n column: asNumber(messageRecord.column),\n ruleId,\n message: text,\n fixable: messageRecord.fix !== undefined,\n severity: asNumber(messageRecord.severity),\n });\n }\n }\n\n return findings;\n}\n\nfunction parseBiomeFindings(output: string, repoPath: string): LintFinding[] {\n const parsed = parseJson(output);\n if (parsed === undefined) {\n return [];\n }\n\n const diagnostics = collectBiomeDiagnostics(parsed);\n const findings: LintFinding[] = [];\n\n for (const diagnostic of diagnostics) {\n const path = extractBiomePath(diagnostic);\n const filePath = normalizeFilePath(path, repoPath);\n if (!filePath) {\n continue;\n }\n\n const message =\n asString(diagnostic.description) ??\n asString(diagnostic.message) ??\n asString(diagnostic.reason);\n if (!message) {\n continue;\n }\n\n const category = asString(diagnostic.category) ?? \"unknown\";\n const position = extractBiomePosition(diagnostic);\n const tags = asArray(diagnostic.tags).map((value) => String(value).toLowerCase());\n\n findings.push({\n filePath,\n line: position?.line,\n column: position?.column,\n ruleId: category,\n message,\n fixable:\n tags.includes(\"fixable\") ||\n tags.includes(\"quickfix\") ||\n diagnostic.suggestedFixes !== undefined,\n severity: normalizeBiomeSeverity(asString(diagnostic.severity)),\n });\n }\n\n return findings;\n}\n\nfunction collectBiomeDiagnostics(value: unknown): Array<Record<string, unknown>> {\n const diagnostics: Array<Record<string, unknown>> = [];\n const queue: unknown[] = [value];\n\n while (queue.length > 0) {\n const current = queue.shift();\n if (current === undefined || current === null) {\n continue;\n }\n\n if (Array.isArray(current)) {\n for (const item of current) {\n queue.push(item);\n }\n continue;\n }\n\n if (typeof current !== \"object\") {\n continue;\n }\n\n const record = current as Record<string, unknown>;\n if (looksLikeBiomeDiagnostic(record)) {\n diagnostics.push(record);\n }\n\n for (const value of Object.values(record)) {\n if (Array.isArray(value) || (value && typeof value === \"object\")) {\n queue.push(value);\n }\n }\n }\n\n return diagnostics;\n}\n\nfunction looksLikeBiomeDiagnostic(record: Record<string, unknown>): boolean {\n if (record.location !== undefined && record.category !== undefined) {\n return true;\n }\n if (\n record.path !== undefined &&\n (record.description !== undefined || record.message !== undefined)\n ) {\n return true;\n }\n return false;\n}\n\nfunction extractBiomePath(diagnostic: Record<string, unknown>): string | undefined {\n const location = toRecord(diagnostic.location);\n const pathValue = location.path;\n if (typeof pathValue === \"string\") {\n return pathValue;\n }\n\n const pathRecord = toRecord(pathValue);\n const file = asString(pathRecord.file);\n if (file) {\n return file;\n }\n\n return asString(diagnostic.filePath);\n}\n\nfunction extractBiomePosition(\n diagnostic: Record<string, unknown>,\n): { line?: number; column?: number } | undefined {\n const location = toRecord(diagnostic.location);\n const span = toRecord(location.span);\n const start = toRecord(span.start);\n\n const line = asNumber(start.line);\n const column = asNumber(start.column);\n if (line !== undefined || column !== undefined) {\n return { line, column };\n }\n\n const lineFallback = asNumber(location.line) ?? asNumber(diagnostic.line);\n const columnFallback = asNumber(location.column) ?? asNumber(diagnostic.column);\n if (lineFallback !== undefined || columnFallback !== undefined) {\n return { line: lineFallback, column: columnFallback };\n }\n\n return undefined;\n}\n\nfunction normalizeBiomeSeverity(severity: string | undefined): number | undefined {\n if (!severity) {\n return undefined;\n }\n const normalized = severity.toLowerCase();\n if (normalized === \"error\") {\n return 2;\n }\n if (normalized === \"warning\" || normalized === \"warn\") {\n return 1;\n }\n return undefined;\n}\n\nfunction buildLintTasks(findings: LintFinding[], linter: \"eslint\" | \"biome\"): Task[] {\n const grouped = new Map<string, LintFinding[]>();\n for (const finding of findings) {\n const existing = grouped.get(finding.filePath);\n if (existing) {\n existing.push(finding);\n } else {\n grouped.set(finding.filePath, [finding]);\n }\n }\n\n const discoveredAt = new Date().toISOString();\n const tasks: Task[] = [];\n\n for (const [filePath, fileFindings] of grouped.entries()) {\n const uniqueRules = Array.from(new Set(fileFindings.map((finding) => finding.ruleId)));\n const fixableCount = fileFindings.filter((finding) => finding.fixable).length;\n const complexity: TaskComplexity =\n fileFindings.length === 1 && fixableCount === 1 ? \"trivial\" : \"simple\";\n\n const headlineRules = uniqueRules.slice(0, 5).join(\", \") || \"unknown\";\n const title = `Fix lint findings in ${filePath}`;\n const description = [\n `Resolve ${fileFindings.length} lint finding(s) reported by ${linter} in \\`${filePath}\\`.`,\n `Primary rules: ${headlineRules}.`,\n fixableCount > 0\n ? `${fixableCount} finding(s) appear auto-fixable.`\n : \"No auto-fixable findings were detected.\",\n ].join(\"\\n\\n\");\n\n const task: Task = {\n id: createTaskId(\"lint\", [filePath], title, `${linter}:${headlineRules}`),\n source: \"lint\",\n title,\n description,\n targetFiles: [filePath],\n priority: 0,\n complexity,\n executionMode: \"new-pr\",\n metadata: {\n scannerId: \"lint\",\n linter,\n filePath,\n issueCount: fileFindings.length,\n ruleIds: uniqueRules,\n fixableCount,\n findings: fileFindings.map((finding) => ({\n line: finding.line ?? null,\n column: finding.column ?? null,\n ruleId: finding.ruleId,\n message: finding.message,\n fixable: finding.fixable,\n severity: finding.severity ?? null,\n })),\n },\n discoveredAt,\n };\n\n tasks.push(task);\n }\n\n return tasks;\n}\n\nfunction createTaskId(\n source: string,\n targetFiles: string[],\n title: string,\n suffix: string,\n): string {\n const content = [source, [...targetFiles].sort().join(\",\"), title, suffix].join(\"::\");\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\nasync function readPackageJson(repoPath: string): Promise<Record<string, unknown>> {\n const packageJsonPath = resolve(repoPath, \"package.json\");\n try {\n const raw = await readFile(packageJsonPath, \"utf8\");\n const parsed = JSON.parse(raw);\n return toRecord(parsed);\n } catch {\n return {};\n }\n}\n\nfunction collectDependencyNames(packageJson: Record<string, unknown>): Set<string> {\n const sections = [\n toRecord(packageJson.dependencies),\n toRecord(packageJson.devDependencies),\n toRecord(packageJson.peerDependencies),\n toRecord(packageJson.optionalDependencies),\n ];\n\n const names = new Set<string>();\n for (const section of sections) {\n for (const key of Object.keys(section)) {\n names.add(key);\n }\n }\n return names;\n}\n\nasync function hasAnyFile(repoPath: string, candidates: readonly string[]): Promise<boolean> {\n for (const candidate of candidates) {\n if (await fileExists(resolve(repoPath, candidate))) {\n return true;\n }\n }\n return false;\n}\n\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction normalizeFilePath(filePath: string | undefined, repoPath: string): string | undefined {\n if (!filePath) {\n return undefined;\n }\n\n if (filePath.startsWith(\"<\")) {\n return undefined;\n }\n\n const absoluteCandidate = resolve(repoPath, filePath);\n const rel = relative(repoPath, absoluteCandidate);\n if (!rel.startsWith(\"..\")) {\n return rel.split(sep).join(\"/\");\n }\n\n const direct = filePath.split(sep).join(\"/\");\n return direct;\n}\n\nfunction normalizeJsonText(text: string): string {\n return text.trim();\n}\n\nfunction parseJson(text: string): unknown {\n if (text.trim().length === 0) {\n return undefined;\n }\n\n try {\n return JSON.parse(text);\n } catch {\n const jsonStart = text.indexOf(\"[\");\n const objectStart = text.indexOf(\"{\");\n const start =\n jsonStart === -1\n ? objectStart\n : objectStart === -1\n ? jsonStart\n : Math.min(jsonStart, objectStart);\n\n if (start < 0) {\n return undefined;\n }\n\n const trimmed = text.slice(start).trim();\n try {\n return JSON.parse(trimmed);\n } catch {\n return undefined;\n }\n }\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n if (value && typeof value === \"object\") {\n return value as Record<string, unknown>;\n }\n return {};\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction asArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction runCommand(\n command: string,\n args: string[],\n options: CommandOptions,\n): Promise<CommandResult> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n signal: options.signal,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n let timedOut = false;\n let killHandle: NodeJS.Timeout | undefined;\n\n child.stdout.on(\"data\", (chunk: Buffer | string) => {\n stdout += chunk.toString();\n });\n\n child.stderr.on(\"data\", (chunk: Buffer | string) => {\n stderr += chunk.toString();\n });\n\n const timeoutHandle = setTimeout(() => {\n timedOut = true;\n child.kill(\"SIGTERM\");\n killHandle = setTimeout(() => child.kill(\"SIGKILL\"), 2_000);\n }, options.timeoutMs);\n\n child.on(\"error\", (error) => {\n clearTimeout(timeoutHandle);\n if (killHandle) {\n clearTimeout(killHandle);\n }\n rejectPromise(error);\n });\n\n child.on(\"close\", (exitCode, signal) => {\n clearTimeout(timeoutHandle);\n if (killHandle) {\n clearTimeout(killHandle);\n }\n\n resolvePromise({\n stdout,\n stderr,\n exitCode,\n signal,\n timedOut,\n });\n });\n });\n}\n","import { createHash } from \"node:crypto\";\nimport { readFile, readdir, stat } from \"node:fs/promises\";\nimport { basename, resolve, sep } from \"node:path\";\nimport type { Task, TaskComplexity, TaskSource } from \"../../core/index.js\";\nimport type { ScanOptions, Scanner } from \"../types.js\";\n\nconst DEFAULT_EXCLUDES = [\".git\", \"node_modules\", \"dist\", \"build\", \"coverage\"] as const;\n\ntype ComplexityBucket = \"small\" | \"medium\" | \"large\";\n\n/**\n * Scanner that identifies source files lacking corresponding test files.\n */\nexport class TestGapScanner implements Scanner {\n public readonly id: TaskSource | string = \"test-gap\";\n public readonly name = \"Test Gap Scanner\";\n\n public async scan(repoPath: string, options: ScanOptions = {}): Promise<Task[]> {\n const maxTasks = options.maxTasks;\n if (typeof maxTasks === \"number\" && maxTasks === 0) {\n return [];\n }\n\n const excludes = mergeExcludes(options.exclude);\n const { sourceFiles, testFiles } = await collectCandidateFiles(repoPath, excludes);\n if (sourceFiles.length === 0) {\n return [];\n }\n\n const coveredSourceKeys = buildCoveredSourceKeySet(testFiles);\n const untestedSourceFiles = sourceFiles.filter(\n (sourceFilePath) => !coveredSourceKeys.has(toSourceKey(sourceFilePath)),\n );\n\n if (untestedSourceFiles.length === 0) {\n return [];\n }\n\n const cappedSourceFiles =\n typeof maxTasks === \"number\" && maxTasks > 0\n ? untestedSourceFiles.slice(0, maxTasks)\n : untestedSourceFiles;\n\n const discoveredAt = new Date().toISOString();\n const tasks: Task[] = [];\n\n for (const sourceFilePath of cappedSourceFiles) {\n const absolutePath = resolve(repoPath, sourceFilePath);\n\n let fileContent = \"\";\n let fileSizeBytes = 0;\n try {\n const [content, fileStats] = await Promise.all([\n readFile(absolutePath, \"utf8\"),\n stat(absolutePath),\n ]);\n fileContent = content;\n fileSizeBytes = fileStats.size;\n } catch {\n continue;\n }\n\n const lineCount = countLines(fileContent);\n const complexityBucket = toComplexityBucket(lineCount);\n const complexity = toTaskComplexity(complexityBucket);\n const estimatedTokens = estimateTokens(complexityBucket);\n const symbols = extractSymbols(fileContent);\n\n const task: Task = {\n id: createTaskId(sourceFilePath),\n source: \"test-gap\" as TaskSource,\n title: `Add tests for ${basename(sourceFilePath)}`,\n description: buildDescription(sourceFilePath, symbols),\n targetFiles: [sourceFilePath],\n priority: 0,\n complexity,\n executionMode: \"new-pr\",\n metadata: {\n scannerId: \"test-gap\",\n filePath: sourceFilePath,\n lineCount,\n fileSizeBytes,\n complexityBucket,\n estimatedTokens,\n symbols,\n },\n discoveredAt,\n };\n\n tasks.push(task);\n }\n\n return tasks;\n }\n}\n\nasync function collectCandidateFiles(\n repoPath: string,\n excludePatterns: string[],\n): Promise<{ sourceFiles: string[]; testFiles: string[] }> {\n const sourceFiles: string[] = [];\n const testFiles: string[] = [];\n const excludeMatchers = excludePatterns.map(compileGlobMatcher);\n\n async function walk(relativeDir: string): Promise<void> {\n const absoluteDir = resolve(repoPath, relativeDir);\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await readdir(absoluteDir, { withFileTypes: true, encoding: \"utf8\" });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const entryName = String(entry.name);\n const relativePath = normalizeRelativePath(\n relativeDir ? `${relativeDir}/${entryName}` : entryName,\n );\n\n if (excludeMatchers.some((matches) => matches(relativePath))) {\n continue;\n }\n\n if (entry.isDirectory()) {\n await walk(relativePath);\n continue;\n }\n\n if (!entry.isFile()) {\n continue;\n }\n\n if (isSourceFile(relativePath)) {\n sourceFiles.push(relativePath);\n }\n\n if (isTestFile(relativePath)) {\n testFiles.push(relativePath);\n }\n }\n }\n\n await walk(\"\");\n\n sourceFiles.sort((left, right) => left.localeCompare(right));\n testFiles.sort((left, right) => left.localeCompare(right));\n\n return { sourceFiles, testFiles };\n}\n\nfunction isSourceFile(filePath: string): boolean {\n if (!filePath.endsWith(\".ts\")) {\n return false;\n }\n\n if (filePath.endsWith(\".d.ts\") || filePath.endsWith(\".test.ts\")) {\n return false;\n }\n\n if (basename(filePath) === \"index.ts\") {\n return false;\n }\n\n const parts = filePath.split(\"/\");\n return parts.includes(\"src\");\n}\n\nfunction isTestFile(filePath: string): boolean {\n if (!filePath.endsWith(\".test.ts\")) {\n return false;\n }\n\n const parts = filePath.split(\"/\");\n return parts.includes(\"tests\") || parts.includes(\"__tests__\");\n}\n\nfunction buildCoveredSourceKeySet(testFiles: string[]): Set<string> {\n const covered = new Set<string>();\n\n for (const testFilePath of testFiles) {\n const candidateSourceKeys = deriveCandidateSourceKeysFromTest(testFilePath);\n for (const sourceKey of candidateSourceKeys) {\n covered.add(sourceKey);\n }\n }\n\n return covered;\n}\n\nfunction deriveCandidateSourceKeysFromTest(testFilePath: string): string[] {\n const normalized = normalizeRelativePath(testFilePath);\n if (!normalized.endsWith(\".test.ts\")) {\n return [];\n }\n\n const withoutSuffix = normalized.slice(0, -\".test.ts\".length);\n const parts = withoutSuffix.split(\"/\");\n const markerIndex = parts.findIndex((part) => part === \"tests\" || part === \"__tests__\");\n if (markerIndex < 0) {\n return [];\n }\n\n const prefix = parts.slice(0, markerIndex);\n const suffix = parts.slice(markerIndex + 1);\n\n const candidates = new Set<string>();\n candidates.add(normalizeRelativePath([...prefix, \"src\", ...suffix].join(\"/\")));\n\n if (prefix[prefix.length - 1] === \"src\") {\n candidates.add(normalizeRelativePath([...prefix, ...suffix].join(\"/\")));\n }\n\n return [...candidates];\n}\n\nfunction toSourceKey(sourceFilePath: string): string {\n const normalized = normalizeRelativePath(sourceFilePath);\n return normalized.endsWith(\".ts\") ? normalized.slice(0, -\".ts\".length) : normalized;\n}\n\nfunction buildDescription(sourceFilePath: string, symbols: string[]): string {\n if (symbols.length === 0) {\n return `Add initial test coverage for \\`${sourceFilePath}\\`. No named functions or classes were detected.`;\n }\n\n const symbolList = symbols.map((symbol) => `\\`${symbol}\\``).join(\", \");\n return `Add test coverage for \\`${sourceFilePath}\\`, including: ${symbolList}.`;\n}\n\nfunction extractSymbols(fileContent: string): string[] {\n const symbols = new Set<string>();\n const patterns = [\n /\\b(?:export\\s+)?(?:async\\s+)?function\\s+([A-Za-z_$][\\w$]*)\\s*\\(/g,\n /\\b(?:export\\s+)?class\\s+([A-Za-z_$][\\w$]*)\\b/g,\n /\\b(?:export\\s+)?(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*(?:async\\s*)?(?:\\([^)]*\\)|[A-Za-z_$][\\w$]*)\\s*=>/g,\n ];\n\n for (const pattern of patterns) {\n let match: RegExpExecArray | null;\n match = pattern.exec(fileContent);\n while (match) {\n const symbolName = match[1];\n if (symbolName) {\n symbols.add(symbolName);\n }\n match = pattern.exec(fileContent);\n }\n }\n\n return [...symbols].sort((left, right) => left.localeCompare(right));\n}\n\nfunction countLines(fileContent: string): number {\n if (fileContent.length === 0) {\n return 0;\n }\n return fileContent.split(/\\r?\\n/).length;\n}\n\nfunction toComplexityBucket(lineCount: number): ComplexityBucket {\n if (lineCount < 50) {\n return \"small\";\n }\n if (lineCount < 200) {\n return \"medium\";\n }\n return \"large\";\n}\n\nfunction toTaskComplexity(bucket: ComplexityBucket): TaskComplexity {\n if (bucket === \"small\") {\n return \"simple\";\n }\n if (bucket === \"medium\") {\n return \"moderate\";\n }\n return \"complex\";\n}\n\nfunction estimateTokens(bucket: ComplexityBucket): number {\n if (bucket === \"small\") {\n return 1_500;\n }\n if (bucket === \"medium\") {\n return 4_000;\n }\n return 8_000;\n}\n\nfunction createTaskId(sourceFilePath: string): string {\n return createHash(\"sha256\").update(sourceFilePath).digest(\"hex\").slice(0, 16);\n}\n\nfunction mergeExcludes(exclude: string[] | undefined): string[] {\n return Array.from(new Set([...DEFAULT_EXCLUDES, ...(exclude ?? [])].filter(Boolean)));\n}\n\nfunction compileGlobMatcher(pattern: string): (filePath: string) => boolean {\n const normalized = normalizeRelativePath(pattern.replace(/^!+/, \"\").trim());\n if (!normalized) {\n return () => false;\n }\n\n if (!normalized.includes(\"*\")) {\n const prefix = normalized.endsWith(\"/\") ? normalized : `${normalized}/`;\n return (filePath: string) =>\n filePath === normalized || filePath.startsWith(prefix) || filePath.endsWith(`/${normalized}`);\n }\n\n const escaped = normalized\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*/g, \"__DOUBLE_STAR__\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/__DOUBLE_STAR__/g, \".*\");\n\n const regex = new RegExp(`^${escaped}$`);\n return (filePath: string) => regex.test(filePath);\n}\n\nfunction normalizeRelativePath(filePath: string): string {\n return filePath.split(sep).join(\"/\");\n}\n","import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { truncate } from \"../../core/utils.js\";\nimport type { Task, TaskComplexity, TaskSource } from \"../../core/index.js\";\nimport type { ScanOptions, Scanner } from \"../types.js\";\n\nconst GITHUB_API_BASE_URL = \"https://api.github.com\";\nconst ISSUES_PER_PAGE = 30;\nconst OAC_PR_PAGE_SIZE = 100;\nconst OAC_PR_TITLE_PREFIX = \"[OAC]\";\nconst TITLE_LIMIT = 120;\nconst DESCRIPTION_LIMIT = 500;\n\nconst ESTIMATED_TOKENS_BY_COMPLEXITY: Record<TaskComplexity, number> = {\n trivial: 1_500,\n simple: 4_000,\n moderate: 9_000,\n complex: 18_000,\n};\n\ninterface GitHubIssueUser {\n login?: unknown;\n}\n\ninterface GitHubIssueLabel {\n name?: unknown;\n}\n\ninterface GitHubIssueResponse {\n number?: unknown;\n title?: unknown;\n body?: unknown;\n html_url?: unknown;\n labels?: unknown;\n user?: unknown;\n created_at?: unknown;\n pull_request?: unknown;\n}\n\ninterface RepoCoordinates {\n owner: string;\n name: string;\n}\n\n/**\n * Scanner that maps open GitHub issues into contribution tasks.\n */\nexport class GitHubIssuesScanner implements Scanner {\n public readonly id: TaskSource | string = \"github-issue\";\n public readonly name = \"GitHub Issues Scanner\";\n\n public constructor(private readonly token?: string) {}\n\n public async scan(repoPath: string, options: ScanOptions = {}): Promise<Task[]> {\n const token = this.token ?? process.env.GITHUB_TOKEN;\n if (!token) {\n return [];\n }\n\n const repo = await resolveRepoCoordinates(repoPath, options);\n if (!repo) {\n return [];\n }\n\n const [issues, claimedIssueNumbers] = await Promise.all([\n fetchOpenIssues(repo, token),\n fetchOacClaimedIssueNumbers(repo, token),\n ]);\n if (issues.length === 0) {\n return [];\n }\n\n const issueLabels = options.issueLabels ?? [];\n const discoveredAt = new Date().toISOString();\n const tasks = issues\n .filter((issue) => issue.pull_request === undefined)\n .filter((issue) => !claimedIssueNumbers.has(asNumber(issue.number) ?? -1))\n .filter((issue) => matchesLabelFilter(issue, issueLabels))\n .map((issue) => mapIssueToTask(issue, discoveredAt))\n .filter((task): task is Task => task !== undefined);\n\n if (typeof options.maxTasks === \"number\" && options.maxTasks >= 0) {\n return tasks.slice(0, options.maxTasks);\n }\n\n return tasks;\n }\n}\n\nasync function resolveRepoCoordinates(\n repoPath: string,\n options: ScanOptions,\n): Promise<RepoCoordinates | undefined> {\n if (options.repo?.owner && options.repo.name) {\n return {\n owner: options.repo.owner,\n name: options.repo.name,\n };\n }\n\n return parseRepoFromGitConfig(repoPath);\n}\n\nasync function fetchOpenIssues(\n repo: RepoCoordinates,\n token: string,\n): Promise<GitHubIssueResponse[]> {\n const url =\n `${GITHUB_API_BASE_URL}/repos/` +\n `${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.name)}` +\n `/issues?state=open&per_page=${ISSUES_PER_PAGE}&sort=updated`;\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/vnd.github.v3+json\",\n },\n signal: AbortSignal.timeout(30_000),\n });\n\n if (!response.ok) {\n return [];\n }\n\n const payload = await response.json();\n if (!Array.isArray(payload)) {\n return [];\n }\n\n return payload.map((item) => toIssueResponse(item));\n } catch {\n return [];\n }\n}\n\n/**\n * Returns issue numbers that already have an open OAC pull request.\n * Used to skip issues during discovery so multiple OAC instances\n * targeting the same repo don't create duplicate PRs.\n */\nasync function fetchOacClaimedIssueNumbers(\n repo: RepoCoordinates,\n token: string,\n): Promise<Set<number>> {\n const url =\n `${GITHUB_API_BASE_URL}/repos/` +\n `${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.name)}` +\n `/pulls?state=open&per_page=${OAC_PR_PAGE_SIZE}&sort=updated&direction=desc`;\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/vnd.github.v3+json\",\n },\n signal: AbortSignal.timeout(15_000),\n });\n\n if (!response.ok) {\n return new Set();\n }\n\n const pulls: unknown = await response.json();\n if (!Array.isArray(pulls)) {\n return new Set();\n }\n\n return extractClaimedIssueNumbers(pulls);\n } catch {\n return new Set();\n }\n}\n\nfunction extractClaimedIssueNumbers(pulls: unknown[]): Set<number> {\n const claimed = new Set<number>();\n const issueRefPattern = /(?:Fixes|Closes|Resolves)\\s+#(\\d+)/gi;\n\n for (const pr of pulls) {\n if (!pr || typeof pr !== \"object\") continue;\n\n const record = pr as Record<string, unknown>;\n const title = typeof record.title === \"string\" ? record.title : \"\";\n if (!title.startsWith(OAC_PR_TITLE_PREFIX)) continue;\n\n const body = typeof record.body === \"string\" ? record.body : \"\";\n for (const match of body.matchAll(issueRefPattern)) {\n const num = Number.parseInt(match[1], 10);\n if (Number.isFinite(num)) {\n claimed.add(num);\n }\n }\n }\n\n return claimed;\n}\n\nasync function parseRepoFromGitConfig(repoPath: string): Promise<RepoCoordinates | undefined> {\n const config = await readGitConfig(repoPath);\n if (!config) {\n return undefined;\n }\n\n const remoteUrl = extractRemoteUrl(config);\n if (!remoteUrl) {\n return undefined;\n }\n\n return parseGitHubRemoteUrl(remoteUrl);\n}\n\nasync function readGitConfig(repoPath: string): Promise<string | undefined> {\n try {\n return await readFile(resolve(repoPath, \".git\", \"config\"), \"utf8\");\n } catch {\n // Fall through and attempt to resolve .git file pointer.\n }\n\n try {\n const gitFile = await readFile(resolve(repoPath, \".git\"), \"utf8\");\n const gitDir = parseGitDirPointer(gitFile);\n if (!gitDir) {\n return undefined;\n }\n\n return await readFile(resolve(repoPath, gitDir, \"config\"), \"utf8\");\n } catch {\n return undefined;\n }\n}\n\nfunction parseGitDirPointer(content: string): string | undefined {\n const match = content.match(/^\\s*gitdir:\\s*(.+)\\s*$/im);\n if (!match?.[1]) {\n return undefined;\n }\n\n return match[1].trim();\n}\n\nfunction extractRemoteUrl(configText: string): string | undefined {\n const lines = configText.split(/\\r?\\n/);\n let activeRemote: string | undefined;\n let firstRemoteUrl: string | undefined;\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith(\"#\") || line.startsWith(\";\")) {\n continue;\n }\n\n const sectionMatch = line.match(/^\\[\\s*remote\\s+\"([^\"]+)\"\\s*\\]$/i);\n if (sectionMatch?.[1]) {\n activeRemote = sectionMatch[1];\n continue;\n }\n\n if (!activeRemote) {\n continue;\n }\n\n const urlMatch = line.match(/^url\\s*=\\s*(.+)$/i);\n if (!urlMatch?.[1]) {\n continue;\n }\n\n const url = urlMatch[1].trim();\n if (activeRemote === \"origin\") {\n return url;\n }\n\n if (!firstRemoteUrl) {\n firstRemoteUrl = url;\n }\n }\n\n return firstRemoteUrl;\n}\n\nconst GITHUB_SSH_PATTERN =\n /^git@github\\.com:(?<owner>[A-Za-z0-9_.-]+)\\/(?<repo>[A-Za-z0-9_.-]+?)(?:\\.git)?$/i;\n\nfunction parseGitHubRemoteUrl(remoteUrl: string): RepoCoordinates | undefined {\n const normalized = remoteUrl.trim();\n if (!normalized) {\n return undefined;\n }\n\n const sshMatch = normalized.match(GITHUB_SSH_PATTERN);\n if (sshMatch?.groups?.owner && sshMatch.groups.repo) {\n return {\n owner: sshMatch.groups.owner,\n name: stripGitSuffix(sshMatch.groups.repo),\n };\n }\n\n const normalizedUrlInput = normalized.startsWith(\"github.com/\")\n ? `https://${normalized}`\n : normalized;\n\n try {\n const url = new URL(normalizedUrlInput);\n if (!isGitHubHost(url.hostname)) {\n return undefined;\n }\n\n const pathParts = url.pathname.split(\"/\").filter(Boolean);\n if (pathParts.length < 2) {\n return undefined;\n }\n\n const owner = pathParts[0];\n const name = stripGitSuffix(pathParts[1]);\n if (!owner || !name) {\n return undefined;\n }\n\n return { owner, name };\n } catch {\n return undefined;\n }\n}\n\nfunction isGitHubHost(hostname: string): boolean {\n const normalized = hostname.toLowerCase();\n return normalized === \"github.com\" || normalized === \"www.github.com\";\n}\n\nfunction stripGitSuffix(value: string): string {\n return value.replace(/\\.git$/i, \"\");\n}\n\n/**\n * Returns true when the issue carries at least one label present in\n * `allowedLabels` (case-insensitive, OR semantics).\n * An empty `allowedLabels` list disables filtering and matches every issue.\n */\nfunction matchesLabelFilter(issue: GitHubIssueResponse, allowedLabels: string[]): boolean {\n if (allowedLabels.length === 0) {\n return true;\n }\n\n const normalized = new Set(allowedLabels.map((l) => l.toLowerCase()));\n const issueLabels = normalizeLabels(issue.labels);\n return issueLabels.some((label) => normalized.has(label.toLowerCase()));\n}\n\nfunction mapIssueToTask(issue: GitHubIssueResponse, discoveredAt: string): Task | undefined {\n const issueNumber = asNumber(issue.number);\n const rawTitle = asString(issue.title)?.trim();\n if (issueNumber === undefined || !rawTitle) {\n return undefined;\n }\n\n const labels = normalizeLabels(issue.labels);\n const complexity = mapComplexityFromLabels(labels);\n const estimatedTokens = ESTIMATED_TOKENS_BY_COMPLEXITY[complexity];\n\n const bodyText = asString(issue.body)?.trim() || \"No description provided.\";\n const labelSummary = labels.length > 0 ? `Labels: ${labels.join(\", \")}` : \"Labels: none\";\n\n const title = truncate(rawTitle, TITLE_LIMIT);\n const description = truncate(`${bodyText}\\n\\n${labelSummary}`, DESCRIPTION_LIMIT);\n const url = asString(issue.html_url) ?? \"\";\n const author = readAuthor(issue.user);\n const createdAt = asString(issue.created_at) ?? discoveredAt;\n\n return {\n id: `github-issue-${issueNumber}`,\n source: \"github-issue\",\n title,\n description,\n targetFiles: [],\n priority: 0,\n complexity,\n executionMode: \"new-pr\",\n linkedIssue: {\n number: issueNumber,\n url,\n labels,\n },\n metadata: {\n issueNumber,\n labels,\n url,\n author,\n createdAt,\n estimatedTokens,\n },\n discoveredAt,\n };\n}\n\nfunction mapComplexityFromLabels(labels: string[]): TaskComplexity {\n const normalized = labels.map((label) => label.toLowerCase());\n\n if (\n normalized.some(\n (label) => label.includes(\"good first issue\") || label.includes(\"good-first-issue\"),\n )\n ) {\n return \"simple\";\n }\n if (normalized.some((label) => label.includes(\"feature\"))) {\n return \"complex\";\n }\n if (normalized.some((label) => label.includes(\"enhancement\"))) {\n return \"moderate\";\n }\n if (normalized.some((label) => label.includes(\"bug\"))) {\n return \"simple\";\n }\n return \"moderate\";\n}\n\nfunction normalizeLabels(rawLabels: unknown): string[] {\n if (!Array.isArray(rawLabels)) {\n return [];\n }\n\n const labels: string[] = [];\n for (const rawLabel of rawLabels) {\n if (typeof rawLabel === \"string\") {\n const trimmed = rawLabel.trim();\n if (trimmed.length > 0) {\n labels.push(trimmed);\n }\n continue;\n }\n\n if (rawLabel && typeof rawLabel === \"object\") {\n const name = asString((rawLabel as GitHubIssueLabel).name)?.trim();\n if (name) {\n labels.push(name);\n }\n }\n }\n\n return Array.from(new Set(labels));\n}\n\nfunction readAuthor(user: unknown): string {\n if (!user || typeof user !== \"object\") {\n return \"unknown\";\n }\n\n const login = asString((user as GitHubIssueUser).login);\n if (!login) {\n return \"unknown\";\n }\n\n return login;\n}\n\n\n\nfunction toIssueResponse(value: unknown): GitHubIssueResponse {\n if (value && typeof value === \"object\") {\n return value as GitHubIssueResponse;\n }\n return {};\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n","import { createHash } from \"node:crypto\";\nimport type { Task } from \"../core/index.js\";\nimport { LintScanner } from \"./scanners/lint-scanner.js\";\nimport { TodoScanner } from \"./scanners/todo-scanner.js\";\nimport type { ScanOptions, Scanner } from \"./types.js\";\n\ninterface DeduplicatedTask {\n task: Task;\n mergedSources: string[];\n duplicateTaskIds: string[];\n}\n\n/**\n * Runs multiple scanners in parallel and returns a deduplicated task list.\n */\nexport class CompositeScanner implements Scanner {\n public readonly id = \"composite\";\n public readonly name = \"Composite Scanner\";\n\n private readonly scanners: Scanner[];\n\n public constructor(scanners: Scanner[] = [new LintScanner(), new TodoScanner()]) {\n this.scanners = scanners;\n }\n\n public async scan(repoPath: string, options: ScanOptions = {}): Promise<Task[]> {\n const settled = await Promise.allSettled(\n this.scanners.map(async (scanner) => ({\n scannerId: scanner.id,\n tasks: await scanner.scan(repoPath, options),\n })),\n );\n\n const collected: Array<{ scannerId: string; task: Task }> = [];\n\n for (const result of settled) {\n if (result.status !== \"fulfilled\") {\n continue;\n }\n\n const scannerId = result.value.scannerId;\n for (const task of result.value.tasks) {\n collected.push({ scannerId, task });\n }\n }\n\n const deduplicated = deduplicateTasks(collected);\n if (typeof options.maxTasks === \"number\" && options.maxTasks >= 0) {\n return deduplicated.slice(0, options.maxTasks);\n }\n\n return deduplicated;\n }\n}\n\nexport function createDefaultCompositeScanner(): CompositeScanner {\n return new CompositeScanner([new LintScanner(), new TodoScanner()]);\n}\n\nfunction deduplicateTasks(candidates: Array<{ scannerId: string; task: Task }>): Task[] {\n const deduplicatedByHash = new Map<string, DeduplicatedTask>();\n\n for (const candidate of candidates) {\n const hash = taskContentHash(candidate.task);\n const existing = deduplicatedByHash.get(hash);\n\n if (!existing) {\n deduplicatedByHash.set(hash, {\n task: candidate.task,\n mergedSources: [candidate.scannerId],\n duplicateTaskIds: [candidate.task.id],\n });\n continue;\n }\n\n const preferIncoming = candidate.task.priority > existing.task.priority;\n const winner = preferIncoming ? candidate.task : existing.task;\n const loser = preferIncoming ? existing.task : candidate.task;\n\n const mergedSources = unique([\n ...existing.mergedSources,\n candidate.scannerId,\n String(loser.source),\n ]);\n const duplicateTaskIds = unique([...existing.duplicateTaskIds, loser.id, winner.id]);\n\n const winnerMetadata = toRecord(winner.metadata);\n const loserMetadata = toRecord(loser.metadata);\n\n deduplicatedByHash.set(hash, {\n task: {\n ...winner,\n metadata: {\n ...loserMetadata,\n ...winnerMetadata,\n mergedSources,\n duplicateTaskIds,\n dedupeHash: hash,\n },\n },\n mergedSources,\n duplicateTaskIds,\n });\n }\n\n const deduplicated = [...deduplicatedByHash.values()].map((entry) => entry.task);\n deduplicated.sort((left, right) => {\n const byPriority = right.priority - left.priority;\n if (byPriority !== 0) {\n return byPriority;\n }\n return left.title.localeCompare(right.title);\n });\n return deduplicated;\n}\n\nfunction taskContentHash(task: Task): string {\n const content = [task.source, [...task.targetFiles].sort().join(\",\"), task.title].join(\"::\");\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n if (value && typeof value === \"object\") {\n return value as Record<string, unknown>;\n }\n return {};\n}\n\nfunction unique(values: string[]): string[] {\n return Array.from(new Set(values.filter((value) => value.trim().length > 0)));\n}\n","import type { OacConfig } from \"../core/index.js\";\nimport { CompositeScanner } from \"./scanner.js\";\nimport { GitHubIssuesScanner } from \"./scanners/github-issues-scanner.js\";\nimport { LintScanner } from \"./scanners/lint-scanner.js\";\nimport { TestGapScanner } from \"./scanners/test-gap-scanner.js\";\nimport { TodoScanner } from \"./scanners/todo-scanner.js\";\nimport type { Scanner } from \"./types.js\";\n\nexport type ScannerName = \"lint\" | \"todo\" | \"test-gap\" | \"github-issues\";\n\n/**\n * Builds a list of scanner instances based on the user's config and\n * whether a GitHub token is available.\n *\n * This is the single source of truth for scanner construction, used by\n * `oac run` (both task and epic modes) and `oac analyze`.\n */\nexport function buildScanners(\n config: OacConfig | null,\n hasGitHubAuth: boolean,\n): { names: ScannerName[]; instances: Scanner[]; composite: CompositeScanner } {\n const names: ScannerName[] = [];\n\n if (config?.discovery.scanners.lint !== false) {\n names.push(\"lint\");\n }\n if (config?.discovery.scanners.todo !== false) {\n names.push(\"todo\");\n }\n if (config?.discovery.scanners.testGap !== false) {\n names.push(\"test-gap\");\n }\n if (hasGitHubAuth) {\n names.push(\"github-issues\");\n }\n\n // If everything was explicitly disabled, fall back to defaults.\n if (names.length === 0) {\n names.push(\"lint\", \"todo\", \"test-gap\");\n }\n\n const unique = [...new Set(names)];\n const instances: Scanner[] = unique.map(instantiateScanner);\n\n return { names: unique, instances, composite: new CompositeScanner(instances) };\n}\n\nfunction instantiateScanner(name: ScannerName): Scanner {\n switch (name) {\n case \"lint\":\n return new LintScanner();\n case \"todo\":\n return new TodoScanner();\n case \"test-gap\":\n return new TestGapScanner();\n case \"github-issues\":\n return new GitHubIssuesScanner();\n }\n}\n\n","import type { Task, TaskComplexity, TaskSource } from \"../core/index.js\";\nimport type { PriorityWeights } from \"./types.js\";\n\nconst IMPACT_BY_SOURCE: Partial<Record<TaskSource, number>> = {\n lint: 22,\n todo: 10,\n \"test-gap\": 24,\n \"dead-code\": 14,\n \"github-issue\": 20,\n custom: 12,\n};\n\nconst FEASIBILITY_BY_COMPLEXITY: Record<TaskComplexity, number> = {\n trivial: 25,\n simple: 20,\n moderate: 12,\n complex: 6,\n};\n\nconst TOKEN_EFFICIENCY_BY_COMPLEXITY: Record<TaskComplexity, number> = {\n trivial: 18,\n simple: 14,\n moderate: 8,\n complex: 4,\n};\n\n/**\n * Rank tasks by computed priority (0-100) and return descending order.\n */\nexport function rankTasks(tasks: Task[]): Task[] {\n const ranked = tasks.map((task) => {\n const scores = scoreTask(task);\n const priority = clamp(\n Math.round(\n scores.impactScore +\n scores.feasibilityScore +\n scores.freshnessScore +\n scores.issueSignals +\n scores.tokenEfficiency,\n ),\n 0,\n 100,\n );\n\n const metadata = toRecord(task.metadata);\n return {\n ...task,\n priority,\n metadata: {\n ...metadata,\n priorityBreakdown: scores,\n },\n };\n });\n\n ranked.sort((left, right) => {\n const byPriority = right.priority - left.priority;\n if (byPriority !== 0) {\n return byPriority;\n }\n return left.title.localeCompare(right.title);\n });\n\n return ranked;\n}\n\nfunction scoreTask(task: Task): PriorityWeights {\n const metadata = toRecord(task.metadata);\n\n const impactScore = scoreImpact(task, metadata);\n const feasibilityScore = scoreFeasibility(task, metadata);\n const freshnessScore = scoreFreshness(task, metadata);\n const issueSignals = scoreIssueSignals(task, metadata);\n const tokenEfficiency = scoreTokenEfficiency(task, metadata, impactScore);\n\n return {\n impactScore,\n feasibilityScore,\n freshnessScore,\n issueSignals,\n tokenEfficiency,\n };\n}\n\nfunction scoreImpact(task: Task, metadata: Record<string, unknown>): number {\n let score = IMPACT_BY_SOURCE[task.source] ?? 12;\n\n const matchCount = readNumber(metadata, \"matchCount\");\n if (task.source === \"todo\" && matchCount !== undefined) {\n if (matchCount >= 4) {\n score += 4;\n } else if (matchCount >= 2) {\n score += 2;\n }\n }\n\n const issueCount = readNumber(metadata, \"issueCount\");\n if (task.source === \"lint\" && issueCount !== undefined && issueCount >= 5) {\n score += 2;\n }\n\n if (task.linkedIssue) {\n score += 2;\n }\n\n return clamp(score, 0, 25);\n}\n\nfunction scoreFeasibility(task: Task, metadata: Record<string, unknown>): number {\n let score = FEASIBILITY_BY_COMPLEXITY[task.complexity];\n\n const fileCount = Math.max(task.targetFiles.length, readNumber(metadata, \"targetFileCount\") ?? 0);\n if (fileCount >= 6) {\n score -= 8;\n } else if (fileCount >= 3) {\n score -= 4;\n }\n\n if (task.executionMode === \"direct-commit\") {\n score -= 2;\n }\n\n return clamp(score, 0, 25);\n}\n\nfunction scoreFreshness(task: Task, metadata: Record<string, unknown>): number {\n const daysSinceChange =\n readNumber(metadata, \"daysSinceLastChange\") ??\n readNumber(metadata, \"freshnessDays\") ??\n getAgeInDays(readString(metadata, \"lastModifiedAt\"));\n\n if (daysSinceChange === undefined) {\n const discoveredAge = getAgeInDays(task.discoveredAt);\n if (discoveredAge === undefined) {\n return 7;\n }\n return clamp(15 - Math.floor(discoveredAge / 3), 4, 15);\n }\n\n if (daysSinceChange <= 3) {\n return 15;\n }\n if (daysSinceChange <= 14) {\n return 12;\n }\n if (daysSinceChange <= 30) {\n return 9;\n }\n if (daysSinceChange <= 90) {\n return 6;\n }\n if (daysSinceChange <= 180) {\n return 4;\n }\n return 2;\n}\n\nfunction scoreIssueSignals(task: Task, metadata: Record<string, unknown>): number {\n let score = 0;\n\n if (task.linkedIssue) {\n score += 5;\n score += Math.min(task.linkedIssue.labels.length, 4);\n }\n\n const labels = task.linkedIssue?.labels.map((label) => label.toLowerCase()) ?? [];\n if (labels.includes(\"good-first-issue\")) {\n score += 2;\n }\n if (labels.includes(\"help-wanted\")) {\n score += 1;\n }\n\n const upvotes = readNumber(metadata, \"upvotes\") ?? readNumber(metadata, \"thumbsUp\") ?? 0;\n const reactions = readNumber(metadata, \"reactions\") ?? 0;\n const maintainerComments =\n readNumber(metadata, \"maintainerComments\") ??\n (readBoolean(metadata, \"hasMaintainerComment\") ? 1 : 0);\n\n score += Math.min(4, Math.floor(upvotes / 2) + Math.floor(reactions / 3));\n score += Math.min(3, maintainerComments);\n\n return clamp(score, 0, 15);\n}\n\nfunction scoreTokenEfficiency(\n task: Task,\n metadata: Record<string, unknown>,\n impactScore: number,\n): number {\n const estimatedTokens =\n readNumber(metadata, \"estimatedTokens\") ??\n readNumber(metadata, \"totalEstimatedTokens\") ??\n readNestedNumber(metadata, \"tokenEstimate\", \"totalEstimatedTokens\");\n\n let score = TOKEN_EFFICIENCY_BY_COMPLEXITY[task.complexity];\n\n if (estimatedTokens !== undefined) {\n if (estimatedTokens <= 1_500) {\n score = 20;\n } else if (estimatedTokens <= 5_000) {\n score = 16;\n } else if (estimatedTokens <= 12_000) {\n score = 12;\n } else if (estimatedTokens <= 25_000) {\n score = 8;\n } else {\n score = 4;\n }\n }\n\n if (task.targetFiles.length >= 4) {\n score -= 2;\n }\n\n // High-impact tasks tolerate slightly lower efficiency.\n if (impactScore >= 20) {\n score += 1;\n }\n\n return clamp(score, 0, 20);\n}\n\nfunction getAgeInDays(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n const time = Date.parse(value);\n if (Number.isNaN(time)) {\n return undefined;\n }\n const now = Date.now();\n const diffMs = Math.max(now - time, 0);\n return Math.floor(diffMs / (24 * 60 * 60 * 1_000));\n}\n\nfunction readNestedNumber(\n metadata: Record<string, unknown>,\n parentKey: string,\n childKey: string,\n): number | undefined {\n const parent = toRecord(metadata[parentKey]);\n return readNumber(parent, childKey);\n}\n\nfunction readNumber(metadata: Record<string, unknown>, key: string): number | undefined {\n const value = metadata[key];\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction readString(metadata: Record<string, unknown>, key: string): string | undefined {\n const value = metadata[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction readBoolean(metadata: Record<string, unknown>, key: string): boolean {\n return metadata[key] === true;\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n if (value && typeof value === \"object\") {\n return value as Record<string, unknown>;\n }\n return {};\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n","import type { Dirent } from \"node:fs\";\nimport { createReadStream } from \"node:fs\";\nimport { mkdir, readFile, readdir, rename, stat, unlink, writeFile } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport { dirname, extname, join, relative, resolve } from \"node:path\";\n\nimport PQueue from \"p-queue\";\n\nimport { createMemoryMonitor } from \"../core/memory.js\";\nimport type { Task, TaskSource } from \"../core/types.js\";\nimport type { CodebaseMap, FileInfo, ModuleInfo, QualityReport } from \"./context-types.js\";\nimport { CompositeScanner } from \"./scanner.js\";\nimport type { RawFinding, ScanOptions, Scanner } from \"./types.js\";\n\n// ── Public types ─────────────────────────────────────────────\n\nexport interface AnalyzeOptions {\n /** Glob patterns to exclude (e.g., [\"dist/**\", \"node_modules/**\"]) */\n exclude?: string[];\n /** Scanners to use. If not provided, uses default CompositeScanner scanners */\n scanners?: Scanner[];\n /** Source directory name to analyze (default: \"src\") */\n sourceDir?: string;\n /** Resolved repo metadata (passed to scanners) */\n repoFullName?: string;\n headSha?: string;\n}\n\n// ── Constants ────────────────────────────────────────────────\n\nconst DEFAULT_EXTENSIONS = new Set([\".ts\", \".tsx\", \".js\", \".jsx\"]);\n\nconst DEFAULT_EXCLUDE_DIRS = new Set([\"node_modules\", \"dist\", \".git\", \"coverage\"]);\n\nconst DEFAULT_EXCLUDE_SUFFIXES = [\n \".d.ts\",\n \".test.ts\",\n \".spec.ts\",\n \".test.tsx\",\n \".spec.tsx\",\n \".test.js\",\n \".spec.js\",\n \".test.jsx\",\n \".spec.jsx\",\n];\n\nconst DEFAULT_MAX_AGE_MS = 86_400_000; // 24 hours\n\n/** Files larger than this are analyzed via streaming to avoid excessive heap allocation. */\nconst LARGE_FILE_THRESHOLD_BYTES = 1_048_576; // 1 MB\n\nconst CONTEXT_DIR_NAME = \".oac/context\";\nconst CODEBASE_MAP_FILE = \"codebase-map.json\";\nconst QUALITY_REPORT_FILE = \"quality-report.json\";\n\n// ── analyzeCodebase ──────────────────────────────────────────\n\nexport async function analyzeCodebase(\n repoPath: string,\n options?: AnalyzeOptions,\n): Promise<{ codebaseMap: CodebaseMap; qualityReport: QualityReport }> {\n const resolvedRepoPath = resolve(repoPath);\n const sourceDir = options?.sourceDir ?? \"src\";\n const srcRoot = join(resolvedRepoPath, sourceDir);\n const userExclude = options?.exclude ?? [];\n const repoFullName = options?.repoFullName ?? \"\";\n const headSha = options?.headSha ?? \"\";\n\n // ── 1. Walk file tree ──────────────────────────────────────\n const allFiles = await walkSourceFiles(srcRoot, userExclude);\n\n // ── 2. Analyze each file (bounded concurrency + memory monitoring)\n const MAX_CONCURRENCY = 50;\n const MIN_CONCURRENCY = 4;\n const analysisQueue = new PQueue({ concurrency: MAX_CONCURRENCY });\n\n const memoryMonitor = createMemoryMonitor({\n intervalMs: 3_000,\n pressureRatio: 0.85,\n onPressure: () => {\n // Reduce concurrency when memory is tight\n const current = analysisQueue.concurrency;\n const reduced = Math.max(MIN_CONCURRENCY, Math.floor(current / 2));\n if (reduced < current) analysisQueue.concurrency = reduced;\n },\n onRelief: () => {\n // Restore concurrency when pressure drops\n const current = analysisQueue.concurrency;\n const restored = Math.min(MAX_CONCURRENCY, current * 2);\n if (restored > current) analysisQueue.concurrency = restored;\n },\n });\n\n const fileInfos = (await Promise.all(\n allFiles.map((absPath) =>\n analysisQueue.add(async () => {\n const relPath = relative(resolvedRepoPath, absPath);\n const info = await analyzeFile(absPath, relPath);\n return { ...info, _absolutePath: absPath };\n }),\n ),\n )) as Array<FileInfo & { _absolutePath: string }>;\n\n memoryMonitor.stop();\n\n // ── 3. Detect modules ─────────────────────────────────────\n const moduleMap = buildModuleMap(fileInfos, sourceDir);\n\n // ── 4. Resolve module dependencies ─────────────────────────\n const moduleNames = new Set(Object.keys(moduleMap));\n const modules: ModuleInfo[] = [];\n\n for (const [moduleName, files] of Object.entries(moduleMap)) {\n const moduleFiles: FileInfo[] = files.map(({ _absolutePath: _, ...fi }) => fi);\n const totalLoc = moduleFiles.reduce((sum, f) => sum + f.loc, 0);\n const allExports = moduleFiles.flatMap((f) => f.exports);\n const dependencies = resolveModuleDependencies(files, moduleName, sourceDir, moduleNames);\n\n modules.push({\n name: moduleName,\n path: moduleName === \"root\" ? sourceDir : `${sourceDir}/${moduleName}`,\n files: moduleFiles,\n totalLoc,\n exports: allExports,\n dependencies,\n });\n }\n\n const totalFiles = fileInfos.length;\n const totalLoc = fileInfos.reduce((sum, f) => sum + f.loc, 0);\n const generatedAt = new Date().toISOString();\n\n const codebaseMap: CodebaseMap = {\n version: 1,\n generatedAt,\n repoFullName,\n headSha,\n modules,\n totalFiles,\n totalLoc,\n };\n\n // ── 5. Run scanners → RawFinding[] ─────────────────────────\n const findings = await runScanners(resolvedRepoPath, sourceDir, options);\n\n // ── 6. Build QualityReport ─────────────────────────────────\n const qualityReport = buildQualityReport(findings, repoFullName, generatedAt);\n\n return { codebaseMap, qualityReport };\n}\n\n// ── persistContext ────────────────────────────────────────────\n\nexport async function persistContext(\n repoPath: string,\n codebaseMap: CodebaseMap,\n qualityReport: QualityReport,\n contextDir?: string,\n): Promise<string> {\n const resolvedDir = contextDir ? resolve(contextDir) : join(resolve(repoPath), CONTEXT_DIR_NAME);\n\n await mkdir(resolvedDir, { recursive: true });\n\n await atomicWriteJson(join(resolvedDir, CODEBASE_MAP_FILE), codebaseMap);\n await atomicWriteJson(join(resolvedDir, QUALITY_REPORT_FILE), qualityReport);\n\n return resolvedDir;\n}\n\n// ── loadContext ───────────────────────────────────────────────\n\nexport async function loadContext(\n repoPath: string,\n contextDir?: string,\n): Promise<{ codebaseMap: CodebaseMap; qualityReport: QualityReport } | null> {\n const resolvedDir = contextDir ? resolve(contextDir) : join(resolve(repoPath), CONTEXT_DIR_NAME);\n\n try {\n const [mapRaw, reportRaw] = await Promise.all([\n readFile(join(resolvedDir, CODEBASE_MAP_FILE), \"utf-8\"),\n readFile(join(resolvedDir, QUALITY_REPORT_FILE), \"utf-8\"),\n ]);\n const codebaseMap = JSON.parse(mapRaw) as CodebaseMap;\n const qualityReport = JSON.parse(reportRaw) as QualityReport;\n return { codebaseMap, qualityReport };\n } catch {\n return null;\n }\n}\n\n// ── isContextStale ───────────────────────────────────────────\n\nexport function isContextStale(\n codebaseMap: CodebaseMap,\n maxAgeMs: number = DEFAULT_MAX_AGE_MS,\n): boolean {\n const generatedAt = new Date(codebaseMap.generatedAt).getTime();\n if (Number.isNaN(generatedAt)) {\n return true;\n }\n return Date.now() - generatedAt > maxAgeMs;\n}\n\n// ── deriveModuleFromPath ─────────────────────────────────────\n\n/**\n * Extracts the module name from a file path relative to the repo root.\n *\n * Examples:\n * src/budget/planner.ts → \"budget\"\n * src/core/types.ts → \"core\"\n * src/cli/commands/run.ts → \"cli\"\n * src/index.ts → \"root\"\n * lib/utils.ts → \"root\"\n */\nexport function deriveModuleFromPath(filePath: string, sourceDir = \"src\"): string {\n // Normalize separators to forward slashes for consistent matching\n const normalized = filePath.replace(/\\\\/g, \"/\");\n const prefix = `${sourceDir.replace(/\\\\/g, \"/\")}/`;\n\n if (!normalized.startsWith(prefix)) {\n return \"root\";\n }\n\n const afterSrc = normalized.slice(prefix.length);\n const firstSlash = afterSrc.indexOf(\"/\");\n if (firstSlash === -1) {\n // File is directly in sourceDir, e.g. src/index.ts\n return \"root\";\n }\n\n return afterSrc.slice(0, firstSlash);\n}\n\n// ── Internal: file walking ───────────────────────────────────\n\nasync function walkSourceFiles(dirPath: string, userExclude: string[]): Promise<string[]> {\n const results: string[] = [];\n\n // Build a set of user-specified directory names to exclude (simple patterns)\n const userExcludeDirs = new Set<string>();\n const userExcludeSuffixes: string[] = [];\n for (const pattern of userExclude) {\n // Strip trailing /** or /* for directory-based exclusion\n const cleaned = pattern.replace(/\\/\\*{1,2}$/, \"\");\n if (cleaned.startsWith(\"*.\")) {\n userExcludeSuffixes.push(cleaned.slice(1)); // e.g. \".map\"\n } else {\n userExcludeDirs.add(cleaned);\n }\n }\n\n function isExcludedFile(name: string): boolean {\n if (!DEFAULT_EXTENSIONS.has(extname(name))) return true;\n if (DEFAULT_EXCLUDE_SUFFIXES.some((suffix) => name.endsWith(suffix))) return true;\n if (userExcludeSuffixes.some((suffix) => name.endsWith(suffix))) return true;\n return false;\n }\n\n function isExcludedDir(name: string): boolean {\n return DEFAULT_EXCLUDE_DIRS.has(name) || userExcludeDirs.has(name);\n }\n\n async function walk(dir: string): Promise<void> {\n let entries: Dirent<string>[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n const subdirs: Promise<void>[] = [];\n for (const entry of entries) {\n if (entry.isDirectory() && !isExcludedDir(entry.name)) {\n subdirs.push(walk(join(dir, entry.name)));\n } else if (entry.isFile() && !isExcludedFile(entry.name)) {\n results.push(join(dir, entry.name));\n }\n }\n await Promise.all(subdirs);\n }\n\n await walk(dirPath);\n results.sort();\n return results;\n}\n\n// ── Internal: single-file analysis ───────────────────────────\n\nasync function analyzeFile(absolutePath: string, relativePath: string): Promise<FileInfo> {\n const fileStat = await stat(absolutePath);\n\n // For large files, stream line-by-line to avoid holding the entire file in memory.\n // Export/import extraction is skipped for these files since regex over multi-MB\n // strings is expensive and the information is low-value for very large files\n // (usually generated / vendored code).\n if (fileStat.size > LARGE_FILE_THRESHOLD_BYTES) {\n const loc = await countLinesStreaming(absolutePath);\n return { path: relativePath, loc, sizeBytes: fileStat.size, exports: [], imports: [] };\n }\n\n const content = await readFile(absolutePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const loc = lines.filter((line) => line.trim().length > 0).length;\n const exports = extractExports(content);\n const imports = extractImports(content);\n\n return {\n path: relativePath,\n loc,\n sizeBytes: fileStat.size,\n exports,\n imports,\n };\n}\n\n/**\n * Count non-empty lines using a streaming readline interface.\n * This avoids loading the entire file into a single V8 string.\n */\nasync function countLinesStreaming(absolutePath: string): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n let loc = 0;\n const rl = createInterface({\n input: createReadStream(absolutePath, { encoding: \"utf-8\" }),\n crlfDelay: Number.POSITIVE_INFINITY,\n });\n rl.on(\"line\", (line) => {\n if (line.trim().length > 0) loc += 1;\n });\n rl.on(\"close\", () => resolve(loc));\n rl.on(\"error\", reject);\n });\n}\n\n// ── Internal: export extraction ──────────────────────────────\n\nfunction extractExports(content: string): string[] {\n const exports: string[] = [];\n const seen = new Set<string>();\n\n const add = (name: string): void => {\n const trimmed = name.trim();\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed);\n exports.push(trimmed);\n }\n };\n\n // export function/class/const/let/var/type/interface/enum NAME\n const namedDeclRe =\n /\\bexport\\s+(?:async\\s+)?(?:function\\*?|class|const|let|var|type|interface|enum)\\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;\n for (const m of content.matchAll(namedDeclRe)) {\n add(m[1]);\n }\n\n // export { Name, Name as Alias, ... }\n const bracedRe = /\\bexport\\s*\\{([^}]+)\\}/g;\n for (const m of content.matchAll(bracedRe)) {\n const inner = m[1];\n for (const item of inner.split(\",\")) {\n const parts = item.trim().split(/\\s+as\\s+/);\n const exportedName = parts.length > 1 ? parts[1].trim() : parts[0].trim();\n if (exportedName) {\n add(exportedName);\n }\n }\n }\n\n // export default\n const defaultRe = /\\bexport\\s+default\\b/;\n if (defaultRe.test(content)) {\n add(\"default\");\n }\n\n return exports;\n}\n\n// ── Internal: import extraction ──────────────────────────────\n\nfunction extractImports(content: string): string[] {\n const imports: string[] = [];\n const seen = new Set<string>();\n\n const add = (path: string): void => {\n const trimmed = path.trim();\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed);\n imports.push(trimmed);\n }\n };\n\n // import ... from \"PATH\" or import \"PATH\"\n const staticImportRe = /\\bimport\\s+(?:[\\s\\S]*?\\s+from\\s+)?[\"']([^\"']+)[\"']/g;\n for (const m of content.matchAll(staticImportRe)) {\n add(m[1]);\n }\n\n // import(\"PATH\")\n const dynamicImportRe = /\\bimport\\s*\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/g;\n for (const m of content.matchAll(dynamicImportRe)) {\n add(m[1]);\n }\n\n return imports;\n}\n\n// ── Internal: module map building ────────────────────────────\n\nfunction buildModuleMap(\n fileInfos: Array<FileInfo & { _absolutePath: string }>,\n sourceDir: string,\n): Record<string, Array<FileInfo & { _absolutePath: string }>> {\n const moduleMap: Record<string, Array<FileInfo & { _absolutePath: string }>> = {};\n\n for (const fi of fileInfos) {\n const moduleName = deriveModuleFromPath(fi.path, sourceDir);\n if (!moduleMap[moduleName]) {\n moduleMap[moduleName] = [];\n }\n moduleMap[moduleName].push(fi);\n }\n\n return moduleMap;\n}\n\n// ── Internal: module dependency resolution ───────────────────\n\nfunction resolveModuleDependencies(\n files: Array<FileInfo & { _absolutePath: string }>,\n currentModule: string,\n sourceDir: string,\n allModuleNames: Set<string>,\n): string[] {\n const deps = new Set<string>();\n\n for (const file of files) {\n for (const importPath of file.imports) {\n // Only consider relative imports — node_modules imports are ignored\n if (!importPath.startsWith(\".\")) continue;\n\n // Resolve the import relative to the file's directory\n const fileDir = dirname(file.path);\n const resolvedImport = join(fileDir, importPath).replace(/\\\\/g, \"/\");\n const importModule = deriveModuleFromPath(resolvedImport, sourceDir);\n\n if (importModule !== currentModule && allModuleNames.has(importModule)) {\n deps.add(importModule);\n }\n }\n }\n\n return [...deps].sort();\n}\n\n// ── Internal: scanner execution ──────────────────────────────\n\nasync function runScanners(\n repoPath: string,\n sourceDir: string,\n options?: AnalyzeOptions,\n): Promise<RawFinding[]> {\n const scanners = options?.scanners;\n const composite = scanners ? new CompositeScanner(scanners) : new CompositeScanner();\n\n const scanOptions: ScanOptions = {\n exclude: options?.exclude,\n };\n\n let tasks: Task[];\n try {\n tasks = await composite.scan(repoPath, scanOptions);\n } catch {\n // If scanning fails entirely, return an empty findings list\n tasks = [];\n }\n\n return tasks.map((task) => taskToRawFinding(task, sourceDir));\n}\n\n// ── Internal: Task → RawFinding conversion ───────────────────\n\nfunction taskToRawFinding(task: Task, sourceDir: string): RawFinding {\n const filePath = task.targetFiles[0] ?? \"\";\n const scannerId =\n typeof task.metadata?.scannerId === \"string\" ? task.metadata.scannerId : task.source;\n\n return {\n scannerId,\n source: task.source,\n filePath,\n module: deriveModuleFromPath(filePath, sourceDir),\n title: task.title,\n description: task.description,\n severity: deriveSeverity(task.source),\n complexity: task.complexity,\n line: typeof task.metadata?.startLine === \"number\" ? task.metadata.startLine : undefined,\n metadata: task.metadata,\n discoveredAt: task.discoveredAt,\n };\n}\n\nfunction deriveSeverity(source: TaskSource): \"info\" | \"warning\" | \"error\" {\n switch (source) {\n case \"lint\":\n return \"warning\";\n case \"todo\":\n return \"info\";\n case \"test-gap\":\n return \"info\";\n case \"github-issue\":\n return \"warning\";\n case \"dead-code\":\n return \"warning\";\n case \"custom\":\n return \"info\";\n default:\n return \"info\";\n }\n}\n\n// ── Internal: QualityReport building ─────────────────────────\n\nfunction buildQualityReport(\n findings: RawFinding[],\n repoFullName: string,\n generatedAt: string,\n): QualityReport {\n const bySource: Record<string, number> = {};\n const byModule: Record<string, number> = {};\n const bySeverity: Record<string, number> = {};\n\n for (const finding of findings) {\n bySource[finding.source] = (bySource[finding.source] ?? 0) + 1;\n const mod = finding.module ?? \"root\";\n byModule[mod] = (byModule[mod] ?? 0) + 1;\n bySeverity[finding.severity] = (bySeverity[finding.severity] ?? 0) + 1;\n }\n\n return {\n version: 1,\n generatedAt,\n repoFullName,\n findings,\n summary: {\n totalFindings: findings.length,\n bySource,\n byModule,\n bySeverity,\n },\n };\n}\n\n// ── Internal: atomic JSON write ──────────────────────────────\n\nasync function atomicWriteJson(filePath: string, data: unknown): Promise<void> {\n const tmpPath = `${filePath}.tmp.${Date.now()}`;\n const content = `${JSON.stringify(data, null, 2)}\\n`;\n\n try {\n await writeFile(tmpPath, content, \"utf-8\");\n await rename(tmpPath, filePath);\n } catch (error) {\n // Clean up temp file on failure\n try {\n await unlink(tmpPath);\n } catch {\n // Ignore cleanup errors\n }\n throw error;\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nimport type { Epic, EpicStatus, Task, TaskComplexity, TaskSource } from \"../core/types.js\";\nimport { deriveModuleFromPath } from \"./analyzer.js\";\nimport type { CodebaseMap, ModuleInfo } from \"./context-types.js\";\nimport type { RawFinding } from \"./types.js\";\n\n// ── Public options ───────────────────────────────────────────\n\nexport interface GrouperOptions {\n /** Max subtasks per epic (default: 10) */\n maxSubtasksPerEpic?: number;\n /** Min findings needed to form an epic (default: 2). Single findings become single-task epics. */\n minFindingsForEpic?: number;\n /** Codebase map for module resolution and context file population */\n codebaseMap?: CodebaseMap;\n}\n\n// ── Constants ────────────────────────────────────────────────\n\nconst DEFAULT_MAX_SUBTASKS = 10;\nconst DEFAULT_MIN_FINDINGS = 2;\nconst MAX_CONTEXT_FILES = 20;\n\n// ── Main entry point ─────────────────────────────────────────\n\n/**\n * Groups raw findings into Epics — coherent units of work that can be\n * executed together in a single agent session.\n */\nexport function groupFindingsIntoEpics(findings: RawFinding[], options?: GrouperOptions): Epic[] {\n const maxSubtasks = options?.maxSubtasksPerEpic ?? DEFAULT_MAX_SUBTASKS;\n const _minFindings = options?.minFindingsForEpic ?? DEFAULT_MIN_FINDINGS;\n const codebaseMap = options?.codebaseMap;\n\n // Step 1 & 2: Derive module for each finding and group by (module + source)\n const groups = new Map<string, RawFinding[]>();\n\n for (const finding of findings) {\n const module = finding.module ?? deriveModuleFromPath(finding.filePath);\n const key = `${module}:${finding.source}`;\n let group = groups.get(key);\n if (!group) {\n group = [];\n groups.set(key, group);\n }\n group.push(finding);\n }\n\n // Step 3 & 4: Apply size limits and handle singletons\n const epics: Epic[] = [];\n\n for (const [key, groupFindings] of groups) {\n const [module, source] = key.split(\":\") as [string, TaskSource];\n\n if (groupFindings.length <= maxSubtasks) {\n // Fits in a single epic (including singletons)\n epics.push(buildEpic(source, module, groupFindings, codebaseMap));\n } else {\n // Split into multiple epics\n const chunks = chunkArray(groupFindings, maxSubtasks);\n for (let i = 0; i < chunks.length; i++) {\n epics.push(\n buildEpic(source, module, chunks[i], codebaseMap, {\n partIndex: i + 1,\n totalParts: chunks.length,\n }),\n );\n }\n }\n }\n\n return epics;\n}\n\n// ── Epic construction ────────────────────────────────────────\n\ninterface PartInfo {\n partIndex: number;\n totalParts: number;\n}\n\nfunction buildEpic(\n source: TaskSource,\n module: string,\n findings: RawFinding[],\n codebaseMap?: CodebaseMap,\n partInfo?: PartInfo,\n): Epic {\n const epicId = randomUUID().slice(0, 16);\n const subtasks = findings.map((f) => findingToTask(f, epicId));\n\n let title = buildEpicTitle(source, module, subtasks);\n if (partInfo) {\n title = `${title} (${partInfo.partIndex}/${partInfo.totalParts})`;\n }\n\n return {\n id: epicId,\n title,\n description: buildEpicDescription(source, module, subtasks),\n scope: module,\n subtasks,\n contextFiles: resolveContextFiles(module, codebaseMap),\n status: \"pending\" as EpicStatus,\n priority: computeEpicPriority(subtasks),\n estimatedTokens: 0, // filled later by estimator\n createdAt: new Date().toISOString(),\n metadata: {\n groupingStrategy: \"by-module\",\n source,\n findingCount: findings.length,\n },\n };\n}\n\n// ── Epic title generation ────────────────────────────────────\n\nfunction buildEpicTitle(source: TaskSource, module: string, _subtasks: Task[]): string {\n const moduleLabel = module === \"root\" ? \"\" : ` for ${module} module`;\n\n switch (source) {\n case \"test-gap\":\n return `Improve test coverage${moduleLabel}`;\n case \"todo\":\n return `Address TODO comments${module === \"root\" ? \"\" : ` in ${module} module`}`;\n case \"lint\":\n return `Fix lint issues${module === \"root\" ? \"\" : ` in ${module} module`}`;\n case \"dead-code\":\n return `Remove dead code${module === \"root\" ? \"\" : ` in ${module} module`}`;\n case \"github-issue\":\n return `Resolve GitHub issues${module === \"root\" ? \"\" : ` in ${module} module`}`;\n case \"custom\":\n return `Address findings${module === \"root\" ? \"\" : ` in ${module} module`}`;\n default:\n return `Address ${source} findings${module === \"root\" ? \"\" : ` in ${module} module`}`;\n }\n}\n\n// ── Epic description generation ──────────────────────────────\n\nfunction buildEpicDescription(source: TaskSource, module: string, subtasks: Task[]): string {\n const lines: string[] = [\n `Grouped ${subtasks.length} ${source} findings in the ${module} module:`,\n \"\",\n ];\n\n for (const task of subtasks) {\n const file = task.targetFiles.length > 0 ? `[${task.targetFiles[0]}] ` : \"\";\n lines.push(`- ${file}${task.title}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n// ── Finding → Task conversion ────────────────────────────────\n\nexport function findingToTask(finding: RawFinding, epicId: string): Task {\n return {\n id: `${finding.source}-${randomUUID().slice(0, 8)}`,\n source: finding.source,\n title: finding.title,\n description: finding.description,\n targetFiles: [finding.filePath].filter(Boolean),\n priority: derivePriorityFromSeverity(finding.severity),\n complexity: finding.complexity,\n executionMode: \"new-pr\",\n metadata: finding.metadata,\n discoveredAt: finding.discoveredAt,\n parentEpicId: epicId,\n };\n}\n\nfunction derivePriorityFromSeverity(severity: \"info\" | \"warning\" | \"error\"): number {\n switch (severity) {\n case \"error\":\n return 80;\n case \"warning\":\n return 50;\n case \"info\":\n return 30;\n }\n}\n\n// ── Context files resolution ─────────────────────────────────\n\nfunction resolveContextFiles(module: string, codebaseMap?: CodebaseMap): string[] {\n if (!codebaseMap) return [];\n\n const moduleInfo: ModuleInfo | undefined = codebaseMap.modules.find((m) => m.name === module);\n if (!moduleInfo) return [];\n\n return moduleInfo.files.map((f) => f.path).slice(0, MAX_CONTEXT_FILES);\n}\n\n// ── Priority & complexity computations ───────────────────────\n\n/**\n * Weighted average of subtask priorities, with a small boost for larger epics.\n */\nexport function computeEpicPriority(subtasks: Task[]): number {\n if (subtasks.length === 0) return 0;\n\n const avg = subtasks.reduce((sum, t) => sum + t.priority, 0) / subtasks.length;\n const sizeBoost = Math.min(10, subtasks.length * 2);\n return Math.min(100, Math.round(avg + sizeBoost));\n}\n\n/**\n * Based on total subtask count and file count:\n * - 1 subtask → subtask's own complexity\n * - 2-3 subtasks → \"simple\"\n * - 4-6 subtasks → \"moderate\"\n * - 7+ subtasks → \"complex\"\n */\nexport function computeEpicComplexity(subtasks: Task[]): TaskComplexity {\n if (subtasks.length === 1) return subtasks[0].complexity;\n if (subtasks.length <= 3) return \"simple\";\n if (subtasks.length <= 6) return \"moderate\";\n return \"complex\";\n}\n\n// Re-export deriveModuleFromPath from analyzer so it is part of epic-grouper's public API\nexport { deriveModuleFromPath } from \"./analyzer.js\";\n\n// ── Utility ──────────────────────────────────────────────────\n\nfunction chunkArray<T>(array: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < array.length; i += size) {\n chunks.push(array.slice(i, i + size));\n }\n return chunks;\n}\n","import { mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport type { Epic } from \"../core/types.js\";\nimport type { Backlog } from \"./context-types.js\";\n\nconst DEFAULT_CONTEXT_DIR = \".oac/context\";\n\n/**\n * Persist the backlog to disk with atomic write (temp file + rename).\n * Creates the directory if it doesn't exist.\n * Returns the path to the written file.\n */\nexport async function persistBacklog(\n repoPath: string,\n backlog: Backlog,\n contextDir?: string,\n): Promise<string> {\n const path = join(repoPath, contextDir ?? DEFAULT_CONTEXT_DIR, \"backlog.json\");\n await mkdir(dirname(path), { recursive: true });\n\n const tempPath = `${path}.tmp`;\n await writeFile(tempPath, JSON.stringify(backlog, null, 2), \"utf8\");\n await rename(tempPath, path);\n\n return path;\n}\n\n/**\n * Load the backlog from disk. Returns null if file doesn't exist.\n */\nexport async function loadBacklog(repoPath: string, contextDir?: string): Promise<Backlog | null> {\n const path = join(repoPath, contextDir ?? DEFAULT_CONTEXT_DIR, \"backlog.json\");\n\n try {\n const content = await readFile(path, \"utf8\");\n return JSON.parse(content) as Backlog;\n } catch (err: unknown) {\n if (err instanceof Error && \"code\" in err && (err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n // JSON parse error or other unexpected read error — treat as corrupted\n if (err instanceof SyntaxError) {\n return null;\n }\n return null;\n }\n}\n\n/**\n * Create a new backlog from scratch.\n */\nexport function createBacklog(repoFullName: string, headSha: string, epics: Epic[]): Backlog {\n return {\n version: 1,\n lastUpdatedAt: new Date().toISOString(),\n repoFullName,\n headSha,\n epics,\n };\n}\n\n/**\n * Update an existing backlog:\n * - Add new epics (dedup by id)\n * - Mark epics as completed\n * - Preserve completed/skipped status from previous runs\n * Returns a new Backlog object (immutable update).\n */\nexport function updateBacklog(\n existing: Backlog,\n newEpics: Epic[],\n completedEpicIds: string[],\n headSha?: string,\n): Backlog {\n const epicMap = new Map<string, Epic>();\n\n // Seed with existing epics\n for (const epic of existing.epics) {\n epicMap.set(epic.id, { ...epic });\n }\n\n // Mark completed epics\n for (const id of completedEpicIds) {\n const epic = epicMap.get(id);\n if (epic) {\n epic.status = \"completed\";\n epic.completedAt = new Date().toISOString();\n }\n }\n\n // Merge new epics: add if missing, update if pending\n for (const epic of newEpics) {\n const existing = epicMap.get(epic.id);\n if (!existing) {\n epicMap.set(epic.id, { ...epic });\n } else if (existing.status === \"pending\") {\n epicMap.set(epic.id, { ...epic });\n }\n // If existing is completed or skipped, preserve that status\n }\n\n const epics = Array.from(epicMap.values());\n\n return {\n version: 1,\n lastUpdatedAt: new Date().toISOString(),\n repoFullName: existing.repoFullName,\n headSha: headSha ?? existing.headSha,\n epics,\n };\n}\n\n/**\n * Get pending epics from a backlog, sorted by priority descending.\n */\nexport function getPendingEpics(backlog: Backlog): Epic[] {\n return backlog.epics\n .filter((e) => e.status === \"pending\")\n .sort((a, b) => b.priority - a.priority);\n}\n"],"mappings":"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","names":["spawn","createHash","readFile","relative","resolve","sep","DEFAULT_TIMEOUT_MS","asString","toRecord","runCommand","asArray","asNumber","value","createTaskId","createHash","readFile","readdir","resolve","sep","DEFAULT_EXCLUDES","mergeExcludes","createTaskId","compileGlobMatcher","normalizeRelativePath","readFile","resolve","asNumber","readFile","resolve","asString","createHash","toRecord","createHash","unique","toRecord","readFile","readdir","stat","relative","resolve","resolve","relative","totalLoc","readFile","readdir","stat","loc","mkdir","readFile","rename","writeFile","dirname","join","existing"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/repo/resolver.ts","../src/repo/metadata-cache.ts","../src/repo/cloner.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { Octokit } from \"@octokit/rest\";\nimport { MetadataCache } from \"./metadata-cache.js\";\nimport type { RepoPermissions, ResolvedRepo } from \"./types.js\";\n\nconst OWNER_REPO_PATTERN = /^(?<owner>[A-Za-z0-9_.-]+)\\/(?<repo>[A-Za-z0-9_.-]+?)(?:\\.git)?$/;\nconst GITHUB_SSH_PATTERN =\n /^git@github\\.com:(?<owner>[A-Za-z0-9_.-]+)\\/(?<repo>[A-Za-z0-9_.-]+?)(?:\\.git)?$/;\n\nexport type RepoResolutionErrorCode =\n | \"INVALID_INPUT\"\n | \"NOT_FOUND\"\n | \"FORBIDDEN\"\n | \"ARCHIVED\"\n | \"UNKNOWN\";\n\nexport class RepoResolutionError extends Error {\n public readonly code: RepoResolutionErrorCode;\n\n public constructor(message: string, code: RepoResolutionErrorCode, cause?: unknown) {\n super(message, { cause });\n this.name = \"RepoResolutionError\";\n this.code = code;\n }\n}\n\ninterface ParsedRepoInput {\n owner: string;\n name: string;\n}\n\nexport async function resolveRepo(input: string): Promise<ResolvedRepo> {\n const parsed = parseRepoInput(input);\n const cache = new MetadataCache();\n const cacheKey = `${parsed.owner}/${parsed.name}`;\n const cached = await cache.get(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const octokit = new Octokit({\n auth: resolveGitHubToken(),\n });\n\n const repoData = await fetchRepo(octokit, parsed.owner, parsed.name);\n if (repoData.archived) {\n throw new RepoResolutionError(\n `Repository \"${repoData.full_name}\" is archived and cannot be used for contributions.`,\n \"ARCHIVED\",\n );\n }\n\n const permissions = normalizePermissions(repoData.private, repoData.permissions);\n if (!permissions.pull) {\n throw new RepoResolutionError(\n `Missing pull permission for \"${repoData.full_name}\".`,\n \"FORBIDDEN\",\n );\n }\n\n const [languages, headSha] = await Promise.all([\n fetchLanguages(octokit, repoData.owner.login, repoData.name),\n fetchHeadSha(octokit, repoData.owner.login, repoData.name, repoData.default_branch),\n ]);\n\n const localPath = defaultLocalPath(repoData.owner.login, repoData.name);\n const resolved: ResolvedRepo = {\n fullName: repoData.full_name,\n owner: repoData.owner.login,\n name: repoData.name,\n localPath,\n worktreePath: join(localPath, \"..\", \".oac-worktrees\", repoData.default_branch),\n meta: {\n defaultBranch: repoData.default_branch,\n language: repoData.language,\n languages,\n size: repoData.size,\n stars: repoData.stargazers_count,\n openIssuesCount: repoData.open_issues_count,\n topics: repoData.topics ?? [],\n license: normalizeLicense(repoData.license?.spdx_id ?? null),\n isArchived: repoData.archived,\n isFork: repoData.fork,\n permissions,\n },\n git: {\n headSha,\n remoteUrl: repoData.clone_url ?? `https://github.com/${repoData.full_name}.git`,\n sshUrl: repoData.ssh_url ?? `git@github.com:${repoData.full_name}.git`,\n isShallowClone: true,\n },\n };\n\n await cache.set(resolved.fullName, resolved);\n return resolved;\n}\n\nfunction parseRepoInput(input: string): ParsedRepoInput {\n const normalized = input.trim();\n if (!normalized) {\n throw new RepoResolutionError(\"Repository input cannot be empty.\", \"INVALID_INPUT\");\n }\n\n const ownerRepoMatch = normalized.match(OWNER_REPO_PATTERN);\n if (ownerRepoMatch?.groups) {\n return {\n owner: ownerRepoMatch.groups.owner,\n name: ownerRepoMatch.groups.repo,\n };\n }\n\n const sshMatch = normalized.match(GITHUB_SSH_PATTERN);\n if (sshMatch?.groups) {\n return {\n owner: sshMatch.groups.owner,\n name: sshMatch.groups.repo,\n };\n }\n\n const normalizedUrlInput = normalized.startsWith(\"github.com/\")\n ? `https://${normalized}`\n : normalized;\n\n try {\n const url = new URL(normalizedUrlInput);\n if (!isGitHubHost(url.hostname)) {\n throw new RepoResolutionError(\n `Only github.com repository URLs are supported, received \"${url.hostname}\".`,\n \"INVALID_INPUT\",\n );\n }\n\n const pathParts = url.pathname.split(\"/\").filter(Boolean);\n if (pathParts.length < 2) {\n throw new RepoResolutionError(`Invalid GitHub repository URL \"${input}\".`, \"INVALID_INPUT\");\n }\n\n const owner = pathParts[0];\n const name = stripGitSuffix(pathParts[1]);\n if (!owner || !name) {\n throw new RepoResolutionError(`Invalid GitHub repository URL \"${input}\".`, \"INVALID_INPUT\");\n }\n\n return { owner, name };\n } catch (error) {\n if (error instanceof RepoResolutionError) {\n throw error;\n }\n\n throw new RepoResolutionError(\n `Expected \"owner/repo\" or a GitHub repository URL, received \"${input}\".`,\n \"INVALID_INPUT\",\n error,\n );\n }\n}\n\nasync function fetchRepo(octokit: Octokit, owner: string, repo: string) {\n try {\n return (await octokit.repos.get({ owner, repo })).data;\n } catch (error) {\n throw toResolutionError(owner, repo, error);\n }\n}\n\nasync function fetchLanguages(\n octokit: Octokit,\n owner: string,\n repo: string,\n): Promise<Record<string, number>> {\n try {\n const response = await octokit.repos.listLanguages({ owner, repo });\n return response.data;\n } catch (error) {\n throw toResolutionError(owner, repo, error);\n }\n}\n\nasync function fetchHeadSha(\n octokit: Octokit,\n owner: string,\n repo: string,\n defaultBranch: string,\n): Promise<string> {\n try {\n const branch = await octokit.repos.getBranch({\n owner,\n repo,\n branch: defaultBranch,\n });\n return branch.data.commit.sha;\n } catch (error) {\n throw toResolutionError(owner, repo, error);\n }\n}\n\nfunction toResolutionError(owner: string, repo: string, error: unknown): RepoResolutionError {\n const fullName = `${owner}/${repo}`;\n const status = isApiError(error) ? error.status : undefined;\n const message =\n typeof error === \"object\" && error && \"message\" in error\n ? String(error.message)\n : \"unknown error\";\n\n if (status === 404) {\n const hasToken = !!(process.env.GITHUB_TOKEN || process.env.GH_TOKEN);\n const hint = hasToken\n ? `If this is a private repo, ensure your token has the \"repo\" scope: gh auth refresh -s repo`\n : \"If this is a private repo, authenticate first: gh auth login\";\n return new RepoResolutionError(\n `Repository \"${fullName}\" was not found on GitHub. ${hint}`,\n \"NOT_FOUND\",\n error,\n );\n }\n\n if (status === 403) {\n return new RepoResolutionError(\n `Access denied for \"${fullName}\". Ensure your token has the \"repo\" scope: gh auth refresh -s repo`,\n \"FORBIDDEN\",\n error,\n );\n }\n\n return new RepoResolutionError(\n `Failed to resolve repository \"${fullName}\": ${message}`,\n \"UNKNOWN\",\n error,\n );\n}\n\nfunction normalizePermissions(\n isPrivateRepo: boolean,\n permissions:\n | {\n admin?: boolean;\n push?: boolean;\n pull?: boolean;\n }\n | undefined,\n): RepoPermissions {\n const pull = permissions?.pull ?? !isPrivateRepo;\n\n return {\n push: permissions?.push ?? false,\n pull,\n admin: permissions?.admin ?? false,\n };\n}\n\nfunction normalizeLicense(spdxId: string | null): string | null {\n if (!spdxId || spdxId === \"NOASSERTION\") {\n return null;\n }\n\n return spdxId;\n}\n\nfunction isGitHubHost(hostname: string): boolean {\n const normalized = hostname.toLowerCase();\n return normalized === \"github.com\" || normalized === \"www.github.com\";\n}\n\nfunction stripGitSuffix(repo: string): string {\n return repo.replace(/\\.git$/i, \"\");\n}\n\nfunction isApiError(error: unknown): error is { status?: number } {\n return typeof error === \"object\" && error !== null && \"status\" in error;\n}\n\nfunction defaultLocalPath(owner: string, name: string): string {\n return join(homedir(), \".oac\", \"cache\", \"repos\", owner, name);\n}\n\nfunction resolveGitHubToken(): string | undefined {\n const githubToken = process.env.GITHUB_TOKEN?.trim();\n if (githubToken) {\n process.env.GITHUB_TOKEN = githubToken;\n return githubToken;\n }\n\n const ghToken = process.env.GH_TOKEN?.trim();\n if (ghToken) {\n process.env.GITHUB_TOKEN = ghToken;\n return ghToken;\n }\n\n try {\n const token = execFileSync(\"gh\", [\"auth\", \"token\"], {\n timeout: 5_000,\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n\n if (token.length > 0) {\n process.env.GITHUB_TOKEN = token;\n return token;\n }\n } catch {\n // gh not installed or not authenticated\n }\n\n return undefined;\n}\n","import { constants as fsConstants } from \"node:fs\";\nimport { access, mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { ResolvedRepo } from \"./types.js\";\n\ninterface MetadataCacheEntry {\n cachedAt: number;\n repo: ResolvedRepo;\n}\n\ninterface MetadataCacheFile {\n version: 1;\n entries: Record<string, MetadataCacheEntry>;\n}\n\nexport interface MetadataCacheOptions {\n filePath?: string;\n ttlMs?: number;\n now?: () => number;\n}\n\nexport const DEFAULT_METADATA_CACHE_PATH = join(homedir(), \".oac\", \"cache\", \"repos.json\");\n\nexport const DEFAULT_METADATA_CACHE_TTL_MS = 60 * 60 * 1000;\n\nconst EMPTY_CACHE: MetadataCacheFile = {\n version: 1,\n entries: {},\n};\n\nexport class MetadataCache {\n private readonly filePath: string;\n private readonly ttlMs: number;\n private readonly now: () => number;\n\n public constructor(options: MetadataCacheOptions = {}) {\n this.filePath = expandHomePath(options.filePath ?? DEFAULT_METADATA_CACHE_PATH);\n this.ttlMs = options.ttlMs ?? DEFAULT_METADATA_CACHE_TTL_MS;\n this.now = options.now ?? Date.now;\n }\n\n public async get(fullName: string): Promise<ResolvedRepo | null> {\n const cache = await this.readCache();\n const key = normalizeCacheKey(fullName);\n const entry = cache.entries[key];\n\n if (!entry) {\n return null;\n }\n\n if (this.now() - entry.cachedAt > this.ttlMs) {\n delete cache.entries[key];\n await this.writeCache(cache);\n return null;\n }\n\n return entry.repo;\n }\n\n public async set(fullName: string, repo: ResolvedRepo): Promise<void> {\n const cache = await this.readCache();\n const key = normalizeCacheKey(fullName);\n cache.entries[key] = {\n cachedAt: this.now(),\n repo,\n };\n await this.writeCache(cache);\n }\n\n public async invalidate(fullName?: string): Promise<void> {\n if (!fullName) {\n await this.writeCache(EMPTY_CACHE);\n return;\n }\n\n const cache = await this.readCache();\n const key = normalizeCacheKey(fullName);\n if (!(key in cache.entries)) {\n return;\n }\n\n delete cache.entries[key];\n await this.writeCache(cache);\n }\n\n private async readCache(): Promise<MetadataCacheFile> {\n if (!(await pathExists(this.filePath))) {\n return { ...EMPTY_CACHE, entries: {} };\n }\n\n try {\n const raw = await readFile(this.filePath, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<MetadataCacheFile>;\n\n if (parsed.version !== 1 || typeof parsed.entries !== \"object\") {\n return { ...EMPTY_CACHE, entries: {} };\n }\n\n return {\n version: 1,\n entries: parsed.entries as Record<string, MetadataCacheEntry>,\n };\n } catch {\n return { ...EMPTY_CACHE, entries: {} };\n }\n }\n\n private async writeCache(cache: MetadataCacheFile): Promise<void> {\n await mkdir(dirname(this.filePath), { recursive: true });\n const tempPath = `${this.filePath}.tmp`;\n await writeFile(tempPath, JSON.stringify(cache, null, 2), \"utf8\");\n await rename(tempPath, this.filePath);\n }\n}\n\nfunction normalizeCacheKey(fullName: string): string {\n return fullName.trim().toLowerCase();\n}\n\nfunction expandHomePath(path: string): string {\n if (path === \"~\") {\n return homedir();\n }\n\n if (path.startsWith(\"~/\")) {\n return join(homedir(), path.slice(2));\n }\n\n return path;\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await access(path, fsConstants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n","import { constants as fsConstants } from \"node:fs\";\nimport { access, mkdir, rm } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport type { ResolvedRepo } from \"./types.js\";\n\nconst CLONE_RETRY_BACKOFF_MS = [1000, 4000, 16000] as const;\nconst GIT_CLONE_TIMEOUT_MS = 300_000; // 5 min rolling timeout for clone\nconst GIT_FETCH_TIMEOUT_MS = 120_000; // 2 min rolling timeout for fetch/sync\n\nexport const DEFAULT_REPO_CACHE_DIR = join(homedir(), \".oac\", \"cache\", \"repos\");\n\nexport async function cloneRepo(\n repo: ResolvedRepo,\n cacheDir: string = DEFAULT_REPO_CACHE_DIR,\n): Promise<string> {\n const cacheRoot = resolveCacheDir(cacheDir);\n const localPath = join(cacheRoot, repo.owner, repo.name);\n await mkdir(dirname(localPath), { recursive: true });\n\n if (await isGitRepository(localPath)) {\n await pullExistingClone(repo, localPath);\n } else if (await pathExists(localPath)) {\n throw new Error(\n `Cannot clone \"${repo.fullName}\" into \"${localPath}\" because the directory exists and is not a git repository.`,\n );\n } else {\n await cloneNewRepository(repo, localPath);\n }\n\n const git = createGit(localPath);\n repo.localPath = localPath;\n repo.worktreePath = join(localPath, \"..\", \".oac-worktrees\", repo.meta.defaultBranch);\n repo.git.headSha = (await git.revparse([\"HEAD\"])).trim();\n repo.git.isShallowClone = await isShallowClone(git);\n repo.git.remoteUrl = await getOriginUrl(git, repo.git.remoteUrl);\n\n return localPath;\n}\n\nasync function cloneNewRepository(repo: ResolvedRepo, localPath: string): Promise<void> {\n const git = createGit(undefined, GIT_CLONE_TIMEOUT_MS);\n const cloneArgs = [\"--depth\", \"1\", \"--branch\", repo.meta.defaultBranch];\n\n try {\n await retryGitOperation(\n () => git.clone(repo.git.remoteUrl, localPath, cloneArgs),\n `clone ${repo.fullName}`,\n );\n } catch (httpsError) {\n if (!repo.git.sshUrl) throw httpsError;\n\n // HTTPS failed — try SSH (e.g. user has SSH keys but no HTTPS credentials)\n await cleanPartialClone(localPath);\n try {\n await retryGitOperation(\n () => git.clone(repo.git.sshUrl!, localPath, cloneArgs),\n `clone ${repo.fullName} (SSH fallback)`,\n );\n } catch (sshError) {\n throw new Error(\n `Failed to clone \"${repo.fullName}\" via both HTTPS and SSH.\\n` +\n \"Ensure git credentials are configured: run `gh auth login` or set up SSH keys.\\n\" +\n `HTTPS error: ${httpsError instanceof Error ? httpsError.message : httpsError}\\n` +\n `SSH error: ${sshError instanceof Error ? sshError.message : sshError}`,\n { cause: sshError },\n );\n }\n }\n}\n\nasync function pullExistingClone(repo: ResolvedRepo, localPath: string): Promise<void> {\n const git = createGit(localPath);\n await ensureOriginRemote(git, repo.git.remoteUrl);\n\n try {\n await retryGitOperation(\n () => git.fetch(\"origin\", repo.meta.defaultBranch, [\"--depth=1\", \"--prune\"]),\n `fetch ${repo.fullName}`,\n );\n } catch (fetchError) {\n if (!repo.git.sshUrl) throw fetchError;\n\n // HTTPS fetch failed — switch remote to SSH and retry\n await ensureOriginRemote(git, repo.git.sshUrl);\n await retryGitOperation(\n () => git.fetch(\"origin\", repo.meta.defaultBranch, [\"--depth=1\", \"--prune\"]),\n `fetch ${repo.fullName} (SSH fallback)`,\n );\n }\n\n await checkoutDefaultBranch(git, repo.meta.defaultBranch);\n\n await retryGitOperation(\n () => hardSyncDefaultBranch(git, repo.meta.defaultBranch),\n `sync ${repo.fullName}`,\n );\n}\n\nasync function checkoutDefaultBranch(git: SimpleGit, branchName: string): Promise<void> {\n try {\n await git.checkout(branchName);\n } catch {\n await git.raw([\"checkout\", \"-B\", branchName, `origin/${branchName}`]);\n }\n}\n\nasync function hardSyncDefaultBranch(git: SimpleGit, branchName: string): Promise<void> {\n // The cache clone is disposable, so force-align it with origin to avoid stale divergence.\n await git.raw([\"reset\", \"--hard\", `origin/${branchName}`]);\n await git.raw([\"clean\", \"-fd\"]);\n}\n\nasync function ensureOriginRemote(git: SimpleGit, remoteUrl: string): Promise<void> {\n const remotes = await git.getRemotes(true);\n const origin = remotes.find((remote) => remote.name === \"origin\");\n\n if (!origin) {\n await git.addRemote(\"origin\", remoteUrl);\n return;\n }\n\n if (origin.refs.fetch !== remoteUrl && origin.refs.push !== remoteUrl) {\n await git.remote([\"set-url\", \"origin\", remoteUrl]);\n }\n}\n\nasync function getOriginUrl(git: SimpleGit, fallbackUrl: string): Promise<string> {\n const remotes = await git.getRemotes(true);\n const origin = remotes.find((remote) => remote.name === \"origin\");\n return origin?.refs.fetch ?? fallbackUrl;\n}\n\nasync function isShallowClone(git: SimpleGit): Promise<boolean> {\n const output = await git.raw([\"rev-parse\", \"--is-shallow-repository\"]);\n return output.trim() === \"true\";\n}\n\nasync function retryGitOperation<T>(\n operation: () => Promise<T>,\n operationName: string,\n): Promise<T> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= CLONE_RETRY_BACKOFF_MS.length; attempt += 1) {\n try {\n return await operation();\n } catch (error) {\n lastError = error;\n if (attempt === CLONE_RETRY_BACKOFF_MS.length) {\n break;\n }\n await sleep(CLONE_RETRY_BACKOFF_MS[attempt]);\n }\n }\n\n throw new Error(\n `Git operation failed after ${CLONE_RETRY_BACKOFF_MS.length + 1} attempts (${operationName}).`,\n { cause: lastError },\n );\n}\n\nfunction resolveCacheDir(cacheDir: string): string {\n const selected = cacheDir.trim().length > 0 ? cacheDir : DEFAULT_REPO_CACHE_DIR;\n return resolve(expandHomePath(selected));\n}\n\nfunction expandHomePath(path: string): string {\n if (path === \"~\") {\n return homedir();\n }\n\n if (path.startsWith(\"~/\")) {\n return join(homedir(), path.slice(2));\n }\n\n return path;\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await access(path, fsConstants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isGitRepository(path: string): Promise<boolean> {\n return pathExists(join(path, \".git\"));\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolvePromise) => {\n setTimeout(resolvePromise, ms);\n });\n}\n\n/**\n * Create a `SimpleGit` instance with `GIT_TERMINAL_PROMPT=0` (prevents\n * silent credential prompts that hang forever) and a rolling timeout that\n * kills the spawned process if it produces no output for `timeoutMs`.\n *\n * NOTE: `simple-git`'s `.env(key, value)` **replaces** the entire process\n * environment. We must spread `process.env` so the child git process still\n * has `HOME`, `PATH`, `SSH_AUTH_SOCK`, etc.\n */\nfunction createGit(baseDir?: string, timeoutMs = GIT_FETCH_TIMEOUT_MS): SimpleGit {\n return simpleGit({\n ...(baseDir ? { baseDir } : {}),\n timeout: { block: timeoutMs },\n }).env({ ...process.env, GIT_TERMINAL_PROMPT: \"0\" });\n}\n\nasync function cleanPartialClone(localPath: string): Promise<void> {\n try {\n await rm(localPath, { recursive: true, force: true });\n } catch {\n /* best-effort cleanup before SSH retry */\n }\n}\n"],"mappings":"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","names":["homedir","join","join","homedir","fsConstants","access","mkdir","homedir","dirname","join","pathExists","expandHomePath"]}