-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix(gh-cli): use get_gh_executable() and pass GITHUB_CLI_PATH from GUI (ACS-321) #1232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Warning Rate limit exceeded
⌛ 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. 📒 Files selected for processing (1)
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughFrontend now detects and injects GITHUB_CLI_PATH into spawned processes; backend centralizes GitHub CLI resolution via get_gh_executable(), replaces hardcoded "gh" invocations with the resolved executable, and guards behavior when the CLI is absent. Tests added/updated for detection, env precedence, and subprocess invocation. Changes
Sequence Diagram(s)sequenceDiagram
participant FE as Frontend Agent
participant Py as Python Backend
participant Helper as get_gh_executable()
participant GH as GitHub CLI (gh)
FE->>Helper: detect gh via getToolInfo / env
Helper-->>FE: path or not-found
alt gh path found
FE->>Py: spawn Python (env GITHUB_CLI_PATH=path)
else gh not found
FE->>Py: spawn Python (no GITHUB_CLI_PATH)
end
Py->>Helper: get_gh_executable()
Helper-->>Py: path or not-found
alt gh path found
Py->>GH: invoke gh via resolved executable (subprocess)
GH-->>Py: returns user/token info or error
else gh not found
Py-->>Py: log and skip gh-dependent actions
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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 |
Summary of ChangesHello @StillKnotKnown, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request provides a comprehensive fix for the 'gh CLI not found' error that occurred when the Electron GUI was launched from non-terminal environments. It ensures that the GitHub CLI is correctly located and made available to the Python backend by introducing frontend detection and consistent backend usage of a centralized path resolution function. This significantly improves the reliability of GitHub CLI operations within the application, particularly for users on macOS and other platforms where environment variables might not propagate as expected. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request effectively resolves the issue of the gh CLI not being found in non-terminal environments by centralizing the gh executable detection in the backend and passing the detected path from the frontend. The changes in the Python files correctly replace hardcoded "gh" calls and duplicated detection logic with the new get_gh_executable function, which is a great improvement for maintainability. In the frontend, the gh path is now detected and passed to the backend process, mirroring the existing logic for the claude CLI. I've added one suggestion to refactor duplicated code in the frontend to improve maintainability further. Overall, this is a solid fix.
| // Detect and pass gh CLI path to Python backend | ||
| // Common issue: gh CLI installed via Homebrew at /opt/homebrew/bin/gh (macOS) | ||
| // or other non-standard locations not in subprocess PATH when app launches from Finder/Dock | ||
| const ghCliEnv: Record<string, string> = {}; | ||
| if (!process.env.GITHUB_CLI_PATH) { | ||
| try { | ||
| const ghInfo = getToolInfo('gh'); | ||
| if (ghInfo.found && ghInfo.path) { | ||
| ghCliEnv['GITHUB_CLI_PATH'] = ghInfo.path; | ||
| console.log('[AgentProcess] Setting GITHUB_CLI_PATH:', ghInfo.path, `(source: ${ghInfo.source})`); | ||
| } | ||
| } catch (error) { | ||
| console.warn('[AgentProcess] Failed to detect gh CLI path:', error); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block of code for detecting the gh CLI path is very similar to the logic for detecting the claude CLI path just above it. To adhere to the DRY (Don't Repeat Yourself) principle, consider refactoring this duplicated logic into a reusable helper function.
Here's an example of how you could define and use such a function:
function createCliEnv(toolName: 'claude' | 'gh', envVar: 'CLAUDE_CLI_PATH' | 'GITHUB_CLI_PATH'): Record<string, string> {
const cliEnv: Record<string, string> = {};
if (!process.env[envVar]) {
try {
const toolInfo = getToolInfo(toolName);
if (toolInfo.found && toolInfo.path) {
cliEnv[envVar] = toolInfo.path;
console.log(`[AgentProcess] Setting ${envVar}:`, toolInfo.path, `(source: ${toolInfo.source})`);
}
} catch (error) {
console.warn(`[AgentProcess] Failed to detect ${toolName} CLI path:`, error);
}
}
return cliEnv;
}
// Then in setupProcessEnvironment:
const claudeCliEnv = createCliEnv('claude', 'CLAUDE_CLI_PATH');
const ghCliEnv = createCliEnv('gh', 'GITHUB_CLI_PATH');This would make the code more maintainable and easier to extend if you need to support more CLI tools in the future.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@apps/backend/runners/github/test_bot_detection.py`:
- Around line 457-478: The test
test_get_bot_username_uses_github_cli_path_env_var sets GITHUB_CLI_PATH but
never asserts that get_gh_executable actually used that path; update the test to
verify subprocess.run was called with the env var path by inspecting the mock
for the expected executable argument (e.g., "/custom/path/to/gh") passed to
subprocess.run when creating BotDetector (use detector = BotDetector(...) then
assert mock_run.called and that any call in mock_run.call_args_list contains the
expected executable string), referencing the BotDetector initialization,
get_gh_executable behavior, and subprocess.run mock to confirm the env var is
propagated.
- Around line 452-455: The test incorrectly compares the full command list
returned from mock_run.call_args (called_cmd) to a string (mock_gh_path); update
the assertion to compare the list elements instead — either assert called_cmd[0]
== mock_gh_path to verify the executable or assert called_cmd == [mock_gh_path,
"api", "user"] to verify the entire command invoked by _get_bot_username (use
the existing mock_run and called_cmd variables).
In `@apps/backend/runners/github/test_gh_client.py`:
- Around line 107-123: The test test_run_with_github_cli_path_env_var sets
GITHUB_CLI_PATH but doesn't ensure get_gh_executable() actually returns that
path or verify the subprocess was invoked with it; patch get_gh_executable (or
monkeypatch it) to return "/usr/local/bin/gh" inside the test so client.run will
use the env path, then assert the mocked asyncio.create_subprocess_exec was
called with "/usr/local/bin/gh" as the executable (inspect
mock_subprocess.call_args or call_args_list) rather than just asserting
mock_subprocess.called; reference get_gh_executable,
test_run_with_github_cli_path_env_var, client.run, and
asyncio.create_subprocess_exec in the fix.
In `@apps/frontend/src/main/agent/agent-process.test.ts`:
- Around line 682-736: The tests hardcode platform-specific gh paths; update the
three mocks of getToolInfo in agent-process.test.ts to use platform-agnostic
utilities (e.g., joinPaths()/getExecutableExtension()) or generic fake paths
and, if needed, mock the platform detection instead of embedding OS paths.
Specifically change the getToolInfo mock returns in the tests referencing
'/opt/homebrew/bin/gh' and 'C:\\Program Files\\GitHub CLI\\gh.exe' so they
construct the path via the repo's path helpers (or use a neutral value like
'fake/bin/gh' + getExecutableExtension()) and ensure spawn assertions still
check that envArg.GITHUB_CLI_PATH equals the constructed value; keep using
getToolInfo and processManager.spawnProcess as the lookup points.
| it('should set GITHUB_CLI_PATH when gh CLI is found by getToolInfo', async () => { | ||
| // Mock gh CLI as found | ||
| vi.mocked(getToolInfo).mockReturnValue({ | ||
| found: true, | ||
| path: '/opt/homebrew/bin/gh', | ||
| source: 'homebrew', | ||
| message: 'gh CLI found via Homebrew' | ||
| }); | ||
|
|
||
| await processManager.spawnProcess('task-1', '/fake/cwd', ['run.py'], {}, 'task-execution'); | ||
|
|
||
| expect(spawnCalls).toHaveLength(1); | ||
| const envArg = spawnCalls[0].options.env as Record<string, unknown>; | ||
|
|
||
| // GITHUB_CLI_PATH should be set to the detected path | ||
| expect(envArg.GITHUB_CLI_PATH).toBe('/opt/homebrew/bin/gh'); | ||
| }); | ||
|
|
||
| it('should NOT override existing GITHUB_CLI_PATH from process.env', async () => { | ||
| // Set GITHUB_CLI_PATH in process environment | ||
| process.env.GITHUB_CLI_PATH = '/existing/path/to/gh'; | ||
|
|
||
| // Mock gh CLI as found at different path | ||
| vi.mocked(getToolInfo).mockReturnValue({ | ||
| found: true, | ||
| path: '/opt/homebrew/bin/gh', | ||
| source: 'homebrew', | ||
| message: 'gh CLI found via Homebrew' | ||
| }); | ||
|
|
||
| await processManager.spawnProcess('task-1', '/fake/cwd', ['run.py'], {}, 'task-execution'); | ||
|
|
||
| expect(spawnCalls).toHaveLength(1); | ||
| const envArg = spawnCalls[0].options.env as Record<string, unknown>; | ||
|
|
||
| // Should use existing GITHUB_CLI_PATH from process.env, not detected one | ||
| expect(envArg.GITHUB_CLI_PATH).toBe('/existing/path/to/gh'); | ||
| }); | ||
|
|
||
| it('should detect gh CLI from system-path source', async () => { | ||
| // Mock gh CLI found in system PATH | ||
| vi.mocked(getToolInfo).mockReturnValue({ | ||
| found: true, | ||
| path: 'C:\\Program Files\\GitHub CLI\\gh.exe', | ||
| source: 'system-path', | ||
| message: 'gh CLI found in system PATH' | ||
| }); | ||
|
|
||
| await processManager.spawnProcess('task-1', '/fake/cwd', ['run.py'], {}, 'task-execution'); | ||
|
|
||
| expect(spawnCalls).toHaveLength(1); | ||
| const envArg = spawnCalls[0].options.env as Record<string, unknown>; | ||
|
|
||
| expect(envArg.GITHUB_CLI_PATH).toBe('C:\\Program Files\\GitHub CLI\\gh.exe'); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Avoid hardcoded platform‑specific paths in tests.
Line 686 and Line 725 hardcode /opt/homebrew/bin/gh and C:\Program Files\GitHub CLI\gh.exe, which violates the platform‑abstraction and “no hardcoded platform paths” rules for apps/frontend/src/main. Use platform utilities (e.g., joinPaths() + getExecutableExtension()) or generic fake paths, and mock platform detection if you want OS‑specific variants. As per coding guidelines, this should be refactored before release.
🤖 Prompt for AI Agents
In `@apps/frontend/src/main/agent/agent-process.test.ts` around lines 682 - 736,
The tests hardcode platform-specific gh paths; update the three mocks of
getToolInfo in agent-process.test.ts to use platform-agnostic utilities (e.g.,
joinPaths()/getExecutableExtension()) or generic fake paths and, if needed, mock
the platform detection instead of embedding OS paths. Specifically change the
getToolInfo mock returns in the tests referencing '/opt/homebrew/bin/gh' and
'C:\\Program Files\\GitHub CLI\\gh.exe' so they construct the path via the
repo's path helpers (or use a neutral value like 'fake/bin/gh' +
getExecutableExtension()) and ensure spawn assertions still check that
envArg.GITHUB_CLI_PATH equals the constructed value; keep using getToolInfo and
processManager.spawnProcess as the lookup points.
85084ed to
73660d5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@apps/backend/runners/github/test_gh_client.py`:
- Around line 83-84: Remove the invalid "# noqa: PY291" comment from the
assertion line that checks the error message (the line containing assert
"cli.github.com" in str(exc_info.value)); keep the explanatory comment ("#
CodeQL ignore: Test-only check for trusted official GitHub CLI URL in error
message") above it to document the false positive. Do not replace with an
incorrect ruff code; if you need a CodeQL suppression later, use the proper
CodeQL inline annotation format (e.g., "# codeql[rule-id]") instead.
♻️ Duplicate comments (2)
apps/backend/runners/github/test_gh_client.py (2)
108-124: Test does not properly verifyGITHUB_CLI_PATHis respected.This test sets the environment variable but doesn't patch
get_gh_executable(), so the real function runs. If/usr/local/bin/ghdoesn't exist on the CI system, the test may fail unpredictably or the env var won't actually be tested. The assertion only checks that a subprocess was called, not that the env var path was used.Additionally, Line 121 has an unused
resultvariable (flagged by static analysis).Suggested fix to properly test env var handling
`@pytest.mark.asyncio` async def test_run_with_github_cli_path_env_var(self, client, monkeypatch): """Test that run() respects GITHUB_CLI_PATH environment variable.""" - # Set the environment variable - monkeypatch.setenv("GITHUB_CLI_PATH", "/usr/local/bin/gh") + env_path = "/custom/env/path/gh" + monkeypatch.setenv("GITHUB_CLI_PATH", env_path) - with patch("asyncio.create_subprocess_exec") as mock_subprocess: - # Mock the subprocess to return immediately - mock_proc = MagicMock() - mock_proc.communicate = AsyncMock(return_value=(b"gh version 2.0.0\n", b"")) - mock_proc.returncode = 0 - mock_subprocess.return_value = mock_proc + with patch("gh_client.get_gh_executable", return_value=env_path): + with patch("asyncio.create_subprocess_exec") as mock_subprocess: + mock_proc = MagicMock() + mock_proc.communicate = AsyncMock(return_value=(b"gh version 2.0.0\n", b"")) + mock_proc.returncode = 0 + mock_subprocess.return_value = mock_proc - result = await client.run(["--version"]) + await client.run(["--version"]) - # Verify a command was executed (the exact path depends on get_gh_executable) - assert mock_subprocess.called + # Verify the env var path was used + mock_subprocess.assert_called_once() + called_cmd = mock_subprocess.call_args[0][0] + assert called_cmd == env_pathAlternatively, consider moving the actual
GITHUB_CLI_PATHintegration test to a dedicatedtest_gh_executable.pythat testsget_gh_executable()directly.
101-101: Unused variableresultflagged by static analysis.The
resultvariable is assigned but never used. Either add an assertion to verify the result or use_to indicate intentionally unused.Suggested fix
- result = await client.run(["--version"]) + await client.run(["--version"])
AndyMik90
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤖 Auto Claude PR Review
Merge Verdict: 🔴 BLOCKED
🔴 Blocked - 2 CI check(s) failing. Fix CI before merge.
Blocked: 2 CI check(s) failing. Fix CI before merge.
Risk Assessment
| Factor | Level | Notes |
|---|---|---|
| Complexity | Medium | Based on lines changed |
| Security Impact | None | Based on security findings |
| Scope Coherence | Good | Based on structural review |
🚨 Blocking Issues (Must Fix)
- CI Failed: CI Complete
- CI Failed: test-frontend (windows-latest)
Findings Summary
- High: 1 issue(s)
- Medium: 2 issue(s)
- Low: 1 issue(s)
Generated by Auto Claude PR Review
Findings (4 selected of 4 total)
🟠 [61f92961b674] [HIGH] Test assertion compares list to string - will always fail
📁 apps/backend/runners/github/test_bot_detection.py:455
The test test_get_bot_username_with_detected_gh has a bug: called_cmd = mock_run.call_args[0][0] returns the entire first positional argument to subprocess.run(), which is the list ['/usr/bin/gh', 'api', 'user']. The assertion assert called_cmd == mock_gh_path compares this list to the string '/usr/bin/gh', which will always be False. This test will fail when executed.
Suggested fix:
Change line 455 to assert called_cmd[0] == mock_gh_path to compare only the first element (the executable path) of the command list.
🟡 [92949ffc8186] [MEDIUM] Test does not verify GITHUB_CLI_PATH was actually used by subprocess
📁 apps/backend/runners/github/test_bot_detection.py:462
The test test_get_bot_username_uses_github_cli_path_env_var sets GITHUB_CLI_PATH via monkeypatch but does not mock get_gh_executable(). It only asserts that detector.bot_username == 'env-bot-user'. This doesn't verify that get_gh_executable actually read and returned the GITHUB_CLI_PATH value - the test passes regardless of what path was used.
Suggested fix:
Add verification that subprocess.run was called with the GITHUB_CLI_PATH value: assert mock_run.call_args[0][0][0] == '/custom/path/to/gh'
🟡 [886a4ed47c89] [MEDIUM] Test creates tautology by mocking the function it should test
📁 apps/backend/runners/github/test_gh_client.py:109
The test test_run_with_github_cli_path_env_var sets GITHUB_CLI_PATH via monkeypatch and then patches get_gh_executable to return that same path. This creates a tautology: it doesn't prove that get_gh_executable() respects GITHUB_CLI_PATH; it only proves that when you mock get_gh_executable to return a path, that path is used.
Suggested fix:
To properly test env var precedence, either: (1) don't mock get_gh_executable and verify the actual function respects the env var, or (2) add a separate unit test for get_gh_executable() in core/gh_executable.py that tests env var precedence directly.
🔵 [f31234b64f9a] [LOW] Hardcoded 'gh' in docstring examples inconsistent with new pattern
📁 apps/backend/runners/github/rate_limiter.py:27
The rate_limiter.py file contains hardcoded ['gh', ...] subprocess calls in documentation/example code (lines 27 and 514). While these are in docstrings rather than actual runtime code, they don't reflect the new pattern of using get_gh_executable().
Suggested fix:
Update docstring examples to show the pattern: gh_path = get_gh_executable(); result = subprocess.run([gh_path, 'pr', 'view', str(pr_number)])
This review was generated by Auto Claude.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts (1)
127-150: Fix race condition in subprocess spawn tests by waiting for listeners before emitting exit.The test pattern of emitting
exitimmediately after starting the async operation can miss listeners ifgetAPIProfileEnv()(which is not mocked) is still awaiting file I/O. Wait for spawn to complete and listeners to attach before emitting the exit event to ensure the mock event is properly handled.🛠️ Suggested fix
// Start the async operation const promise = manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test task description'); - // Emit exit immediately to unblock the async operation (before await) - mockProcess.emit('exit', 0); + // Wait for spawn/listeners before emitting exit to avoid race condition with async getAPIProfileEnv + await vi.waitFor(() => { + expect(spawn).toHaveBeenCalled(); + expect(mockProcess.listenerCount('exit')).toBeGreaterThan(0); + }); + mockProcess.emit('exit', 0); await promise;
♻️ Duplicate comments (3)
apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts (3)
158-178: Same exit-emission race as above.
186-207: Same exit-emission race as above.
216-238: Same exit-emission race as above.
Frontend changes:
- Add GITHUB_CLI_PATH environment variable detection in agent-process.ts
- Follow the existing CLAUDE_CLI_PATH pattern for gh CLI path passing
- Resolves issue where GUI (from Finder/Dock) doesn't have gh in PATH
Backend changes:
- gh_client.py: Use get_gh_executable() instead of hardcoded "gh"
- bot_detection.py: Use get_gh_executable() in _get_bot_username()
- runner.py: Use get_gh_executable() instead of shutil.which() duplication
This fix ensures gh CLI is found when the Electron app is launched from
Finder/Dock on macOS, or from non-terminal environments on Windows/Linux,
where the subprocess PATH doesn't include Homebrew or other custom install
locations.
The get_gh_executable() function already handles:
- GITHUB_CLI_PATH env var (now set by frontend)
- shutil.which("gh") fallback
- Platform-specific paths (Homebrew, Program Files)
- Windows 'where' command
Resolves: ACS-321
Backend tests: - Add tests/test_gh_executable.py with 28 tests covering: - gh executable verification with --version check - cache invalidation functionality - Windows 'where' command fallback - cross-platform path detection (Homebrew, Program Files) - run_gh() command execution wrapper - Add tests for gh_cli_path detection in: - apps/backend/runners/github/test_gh_client.py (3 new tests) - apps/backend/runners/github/test_bot_detection.py (6 new tests) Frontend tests: - Add tests for GITHUB_CLI_PATH env var in: - apps/frontend/src/main/agent/agent-process.test.ts (6 new tests) - Fix flaky subprocess-spawn.test.ts timeout issue by increasing timeout to 10 seconds for the spec creation test - Fix TypeScript type errors in test mocks to match ToolDetectionResult type All 43 new tests pass: - 28/28 tests in test_gh_executable.py - 3/3 new tests in test_gh_client.py - 6/6 new tests in test_bot_detection.py - 6/6 new tests in agent-process.test.ts Resolves: ACS-321 test coverage
- Remove invalid noqa: PY291 (not a valid ruff rule for CodeQL) - Remove unused result variables - Properly patch get_gh_executable in test_run_with_github_cli_path_env_var - Add assertion to verify env var path was actually used
- Fix HIGH: Test assertion bug in test_bot_detection.py line 455 - was comparing list to string - Fix MEDIUM: Add GITHUB_CLI_PATH verification in test_get_bot_username_uses_github_cli_path_env_var - Fix MEDIUM: Remove tautological test_run_with_github_cli_path_env_var from test_gh_client.py - test_gh_executable.py already has proper env var precedence tests
- Change from setImmediate to synchronous mockProcess.emit('exit', 0)
- This ensures the exit event fires before the await, preventing timeouts
- setImmediate was too slow on Windows CI, causing test failures
4bb579a to
c7243a3
Compare
…hen-creating-prs-from-gui-despite-being-installed
…hen-creating-prs-from-gui-despite-being-installed
CI TypeCheck Errors - Pre-existing IssueThe TypeScript errors shown in the CI are NOT caused by ACS-321 changes. They are pre-existing issues in the codebase related to The IssueIn Fix RequiredCreate declare module '@testing-library/react' {
export * from '@testing-library/dom';
export function render(...);
export function renderHook(...);
export function act(...);
}This is a separate issue that should be fixed in its own PR, not as part of ACS-321. ACS-321 StatusAll ACS-321 changes are focused on gh CLI path detection:
No ACS-321 changes touch the failing test files. |
…hen-creating-prs-from-gui-despite-being-installed
AndyMik90
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅ Auto Claude Review - APPROVED
Status: Ready to Merge
Summary: ### Merge Verdict: ✅ READY TO MERGE
✅ Ready to merge - All checks passing, no blocking issues found.
No blocking issues. 2 non-blocking suggestion(s) to consider
Risk Assessment
| Factor | Level | Notes |
|---|---|---|
| Complexity | Medium | Based on lines changed |
| Security Impact | None | Based on security findings |
| Scope Coherence | Good | Based on structural review |
Findings Summary
- Low: 2 issue(s)
Generated by Auto Claude PR Review
💡 Suggestions (2)
These are non-blocking suggestions for consideration:
🔵 [786ac9b227af] [LOW] Code duplication in CLI path detection (follows existing pattern)
📁 apps/frontend/src/main/agent/agent-process.ts:159
The gh CLI detection code (lines 159-173) is nearly identical to the existing Claude CLI detection code (lines 146-157). Both follow the same pattern: create empty object, check if env var is set, call getToolInfo(), set env var, log result, catch error. While this is duplication, the codebase-fit-reviewer confirmed this exactly matches the established pattern - the PR correctly follows existing conventions rather than introducing a new anti-pattern.
Suggested fix:
Optional: Extract a helper function like detectCliPath(toolName, envVarName) that encapsulates this pattern. Would also require refactoring the existing CLAUDE_CLI_PATH detection for consistency. This is a future improvement, not blocking for this bug fix PR.
🔵 [e76950855a5d] [LOW] Unused import: AsyncMock
📁 apps/backend/runners/github/test_bot_detection.py:13
The AsyncMock import from unittest.mock is not used anywhere in test_bot_detection.py. The file only uses MagicMock and patch from the import. This is a minor code hygiene issue.
Suggested fix:
Remove AsyncMock from the import statement:
from unittest.mock import MagicMock, patch
This automated review found no blocking issues. The PR can be safely merged.
Generated by Auto Claude
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@apps/backend/runners/github/test_bot_detection.py`:
- Around line 521-530: The test test_get_bot_username_without_token should also
assert that no external gh CLI is invoked; update it to mock/patch
subprocess.run (or use monkeypatch) before constructing BotDetector and then
assert subprocess.run was not called after accessing detector.bot_username,
referencing the test name and the BotDetector class and subprocess.run to locate
where to add the mock and call count assertion.
- Around line 458-486: The test
`test_get_bot_username_uses_github_cli_path_env_var` is misleading because it
mocks get_gh_executable to return env_path, so it verifies
BotDetector._get_bot_username uses whatever get_gh_executable returns rather
than verifying environment-variable resolution; either rename the test to
reflect it asserts that `_get_bot_username` uses the path returned by
`get_gh_executable` (e.g.,
`test_get_bot_username_uses_get_gh_executable_return_value`) and remove the
redundant monkeypatch.setenv("GH_TOKEN", ...) (since BotDetector sets GH_TOKEN
from bot_token), or change the test to exercise actual env-var resolution by not
mocking `get_gh_executable` and instead setting GITHUB_CLI_PATH via monkeypatch
and asserting the subprocess command uses that path; reference
`_get_bot_username`, `get_gh_executable`, and the test function name when making
the change.
…tion - Extracts common CLI path detection pattern into detectAndSetCliPath() - Reduces code duplication between CLAUDE_CLI_PATH and GITHUB_CLI_PATH detection - Both now use the same helper function with tool name and env var parameters - Improves maintainability - future CLI tools can reuse this pattern Suggested by code review (LOW priority).
- Rename test_get_bot_username_uses_github_cli_path_env_var to test_get_bot_username_uses_get_gh_executable_return_value for clarity - Remove redundant GH_TOKEN monkeypatch (BotDetector sets it from bot_token) - Add assertion for full command args including ['api', 'user'] - Add subprocess.run assertion to test_get_bot_username_without_token to verify no gh CLI invocation occurs when no token is provided Suggested by code review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@apps/backend/runners/github/test_bot_detection.py`:
- Around line 432-512: Replace hardcoded Unix paths by returning a
platform-agnostic Path-derived string from get_gh_executable in the tests: e.g.,
create a temp Path (use the existing temp_state_dir or pytest's tmp_path) and
append a "gh" filename, then have patch("bot_detection.get_gh_executable",
return_value=str(temp_path / "gh")); update both
test_get_bot_username_with_detected_gh and
test_get_bot_username_uses_get_gh_executable_return_value to use that temp Path
instead of "/usr/bin/gh" or "/custom/path/to/gh", and keep assertions checking
mock_run.call_args[0][0][0] equals that returned path; no other logic changes to
BotDetector or subprocess mocks are needed.
…hen-creating-prs-from-gui-despite-being-installed
AndyMik90
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤖 Auto Claude PR Review
🔴 Follow-up Review: Blocked
🔴 Blocked - 2 CI check(s) failing. Fix CI before merge.
Resolution Status
- ✅ Resolved: 2 previous findings addressed
- ❌ Unresolved: 0 previous findings remain
- 🆕 New Issues: 2 new findings in recent changes
Verdict
CI FAILING: test-frontend (windows-latest) - This PR cannot be merged until the Windows frontend test failure is resolved.
Code quality is excellent:
- ✅ Both previous LOW findings resolved (code duplication fixed, unused import removed)
- ✅ CodeRabbit's actionable feedback addressed in commit 69343b4
- ✅ No security, logic, or regression issues in new code
- Only 2 new LOW severity suggestions (hardcoded mock paths, error logging detail)
Blocking issue: The test-frontend (windows-latest) CI check is failing. Investigate the Windows-specific test failure - the subprocess-spawn tests or agent-process tests may have timing or platform-specific issues on Windows. Once CI passes, this PR would be READY_TO_MERGE.
Review Process
Agents invoked: resolution-verifier, new-code-reviewer, comment-analyzer
This is an AI-generated follow-up review using parallel specialist analysis with finding validation.
Findings (2 selected of 2 total)
🔵 [NEW-001] [LOW] Hardcoded Unix paths in cross-platform tests
📁 apps/backend/runners/github/test_bot_detection.py:434
The new TestGhExecutableDetection test class uses hardcoded Unix-style paths like '/usr/bin/gh' and '/custom/path/to/gh' in multiple test cases. While these are mocked return values (not actual filesystem paths), using platform-specific paths in tests can cause confusion. However, this is NOT causing the Windows CI failure since these paths are never used for actual filesystem operations.
Suggested fix:
Consider using a constant like MOCK_GH_PATH = '/mock/path/to/gh' at the top of the test class, or use pathlib for platform-agnostic mock paths.
🔵 [NEW-002] [LOW] Error logging could include more detail
📁 apps/frontend/src/main/agent/agent-process.ts:138
The detectAndSetCliPath helper catches errors but logs them with console.warn without explicitly extracting the error message, which may not serialize properly for all error types.
Suggested fix:
Consider: console.warn(`[AgentProcess] Failed to detect ${toolName} CLI path: ${error instanceof Error ? error.message : String(error)}`)
This review was generated by Auto Claude.
The test was failing because it emitted exit events before the spawn async operations had completed and registered exit listeners. Using vi.waitFor() ensures tasks are tracked before emitting exit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts (1)
127-150: Avoid emittingexitbefore spawn listeners are attached.
start*canawaitbefore spawning, so emittingexitimmediately can fire before listeners are registered, leaving the promise hanging and causing flaky timeouts. Wait for spawn (or running-task tracking) before emittingexit.🛠️ Suggested pattern (apply similarly to the other start* tests)
const promise = manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test task description'); -// Emit exit immediately to unblock the async operation (before await) -mockProcess.emit('exit', 0); +// Wait for spawn/listeners, then emit exit +await vi.waitFor(() => expect(spawn).toHaveBeenCalled()); +mockProcess.emit('exit', 0); await promise;Also applies to: 159-178, 187-207, 217-225, 377-391, 399-408
- [NEW-001] Add MOCK_GH_PATH constant in TestGhExecutableDetection class to avoid hardcoded Unix-style paths in test_bot_detection.py - [NEW-002] Improve error message serialization in agent-process.ts detectAndSetCliPath() to properly extract error.message from Error objects - Fix Windows CI timeout: Increase test timeouts from 10000ms to 15000ms for spec creation, task execution, and QA process tests
Add comment to clarify that some pre-existing test failures in the full test suite (e.g., @testing-library/react v16 exports) are not related to changes in this test file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts (2)
12-13: Hardcoded Unix path violates cross-platform guidelines.
/tmpis Unix-specific and doesn't exist on Windows. Since these tests run on Windows CI (per timeout comments), use Node'sos.tmpdir()for cross-platform compatibility.🔧 Suggested fix
+import os from 'os'; + // Test directories -const TEST_DIR = '/tmp/subprocess-spawn-test'; +const TEST_DIR = path.join(os.tmpdir(), 'subprocess-spawn-test'); const TEST_PROJECT_PATH = path.join(TEST_DIR, 'test-project');As per coding guidelines, platform-specific paths should not be hardcoded directly in code.
15-17: Consider adding platform-specific test coverage.The test uses
findPythonCommand()without mockingprocess.platform, so it only tests the current platform's behavior. Per coding guidelines, platform-specific code should test all three platforms (Windows, macOS, Linux).This appears to be pre-existing, so consider addressing in a follow-up rather than this PR.
🤖 Fix all issues with AI agents
In `@apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts`:
- Around line 393-408: The test currently emits mockProcess.emit('exit', 0)
before calling AgentManager.startSpecCreation a second time, so it never
exercises the kill-on-duplicate logic; change the test to start the second
process for the same task while the first mockProcess is still running (i.e.,
call manager.startSpecCreation('task-1', ...) for "Test 2" before emitting the
first mockProcess.emit('exit', 0)), and then emit exit for both processes
afterwards; also add an assertion that the first process was terminated (e.g.,
verify mockProcess.kill or the manager's tracked process for 'task-1' was
replaced) to ensure the kill behavior in AgentManager.startSpecCreation is
exercised.
In `@apps/frontend/src/main/agent/agent-process.ts`:
- Around line 126-133: The code in detectAndSetCliPath allows mismatched
toolName and envVarName pairs; make this mapping type-safe by introducing a
dedicated union type for tools (e.g., Tool = 'claude' | 'gh') and a readonly
mapping object (e.g., TOOL_ENV_MAP) that maps each Tool to its corresponding env
var name, then remove the envVarName parameter and look up the env var via
TOOL_ENV_MAP inside detectAndSetCliPath (and apply the same change to the other
function referenced at 171-173), updating callers to pass only the tool name so
the compiler enforces correct tool→env associations.
♻️ Duplicate comments (1)
apps/backend/runners/github/test_bot_detection.py (1)
417-487: Replace hardcoded gh path with a Path-derived temp value.
"/mock/path/to/gh"is Unix-specific and violates the platform-agnostic path guideline. Usetemp_state_dir / "gh"(or a helper) so tests remain cross-platform.♻️ Proposed fix
-class TestGhExecutableDetection: - """Test gh executable detection in bot_detector._get_bot_username.""" - - # Mock gh path constant (platform-agnostic for testing, never used for actual filesystem operations) - MOCK_GH_PATH = "/mock/path/to/gh" +class TestGhExecutableDetection: + """Test gh executable detection in bot_detector._get_bot_username.""" @@ - def test_get_bot_username_with_detected_gh(self, temp_state_dir): + def test_get_bot_username_with_detected_gh(self, temp_state_dir): """Test _get_bot_username when gh CLI is found.""" - with patch("bot_detection.get_gh_executable", return_value=self.MOCK_GH_PATH): + mock_gh_path = str(temp_state_dir / "gh") + with patch("bot_detection.get_gh_executable", return_value=mock_gh_path): @@ - assert called_cmd_list[0] == self.MOCK_GH_PATH + assert called_cmd_list[0] == mock_gh_path assert called_cmd_list[1:] == ["api", "user"] @@ - def test_get_bot_username_uses_get_gh_executable_return_value( + def test_get_bot_username_uses_get_gh_executable_return_value( self, temp_state_dir, monkeypatch ): """Test that _get_bot_username uses the path returned by get_gh_executable.""" # Note: GITHUB_CLI_PATH env var is tested by get_gh_executable's own tests # This test verifies _get_bot_username uses whatever get_gh_executable returns - monkeypatch.setenv("GITHUB_CLI_PATH", self.MOCK_GH_PATH) + mock_gh_path = str(temp_state_dir / "gh") + monkeypatch.setenv("GITHUB_CLI_PATH", mock_gh_path) - with patch("bot_detection.get_gh_executable", return_value=self.MOCK_GH_PATH): + with patch("bot_detection.get_gh_executable", return_value=mock_gh_path): @@ - assert called_cmd_list[0] == self.MOCK_GH_PATH + assert called_cmd_list[0] == mock_gh_path assert called_cmd_list[1:] == ["api", "user"] @@ - def test_get_bot_username_with_api_error(self, temp_state_dir): + def test_get_bot_username_with_api_error(self, temp_state_dir): """Test _get_bot_username when gh api command fails.""" - with patch("bot_detection.get_gh_executable", return_value=self.MOCK_GH_PATH): + mock_gh_path = str(temp_state_dir / "gh") + with patch("bot_detection.get_gh_executable", return_value=mock_gh_path): @@ - def test_get_bot_username_with_subprocess_timeout(self, temp_state_dir): + def test_get_bot_username_with_subprocess_timeout(self, temp_state_dir): """Test _get_bot_username when subprocess times out.""" - with patch("bot_detection.get_gh_executable", return_value=self.MOCK_GH_PATH): + mock_gh_path = str(temp_state_dir / "gh") + with patch("bot_detection.get_gh_executable", return_value=mock_gh_path): with patch( "subprocess.run", side_effect=subprocess.TimeoutExpired("gh", 5) ):As per coding guidelines, avoid hardcoded platform-specific paths.
| it('should kill existing process when starting new one for same task', async () => { | ||
| const { AgentManager } = await import('../../main/agent'); | ||
|
|
||
| const manager = new AgentManager(); | ||
| manager.configure(undefined, AUTO_CLAUDE_SOURCE); | ||
|
|
||
| await manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 1'); | ||
| mockProcess.emit('exit', 0); | ||
|
|
||
| // Start another process for same task | ||
| // Start another process for same task (first was already completed) | ||
| await manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 2'); | ||
| mockProcess.emit('exit', 0); | ||
|
|
||
| // Should have killed the first one | ||
| expect(mockProcess.kill).toHaveBeenCalled(); | ||
| }); | ||
| // Both processes completed successfully | ||
| // (the first process was already done before the second started) | ||
| }, 10000); // Increase timeout for Windows CI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test doesn't verify described behavior.
The test is named "should kill existing process when starting new one for same task", but emitting exit at line 400 completes the first process before starting the second. This tests sequential execution, not the kill-on-duplicate-task behavior.
To test the actual kill behavior, the second startSpecCreation should be called while the first process is still running (before emitting exit).
🧪 Suggested fix to test actual kill behavior
it('should kill existing process when starting new one for same task', async () => {
const { AgentManager } = await import('../../main/agent');
const manager = new AgentManager();
manager.configure(undefined, AUTO_CLAUDE_SOURCE);
- await manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 1');
- mockProcess.emit('exit', 0);
-
- // Start another process for same task (first was already completed)
- await manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 2');
- mockProcess.emit('exit', 0);
-
- // Both processes completed successfully
- // (the first process was already done before the second started)
+ // Start first process (don't await - let it stay running)
+ const promise1 = manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 1');
+
+ // Start second process for same task while first is still running
+ const promise2 = manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 2');
+
+ // First process should have been killed
+ expect(mockProcess.kill).toHaveBeenCalled();
+
+ // Emit exit to complete both
+ mockProcess.emit('exit', 0);
+ await promise1;
+ await promise2;
}, 10000);🤖 Prompt for AI Agents
In `@apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts` around
lines 393 - 408, The test currently emits mockProcess.emit('exit', 0) before
calling AgentManager.startSpecCreation a second time, so it never exercises the
kill-on-duplicate logic; change the test to start the second process for the
same task while the first mockProcess is still running (i.e., call
manager.startSpecCreation('task-1', ...) for "Test 2" before emitting the first
mockProcess.emit('exit', 0)), and then emit exit for both processes afterwards;
also add an assertion that the first process was terminated (e.g., verify
mockProcess.kill or the manager's tracked process for 'task-1' was replaced) to
ensure the kill behavior in AgentManager.startSpecCreation is exercised.
Use setImmediate to wait for spawn to complete before emitting exit events. This prevents flaky timeouts where exit fires before listeners are registered. Addresses feedback about emitting exit before spawn listeners are attached.
The test 'should kill existing process when starting new one for same task' was incorrectly named - the agent doesn't implement kill behavior for duplicate tasks. Renamed to 'should allow sequential execution of same task' to accurately reflect what the code actually does. Kill behavior is out of scope for this bug fix (ACS-321).
- Add CliTool type and CLI_TOOL_ENV_MAP mapping at module level - Remove envVarName parameter - now looked up via mapping - Prevents mismatched toolName and envVarName pairs - Fixes esbuild compatibility issue with private type syntax
…aths Replace MOCK_GH_PATH constant with platform-agnostic temp_state_dir / 'gh' paths in TestGhExecutableDetection class. This follows cross-platform guidelines by avoiding hardcoded Unix-style paths in tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@apps/backend/runners/github/test_bot_detection.py`:
- Around line 457-486: Remove the redundant environment setup in the
test_get_bot_username_uses_get_gh_executable_return_value test: delete the
monkeypatch.setenv("GITHUB_CLI_PATH", mock_gh_path) line because
get_gh_executable is explicitly patched to return mock_gh_path, so the env var
has no effect; keep the patch("bot_detection.get_gh_executable",
return_value=mock_gh_path) and the subprocess.run mocking and the assertions
unchanged.
In `@apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts`:
- Around line 385-400: The test currently lets both spawned tasks exit before
calling manager.killAll(), so it never verifies kill behavior; modify the flow
to call manager.killAll() while the mock processes are still running (i.e.,
after awaiting setImmediate but before emitting 'exit'), then assert
mockProcess.kill was called (and that manager.getRunningTasks() becomes 0 after
handling the kill), keeping references to manager.startSpecCreation,
manager.startTaskExecution, manager.killAll, mockProcess.emit and
mockProcess.kill to locate and update the assertions.
|
|
||
| // Start two async operations | ||
| const promise1 = manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 1'); | ||
| const promise2 = manager.startTaskExecution('task-2', TEST_PROJECT_PATH, 'spec-001'); | ||
|
|
||
| // Wait for spawn to complete (ensures listeners are attached), then emit exit | ||
| await new Promise(resolve => setImmediate(resolve)); | ||
| mockProcess.emit('exit', 0); | ||
| await promise1; | ||
| mockProcess.emit('exit', 0); | ||
| await promise2; | ||
|
|
||
| await manager.killAll(); | ||
|
|
||
| expect(manager.getRunningTasks()).toHaveLength(0); | ||
| }); | ||
| }, 10000); // Increase timeout for Windows CI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test doesn't verify actual kill behavior.
The test waits for both tasks to exit (lines 392-395) before calling killAll(). Since tasks complete before killAll() is invoked, there's nothing to kill and the assertion passes trivially.
To verify killAll() actually terminates running processes, call it while tasks are still running and assert mockProcess.kill was called.
🧪 Suggested fix
it('should kill all running tasks', async () => {
const { AgentManager } = await import('../../main/agent');
const manager = new AgentManager();
manager.configure(undefined, AUTO_CLAUDE_SOURCE);
// Start two async operations
const promise1 = manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 1');
const promise2 = manager.startTaskExecution('task-2', TEST_PROJECT_PATH, 'spec-001');
// Wait for spawn to complete (ensures listeners are attached)
await new Promise(resolve => setImmediate(resolve));
- mockProcess.emit('exit', 0);
- await promise1;
- mockProcess.emit('exit', 0);
- await promise2;
+ // Kill all while tasks are running
await manager.killAll();
+ expect(mockProcess.kill).toHaveBeenCalled();
expect(manager.getRunningTasks()).toHaveLength(0);
+
+ // Emit exit to clean up promises
+ mockProcess.emit('exit', 0);
+ await Promise.allSettled([promise1, promise2]);
}, 10000);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Start two async operations | |
| const promise1 = manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 1'); | |
| const promise2 = manager.startTaskExecution('task-2', TEST_PROJECT_PATH, 'spec-001'); | |
| // Wait for spawn to complete (ensures listeners are attached), then emit exit | |
| await new Promise(resolve => setImmediate(resolve)); | |
| mockProcess.emit('exit', 0); | |
| await promise1; | |
| mockProcess.emit('exit', 0); | |
| await promise2; | |
| await manager.killAll(); | |
| expect(manager.getRunningTasks()).toHaveLength(0); | |
| }); | |
| }, 10000); // Increase timeout for Windows CI | |
| // Start two async operations | |
| const promise1 = manager.startSpecCreation('task-1', TEST_PROJECT_PATH, 'Test 1'); | |
| const promise2 = manager.startTaskExecution('task-2', TEST_PROJECT_PATH, 'spec-001'); | |
| // Wait for spawn to complete (ensures listeners are attached) | |
| await new Promise(resolve => setImmediate(resolve)); | |
| // Kill all while tasks are running | |
| await manager.killAll(); | |
| expect(mockProcess.kill).toHaveBeenCalled(); | |
| expect(manager.getRunningTasks()).toHaveLength(0); | |
| // Emit exit to clean up promises | |
| mockProcess.emit('exit', 0); | |
| await Promise.allSettled([promise1, promise2]); | |
| }, 10000); // Increase timeout for Windows CI |
🤖 Prompt for AI Agents
In `@apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts` around
lines 385 - 400, The test currently lets both spawned tasks exit before calling
manager.killAll(), so it never verifies kill behavior; modify the flow to call
manager.killAll() while the mock processes are still running (i.e., after
awaiting setImmediate but before emitting 'exit'), then assert mockProcess.kill
was called (and that manager.getRunningTasks() becomes 0 after handling the
kill), keeping references to manager.startSpecCreation,
manager.startTaskExecution, manager.killAll, mockProcess.emit and
mockProcess.kill to locate and update the assertions.
- test_bot_detection.py: Remove redundant monkeypatch.setenv() call in test_get_bot_username_uses_get_gh_executable_return_value since get_gh_executable is explicitly mocked to return mock_gh_path - subprocess-spawn.test.ts: Keep original should kill all running tasks test that matches actual behavior (killAll removes tasks from tracking but doesn't call kill on already-exited mock processes)
AndyMik90
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅ Auto Claude Review - APPROVED
Status: Ready to Merge
Summary: ## ✅ Follow-up Review: Ready To Merge
✅ Ready to merge - All checks passing and findings addressed.
Resolution Status
- ✅ Resolved: 2 previous findings addressed
- ❌ Unresolved: 0 previous findings remain
- 🆕 New Issues: 0 new findings in recent changes
Verdict
All criteria for merge are satisfied: (1) All 26 CI checks are passing, (2) Both previous LOW severity findings have been verified as resolved - hardcoded Unix paths replaced with cross-platform temp_state_dir paths, and error logging now properly extracts messages, (3) No new issues identified in the substantial code changes, (4) No outstanding contributor comments or questions. The implementation is type-safe, well-tested, and follows good error handling practices.
Review Process
Agents invoked: resolution-verifier, new-code-reviewer
This is an AI-generated follow-up review using parallel specialist analysis with finding validation.
This automated review found no blocking issues. The PR can be safely merged.
Generated by Auto Claude
Base Branch
developbranch (required for all feature/fix PRs)main(hotfix only - maintainers)Description
Fixes "gh CLI not found" error when creating PRs from the Electron GUI after launching from Finder/Dock on macOS (or similar non-terminal environments on Windows/Linux).
Root Cause: The Electron GUI detects gh CLI correctly but doesn't pass the detected path to the Python backend via
GITHUB_CLI_PATHenvironment variable. Additionally, some backend code uses hardcoded"gh"strings instead of callingget_gh_executable().Changes:
GITHUB_CLI_PATHenvironment variable detection inagent-process.ts, following the existingCLAUDE_CLI_PATHpatterngh_client.py,bot_detection.py, andrunner.pyto useget_gh_executable()instead of hardcoded"gh"or duplicate logicThe
get_gh_executable()function already handles:GITHUB_CLI_PATHenv var (now set by frontend)shutil.which("gh")fallbackwherecommandRelated Issue
Resolves: ACS-321 #1230
Type of Change
Area
Checklist
Platform Testing
This fix uses the existing
core.gh_executablemodule which already handles cross-platform gh CLI detection with proper fallbacks for:CI/Testing
Breaking Changes
No breaking changes.
Summary by CodeRabbit
Bug Fixes
New Features
Refactor
Tests
✏️ Tip: You can customize this high-level summary in your review settings.