@open330/oac 2026.4.3 → 2026.220.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +115 -0
- package/README.md +2 -2
- package/dist/{chunk-YWIB3TRI.js → chunk-6A37SKAJ.js} +15 -2
- package/dist/chunk-6A37SKAJ.js.map +1 -0
- package/dist/{chunk-ZRYAHZQJ.js → chunk-7C7SC4TZ.js} +1 -1
- package/dist/{chunk-XUW3XWTX.js → chunk-7Y4LZUDP.js} +89 -121
- package/dist/chunk-7Y4LZUDP.js.map +1 -0
- package/dist/{chunk-CJAJ4MBO.js → chunk-OS3XDHOJ.js} +57 -18
- package/dist/chunk-OS3XDHOJ.js.map +1 -0
- package/dist/{chunk-HDMLNOND.js → chunk-OTPXGXO7.js} +44 -18
- package/dist/chunk-OTPXGXO7.js.map +1 -0
- package/dist/{chunk-7FWC3Z4W.js → chunk-QPVNC7S4.js} +479 -196
- package/dist/chunk-QPVNC7S4.js.map +1 -0
- package/dist/cli/cli.js +6 -6
- package/dist/cli/index.js +6 -6
- package/dist/completion/index.js +4 -8
- package/dist/completion/index.js.map +1 -1
- package/dist/core/index.d.ts +16 -1
- package/dist/core/index.js +8 -4
- package/dist/dashboard/index.js +33 -24
- package/dist/dashboard/index.js.map +1 -1
- package/dist/discovery/index.d.ts +18 -2
- package/dist/discovery/index.js +4 -2
- package/dist/execution/index.d.ts +45 -1
- package/dist/execution/index.js +7 -3
- package/dist/repo/index.d.ts +2 -2
- package/dist/repo/index.js +1 -1
- package/dist/{types-CYCwgojB.d.ts → types-3_IAAxh5.d.ts} +1 -0
- package/docs/config-reference.md +271 -0
- package/docs/multi-agent-support-technical-spec.md +312 -0
- package/package.json +23 -18
- package/dist/chunk-7FWC3Z4W.js.map +0 -1
- package/dist/chunk-CJAJ4MBO.js.map +0 -1
- package/dist/chunk-HDMLNOND.js.map +0 -1
- package/dist/chunk-XUW3XWTX.js.map +0 -1
- package/dist/chunk-YWIB3TRI.js.map +0 -1
- /package/dist/{chunk-ZRYAHZQJ.js.map → chunk-7C7SC4TZ.js.map} +0 -0
|
@@ -169,6 +169,7 @@ async function resolveRepo(input) {
|
|
|
169
169
|
git: {
|
|
170
170
|
headSha,
|
|
171
171
|
remoteUrl: repoData.clone_url ?? `https://github.com/${repoData.full_name}.git`,
|
|
172
|
+
sshUrl: repoData.ssh_url ?? `git@github.com:${repoData.full_name}.git`,
|
|
172
173
|
isShallowClone: true
|
|
173
174
|
}
|
|
174
175
|
};
|
|
@@ -332,11 +333,13 @@ function resolveGitHubToken() {
|
|
|
332
333
|
|
|
333
334
|
// src/repo/cloner.ts
|
|
334
335
|
import { constants as fsConstants2 } from "fs";
|
|
335
|
-
import { access as access2, mkdir as mkdir2 } from "fs/promises";
|
|
336
|
+
import { access as access2, mkdir as mkdir2, rm } from "fs/promises";
|
|
336
337
|
import { homedir as homedir3 } from "os";
|
|
337
338
|
import { dirname as dirname2, join as join3, resolve } from "path";
|
|
338
339
|
import { simpleGit } from "simple-git";
|
|
339
340
|
var CLONE_RETRY_BACKOFF_MS = [1e3, 4e3, 16e3];
|
|
341
|
+
var GIT_CLONE_TIMEOUT_MS = 3e5;
|
|
342
|
+
var GIT_FETCH_TIMEOUT_MS = 12e4;
|
|
340
343
|
var DEFAULT_REPO_CACHE_DIR = join3(homedir3(), ".oac", "cache", "repos");
|
|
341
344
|
async function cloneRepo(repo, cacheDir = DEFAULT_REPO_CACHE_DIR) {
|
|
342
345
|
const cacheRoot = resolveCacheDir(cacheDir);
|
|
@@ -351,7 +354,7 @@ async function cloneRepo(repo, cacheDir = DEFAULT_REPO_CACHE_DIR) {
|
|
|
351
354
|
} else {
|
|
352
355
|
await cloneNewRepository(repo, localPath);
|
|
353
356
|
}
|
|
354
|
-
const git =
|
|
357
|
+
const git = createGit(localPath);
|
|
355
358
|
repo.localPath = localPath;
|
|
356
359
|
repo.worktreePath = join3(localPath, "..", ".oac-worktrees", repo.meta.defaultBranch);
|
|
357
360
|
repo.git.headSha = (await git.revparse(["HEAD"])).trim();
|
|
@@ -360,24 +363,48 @@ async function cloneRepo(repo, cacheDir = DEFAULT_REPO_CACHE_DIR) {
|
|
|
360
363
|
return localPath;
|
|
361
364
|
}
|
|
362
365
|
async function cloneNewRepository(repo, localPath) {
|
|
363
|
-
const git =
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
366
|
+
const git = createGit(void 0, GIT_CLONE_TIMEOUT_MS);
|
|
367
|
+
const cloneArgs = ["--depth", "1", "--branch", repo.meta.defaultBranch];
|
|
368
|
+
try {
|
|
369
|
+
await retryGitOperation(
|
|
370
|
+
() => git.clone(repo.git.remoteUrl, localPath, cloneArgs),
|
|
371
|
+
`clone ${repo.fullName}`
|
|
372
|
+
);
|
|
373
|
+
} catch (httpsError) {
|
|
374
|
+
if (!repo.git.sshUrl) throw httpsError;
|
|
375
|
+
await cleanPartialClone(localPath);
|
|
376
|
+
try {
|
|
377
|
+
await retryGitOperation(
|
|
378
|
+
() => git.clone(repo.git.sshUrl, localPath, cloneArgs),
|
|
379
|
+
`clone ${repo.fullName} (SSH fallback)`
|
|
380
|
+
);
|
|
381
|
+
} catch (sshError) {
|
|
382
|
+
throw new Error(
|
|
383
|
+
`Failed to clone "${repo.fullName}" via both HTTPS and SSH.
|
|
384
|
+
Ensure git credentials are configured: run \`gh auth login\` or set up SSH keys.
|
|
385
|
+
HTTPS error: ${httpsError instanceof Error ? httpsError.message : httpsError}
|
|
386
|
+
SSH error: ${sshError instanceof Error ? sshError.message : sshError}`,
|
|
387
|
+
{ cause: sshError }
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
373
391
|
}
|
|
374
392
|
async function pullExistingClone(repo, localPath) {
|
|
375
|
-
const git =
|
|
393
|
+
const git = createGit(localPath);
|
|
376
394
|
await ensureOriginRemote(git, repo.git.remoteUrl);
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
395
|
+
try {
|
|
396
|
+
await retryGitOperation(
|
|
397
|
+
() => git.fetch("origin", repo.meta.defaultBranch, ["--depth=1", "--prune"]),
|
|
398
|
+
`fetch ${repo.fullName}`
|
|
399
|
+
);
|
|
400
|
+
} catch (fetchError) {
|
|
401
|
+
if (!repo.git.sshUrl) throw fetchError;
|
|
402
|
+
await ensureOriginRemote(git, repo.git.sshUrl);
|
|
403
|
+
await retryGitOperation(
|
|
404
|
+
() => git.fetch("origin", repo.meta.defaultBranch, ["--depth=1", "--prune"]),
|
|
405
|
+
`fetch ${repo.fullName} (SSH fallback)`
|
|
406
|
+
);
|
|
407
|
+
}
|
|
381
408
|
await checkoutDefaultBranch(git, repo.meta.defaultBranch);
|
|
382
409
|
await retryGitOperation(
|
|
383
410
|
() => hardSyncDefaultBranch(git, repo.meta.defaultBranch),
|
|
@@ -462,6 +489,18 @@ function sleep(ms) {
|
|
|
462
489
|
setTimeout(resolvePromise, ms);
|
|
463
490
|
});
|
|
464
491
|
}
|
|
492
|
+
function createGit(baseDir, timeoutMs = GIT_FETCH_TIMEOUT_MS) {
|
|
493
|
+
return simpleGit({
|
|
494
|
+
...baseDir ? { baseDir } : {},
|
|
495
|
+
timeout: { block: timeoutMs }
|
|
496
|
+
}).env({ ...process.env, GIT_TERMINAL_PROMPT: "0" });
|
|
497
|
+
}
|
|
498
|
+
async function cleanPartialClone(localPath) {
|
|
499
|
+
try {
|
|
500
|
+
await rm(localPath, { recursive: true, force: true });
|
|
501
|
+
} catch {
|
|
502
|
+
}
|
|
503
|
+
}
|
|
465
504
|
|
|
466
505
|
export {
|
|
467
506
|
DEFAULT_METADATA_CACHE_PATH,
|
|
@@ -472,4 +511,4 @@ export {
|
|
|
472
511
|
DEFAULT_REPO_CACHE_DIR,
|
|
473
512
|
cloneRepo
|
|
474
513
|
};
|
|
475
|
-
//# sourceMappingURL=chunk-
|
|
514
|
+
//# sourceMappingURL=chunk-OS3XDHOJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
createMemoryMonitor
|
|
3
|
-
|
|
2
|
+
createMemoryMonitor,
|
|
3
|
+
truncate
|
|
4
|
+
} from "./chunk-6A37SKAJ.js";
|
|
4
5
|
|
|
5
6
|
// src/discovery/scanners/todo-scanner.ts
|
|
6
7
|
import { spawn } from "child_process";
|
|
@@ -289,12 +290,6 @@ function extractTodoKeyword(lineText) {
|
|
|
289
290
|
}
|
|
290
291
|
return match[1].toUpperCase();
|
|
291
292
|
}
|
|
292
|
-
function truncate(value, maxLength) {
|
|
293
|
-
if (value.length <= maxLength) {
|
|
294
|
-
return value;
|
|
295
|
-
}
|
|
296
|
-
return `${value.slice(0, maxLength - 1)}\u2026`;
|
|
297
|
-
}
|
|
298
293
|
function createTaskId(source, targetFiles, title, suffix) {
|
|
299
294
|
const base = [source, [...targetFiles].sort().join(","), title, suffix].join("::");
|
|
300
295
|
return createHash("sha256").update(base).digest("hex").slice(0, 16);
|
|
@@ -1194,7 +1189,8 @@ async function fetchOpenIssues(repo, token) {
|
|
|
1194
1189
|
headers: {
|
|
1195
1190
|
Authorization: `Bearer ${token}`,
|
|
1196
1191
|
Accept: "application/vnd.github.v3+json"
|
|
1197
|
-
}
|
|
1192
|
+
},
|
|
1193
|
+
signal: AbortSignal.timeout(3e4)
|
|
1198
1194
|
});
|
|
1199
1195
|
if (!response.ok) {
|
|
1200
1196
|
return [];
|
|
@@ -1324,8 +1320,8 @@ function mapIssueToTask(issue, discoveredAt) {
|
|
|
1324
1320
|
const estimatedTokens = ESTIMATED_TOKENS_BY_COMPLEXITY[complexity];
|
|
1325
1321
|
const bodyText = asString3(issue.body)?.trim() || "No description provided.";
|
|
1326
1322
|
const labelSummary = labels.length > 0 ? `Labels: ${labels.join(", ")}` : "Labels: none";
|
|
1327
|
-
const title =
|
|
1328
|
-
const description =
|
|
1323
|
+
const title = truncate(rawTitle, TITLE_LIMIT);
|
|
1324
|
+
const description = truncate(`${bodyText}
|
|
1329
1325
|
|
|
1330
1326
|
${labelSummary}`, DESCRIPTION_LIMIT);
|
|
1331
1327
|
const url = asString3(issue.html_url) ?? "";
|
|
@@ -1406,12 +1402,6 @@ function readAuthor(user) {
|
|
|
1406
1402
|
}
|
|
1407
1403
|
return login;
|
|
1408
1404
|
}
|
|
1409
|
-
function truncate2(value, maxLength) {
|
|
1410
|
-
if (value.length <= maxLength) {
|
|
1411
|
-
return value;
|
|
1412
|
-
}
|
|
1413
|
-
return `${value.slice(0, maxLength - 1)}\u2026`;
|
|
1414
|
-
}
|
|
1415
1405
|
function toIssueResponse(value) {
|
|
1416
1406
|
if (value && typeof value === "object") {
|
|
1417
1407
|
return value;
|
|
@@ -1524,6 +1514,41 @@ function unique(values) {
|
|
|
1524
1514
|
return Array.from(new Set(values.filter((value) => value.trim().length > 0)));
|
|
1525
1515
|
}
|
|
1526
1516
|
|
|
1517
|
+
// src/discovery/scanner-factory.ts
|
|
1518
|
+
function buildScanners(config, hasGitHubAuth) {
|
|
1519
|
+
const names = [];
|
|
1520
|
+
if (config?.discovery.scanners.lint !== false) {
|
|
1521
|
+
names.push("lint");
|
|
1522
|
+
}
|
|
1523
|
+
if (config?.discovery.scanners.todo !== false) {
|
|
1524
|
+
names.push("todo");
|
|
1525
|
+
}
|
|
1526
|
+
if (config?.discovery.scanners.testGap !== false) {
|
|
1527
|
+
names.push("test-gap");
|
|
1528
|
+
}
|
|
1529
|
+
if (hasGitHubAuth) {
|
|
1530
|
+
names.push("github-issues");
|
|
1531
|
+
}
|
|
1532
|
+
if (names.length === 0) {
|
|
1533
|
+
names.push("lint", "todo", "test-gap");
|
|
1534
|
+
}
|
|
1535
|
+
const unique2 = [...new Set(names)];
|
|
1536
|
+
const instances = unique2.map(instantiateScanner);
|
|
1537
|
+
return { names: unique2, instances, composite: new CompositeScanner(instances) };
|
|
1538
|
+
}
|
|
1539
|
+
function instantiateScanner(name) {
|
|
1540
|
+
switch (name) {
|
|
1541
|
+
case "lint":
|
|
1542
|
+
return new LintScanner();
|
|
1543
|
+
case "todo":
|
|
1544
|
+
return new TodoScanner();
|
|
1545
|
+
case "test-gap":
|
|
1546
|
+
return new TestGapScanner();
|
|
1547
|
+
case "github-issues":
|
|
1548
|
+
return new GitHubIssuesScanner();
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1527
1552
|
// src/discovery/ranker.ts
|
|
1528
1553
|
var IMPACT_BY_SOURCE = {
|
|
1529
1554
|
lint: 22,
|
|
@@ -2323,6 +2348,7 @@ export {
|
|
|
2323
2348
|
GitHubIssuesScanner,
|
|
2324
2349
|
CompositeScanner,
|
|
2325
2350
|
createDefaultCompositeScanner,
|
|
2351
|
+
buildScanners,
|
|
2326
2352
|
rankTasks,
|
|
2327
2353
|
analyzeCodebase,
|
|
2328
2354
|
persistContext,
|
|
@@ -2339,4 +2365,4 @@ export {
|
|
|
2339
2365
|
updateBacklog,
|
|
2340
2366
|
getPendingEpics
|
|
2341
2367
|
};
|
|
2342
|
-
//# sourceMappingURL=chunk-
|
|
2368
|
+
//# sourceMappingURL=chunk-OTPXGXO7.js.map
|