feat(worker): apply real ai edits and send vercel preview link#492
feat(worker): apply real ai edits and send vercel preview link#492
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 7 minutes and 58 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
Walkthrough이번 변경은 AI 검사기 워커 스크립트의 핵심 동작 흐름을 재정비했습니다. 패치 획득 로직을 통합하여 외부 엔드포인트와 로컬 Codex 중 하나를 선택 가능하도록 했고, 깃 작업 트리 안정성을 강화했으며, 커밋 조건을 더욱 엄격하게 정의했습니다. 또한 프리뷰 URL 해석 과정을 확장하여 Vercel API, GitHub 커밋 상태, PR 댓글 등 다양한 경로를 순차적으로 시도하도록 개선했으며, 관련 환경 변수 및 동작 방식을 문서화했습니다. Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
주요 변경 사항스크립트 변경 (
|
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Description check | ❓ Inconclusive | 설명에서 핵심 변경사항(로컬 Codex 폴백, 메타데이터 변경 감지, Vercel 미리보기 URL 해석, 문서화)은 명시되어 있으나 저장소의 필수 템플릿 구조(관련 이슈, 특이 사항, 리뷰 요구사항 섹션)를 따르지 않습니다. | 저장소 템플릿에 맞춰 관련 이슈 번호, 특이 사항(Node.js 버전 호환성), 리뷰 중점 사항을 구조화된 형식으로 추가하기를 권장합니다. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | 제목은 주요 변경사항인 '로컬 Codex 폴백 추가'와 'Vercel 미리보기 링크 전송'을 명확하게 요약하고 있습니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
codex/fix-turbo-web-build-env-warnings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3c28fa298b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| previewUrl = | ||
| (await getPreviewUrlFromVercel(branchName)) || | ||
| (await getPreviewUrlFromGitHubCommitStatus(githubToken, owner, repoName, commitSha)) || | ||
| previewUrl; |
There was a problem hiding this comment.
Bypass long status polling when preview template is available
The preview resolution chain always awaits getPreviewUrlFromGitHubCommitStatus(...) before using the template fallback, so when VERCEL_TOKEN/VERCEL_PROJECT_ID are unset (or no Vercel status is posted) each task can block for the full default timeout (AI_INSPECTOR_VERCEL_PREVIEW_TIMEOUT_MS, 240000 ms) even though AI_INSPECTOR_PREVIEW_URL_TEMPLATE already provides a usable URL. This adds a multi-minute delay to task completion, Firestore updates, and Discord notifications in the common non-Vercel-token setup.
Useful? React with 👍 / 👎.
| const queued = await db | ||
| .collection(collectionName) | ||
| .where("status", "==", "queued") | ||
| .orderBy("createdAt", "asc") | ||
| .limit(10) | ||
| .get(); |
There was a problem hiding this comment.
Preserve queue ordering before applying task limit
The query now applies .limit(10) without orderBy("createdAt", "asc"), and only then sorts those 10 docs in memory. When more than 10 tasks are queued, this no longer guarantees oldest-first processing globally, so older requests outside the first limited batch can be delayed significantly (and under sustained load, repeatedly deferred).
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b199b34eae
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const baseBranch = process.env.AI_INSPECTOR_BASE_BRANCH || "main"; | ||
| const collectionName = process.env.AI_INSPECTOR_FIRESTORE_COLLECTION || "aiInspectorTasks"; | ||
|
|
||
| assertCleanWorkingTree(); |
There was a problem hiding this comment.
Reset worktree after task failure
Enforcing assertCleanWorkingTree() at startup causes the worker loop to halt permanently after a single failed task, because failure paths later in main can leave staged/untracked files (the task markdown is written and added before AI execution, and errors like missing codex or the new real-change check can throw afterward) but the catch block never cleans the repo state. In that scenario, every subsequent run fails before claiming a queued task until someone manually cleans the worktree.
Useful? React with 👍 / 👎.
b199b34 to
09eac11
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
.github/scripts/ai-inspector-worker.mjs (2)
290-324:codex명령어 실패 시 에러 메시지 개선을 고려해보세요.
codex가 설치되지 않았거나 실행 실패 시,execFileSync가 던지는 에러 메시지가 사용자에게 명확하지 않을 수 있습니다.
현재 동작
- Line 314에서
codex실행 실패 시 일반적인ENOENT또는 프로세스 에러가 전파됩니다.개선 제안
- try-catch로 감싸서 "Codex CLI가 설치되지 않았거나 실행에 실패했습니다" 같은 명확한 메시지를 제공하면 디버깅이 쉬워집니다.
💡 에러 핸들링 개선 예시
args.push(buildCodexPrompt({ taskId, task, repository, baseBranch, branchName })); - runCommand("codex", args, { env: process.env }); + try { + runCommand("codex", args, { env: process.env }); + } catch (error) { + const message = error?.code === "ENOENT" + ? "Codex CLI is not installed or not in PATH." + : `Codex execution failed: ${error.message}`; + throw new Error(message); + } const summary = fs.existsSync(outputPath) ? fs.readFileSync(outputPath, "utf8").trim() : "";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/scripts/ai-inspector-worker.mjs around lines 290 - 324, The runLocalCodexEdit function should handle failures from the external "codex" invocation more gracefully: wrap the runCommand("codex", args, { env: process.env }) call in a try/catch, and on error throw or return a new error/response that includes a clear, actionable message like "Codex CLI is not installed or failed to run" combined with the original error.message (handle ENOENT specially), and ensure the temporary outputPath is removed in a finally block so fs.rmSync(outputPath, { force: true }) always runs; update references in runLocalCodexEdit to propagate this clearer error instead of letting execFileSync errors bubble raw.
475-484: 불필요한 조건 검사가 있습니다.Line 453의 정규식
vercelUrlPattern이 이미.vercel.app을 포함하는 URL만 매칭하므로, Line 480의.includes(".vercel.app")검사는 항상true입니다.
현재 코드 흐름
matches는 정규식으로 추출되어 항상.vercel.app포함lastKnownVercelUrl = matches[0]이므로.vercel.app보장- Line 480 조건은 항상 참
영향
- 동작에는 문제 없음, 단순 코드 명확성 개선 사항
♻️ 간소화 제안
const matches = body.match(vercelUrlPattern); if (matches && matches.length > 0) { - lastKnownVercelUrl = matches[0]; - if (lastKnownVercelUrl.includes(".vercel.app")) { - return lastKnownVercelUrl; - } + return matches[0]; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/scripts/ai-inspector-worker.mjs around lines 475 - 484, The code performs a redundant check — the vercelUrlPattern regex already matches only URLs containing ".vercel.app", so the `.includes(".vercel.app")` check inside the loop is unnecessary; simplify the for-loop in ai-inspector-worker.mjs by removing the `.includes` conditional and directly assign/return the matched URL (use matches[0] or set lastKnownVercelUrl = matches[0] then return lastKnownVercelUrl) within the loop where vercelUrlPattern and lastKnownVercelUrl are used to keep behavior identical but clearer.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/scripts/ai-inspector-worker.mjs:
- Around line 514-541: The resolvePreviewUrl function calls
getPreviewUrlFromVercel, getPreviewUrlFromGitHubCommitStatus, and
getPreviewUrlFromGitHubPrComments sequentially each with long independent
timeouts causing cumulative delays; change resolvePreviewUrl to enforce a shared
overall deadline (e.g., create a single timeout Promise or deadline timestamp)
and pass a remaining-time or abort signal into each polling function
(getPreviewUrlFromVercel, getPreviewUrlFromGitHubCommitStatus,
getPreviewUrlFromGitHubPrComments) so each call uses the shared deadline and
returns quickly when the global timeout is reached (alternatively set much
smaller per-call timeouts like 60s), ensuring resolvePreviewUrl falls back to
templateUrl when the global deadline expires.
---
Nitpick comments:
In @.github/scripts/ai-inspector-worker.mjs:
- Around line 290-324: The runLocalCodexEdit function should handle failures
from the external "codex" invocation more gracefully: wrap the
runCommand("codex", args, { env: process.env }) call in a try/catch, and on
error throw or return a new error/response that includes a clear, actionable
message like "Codex CLI is not installed or failed to run" combined with the
original error.message (handle ENOENT specially), and ensure the temporary
outputPath is removed in a finally block so fs.rmSync(outputPath, { force: true
}) always runs; update references in runLocalCodexEdit to propagate this clearer
error instead of letting execFileSync errors bubble raw.
- Around line 475-484: The code performs a redundant check — the
vercelUrlPattern regex already matches only URLs containing ".vercel.app", so
the `.includes(".vercel.app")` check inside the loop is unnecessary; simplify
the for-loop in ai-inspector-worker.mjs by removing the `.includes` conditional
and directly assign/return the matched URL (use matches[0] or set
lastKnownVercelUrl = matches[0] then return lastKnownVercelUrl) within the loop
where vercelUrlPattern and lastKnownVercelUrl are used to keep behavior
identical but clearer.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 273845c2-5603-4aed-8e8c-f1481ce74223
📒 Files selected for processing (2)
.github/scripts/ai-inspector-worker.mjsREADME.md
| const resolvePreviewUrl = async ({ token, owner, repo, branchName, commitSha, prNumber }) => { | ||
| const templateUrl = normalizePreviewUrl(getPreviewUrl(branchName)); | ||
|
|
||
| try { | ||
| const vercelApiUrl = normalizePreviewUrl(await getPreviewUrlFromVercel(branchName)); | ||
| if (vercelApiUrl) { | ||
| return vercelApiUrl; | ||
| } | ||
|
|
||
| const commitStatusUrl = normalizePreviewUrl(await getPreviewUrlFromGitHubCommitStatus(token, owner, repo, commitSha)); | ||
| if (commitStatusUrl.includes(".vercel.app")) { | ||
| return commitStatusUrl; | ||
| } | ||
|
|
||
| const commentUrl = normalizePreviewUrl(await getPreviewUrlFromGitHubPrComments(token, owner, repo, prNumber)); | ||
| if (commentUrl) { | ||
| return commentUrl; | ||
| } | ||
|
|
||
| if (commitStatusUrl) { | ||
| return commitStatusUrl; | ||
| } | ||
| } catch (previewError) { | ||
| console.error("Preview URL resolution failed", previewError); | ||
| } | ||
|
|
||
| return templateUrl; | ||
| }; |
There was a problem hiding this comment.
Preview URL 조회 시 타임아웃이 누적될 수 있습니다.
resolvePreviewUrl이 여러 폴링 함수를 순차적으로 호출하는데, 각 함수가 독립적인 타임아웃(기본 240초)을 가지고 있어 최악의 경우 총 ~12분이 소요될 수 있습니다.
-
현재 흐름
getPreviewUrlFromVercel→ 최대 240초getPreviewUrlFromGitHubCommitStatus→ 최대 240초getPreviewUrlFromGitHubPrComments→ 최대 240초- 총합: 최대 720초 (12분)
-
영향
- 워커 실행 시간이 예상보다 길어질 수 있음
- 특히 Vercel API 토큰이 없고, GitHub commit status에도 URL이 없는 경우 발생
-
개선 방안 (선택적)
- 전체 preview 조회에 공유 deadline 적용
- 또는 각 단계별 타임아웃 단축 (예: 60초씩)
💡 공유 deadline 적용 예시
const resolvePreviewUrl = async ({ token, owner, repo, branchName, commitSha, prNumber }) => {
const templateUrl = normalizePreviewUrl(getPreviewUrl(branchName));
+ const totalTimeoutMs = Number(process.env.AI_INSPECTOR_VERCEL_PREVIEW_TIMEOUT_MS ?? "240000");
+ const deadline = Date.now() + totalTimeoutMs;
try {
- const vercelApiUrl = normalizePreviewUrl(await getPreviewUrlFromVercel(branchName));
+ const vercelApiUrl = normalizePreviewUrl(await getPreviewUrlFromVercel(branchName, deadline));
if (vercelApiUrl) {
return vercelApiUrl;
}
+
+ if (Date.now() >= deadline) return templateUrl;
- const commitStatusUrl = normalizePreviewUrl(await getPreviewUrlFromGitHubCommitStatus(token, owner, repo, commitSha));
+ const commitStatusUrl = normalizePreviewUrl(await getPreviewUrlFromGitHubCommitStatus(token, owner, repo, commitSha, deadline));
// ... 이하 동일하게 deadline 전달🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/scripts/ai-inspector-worker.mjs around lines 514 - 541, The
resolvePreviewUrl function calls getPreviewUrlFromVercel,
getPreviewUrlFromGitHubCommitStatus, and getPreviewUrlFromGitHubPrComments
sequentially each with long independent timeouts causing cumulative delays;
change resolvePreviewUrl to enforce a shared overall deadline (e.g., create a
single timeout Promise or deadline timestamp) and pass a remaining-time or abort
signal into each polling function (getPreviewUrlFromVercel,
getPreviewUrlFromGitHubCommitStatus, getPreviewUrlFromGitHubPrComments) so each
call uses the shared deadline and returns quickly when the global timeout is
reached (alternatively set much smaller per-call timeouts like 60s), ensuring
resolvePreviewUrl falls back to templateUrl when the global deadline expires.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 491afd708c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (webPreviewUrl && adminPreviewUrl) { | ||
| return { |
There was a problem hiding this comment.
Return after finding a single preview URL
getPreviewUrlsFromGitHubPrComments only exits early when both web and admin URLs are present, so in environments where only one preview URL is posted (or one app fails to deploy) it will keep polling until timeout (AI_INSPECTOR_VERCEL_PREVIEW_TIMEOUT_MS, default 240000 ms) even after a usable URL was already found. This delays task completion, Firestore updates, and Discord notifications for every affected task.
Useful? React with 👍 / 👎.
|
|
||
| while (Date.now() < deadline) { | ||
| const response = await fetch( | ||
| `https://api.github.com/repos/${owner}/${repo}/issues/${prNumber}/comments?per_page=50`, |
There was a problem hiding this comment.
Paginate PR comments when scanning for Vercel links
The comment scan requests only ?per_page=50 on a single page, so preview URLs are missed whenever the relevant Vercel comment is outside that first page (for example, long-lived PRs with heavy discussion). In that case the worker can incorrectly leave previewWebUrl/previewAdminUrl empty even though the PR already contains valid preview links.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c21d52ada3
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| try { | ||
| const vercelApiUrl = normalizePreviewUrl(await getPreviewUrlFromVercel(branchName)); | ||
| const commitStatusUrl = normalizePreviewUrl(await getPreviewUrlFromGitHubCommitStatus(token, owner, repo, commitSha)); | ||
| const commentPreviewUrls = await getPreviewUrlsFromGitHubPrComments(token, owner, repo, prNumber); |
There was a problem hiding this comment.
Isolate preview source failures before falling back
Keep each preview source fetch independent: these three awaits are wrapped by one try, so if the first or second call throws (for example, invalid VERCEL_TOKEN, GitHub rate-limit, or transient 5xx), the function immediately jumps to catch and returns emptyPreviewUrls without attempting the remaining fallback sources. That means a single provider outage can suppress valid preview links that are still available from GitHub status/comments.
Useful? React with 👍 / 👎.
Summary\n- add local Codex fallback so inspector tasks apply real code changes even without external patch endpoint\n- fail task when only metadata markdown changed (prevents task-only PRs)\n- resolve preview URL from Vercel API or GitHub Vercel commit status and include it in Firestore + Discord notification\n- document new worker env options and runtime requirements\n\n## Verification\n- node --check .github/scripts/ai-inspector-worker.mjs\n- node --check scripts/ai-inspector-worker-loop.mjs\n- local worker run in clean worktree ( WARN Unsupported engine: wanted: {"node":"22.x"} (current: {"node":"v23.10.0","pnpm":"9.0.0"})
ELIFECYCLE Command failed with exit code 1.)\n