-
Notifications
You must be signed in to change notification settings - Fork 397
GitHub category #216
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
GitHub category #216
Conversation
…gement - Modified the build command to first execute the build:packages script, ensuring all necessary packages are built before the UI. - Streamlined the build:packages command by consolidating workspace flags for better readability and maintenance.
|
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. WalkthroughAdds GitHub integration (server routes, CLI wrappers, UI views, Electron & HTTP client bindings and mocks), removes Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as GitHub UI
participant Electron as ElectronAPI
participant HttpClient as HttpApiClient
participant Server as Server (/api/github)
participant Shell as Shell (git/gh CLI)
rect rgb(230,240,255)
Note over User,UI: Remote detection & view mount
User->>UI: Open GitHub view
UI->>Electron: getElectronAPI().github.checkRemote(projectPath)
Electron->>HttpClient: (web) POST /api/github/check-remote
HttpClient->>Server: POST /api/github/check-remote
Server->>Shell: git remote get-url origin
Shell-->>Server: origin URL or error
Server-->>HttpClient: { hasGitHubRemote, owner, repo }
HttpClient-->>Electron: response
Electron-->>UI: remote status
UI->>UI: show/hide GitHub sidebar section
end
rect rgb(230,255,230)
Note over User,Server: Fetch issues or PRs
User->>UI: click refresh issues/prs
UI->>Electron: github.listIssues()/listPRs()
Electron->>HttpClient: POST /api/github/issues or /api/github/prs
HttpClient->>Server: request
Server->>Shell: gh issue list / gh pr list (open & closed/merged)
Shell-->>Server: JSON arrays
Server->>Server: parse & format results
Server-->>HttpClient: formatted payload
HttpClient-->>Electron: results
Electron-->>UI: results
UI->>User: render list and details
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes
Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
Summary of ChangesHello @webdevcody, 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 significantly enhances the application by integrating GitHub functionality, allowing users to view and interact with their project's issues and pull requests directly within the interface. It also refines the internal data structures for features and suggestions by removing redundant 'steps' information, and improves the auto-mode's feature completion workflow by dynamically adjusting verification status based on testing preferences. Additionally, the project creation process has been updated for better efficiency and clarity. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Ignored Files
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 introduces a significant new feature for GitHub integration, including server-side endpoints to fetch issues and pull requests, and corresponding UI views to display them. The implementation is well-structured, adding new routes and components logically. I've identified a few areas for improvement, including a bug in the GitHub URL parsing logic, opportunities to improve performance by parallelizing API calls, and ways to enhance type safety and error handling. Additionally, the removal of the steps property from features has been consistently applied across the codebase.
| const httpsMatch = remoteUrl.match(/https:\/\/github\.com\/([^/]+)\/([^/.]+)/); | ||
| const sshMatch = remoteUrl.match(/git@github\.com:([^/]+)\/([^/.]+)/); |
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.
The regular expressions used to capture the repository name are incorrect for repositories that contain a dot in their name. For example, for a URL like https://github.com/owner/my.repo.git, the current regex ([^/.]+) will only capture my. This should be changed to capture the full repository name.
| const httpsMatch = remoteUrl.match(/https:\/\/github\.com\/([^/]+)\/([^/.]+)/); | |
| const sshMatch = remoteUrl.match(/git@github\.com:([^/]+)\/([^/.]+)/); | |
| const httpsMatch = remoteUrl.match(/https:\/\/github\.com\/([^/]+)\/(.+)/); | |
| const sshMatch = remoteUrl.match(/git@github\.com:([^/]+)\/(.+)/); |
| @@ -0,0 +1,71 @@ | |||
| /** | |||
| * GET /check-github-remote endpoint - Check if project has a GitHub remote | |||
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.
The comment indicates this is a GET endpoint, but it's registered as a POST route in apps/server/src/routes/github/index.ts. The documentation should be consistent with the implementation.
| * GET /check-github-remote endpoint - Check if project has a GitHub remote | |
| * POST /check-github-remote endpoint - Check if project has a GitHub remote |
| export interface GitHubIssue { | ||
| number: number; | ||
| title: string; | ||
| state: string; |
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.
| const { stdout: openStdout } = await execAsync( | ||
| 'gh issue list --state open --json number,title,state,author,createdAt,labels,url,body --limit 100', | ||
| { | ||
| cwd: projectPath, | ||
| env: execEnv, | ||
| } | ||
| ); | ||
|
|
||
| // Fetch closed issues | ||
| const { stdout: closedStdout } = await execAsync( | ||
| 'gh issue list --state closed --json number,title,state,author,createdAt,labels,url,body --limit 50', | ||
| { | ||
| cwd: projectPath, | ||
| env: execEnv, | ||
| } | ||
| ); |
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.
The calls to fetch open and closed issues are made sequentially. This can be optimized by running them in parallel using Promise.all, which will reduce the total response time.
| const { stdout: openStdout } = await execAsync( | |
| 'gh issue list --state open --json number,title,state,author,createdAt,labels,url,body --limit 100', | |
| { | |
| cwd: projectPath, | |
| env: execEnv, | |
| } | |
| ); | |
| // Fetch closed issues | |
| const { stdout: closedStdout } = await execAsync( | |
| 'gh issue list --state closed --json number,title,state,author,createdAt,labels,url,body --limit 50', | |
| { | |
| cwd: projectPath, | |
| env: execEnv, | |
| } | |
| ); | |
| // Fetch open and closed issues in parallel | |
| const [openResult, closedResult] = await Promise.all([ | |
| execAsync( | |
| 'gh issue list --state open --json number,title,state,author,createdAt,labels,url,body --limit 100', | |
| { | |
| cwd: projectPath, | |
| env: execEnv, | |
| } | |
| ), | |
| execAsync( | |
| 'gh issue list --state closed --json number,title,state,author,createdAt,labels,url,body --limit 50', | |
| { | |
| cwd: projectPath, | |
| env: execEnv, | |
| } | |
| ), | |
| ]); | |
| const { stdout: openStdout } = openResult; | |
| const { stdout: closedStdout } = closedResult; |
| success: true, | ||
| openIssues, | ||
| closedIssues, | ||
| issues: [...openIssues, ...closedIssues], |
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.
| export interface GitHubPR { | ||
| number: number; | ||
| title: string; | ||
| state: string; |
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.
| isDraft: boolean; | ||
| headRefName: string; | ||
| reviewDecision: string | null; | ||
| mergeable: string; |
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.
| const { stdout: openStdout } = await execAsync( | ||
| 'gh pr list --state open --json number,title,state,author,createdAt,labels,url,isDraft,headRefName,reviewDecision,mergeable,body --limit 100', | ||
| { | ||
| cwd: projectPath, | ||
| env: execEnv, | ||
| } | ||
| ); | ||
|
|
||
| // Fetch merged PRs | ||
| const { stdout: mergedStdout } = await execAsync( | ||
| 'gh pr list --state merged --json number,title,state,author,createdAt,labels,url,isDraft,headRefName,reviewDecision,mergeable,body --limit 50', | ||
| { | ||
| cwd: projectPath, | ||
| env: execEnv, | ||
| } | ||
| ); |
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.
Similar to the issues endpoint, the calls to fetch open and merged pull requests are sequential. They can be run in parallel with Promise.all to improve performance.
| const { stdout: openStdout } = await execAsync( | |
| 'gh pr list --state open --json number,title,state,author,createdAt,labels,url,isDraft,headRefName,reviewDecision,mergeable,body --limit 100', | |
| { | |
| cwd: projectPath, | |
| env: execEnv, | |
| } | |
| ); | |
| // Fetch merged PRs | |
| const { stdout: mergedStdout } = await execAsync( | |
| 'gh pr list --state merged --json number,title,state,author,createdAt,labels,url,isDraft,headRefName,reviewDecision,mergeable,body --limit 50', | |
| { | |
| cwd: projectPath, | |
| env: execEnv, | |
| } | |
| ); | |
| // Fetch open and merged PRs in parallel | |
| const [openResult, mergedResult] = await Promise.all([ | |
| execAsync( | |
| 'gh pr list --state open --json number,title,state,author,createdAt,labels,url,isDraft,headRefName,reviewDecision,mergeable,body --limit 100', | |
| { | |
| cwd: projectPath, | |
| env: execEnv, | |
| } | |
| ), | |
| execAsync( | |
| 'gh pr list --state merged --json number,title,state,author,createdAt,labels,url,isDraft,headRefName,reviewDecision,mergeable,body --limit 50', | |
| { | |
| cwd: projectPath, | |
| env: execEnv, | |
| } | |
| ), | |
| ]); | |
| const { stdout: openStdout } = openResult; | |
| const { stdout: mergedStdout } = mergedResult; |
| success: true, | ||
| openPRs, | ||
| mergedPRs, | ||
| prs: [...openPRs, ...mergedPRs], |
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.
| } catch { | ||
| setHasGitHubRemote(false); | ||
| } |
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.
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
♻️ Duplicate comments (1)
apps/server/src/routes/github/routes/list-issues.ts (1)
9-16: Duplicate type definitions.Same as noted in
list-prs.ts- these types should be consolidated incommon.ts.
🧹 Nitpick comments (11)
apps/server/src/services/auto-mode-service.ts (1)
1661-1738: Clean bifurcation of verification instructions based onskipTests.The conditional prompt generation is well-structured:
- Manual mode (
skipTests=true): Straightforward implementation with summary- Auto mode (
skipTests=false): Includes Playwright verification workflowOne consideration: the Playwright instructions (lines 1704-1717) assume Playwright is installed and configured in the project. If the project doesn't have Playwright set up, the agent may fail during verification.
Consider adding a note about Playwright prerequisites
You could add guidance for the agent to check for Playwright availability first, or to gracefully skip verification if Playwright isn't configured:
## Verification with Playwright (REQUIRED) After implementing the feature, you MUST verify it works correctly using Playwright: +**Note:** If Playwright is not installed in this project, check for alternative testing frameworks (Jest, Vitest, Cypress) or verify manually. + 1. **Create a temporary Playwright test** to verify the feature works as expectedapps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts (1)
125-264: Consider extracting shared logic to reduce duplication.The
handleCreateFromTemplateandhandleCreateFromCustomUrlfunctions share substantial logic (~60 lines of nearly identical code):
- Clone repository
- Initialize project structure
- Write app_spec.txt
- Determine theme
- Upsert project and update state
- Show toast notification
The only differences are the app_spec.txt content and toast messages. Consider extracting the common flow into a helper function that accepts callbacks or parameters for the variable parts. This would improve maintainability and reduce the risk of divergence.
💡 Example refactor approach
const handleCreateFromRepository = async ( repoUrl: string, projectName: string, parentDir: string, generateAppSpec: (projectPath: string) => string, successMessage: { description: string } ) => { setIsCreatingProject(true); try { const api = getElectronAPI(); const cloneResult = await api.templates.clone(repoUrl, projectName, parentDir); if (!cloneResult.success) { throw new Error(cloneResult.error || 'Failed to clone repository'); } if (!cloneResult.projectPath) { throw new Error('Clone succeeded but no project path was returned'); } const projectPath = cloneResult.projectPath; await initializeProject(projectPath); await api.writeFile(`${projectPath}/.automaker/app_spec.txt`, generateAppSpec(projectPath)); const trashedProject = trashedProjects.find((p) => p.path === projectPath); const effectiveTheme = (trashedProject?.theme as ThemeMode | undefined) || (currentProject?.theme as ThemeMode | undefined) || globalTheme; upsertAndSetCurrentProject(projectPath, projectName, effectiveTheme); setShowNewProjectModal(false); setNewProjectName(projectName); setNewProjectPath(projectPath); setShowOnboardingDialog(true); toast.success('Project created', successMessage); } catch (error) { console.error('[ProjectCreation] Failed to create project:', error); toast.error('Failed to create project', { description: error instanceof Error ? error.message : 'Unknown error', }); } finally { setIsCreatingProject(false); } };Then use it in both functions:
const handleCreateFromTemplate = (template, projectName, parentDir) => handleCreateFromRepository( template.repoUrl, projectName, parentDir, () => `<project_specification>...template content...</project_specification>`, { description: `Created ${projectName} from ${template.name}` } );apps/ui/src/components/views/board-view/dialogs/feature-suggestions-dialog.tsx (1)
230-281: Clarify the skipTests comment.The feature creation logic correctly excludes the
stepsfield, aligning with the PR's broader changes. However, line 249 has a potentially confusing comment:skipTests: true, // As specified, testing mode trueThe comment "testing mode true" is misleading because
skipTests: truemeans automated testing is disabled (tests will be skipped). Consider clarifying this comment or removing it entirely:🔎 Suggested clarification
- skipTests: true, // As specified, testing mode true + skipTests: true, // Imported features default to skipping automated testsapps/ui/src/components/layout/sidebar/hooks/use-navigation.ts (1)
3-13: Consider removing unused Zap icon import.The
Zapicon is imported but not used in this file. Consider removing it to keep imports clean.🔎 Proposed cleanup
import { FileText, LayoutGrid, Bot, BookOpen, UserCircle, Terminal, CircleDot, GitPullRequest, - Zap, } from 'lucide-react';apps/server/src/routes/github/routes/common.ts (1)
10-24: Consider documenting Unix-only PATH construction.The PATH extension logic is well-structured and covers common tool installation locations on Unix-like systems (macOS and Linux). However, this code assumes Unix path separators (
:) and won't work on Windows (which uses;).If Windows support is planned, consider using
path.delimiterfrom Node'spathmodule:🔎 Proposed cross-platform alternative
+import { delimiter } from 'path'; + export const extendedPath = [ process.env.PATH, '/opt/homebrew/bin', '/usr/local/bin', '/home/linuxbrew/.linuxbrew/bin', `${process.env.HOME}/.local/bin`, ] .filter(Boolean) - .join(':'); + .join(delimiter);Otherwise, consider adding a comment documenting that this is Unix-only:
+// Unix-only PATH extension (macOS/Linux) export const extendedPath = [apps/ui/src/lib/http-api-client.ts (1)
24-26: Unused imports:GitHubIssueandGitHubPR.These types are imported but not used in this file. Only
GitHubAPIis needed for the interface type. Consider removing the unused imports to keep the code clean.🔎 Proposed fix
- GitHubAPI, - GitHubIssue, - GitHubPR, + GitHubAPI,apps/server/src/routes/github/routes/check-github-remote.ts (1)
33-43: Regex patterns may miss repository names containing dots.The character class
[^/.]+excludes dots, which could fail to match valid repository names likemy.awesome.repo. GitHub allows dots in repository names.🔎 Proposed fix to handle repo names with dots
- const httpsMatch = remoteUrl.match(/https:\/\/github\.com\/([^/]+)\/([^/.]+)/); - const sshMatch = remoteUrl.match(/git@github\.com:([^/]+)\/([^/.]+)/); + const httpsMatch = remoteUrl.match(/https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/); + const sshMatch = remoteUrl.match(/git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/); const match = httpsMatch || sshMatch; if (match) { status.hasGitHubRemote = true; status.owner = match[1]; - status.repo = match[2].replace(/\.git$/, ''); + status.repo = match[2]; }apps/ui/src/components/views/github-prs-view.tsx (2)
10-11: Unused import:AlertCircle.
AlertCircleis imported but never used in the component.🔎 Proposed fix
X, - AlertCircle, } from 'lucide-react';
251-260: Minor inefficiency:getReviewStatuscalled multiple times for the same PR.Consider calling it once and storing the result:
🔎 Proposed optimization
+ {(() => { + const reviewStatus = getReviewStatus(selectedPR); + return reviewStatus ? ( - {getReviewStatus(selectedPR) && ( <span className={cn( 'px-2 py-0.5 rounded-full text-xs font-medium', - getReviewStatus(selectedPR)!.bg, - getReviewStatus(selectedPR)!.color + reviewStatus.bg, + reviewStatus.color )} > - {getReviewStatus(selectedPR)!.label} + {reviewStatus.label} </span> - )} + ) : null; + })()}apps/server/src/routes/github/routes/list-prs.ts (1)
9-16: Consider consolidating shared type definitions.
GitHubLabelandGitHubAuthorinterfaces are duplicated in bothlist-prs.tsandlist-issues.ts. Extract these shared types tocommon.tsto maintain DRY and ensure consistency.🔎 Proposed refactor
Move to
common.ts:export interface GitHubLabel { name: string; color: string; } export interface GitHubAuthor { login: string; }Then import in both files:
-export interface GitHubLabel { - name: string; - color: string; -} - -export interface GitHubAuthor { - login: string; -} +import { GitHubLabel, GitHubAuthor } from './common.js'; + +export type { GitHubLabel, GitHubAuthor };apps/ui/src/lib/electron.ts (1)
95-159: Type definitions duplicate server-side types.These interfaces duplicate definitions from the server (
list-prs.ts,list-issues.ts,check-github-remote.ts). While this is common in client/server architectures, consider:
- Creating a shared types package (e.g.,
@automaker/types)- Or generating client types from server definitions
This would prevent drift between client and server type definitions.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (31)
.github/workflows/security-audit.ymlapps/server/src/index.tsapps/server/src/routes/github/index.tsapps/server/src/routes/github/routes/check-github-remote.tsapps/server/src/routes/github/routes/common.tsapps/server/src/routes/github/routes/list-issues.tsapps/server/src/routes/github/routes/list-prs.tsapps/server/src/routes/suggestions/generate-suggestions.tsapps/server/src/services/auto-mode-service.tsapps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsxapps/ui/src/components/layout/sidebar/hooks/use-navigation.tsapps/ui/src/components/layout/sidebar/hooks/use-project-creation.tsapps/ui/src/components/views/analysis-view.tsxapps/ui/src/components/views/board-view.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-content-sections.tsxapps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsxapps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsxapps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsxapps/ui/src/components/views/board-view/dialogs/feature-suggestions-dialog.tsxapps/ui/src/components/views/board-view/hooks/use-board-actions.tsapps/ui/src/components/views/board-view/shared/testing-tab-content.tsxapps/ui/src/components/views/github-issues-view.tsxapps/ui/src/components/views/github-prs-view.tsxapps/ui/src/components/views/interview-view.tsxapps/ui/src/lib/electron.tsapps/ui/src/lib/http-api-client.tsapps/ui/src/routes/github-issues.tsxapps/ui/src/routes/github-prs.tsxapps/ui/src/store/app-store.tslibs/types/src/feature.tspackage.json
💤 Files with no reviewable changes (7)
- libs/types/src/feature.ts
- apps/ui/src/components/views/board-view/hooks/use-board-actions.ts
- apps/ui/src/store/app-store.ts
- apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx
- apps/ui/src/components/views/interview-view.tsx
- apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx
- apps/ui/src/components/views/analysis-view.tsx
🧰 Additional context used
🧬 Code graph analysis (13)
apps/server/src/index.ts (1)
apps/server/src/routes/github/index.ts (1)
createGitHubRoutes(10-18)
apps/server/src/routes/github/index.ts (4)
apps/ui/src/utils/router.ts (1)
router(11-15)apps/server/src/routes/github/routes/check-github-remote.ts (1)
createCheckGitHubRemoteHandler(51-71)apps/server/src/routes/github/routes/list-issues.ts (1)
createListIssuesHandler(37-89)apps/server/src/routes/github/routes/list-prs.ts (1)
createListPRsHandler(41-93)
apps/ui/src/routes/github-issues.tsx (2)
apps/ui/src/routes/github-prs.tsx (1)
Route(4-6)apps/ui/src/components/views/github-issues-view.tsx (1)
GitHubIssuesView(8-266)
apps/ui/src/routes/github-prs.tsx (2)
apps/ui/src/routes/github-issues.tsx (1)
Route(4-6)apps/ui/src/components/views/github-prs-view.tsx (1)
GitHubPRsView(17-321)
apps/ui/src/components/layout/sidebar/hooks/use-navigation.ts (3)
apps/server/src/routes/github/routes/check-github-remote.ts (1)
checkGitHubRemote(15-49)apps/ui/src/lib/electron.ts (1)
getElectronAPI(617-626)apps/ui/src/components/layout/sidebar/types.ts (1)
NavSection(4-7)
apps/server/src/routes/github/routes/check-github-remote.ts (1)
apps/server/src/routes/github/routes/common.ts (4)
execAsync(8-8)execEnv(21-24)logError(33-35)getErrorMessage(26-31)
apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx (2)
apps/ui/src/store/app-store.ts (1)
useAppStore(891-2641)apps/ui/src/components/views/board-view/components/kanban-card/card-content-sections.tsx (1)
CardContentSections(9-50)
apps/ui/src/components/views/board-view/components/kanban-card/card-content-sections.tsx (2)
libs/types/src/feature.ts (1)
Feature(15-48)apps/ui/src/store/app-store.ts (1)
Feature(263-287)
apps/ui/src/lib/http-api-client.ts (1)
apps/ui/src/lib/electron.ts (1)
GitHubAPI(138-159)
apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts (1)
apps/ui/src/lib/project-init.ts (1)
initializeProject(38-133)
apps/server/src/routes/github/routes/list-issues.ts (2)
apps/server/src/routes/github/routes/check-github-remote.ts (1)
checkGitHubRemote(15-49)apps/server/src/routes/github/routes/common.ts (4)
execAsync(8-8)execEnv(21-24)logError(33-35)getErrorMessage(26-31)
apps/ui/src/components/views/github-issues-view.tsx (3)
apps/server/src/routes/github/routes/list-issues.ts (1)
GitHubIssue(18-27)apps/ui/src/lib/electron.ts (2)
GitHubIssue(105-114)getElectronAPI(617-626)apps/ui/src/lib/utils.ts (1)
cn(5-7)
apps/ui/src/lib/electron.ts (3)
apps/server/src/routes/github/routes/list-issues.ts (3)
GitHubLabel(9-12)GitHubAuthor(14-16)GitHubIssue(18-27)apps/server/src/routes/github/routes/list-prs.ts (3)
GitHubLabel(9-12)GitHubAuthor(14-16)GitHubPR(18-31)apps/server/src/routes/github/routes/check-github-remote.ts (1)
GitHubRemoteStatus(8-13)
🔇 Additional comments (37)
apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx (1)
54-56: Stylistic refactor—no functional impact.The onClick handler has been reformatted from a concise arrow function to a block-bodied version. This is a pure style change; the navigate call and routing logic remain identical and correct. If this aligns with your project's linting or code style conventions, it's fine to keep.
apps/server/src/routes/suggestions/generate-suggestions.ts (2)
33-33: LGTM! Schema correctly updated to remove steps.The required fields array is now consistent with the properties definition and the broader changes across the codebase to remove steps from suggestions.
61-62: LGTM! Prompt correctly updated after removing steps.The prompt instructions have been properly renumbered and now align perfectly with the JSON schema definition. The instructions remain clear and comprehensive.
apps/server/src/services/auto-mode-service.ts (2)
602-613: LGTM!The conditional logic for
finalStatusis clear and well-documented. The comments accurately explain the two modes:
skipTests=false→ automated testing completed →verifiedskipTests=true→ manual verification required →waiting_approvalSince
featureis already null-checked earlier (lines 512-514), accessingfeature.skipTestsdirectly is safe here.
874-883: LGTM!The optional chaining on
feature?.skipTestsis appropriate here sincefeaturemay be null infollowUpFeature. Whenfeatureis null orskipTestsis undefined, the falsy value correctly defaults to'verified', maintaining consistency with the mainexecuteFeaturelogic.package.json (2)
20-20: The exclusion ofapps/serverfrom the main build is intentional.The codebase deliberately separates server and UI builds. The main
buildscript targets the UI/Electron distribution, whileapps/serverhas its ownbuild:servercommand. CI workflows confirm this pattern: the PR check only runsbuild:electron:dir, and server tests run separately withtest:server:coverage. During development,dev:fullorchestrates both independently using concurrent execution. This architecture is by design.Likely an incorrect or invalid review comment.
21-21: No action needed — npm runs multiple-wflags sequentially, not in parallel.The
build:packagescommand specifies multiple-wflags, but npm workspace behavior runs these sequentially in the order provided, not in parallel. The specified build order (types → platform → utils → prompts → model-resolver → dependency-resolver → git-utils) correctly respects all package interdependencies, so there is no race condition risk.Likely an incorrect or invalid review comment.
apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts (3)
43-43: LGTM: API call updated correctly.The change from
fs.writeFiletowriteFilealigns with the refactored Electron API structure.
106-106: LGTM: API call updated correctly.The change from
fs.createFoldertomkdiraligns with the refactored Electron API structure.
142-142: LGTM: API calls updated correctly.The changes from
fs.writeFiletowriteFilealign with the refactored Electron API structure.Also applies to: 214-214
apps/ui/src/components/views/board-view/dialogs/feature-suggestions-dialog.tsx (1)
455-459: LGTM! Clean removal of steps UI.The expanded suggestion view now correctly displays only the reasoning field, consistent with the removal of steps from the feature model throughout this PR.
apps/ui/src/components/layout/sidebar/hooks/use-navigation.ts (2)
65-87: LGTM! Robust GitHub remote detection.The effect properly checks for GitHub remotes when the project changes, with appropriate error handling. The defensive checks (both
result.successandresult.hasGitHubRemote === true) prevent false positives.
152-183: Clean implementation of conditional GitHub navigation.The GitHub section is correctly added only when a GitHub remote is detected. The navigation items follow the existing pattern and will integrate seamlessly with the routing system.
apps/server/src/routes/github/routes/common.ts (1)
26-35: LGTM! Standard error handling utilities.The error handling helpers follow best practices for safely converting unknown error types to strings and providing consistent logging with contextual prefixes.
apps/ui/src/components/views/board-view/shared/testing-tab-content.tsx (2)
5-16: LGTM! Simplified testing configuration.The props interface correctly removes steps-related fields while preserving the core testing toggle functionality and test ID isolation.
34-37: Clear and informative user guidance.The updated description properly explains the automated testing behavior using Playwright, with clear distinction between enabled and disabled modes.
apps/server/src/index.ts (2)
49-49: LGTM! Consistent route import.The import statement follows the established pattern for route modules in this file.
149-149: LGTM! Proper route registration.The GitHub routes are correctly mounted at
/api/githubunder authentication middleware, following the established pattern for other API routes.apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx (2)
64-64: LGTM! Minimal store subscription.The component correctly subscribes only to
useWorktrees, which is the only store value needed after removing steps-related functionality.
153-153: LGTM! Clean component integration.The props correctly match the updated
CardContentSectionsinterface after removing steps-related functionality.apps/ui/src/components/views/board-view.tsx (2)
472-510: LGTM! Appropriate feature configuration for conflict resolution workflow.The feature data correctly excludes
stepsand includes a cleartitlefield. The high priority and detailed description are appropriate for automated conflict resolution.
427-469: Unable to verify title field support in Feature interface.Verification of the Feature interface definition and API implementation cannot be completed due to repository access limitations. Manual code review is required to confirm whether the
titlefield is properly supported in the Feature interface and whether the feature creation API correctly handles this field before approving the featureData structure..github/workflows/security-audit.yml (1)
1-30: Well-structured security audit workflow.The workflow follows GitHub Actions best practices with appropriate triggers (PRs, all branches, main/master pushes, and weekly scheduled runs). The audit level is set to moderate, which is a reasonable balance for catching security issues without excessive noise. Using
actions/checkout@v4and pinning to a specific major version is recommended.Verify that the custom action referenced at
./.github/actions/setup-projectexists and is properly configured in your repository.apps/ui/src/routes/github-issues.tsx (1)
1-6: LGTM!Clean route definition that follows the established pattern used by other routes in the codebase (e.g.,
/github-prs).apps/ui/src/routes/github-prs.tsx (1)
1-6: LGTM!Consistent route definition following the same pattern as the issues route.
apps/ui/src/lib/http-api-client.ts (1)
749-754: LGTM!The GitHub API surface is correctly implemented, following the same pattern as other API namespaces in the client. The methods properly delegate to the corresponding server endpoints.
apps/ui/src/components/views/board-view/components/kanban-card/card-content-sections.tsx (1)
1-50: LGTM!Clean removal of the
showStepsprop and related UI. The remaining branch and PR URL display logic is well-implemented with proper event propagation handling and URL validation.apps/server/src/routes/github/routes/check-github-remote.ts (1)
51-71: LGTM!The handler factory follows the established pattern with proper input validation, error handling, and structured JSON responses.
apps/ui/src/components/views/github-issues-view.tsx (1)
17-43: LGTM!The fetch logic is well-structured with proper error handling, state management, and the
useCallbackdependency oncurrentProject?.pathensures re-fetching when the project changes.apps/ui/src/components/views/github-prs-view.tsx (1)
26-52: LGTM!The fetch logic mirrors the issues view with appropriate error handling and state management for PRs.
apps/server/src/routes/github/index.ts (1)
10-18: LGTM!Clean router setup with a factory pattern that promotes testability. The use of POST for these endpoints is reasonable since they require
projectPathin the request body. Authentication middleware is properly applied at the/apilevel, protecting all GitHub routes.apps/server/src/routes/github/routes/list-prs.ts (2)
62-87: LGTM!The handler implementation is well-structured with:
- Proper separation of open and merged PR queries
- Sensible limits (100 open, 50 merged)
- Safe JSON parsing with fallback to empty arrays
- Clean response structure offering both separate and combined arrays
44-49: UsevalidatePathParamsmiddleware to validateprojectPathagainst allowed directories.The route extracts
projectPathfrom the request body without validating it against the configured allowed root directory. WhilecheckGitHubRemoteensures the path points to a git repository with a GitHub remote, it does not prevent path traversal to other git repositories on the system. Apply the existingvalidatePathParamsmiddleware (or callvalidatePathdirectly) to prevent unauthorized access to arbitrary repositories.apps/server/src/routes/github/routes/list-issues.ts (1)
37-89: LGTM!The implementation correctly mirrors the PR listing pattern with appropriate adjustments for issues (using
--state closedinstead of--state merged). Error handling and response structure are consistent.apps/ui/src/lib/electron.ts (3)
138-159: LGTM!The
GitHubAPIinterface follows the established patterns in this file with consistent success/error response shapes. Method signatures align with the server endpoints.
2593-2623: LGTM!The mock GitHub API implementation is consistent with other mock APIs in this file:
- Appropriate console.log for debugging
- Returns sensible defaults (no GitHub remote, empty arrays)
- Success responses match the interface contracts
394-394: LGTM!Adding
githubas an optional property is the correct approach, maintaining backward compatibility while extending the API surface.
| const cloneResult = await api.templates.clone(template.repoUrl, projectName, parentDir); | ||
| if (!cloneResult.success) { | ||
| throw new Error(cloneResult.error || 'Failed to clone template'); | ||
| } | ||
| const projectPath = cloneResult.projectPath!; |
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.
Add explicit validation for projectPath after successful clone.
While the API contract states that projectPath should be present when success is true, using the non-null assertion operator (!) is risky. If the API returns an unexpected result or has a bug, the code will fail with a cryptic error later rather than a clear validation error here.
🔎 Suggested fix: Add explicit validation
const cloneResult = await api.templates.clone(template.repoUrl, projectName, parentDir);
if (!cloneResult.success) {
throw new Error(cloneResult.error || 'Failed to clone template');
}
-const projectPath = cloneResult.projectPath!;
+if (!cloneResult.projectPath) {
+ throw new Error('Clone succeeded but no project path was returned');
+}
+const projectPath = cloneResult.projectPath;📝 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.
| const cloneResult = await api.templates.clone(template.repoUrl, projectName, parentDir); | |
| if (!cloneResult.success) { | |
| throw new Error(cloneResult.error || 'Failed to clone template'); | |
| } | |
| const projectPath = cloneResult.projectPath!; | |
| const cloneResult = await api.templates.clone(template.repoUrl, projectName, parentDir); | |
| if (!cloneResult.success) { | |
| throw new Error(cloneResult.error || 'Failed to clone template'); | |
| } | |
| if (!cloneResult.projectPath) { | |
| throw new Error('Clone succeeded but no project path was returned'); | |
| } | |
| const projectPath = cloneResult.projectPath; |
🤖 Prompt for AI Agents
In apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts around
lines 132 to 136, the code uses a non-null assertion for cloneResult.projectPath
after a successful clone; add an explicit runtime validation: after checking
cloneResult.success, verify that cloneResult.projectPath is a non-empty string
(or valid path) and throw a clear, descriptive Error if it is missing or invalid
instead of using the `!` operator, so callers get an immediate, actionable
validation error; update types or narrow the variable as needed before
continuing.
| const cloneResult = await api.templates.clone(repoUrl, projectName, parentDir); | ||
| if (!cloneResult.success) { | ||
| throw new Error(cloneResult.error || 'Failed to clone repository'); | ||
| } | ||
| const projectPath = cloneResult.projectPath!; |
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.
Add explicit validation for projectPath after successful clone.
Similar to the issue in handleCreateFromTemplate, using the non-null assertion operator on cloneResult.projectPath is risky. Add an explicit check to ensure projectPath is defined before using it.
🔎 Suggested fix: Add explicit validation
const cloneResult = await api.templates.clone(repoUrl, projectName, parentDir);
if (!cloneResult.success) {
throw new Error(cloneResult.error || 'Failed to clone repository');
}
-const projectPath = cloneResult.projectPath!;
+if (!cloneResult.projectPath) {
+ throw new Error('Clone succeeded but no project path was returned');
+}
+const projectPath = cloneResult.projectPath;📝 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.
| const cloneResult = await api.templates.clone(repoUrl, projectName, parentDir); | |
| if (!cloneResult.success) { | |
| throw new Error(cloneResult.error || 'Failed to clone repository'); | |
| } | |
| const projectPath = cloneResult.projectPath!; | |
| const cloneResult = await api.templates.clone(repoUrl, projectName, parentDir); | |
| if (!cloneResult.success) { | |
| throw new Error(cloneResult.error || 'Failed to clone repository'); | |
| } | |
| if (!cloneResult.projectPath) { | |
| throw new Error('Clone succeeded but no project path was returned'); | |
| } | |
| const projectPath = cloneResult.projectPath; |
🤖 Prompt for AI Agents
In apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts around
lines 204 to 208, the code assumes cloneResult.projectPath is non-null after a
successful clone; add an explicit runtime check for projectPath instead of using
the non-null assertion. After confirming cloneResult.success, verify projectPath
is a non-empty string (e.g., if (!cloneResult.projectPath) throw new
Error('Clone succeeded but projectPath is missing')); then use the validated
projectPath variable for subsequent operations so callers never rely on a forced
non-null assertion.
| function IssueRow({ issue, isSelected, onClick, onOpenExternal, formatDate }: IssueRowProps) { | ||
| return ( | ||
| <div | ||
| className={cn( | ||
| 'flex items-start gap-3 p-3 cursor-pointer hover:bg-accent/50 transition-colors', | ||
| isSelected && 'bg-accent' | ||
| )} | ||
| onClick={onClick} | ||
| > | ||
| {issue.state === 'OPEN' ? ( | ||
| <Circle className="h-4 w-4 text-green-500 mt-0.5 flex-shrink-0" /> | ||
| ) : ( | ||
| <CheckCircle2 className="h-4 w-4 text-purple-500 mt-0.5 flex-shrink-0" /> | ||
| )} | ||
|
|
||
| <div className="flex-1 min-w-0"> | ||
| <div className="flex items-center gap-2"> | ||
| <span className="text-sm font-medium truncate">{issue.title}</span> | ||
| </div> | ||
|
|
||
| <div className="flex items-center gap-2 mt-1 flex-wrap"> | ||
| <span className="text-xs text-muted-foreground"> | ||
| #{issue.number} opened {formatDate(issue.createdAt)} by {issue.author.login} | ||
| </span> | ||
| </div> | ||
|
|
||
| {issue.labels.length > 0 && ( | ||
| <div className="flex items-center gap-1 mt-2 flex-wrap"> | ||
| {issue.labels.map((label) => ( | ||
| <span | ||
| key={label.name} | ||
| className="px-1.5 py-0.5 text-[10px] font-medium rounded-full" | ||
| style={{ | ||
| backgroundColor: `#${label.color}20`, | ||
| color: `#${label.color}`, | ||
| border: `1px solid #${label.color}40`, | ||
| }} | ||
| > | ||
| {label.name} | ||
| </span> | ||
| ))} | ||
| </div> | ||
| )} | ||
| </div> | ||
|
|
||
| <Button | ||
| variant="ghost" | ||
| size="sm" | ||
| className="flex-shrink-0 opacity-0 group-hover:opacity-100" | ||
| onClick={(e) => { | ||
| e.stopPropagation(); | ||
| onOpenExternal(); | ||
| }} | ||
| > | ||
| <ExternalLink className="h-3.5 w-3.5" /> | ||
| </Button> | ||
| </div> |
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.
Bug: External link button won't appear on hover due to missing group class.
The button uses group-hover:opacity-100 but the parent div (line 278) doesn't have the group class, so the hover reveal effect won't work.
🔎 Proposed fix
<div
className={cn(
- 'flex items-start gap-3 p-3 cursor-pointer hover:bg-accent/50 transition-colors',
+ 'group flex items-start gap-3 p-3 cursor-pointer hover:bg-accent/50 transition-colors',
isSelected && 'bg-accent'
)}
onClick={onClick}
>🤖 Prompt for AI Agents
In apps/ui/src/components/views/github-issues-view.tsx around lines 276 to 332,
the parent div wrapping the issue row is missing the "group" class so the
Button's "group-hover:opacity-100" rule never triggers; add "group" to that
parent div's className (preserving existing classes and conditional isSelected
class) so the external link button becomes visible on hover, and keep the
existing e.stopPropagation handler intact.
| return ( | ||
| <div | ||
| className={cn( | ||
| 'flex items-start gap-3 p-3 cursor-pointer hover:bg-accent/50 transition-colors', | ||
| isSelected && 'bg-accent' | ||
| )} | ||
| onClick={onClick} | ||
| > | ||
| {pr.state === 'MERGED' ? ( | ||
| <GitMerge className="h-4 w-4 text-purple-500 mt-0.5 flex-shrink-0" /> | ||
| ) : ( | ||
| <GitPullRequest className="h-4 w-4 text-green-500 mt-0.5 flex-shrink-0" /> | ||
| )} | ||
|
|
||
| <div className="flex-1 min-w-0"> | ||
| <div className="flex items-center gap-2"> | ||
| <span className="text-sm font-medium truncate">{pr.title}</span> | ||
| {pr.isDraft && ( | ||
| <span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-muted text-muted-foreground flex-shrink-0"> | ||
| Draft | ||
| </span> | ||
| )} | ||
| </div> | ||
|
|
||
| <div className="flex items-center gap-2 mt-1 flex-wrap"> | ||
| <span className="text-xs text-muted-foreground"> | ||
| #{pr.number} opened {formatDate(pr.createdAt)} by {pr.author.login} | ||
| </span> | ||
| {pr.headRefName && ( | ||
| <span className="text-xs text-muted-foreground font-mono bg-muted px-1 rounded"> | ||
| {pr.headRefName} | ||
| </span> | ||
| )} | ||
| </div> | ||
|
|
||
| <div className="flex items-center gap-2 mt-2 flex-wrap"> | ||
| {/* Review Status */} | ||
| {reviewStatus && ( | ||
| <span | ||
| className={cn( | ||
| 'px-1.5 py-0.5 text-[10px] font-medium rounded', | ||
| reviewStatus.bg, | ||
| reviewStatus.color | ||
| )} | ||
| > | ||
| {reviewStatus.label} | ||
| </span> | ||
| )} | ||
|
|
||
| {/* Labels */} | ||
| {pr.labels.map((label) => ( | ||
| <span | ||
| key={label.name} | ||
| className="px-1.5 py-0.5 text-[10px] font-medium rounded-full" | ||
| style={{ | ||
| backgroundColor: `#${label.color}20`, | ||
| color: `#${label.color}`, | ||
| border: `1px solid #${label.color}40`, | ||
| }} | ||
| > | ||
| {label.name} | ||
| </span> | ||
| ))} | ||
| </div> | ||
| </div> | ||
|
|
||
| <Button | ||
| variant="ghost" | ||
| size="sm" | ||
| className="flex-shrink-0 opacity-0 group-hover:opacity-100" | ||
| onClick={(e) => { | ||
| e.stopPropagation(); | ||
| onOpenExternal(); | ||
| }} | ||
| > | ||
| <ExternalLink className="h-3.5 w-3.5" /> | ||
| </Button> | ||
| </div> |
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.
Bug: External link button won't appear on hover due to missing group class.
Same issue as in GitHubIssuesView - the button uses group-hover:opacity-100 but the parent div lacks the group class.
🔎 Proposed fix
<div
className={cn(
- 'flex items-start gap-3 p-3 cursor-pointer hover:bg-accent/50 transition-colors',
+ 'group flex items-start gap-3 p-3 cursor-pointer hover:bg-accent/50 transition-colors',
isSelected && 'bg-accent'
)}
onClick={onClick}
>🤖 Prompt for AI Agents
In apps/ui/src/components/views/github-prs-view.tsx around lines 342 to 419, the
external link Button uses group-hover:opacity-100 but the parent div is missing
the required "group" class; add "group" to the parent div's className (the
cn(...) call) so the child's group-hover utility takes effect (keep existing
classes and conditional isSelected class intact).
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 (1)
apps/server/src/services/auto-mode-service.ts (1)
1643-1692: Hardcoded Playwright assumption may break auto-verification for projects without it.The automated verification instructions (lines 1654-1691) assume Playwright is installed and configured. Projects using other testing frameworks (Jest, Vitest, Cypress, etc.) or those without any test runner will fail verification.
Consider one of these approaches:
- Auto-detect the testing framework from package.json scripts or dependencies
- Make the verification approach configurable via project settings
- Provide framework-agnostic instructions like "run the project's test suite to verify"
- Document the Playwright requirement and provide a fallback to manual verification (skipTests=true) for projects without it
Example: Framework-agnostic verification instructions
-## Verification with Playwright (REQUIRED) +## Verification (REQUIRED) -After implementing the feature, you MUST verify it works correctly using Playwright: +After implementing the feature, you MUST verify it works correctly: -1. **Create a temporary Playwright test** to verify the feature works as expected -2. **Run the test** to confirm the feature is working -3. **Delete the test file** after verification - this is a temporary verification test, not a permanent test suite addition +1. **Check for available test commands** in package.json (npm test, npm run test:e2e, etc.) +2. **Create a temporary verification test** using the project's testing framework +3. **Run the test** to confirm the feature works as expected +4. **Delete the test file** after verification (temporary verification only) -Example verification workflow: -\`\`\`bash -# Create a simple verification test -npx playwright test my-verification-test.spec.ts - -# After successful verification, delete the test -rm my-verification-test.spec.ts -\`\`\` +Adapt your verification approach to the project's existing testing setup.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
apps/server/src/index.tsapps/server/src/services/auto-mode-service.tsapps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsxapps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsxapps/ui/src/lib/electron.tsapps/ui/src/lib/http-api-client.tsapps/ui/src/store/app-store.tslibs/types/src/feature.ts
💤 Files with no reviewable changes (3)
- apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx
- apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx
- libs/types/src/feature.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/server/src/index.ts
🧰 Additional context used
🧬 Code graph analysis (2)
apps/ui/src/lib/http-api-client.ts (1)
apps/ui/src/lib/electron.ts (1)
GitHubAPI(138-159)
apps/ui/src/lib/electron.ts (3)
apps/server/src/routes/github/routes/list-issues.ts (3)
GitHubLabel(9-12)GitHubAuthor(14-16)GitHubIssue(18-27)apps/server/src/routes/github/routes/list-prs.ts (3)
GitHubLabel(9-12)GitHubAuthor(14-16)GitHubPR(18-31)apps/server/src/routes/github/routes/check-github-remote.ts (1)
GitHubRemoteStatus(8-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: e2e
🔇 Additional comments (5)
apps/ui/src/lib/http-api-client.ts (1)
24-26: LGTM! Clean GitHub API integration.The GitHub API implementation follows the established patterns in this file. The endpoints are properly typed, and the request structure (POST with projectPath payload) aligns with the server-side routes.
Also applies to: 749-754
apps/ui/src/store/app-store.ts (1)
254-270: LGTM! Proper type refinement for UI layer.The Feature interface correctly extends BaseFeature while refining types for UI-specific needs. The pattern of using
Omitto exclude base fields and then re-adding them with stricter or UI-specific types is appropriate here.apps/ui/src/lib/electron.ts (3)
95-159: LGTM! Type definitions align with server contracts.The GitHub type definitions (GitHubLabel, GitHubAuthor, GitHubIssue, GitHubPR, GitHubRemoteStatus) and the GitHubAPI interface properly match the server-side implementations. All response types include appropriate success/error handling.
394-394: LGTM! Proper API surface extension.The GitHub API is correctly added as an optional property on the ElectronAPI interface, maintaining backward compatibility and following the pattern of other optional API surfaces.
942-943: LGTM! Appropriate mock implementation.The mock GitHub API implementation returns sensible empty/false values for development and testing. The console logging aids debugging, and the response structure properly matches the API contracts.
Also applies to: 2605-2635
| // Determine final status based on testing mode: | ||
| // - skipTests=false (automated testing): go directly to 'verified' (no manual verify needed) | ||
| // - skipTests=true (manual verification): go to 'waiting_approval' for manual review | ||
| const finalStatus = feature.skipTests ? 'waiting_approval' : 'verified'; | ||
| await this.updateFeatureStatus(projectPath, featureId, finalStatus); |
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Explore repository structure and find the target file
echo "=== Repository structure ==="
git ls-files | head -20
echo ""
echo "=== Looking for auto-mode-service.ts ==="
find . -name "auto-mode-service.ts" -type f
echo ""
echo "=== Checking if feature.json files exist ==="
fd -e json feature.json || echo "No feature.json files found"
echo ""
echo "=== Searching for TypeScript feature-related files ==="
fd -type f -name "*.ts" | grep -i feature | head -20Repository: AutoMaker-Org/automaker
Length of output: 957
🏁 Script executed:
#!/bin/bash
# Examine the auto-mode-service.ts file, particularly around lines 610-614
echo "=== Examining auto-mode-service.ts lines 600-630 ==="
if [ -f "apps/server/src/services/auto-mode-service.ts" ]; then
sed -n '600,630p' "apps/server/src/services/auto-mode-service.ts" | cat -n
else
echo "File not found"
fi
echo ""
echo "=== Checking lines 880-900 for consistency ==="
if [ -f "apps/server/src/services/auto-mode-service.ts" ]; then
sed -n '880,900p' "apps/server/src/services/auto-mode-service.ts" | cat -n
fi
echo ""
echo "=== Looking for feature interface/type definition ==="
rg "interface.*Feature|type.*Feature" --type ts -A 10 | head -50Repository: AutoMaker-Org/automaker
Length of output: 5300
🏁 Script executed:
#!/bin/bash
# Search for skipTests usage and definition throughout the codebase
echo "=== Searching for skipTests in the codebase ==="
rg "skipTests" --type ts -B 2 -A 2
echo ""
echo "=== Searching for feature type definition with skipTests ==="
rg "skipTests.*\?" --type ts | head -20Repository: AutoMaker-Org/automaker
Length of output: 23321
🏁 Script executed:
#!/bin/bash
# Check how feature data is initialized and if skipTests has a default value
echo "=== Searching for feature initialization or factory methods ==="
rg "feature\s*=\s*|new Feature|createFeature" --type ts -A 3 | head -100
echo ""
echo "=== Looking for database schema or migrations ==="
fd -type f -name "*.ts" | xargs rg -l "skipTests\|Feature.*schema" | head -10Repository: AutoMaker-Org/automaker
Length of output: 7412
🏁 Script executed:
#!/bin/bash
# Check how features are persisted and if skipTests is properly saved/loaded
echo "=== Looking for feature persistence code ==="
rg "updateFeatureStatus|saveFeature|persistFeature" --type ts -B 2 -A 5 | head -80
echo ""
echo "=== Checking feature serialization/deserialization ==="
rg "JSON.stringify.*feature|JSON.parse.*feature" --type ts -B 2 -A 2 | head -50
echo ""
echo "=== Looking for feature data initialization in tests ==="
rg "Feature\|skipTests" --type ts apps/server/tests | head -40Repository: AutoMaker-Org/automaker
Length of output: 11905
🏁 Script executed:
#!/bin/bash
# Check how feature data flows - from creation to execution
echo "=== Searching for Feature type usage in auto-mode-service.ts ==="
sed -n '1,50p' apps/server/src/services/auto-mode-service.ts | cat -n
echo ""
echo "=== Check imports and Feature type definition ==="
grep -n "import.*Feature\|type Feature" apps/server/src/services/auto-mode-service.ts | head -10
echo ""
echo "=== Verify how feature is loaded in executeFeature ==="
sed -n '515,530p' apps/server/src/services/auto-mode-service.ts | cat -nRepository: AutoMaker-Org/automaker
Length of output: 3419
🏁 Script executed:
#!/bin/bash
# Examine the Feature type definition more thoroughly
echo "=== Full Feature interface definition ==="
cat -n libs/types/src/feature.ts | grep -A 50 "export interface Feature"Repository: AutoMaker-Org/automaker
Length of output: 1953
Clarify default behavior for existing features without skipTests field.
The skipTests field is optional in the Feature interface. When undefined, the ternary operator feature.skipTests ? 'waiting_approval' : 'verified' treats it as falsy, defaulting features to 'verified' (auto-verified).
For existing features created before this PR (without an explicit skipTests value), this means they will automatically skip manual verification and receive 'verified' status. Ensure this backward-compatible default is intentional. If all features should require explicit verification setting, consider using feature.skipTests ?? false instead of relying on falsy evaluation, or add a migration to set skipTests: false for existing features.
🤖 Prompt for AI Agents
In apps/server/src/services/auto-mode-service.ts around lines 610 to 614, the
ternary uses feature.skipTests as a boolean but skipTests is optional so
undefined will be treated as falsy and incorrectly auto-verify older features;
change the evaluation to explicitly default undefined to false (e.g., use
feature.skipTests ?? false) so existing features behave as intended, or if you
prefer a data fix create a one-time migration that sets skipTests: false on
existing records before using the field.
| // Available models for feature execution | ||
| export type ClaudeModel = 'opus' | 'sonnet' | 'haiku'; |
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for ClaudeModel type usage in the codebase (excluding the definition file)
rg -n "ClaudeModel" --type=ts --type=tsx -C 2 -g '!apps/ui/src/store/app-store.ts'Repository: AutoMaker-Org/automaker
Length of output: 94
🏁 Script executed:
#!/bin/bash
# Search for ClaudeModel type usage excluding the definition file
# Use glob patterns instead of file type flags
rg -n "ClaudeModel" -g '*.ts' -g '*.tsx' -g '!apps/ui/src/store/app-store.ts'Repository: AutoMaker-Org/automaker
Length of output: 321
🏁 Script executed:
#!/bin/bash
# Search for exact ClaudeModel type usage with word boundaries
rg -w "ClaudeModel" -g '*.ts' -g '*.tsx' -g '!apps/ui/src/store/app-store.ts'Repository: AutoMaker-Org/automaker
Length of output: 49
🏁 Script executed:
#!/bin/bash
# Search for imports of ClaudeModel from app-store.ts
rg "from.*app-store|import.*ClaudeModel" -g '*.ts' -g '*.tsx'Repository: AutoMaker-Org/automaker
Length of output: 11541
Remove unused ClaudeModel type or confirm future use.
The exported ClaudeModel type is not imported or used anywhere in the codebase and appears to be dead code. Either remove it or confirm it's intended for future implementation.
🤖 Prompt for AI Agents
In apps/ui/src/store/app-store.ts around lines 251 to 252, the exported
ClaudeModel type appears unused; either remove the declaration to eliminate dead
code (delete the export and its type union) or, if it's intended for future use,
retain it but add a clear TODO comment referencing the intended feature and a
ticket/issue number and ensure it's imported/used where planned; pick one option
and apply it so the codebase has no unexplained unused exports.
- Introduced a comprehensive E2E Testing Guide outlining best practices for Playwright tests, including principles for test isolation, element selection, and setup utilities. - Added new test files for project creation and opening existing projects, ensuring functionality for creating blank projects and projects from GitHub templates. - Implemented utility functions for setting up test states and managing localStorage, enhancing maintainability and reducing boilerplate 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
🧹 Nitpick comments (2)
apps/ui/tests/open-project.spec.ts (1)
117-118: Consider wrapping subdirectory checks in polling for consistency.Lines 112-114 use
toPassfor polling thecategories.jsoncheck, but lines 117-118 use synchronous assertions forfeaturesandcontextdirectories. If initialization is async, these could intermittently fail.🔎 Suggested improvement for consistent polling
- // Verify subdirectories were created - expect(fs.existsSync(path.join(automakerDir, 'features'))).toBe(true); - expect(fs.existsSync(path.join(automakerDir, 'context'))).toBe(true); + // Verify subdirectories were created + await expect(async () => { + expect(fs.existsSync(path.join(automakerDir, 'features'))).toBe(true); + expect(fs.existsSync(path.join(automakerDir, 'context'))).toBe(true); + }).toPass({ timeout: 10000 });apps/ui/tests/utils/project/setup.ts (1)
166-191: Inconsistent use of hardcoded version instead of STORE_VERSIONS.
setupMockProjectand many other existing functions still useversion: 2directly instead of the centralizedSTORE_VERSIONS.APP_STORE. This creates maintenance burden if the version changes.🔎 Example refactor for setupMockProject
export async function setupMockProject(page: Page): Promise<void> { - await page.addInitScript(() => { + await page.addInitScript((versions: typeof STORE_VERSIONS) => { const mockProject = { id: 'test-project-1', name: 'Test Project', path: '/mock/test-project', lastOpened: new Date().toISOString(), }; const mockState = { state: { projects: [mockProject], currentProject: mockProject, theme: 'dark', sidebarOpen: true, apiKeys: { anthropic: '', google: '' }, chatSessions: [], chatHistoryOpen: false, maxConcurrency: 3, }, - version: 2, // Must match app-store.ts persist version + version: versions.APP_STORE, }; localStorage.setItem('automaker-storage', JSON.stringify(mockState)); - }); + }, STORE_VERSIONS); }This applies to:
setupMockProject,setupMockProjectWithConcurrency,setupMockProjectAtConcurrencyLimit,setupMockProjectWithFeatures,setupMockProjectWithContextFile,setupMockProjectWithInProgressFeatures,setupMockProjectWithView,setupEmptyLocalStorage,setupMockProjectsWithoutCurrent,setupMockProjectWithSkipTestsFeatures,setupMockMultipleProjects,setupMockProjectWithAgentOutput,setupMockProjectWithWaitingApprovalFeatures,setupFirstRun, andsetupMockProjectWithProfiles.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/ui/tests/e2e-testing-guide.mdapps/ui/tests/open-project.spec.tsapps/ui/tests/project-creation.spec.tsapps/ui/tests/utils/project/setup.ts
✅ Files skipped from review due to trivial changes (1)
- apps/ui/tests/e2e-testing-guide.md
🧰 Additional context used
🧬 Code graph analysis (2)
apps/ui/tests/project-creation.spec.ts (2)
apps/ui/tests/utils/git/worktree.ts (2)
createTempDirPath(52-55)cleanupTempDir(149-153)apps/ui/tests/utils/project/setup.ts (1)
setupWelcomeView(39-86)
apps/ui/tests/open-project.spec.ts (2)
apps/ui/tests/utils/git/worktree.ts (2)
createTempDirPath(52-55)cleanupTempDir(149-153)apps/ui/tests/utils/project/setup.ts (1)
setupWelcomeView(39-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: e2e
🔇 Additional comments (7)
apps/ui/tests/open-project.spec.ts (2)
1-14: LGTM!Clear documentation and appropriate imports for the E2E test. The imports from
./utilsare correctly referencing the shared test utilities.
16-30: LGTM!Good use of
beforeAll/afterAllfor temp directory lifecycle. The unique temp dir path prevents test isolation issues when running in parallel.apps/ui/tests/project-creation.spec.ts (2)
1-28: LGTM!Standard test scaffolding with proper setup/teardown for temp directory management.
30-98: LGTM!Well-structured test for blank project creation. Good coverage of:
- UI interaction flow (modals, inputs, buttons)
- Filesystem verification (project structure, app_spec.txt content)
- Project selector validation
apps/ui/tests/utils/project/setup.ts (3)
39-86: LGTM!Well-documented function with proper TypeScript typing. The use of
addInitScriptwith a parameter object ensures the version constants are properly serialized to the browser context.
97-160: LGTM!The
setupRealProjectfunction follows the same pattern assetupWelcomeViewand properly handles the optionalsetAsCurrentbehavior.
756-771: LGTM!Good refactor of
setupCompleteto use the centralizedSTORE_VERSIONSconstant.
| test('should create a new project from GitHub template', async ({ page }) => { | ||
| // Increase timeout for this test since git clone takes time | ||
| test.setTimeout(60000); | ||
|
|
||
| const projectName = `template-project-${Date.now()}`; | ||
|
|
||
| // Set up welcome view with workspace directory pre-configured | ||
| await setupWelcomeView(page, { workspaceDir: TEST_TEMP_DIR }); | ||
|
|
||
| // Navigate to the app | ||
| await page.goto('/'); | ||
| await page.waitForLoadState('networkidle'); | ||
|
|
||
| // Wait for welcome view to be visible | ||
| await expect(page.locator('[data-testid="welcome-view"]')).toBeVisible({ timeout: 10000 }); | ||
|
|
||
| // Click the "Create New Project" dropdown button | ||
| const createButton = page.locator('[data-testid="create-new-project"]'); | ||
| await expect(createButton).toBeVisible(); | ||
| await createButton.click(); | ||
|
|
||
| // Click "Quick Setup" option from the dropdown | ||
| const quickSetupOption = page.locator('[data-testid="quick-setup-option"]'); | ||
| await expect(quickSetupOption).toBeVisible(); | ||
| await quickSetupOption.click(); | ||
|
|
||
| // Wait for the new project modal to appear | ||
| const modal = page.locator('[data-testid="new-project-modal"]'); | ||
| await expect(modal).toBeVisible({ timeout: 5000 }); | ||
|
|
||
| // Enter the project name first | ||
| const projectNameInput = page.locator('[data-testid="project-name-input"]'); | ||
| await expect(projectNameInput).toBeVisible(); | ||
| await projectNameInput.fill(projectName); | ||
|
|
||
| // Wait for workspace directory to be loaded | ||
| await expect(page.getByText('Will be created at:')).toBeVisible({ timeout: 5000 }); | ||
|
|
||
| // Click on the "Starter Kit" tab | ||
| const starterKitTab = modal.getByText('Starter Kit'); | ||
| await expect(starterKitTab).toBeVisible(); | ||
| await starterKitTab.click(); | ||
|
|
||
| // Select the first template (Automaker Starter Kit) | ||
| const firstTemplate = page.locator('[data-testid="template-automaker-starter-kit"]'); | ||
| await expect(firstTemplate).toBeVisible(); | ||
| await firstTemplate.click(); | ||
|
|
||
| // Verify the template is selected (check mark should appear) | ||
| await expect(firstTemplate.locator('.lucide-check')).toBeVisible(); | ||
|
|
||
| // Click the Create Project button | ||
| const createProjectButton = page.locator('[data-testid="confirm-create-project"]'); | ||
| await expect(createProjectButton).toBeVisible(); | ||
| await createProjectButton.click(); | ||
|
|
||
| // Wait for git clone to complete and board view to appear | ||
| // This takes longer due to the git clone operation | ||
| await expect(page.locator('[data-testid="board-view"]')).toBeVisible({ timeout: 45000 }); | ||
|
|
||
| // Verify the project name appears in the project selector (sidebar) | ||
| await expect( | ||
| page.locator('[data-testid="project-selector"]').getByText(projectName) | ||
| ).toBeVisible({ timeout: 5000 }); | ||
|
|
||
| // Verify the project was cloned in the filesystem | ||
| const projectPath = path.join(TEST_TEMP_DIR, projectName); | ||
| expect(fs.existsSync(projectPath)).toBe(true); | ||
|
|
||
| // Verify .automaker directory was created | ||
| const automakerDir = path.join(projectPath, '.automaker'); | ||
| expect(fs.existsSync(automakerDir)).toBe(true); | ||
|
|
||
| // Verify app_spec.txt was created with template info | ||
| const appSpecPath = path.join(automakerDir, 'app_spec.txt'); | ||
| expect(fs.existsSync(appSpecPath)).toBe(true); | ||
| const appSpecContent = fs.readFileSync(appSpecPath, 'utf-8'); | ||
| expect(appSpecContent).toContain(projectName); | ||
| expect(appSpecContent).toContain('Automaker Starter Kit'); | ||
|
|
||
| // Verify the template files were cloned (check for package.json which should exist in the template) | ||
| const packageJsonPath = path.join(projectPath, 'package.json'); | ||
| expect(fs.existsSync(packageJsonPath)).toBe(true); | ||
|
|
||
| // Verify it's a git repository (cloned from GitHub) | ||
| const gitDir = path.join(projectPath, '.git'); | ||
| expect(fs.existsSync(gitDir)).toBe(true); | ||
| }); |
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.
Consider conditionally skipping this test in CI environments without network access, or document the GitHub/network dependency.
This test performs an actual git clone operation with a 45-second timeout. External network calls and third-party services you don't control are common sources of test flakiness and failures. Network-dependent tests risk failing in air-gapped CI runners or during GitHub outages.
Options:
- Add a skip condition using
test.skip(process.env.CI, 'reason')if running in CI without network, or - Mock a local git server instead of cloning from GitHub (tools exist for this purpose), or
- Document this test's network requirement clearly in the test file or CI configuration so teams understand why it may fail intermittently.
🤖 Prompt for AI Agents
In apps/ui/tests/project-creation.spec.ts around lines 100 to 187, the
integration test performs a real git clone which will fail on air-gapped CI or
flaky networks; update the test to conditionally skip in CI or when network
access is disallowed and document the dependency. Add a guard at the top or
right before the test such as using test.skip(process.env.CI &&
!process.env.ALLOW_NETWORK_TESTS, 'skipping network-dependent test in
CI/no-network environments') or detect network reachability and call
test.skip(...) when unreachable; alternatively add a clear file-level
comment/README note explaining the GitHub/network requirement and how to enable
the test (e.g., set ALLOW_NETWORK_TESTS=true or run on runners with network
access).
| /** | ||
| * Store version constants - centralized to avoid hardcoding across tests | ||
| * These MUST match the versions used in the actual stores | ||
| */ | ||
| const STORE_VERSIONS = { | ||
| APP_STORE: 2, // Must match app-store.ts persist version | ||
| SETUP_STORE: 0, // setup-store.ts doesn't specify a version, so zustand defaults to 0 | ||
| } as const; |
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check APP_STORE version in app-store.ts
echo "=== app-store.ts persist version ==="
find . -name "app-store.ts" -o -name "app-store.tsx" | head -5
echo ""
echo "=== Searching for app-store ==="
fd -e ts -e tsx -x grep -l "app-store" {} \; | head -10
echo ""
echo "=== Checking for persist with version ==="
fd -e ts -e tsx "store" | head -20 | xargs grep -l "persist" | head -10Repository: AutoMaker-Org/automaker
Length of output: 789
🏁 Script executed:
#!/bin/bash
# Find all store files
echo "=== Looking for store files ==="
find . -path ./node_modules -prune -o -name "*store*.ts" -o -name "*store*.tsx" | grep -v node_modules | head -20Repository: AutoMaker-Org/automaker
Length of output: 221
🏁 Script executed:
#!/bin/bash
# Search for app-store and setup-store with persist version declarations
echo "=== Searching for app-store persist version ==="
rg -n "version\s*[:=]" --type ts --type tsx | grep -i "app-store" -A3 -B3
echo ""
echo "=== Searching for setup-store persist version ==="
rg -n "version\s*[:=]" --type ts --type tsx | grep -i "setup-store" -A3 -B3
echo ""
echo "=== Finding all store files with persist ==="
rg -l "persist\(" --type ts --type tsx | grep storeRepository: AutoMaker-Org/automaker
Length of output: 312
🏁 Script executed:
#!/bin/bash
# Read app-store.ts and look for persist version
echo "=== app-store.ts persist config ==="
head -100 ./apps/ui/src/store/app-store.ts | grep -A 10 -B 5 "persist\|version"
echo ""
echo "=== setup-store.ts persist config ==="
head -100 ./apps/ui/src/store/setup-store.ts | grep -A 10 -B 5 "persist\|version"Repository: AutoMaker-Org/automaker
Length of output: 1125
🏁 Script executed:
#!/bin/bash
# Read app-store.ts and look for persist configuration with version
echo "=== app-store.ts - searching for persist() configuration ==="
cat ./apps/ui/src/store/app-store.ts | grep -A 20 "persist("
echo ""
echo "=== setup-store.ts - searching for persist() configuration ==="
cat ./apps/ui/src/store/setup-store.ts | grep -A 20 "persist("Repository: AutoMaker-Org/automaker
Length of output: 1356
🏁 Script executed:
#!/bin/bash
# Read app-store.ts and look for the persist options (second argument)
echo "=== app-store.ts - full persist configuration ==="
cat ./apps/ui/src/store/app-store.ts | grep -A 50 "persist(" | tail -40
echo ""
echo "=== setup-store.ts - full persist configuration ==="
cat ./apps/ui/src/store/setup-store.ts | grep -A 50 "persist(" | tail -40Repository: AutoMaker-Org/automaker
Length of output: 2585
🏁 Script executed:
#!/bin/bash
# Read app-store.ts and look for the closing bracket of persist options
echo "=== app-store.ts - persist options ==="
cat ./apps/ui/src/store/app-store.ts | grep -A 100 "persist(" | grep -A 10 "}, {" | head -20
echo ""
echo "=== setup-store.ts - persist options (complete) ==="
cat ./apps/ui/src/store/setup-store.ts | grep -A 100 "persist(" | grep -A 15 "partialize:"Repository: AutoMaker-Org/automaker
Length of output: 343
🏁 Script executed:
#!/bin/bash
# Get the complete persist closing bracket and options for app-store.ts
echo "=== app-store.ts - complete file to find persist closing ==="
wc -l ./apps/ui/src/store/app-store.ts
echo ""
echo "=== app-store.ts - last 100 lines ==="
tail -100 ./apps/ui/src/store/app-store.ts
echo ""
echo "=== setup-store.ts - complete file to find persist closing ==="
wc -l ./apps/ui/src/store/setup-store.ts
echo ""
echo "=== setup-store.ts - last 50 lines ==="
tail -50 ./apps/ui/src/store/setup-store.tsRepository: AutoMaker-Org/automaker
Length of output: 6327
🏁 Script executed:
#!/bin/bash
# Find the version property in persist options for app-store.ts
echo "=== app-store.ts - search for 'version:' in persist options ==="
grep -n "version:" ./apps/ui/src/store/app-store.ts
echo ""
echo "=== app-store.ts - lines around version property ==="
grep -B 5 -A 5 "version:" ./apps/ui/src/store/app-store.ts | head -30Repository: AutoMaker-Org/automaker
Length of output: 1460
🏁 Script executed:
#!/bin/bash
# Verify setup-store.ts does NOT have a version property
echo "=== setup-store.ts - complete persist options ==="
grep -A 20 "persist(" ./apps/ui/src/store/setup-store.ts | tail -25Repository: AutoMaker-Org/automaker
Length of output: 631
Good centralization of version constants.
This approach prevents version drift. The comments clearly indicate the dependency on actual store versions.
However, the SETUP_STORE: 0 constant is incorrect. The setup-store.ts file has no version property in its persist options, meaning version checking is disabled entirely—not defaulting to 0. Add version: 0 to setup-store.ts's persist configuration, or remove SETUP_STORE from the constant if version management is not needed for that store.
🤖 Prompt for AI Agents
In apps/ui/tests/utils/project/setup.ts around lines 3 to 10, SETUP_STORE is set
to 0 but setup-store.ts does not define a persist version (version checking is
disabled), so the constant is incorrect; either add version: 0 to the persist
options in setup-store.ts to enable versioning and keep SETUP_STORE: 0, or
remove SETUP_STORE from the centralized STORE_VERSIONS if you do not intend to
manage versions for the setup store—update the tests/constants accordingly to
reflect the chosen approach.
- Updated the list-issues and list-prs handlers to fetch open and closed issues, as well as open and merged PRs in parallel, improving performance. - Removed the redundant 'issues' and 'prs' properties from the result interfaces to streamline the response structure. - Added 'skipTests' flag in integration tests to indicate tests that should be skipped, enhancing test management.
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
♻️ Duplicate comments (1)
apps/server/src/routes/github/routes/list-issues.ts (1)
21-21: Use literal type forstateproperty.The
stateproperty should use a literal type ('OPEN' | 'CLOSED') instead of a genericstringfor better type safety.
🧹 Nitpick comments (1)
apps/server/src/routes/github/routes/list-issues.ts (1)
77-78: Consider more defensive JSON parsing.While the current error handling will catch JSON parsing failures, adding explicit validation or a more informative error message could improve debuggability when the GitHub CLI returns unexpected output.
💡 Optional enhancement
-const openIssues: GitHubIssue[] = JSON.parse(openStdout || '[]'); -const closedIssues: GitHubIssue[] = JSON.parse(closedStdout || '[]'); +let openIssues: GitHubIssue[] = []; +let closedIssues: GitHubIssue[] = []; + +try { + openIssues = JSON.parse(openStdout || '[]'); + closedIssues = JSON.parse(closedStdout || '[]'); +} catch (parseError) { + logError(parseError, 'Failed to parse GitHub CLI output'); + throw new Error('Invalid response from GitHub CLI'); +}
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/server/src/routes/github/routes/list-issues.tsapps/server/src/routes/github/routes/list-prs.tsapps/server/tests/integration/services/auto-mode-service.integration.test.ts
✅ Files skipped from review due to trivial changes (1)
- apps/server/tests/integration/services/auto-mode-service.integration.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/server/src/routes/github/routes/list-prs.ts
🧰 Additional context used
🧬 Code graph analysis (1)
apps/server/src/routes/github/routes/list-issues.ts (4)
apps/server/src/routes/github/routes/list-prs.ts (2)
GitHubLabel(9-12)GitHubAuthor(14-16)apps/ui/src/lib/electron.ts (3)
GitHubLabel(96-99)GitHubAuthor(101-103)GitHubIssue(105-114)apps/server/src/routes/github/routes/check-github-remote.ts (1)
checkGitHubRemote(15-49)apps/server/src/routes/github/routes/common.ts (4)
execAsync(8-8)execEnv(21-24)logError(33-35)getErrorMessage(26-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: e2e
🔇 Additional comments (1)
apps/server/src/routes/github/routes/list-issues.ts (1)
56-72: Excellent optimization - parallel issue fetching implemented.The parallel fetching of open and closed issues using
Promise.alladdresses the previous review feedback and will improve response times.
| export interface GitHubLabel { | ||
| name: string; | ||
| color: string; | ||
| } | ||
|
|
||
| export interface GitHubAuthor { | ||
| login: string; | ||
| } | ||
|
|
||
| export interface GitHubIssue { | ||
| number: number; | ||
| title: string; | ||
| state: string; | ||
| author: GitHubAuthor; | ||
| createdAt: string; | ||
| labels: GitHubLabel[]; | ||
| url: string; | ||
| body: string; | ||
| } |
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
Extract duplicated type definitions to a shared module.
The interfaces GitHubLabel, GitHubAuthor, and GitHubIssue are duplicated across multiple files:
apps/server/src/routes/github/routes/list-prs.tsapps/ui/src/lib/electron.ts- This file
Centralizing these types in a shared module will prevent definition drift and reduce maintenance burden.
💡 Suggested approach
Consider creating a shared types file such as apps/server/src/routes/github/types.ts to export these common interfaces, then import them in both route handlers.
🤖 Prompt for AI Agents
In apps/server/src/routes/github/routes/list-issues.ts lines 9-27: the
interfaces GitHubLabel, GitHubAuthor, and GitHubIssue are duplicated across
multiple files; extract them into a single exported module (e.g.,
apps/server/src/routes/github/types.ts) that exports these three interfaces,
then replace the local definitions with an import from that new module in this
file and also update apps/server/src/routes/github/routes/list-prs.ts and
apps/ui/src/lib/electron.ts to import the shared types; ensure the new types
file uses named exports and adjust relative import paths in each file
accordingly so all references compile.
| const [openResult, closedResult] = await Promise.all([ | ||
| execAsync( | ||
| 'gh issue list --state open --json number,title,state,author,createdAt,labels,url,body --limit 100', | ||
| { | ||
| cwd: projectPath, | ||
| env: execEnv, | ||
| } | ||
| ), | ||
| execAsync( | ||
| 'gh issue list --state closed --json number,title,state,author,createdAt,labels,url,body --limit 50', | ||
| { | ||
| cwd: projectPath, | ||
| env: execEnv, | ||
| } | ||
| ), |
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.
Add timeout to prevent indefinite blocking on CLI commands.
The GitHub CLI commands lack timeout protection. If the gh process hangs due to network issues, rate limits, or other failures, the request thread will block indefinitely, degrading service availability.
🔧 Recommended fix
Add a timeout to the execAsync options:
const [openResult, closedResult] = await Promise.all([
execAsync(
'gh issue list --state open --json number,title,state,author,createdAt,labels,url,body --limit 100',
{
cwd: projectPath,
env: execEnv,
+ timeout: 30000, // 30 second timeout
}
),
execAsync(
'gh issue list --state closed --json number,title,state,author,createdAt,labels,url,body --limit 50',
{
cwd: projectPath,
env: execEnv,
+ timeout: 30000, // 30 second timeout
}
),
]);🤖 Prompt for AI Agents
In apps/server/src/routes/github/routes/list-issues.ts around lines 57 to 71,
the two execAsync calls invoking the `gh` CLI lack a timeout and can block
forever; add a timeout option (e.g. timeout: 30000) to each execAsync options
object so the child process is killed after a reasonable period, and update the
surrounding error handling to catch timeout errors (or treat them as transient
failures) and return/throw an appropriate error (e.g. 504 or a descriptive log)
instead of allowing indefinite blocking.
Summary by CodeRabbit
New Features
Improvements
Documentation
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.