Skip to content

Conversation

@webdevcody
Copy link
Collaborator

@webdevcody webdevcody commented Dec 22, 2025

Summary by CodeRabbit

  • New Features

    • GitHub integration: in-app Issues and PRs views with navigation and remote detection
  • Improvements

    • Simplified feature model and UI: removed manual "steps" from creation, editing, and views
    • Auto-mode: conditional auto-verification and verification guidance
    • Project creation/onboarding robustness
  • Documentation

    • Added Playwright end-to-end testing guide
  • Tests

    • New e2e tests for project creation and opening
  • Chores

    • Added security audit CI workflow

✏️ Tip: You can customize this high-level summary in your review settings.

Test User added 2 commits December 22, 2025 02:33
…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.
@coderabbitai
Copy link

coderabbitai bot commented Dec 22, 2025

Note

Other AI code review bot(s) detected

CodeRabbit 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.

Walkthrough

Adds GitHub integration (server routes, CLI wrappers, UI views, Electron & HTTP client bindings and mocks), removes steps from features/suggestions across types and UI, adjusts auto-mode verification behavior using skipTests, updates project-creation clone calls, and adds a Security Audit GitHub Actions workflow.

Changes

Cohort / File(s) Summary
CI — Security Audit Workflow
\.github/workflows/security-audit.yml
New GitHub Actions workflow triggered on PRs, pushes to main/master, and weekly; runs local setup action ./.github/actions/setup-project and executes npm audit at moderate.
Server — GitHub Routes & Utilities
apps/server/src/index.ts, apps/server/src/routes/github/index.ts, apps/server/src/routes/github/routes/check-github-remote.ts, apps/server/src/routes/github/routes/common.ts, apps/server/src/routes/github/routes/list-issues.ts, apps/server/src/routes/github/routes/list-prs.ts
New /api/github endpoints (check-remote, issues, prs) with shared exec/env helpers; call git/gh CLI, parse JSON, and return structured results with error handling.
UI — GitHub Views & Routes
apps/ui/src/components/views/github-issues-view.tsx, apps/ui/src/components/views/github-prs-view.tsx, apps/ui/src/routes/github-issues.tsx, apps/ui/src/routes/github-prs.tsx
New React views and router entries to list and inspect GitHub issues and PRs (loading, refresh, error, detail panels).
UI — Navigation Integration
apps/ui/src/components/layout/sidebar/hooks/use-navigation.ts, apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx
Electron API remote check added; sidebar conditionally shows a GitHub section (Issues, Pull Requests) when repo has a GitHub remote.
Client APIs & Mocks
apps/ui/src/lib/electron.ts, apps/ui/src/lib/http-api-client.ts
Added GitHub types and github API surface to ElectronAPI and HttpApiClient; implemented mock GitHub API for local/web mocks.
Remove steps — Server Suggestions
apps/server/src/routes/suggestions/generate-suggestions.ts
Removed steps from suggestion JSON schema, fallback objects, and prompt text.
Remove steps — UI: Views, Dialogs, Hooks
apps/ui/src/components/views/analysis-view.tsx, apps/ui/src/components/views/board-view.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/board-view/dialogs/edit-feature-dialog.tsx, apps/ui/src/components/views/board-view/dialogs/feature-suggestions-dialog.tsx, apps/ui/src/components/views/board-view/hooks/use-board-actions.ts
Dropped steps from DetectedFeature and feature payloads; dialogs, suggestion imports, and creation/update flows no longer include steps.
Remove steps — UI Components
apps/ui/src/components/views/board-view/components/kanban-card/card-content-sections.tsx, apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx, apps/ui/src/components/views/board-view/shared/testing-tab-content.tsx
Removed steps-related props/UI (showSteps, steps, onStepsChange) and inputs; testing tab now shows Playwright-like verification instructions.
Types & Store — Feature Shape
libs/types/src/feature.ts, apps/ui/src/store/app-store.ts
Removed steps?: string[] from public Feature type; store Feature shape augmented with id, title, titleGenerating, imagePaths, etc.; added ClaudeModel type and removed some legacy re-exports.
Auto-Mode & Project Creation
apps/server/src/services/auto-mode-service.ts, apps/ui/src/components/hooks/use-project-creation.ts
Auto-mode computes finalStatus based on feature?.skipTests and injects verification instructions into prompts; project creation now uses templates.clone and verifies clone results before proceeding.
Tests & Test Utilities
apps/ui/tests/e2e-testing-guide.md, apps/ui/tests/open-project.spec.ts, apps/ui/tests/project-creation.spec.ts, apps/ui/tests/utils/project/setup.ts
New Playwright guide, new e2e tests for opening/creating projects, and test setup utilities (STORE_VERSIONS, setupWelcomeView, setupRealProject, TestProject types).
Misc — Small UI Style Change
apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx
Minor syntactic rewrite of nav item onClick handler (no behavior change).

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

  • Areas to focus during review:
    • Robustness and parsing of Git/GH CLI invocations and env/PATH handling (server github routes, common.ts).
    • Consistency between Electron API types, HttpApiClient routes, and server endpoints (mocks vs real behavior).
    • Broad impact of removing steps across types, store, dialogs, UI rendering, and e2e tests.
    • Auto-mode finalStatus computation and prompt injection correctness.
    • Project-creation clone flow and error handling around templates.clone results.

Possibly related PRs

Suggested labels

Refactor, Tests

Poem

🐰 I hopped through code at break of day,
Steps softly slipped and hopped away.
GitHub doors now open wide,
Issues, PRs, and CI stride.
A carrot-toast to tests — hooray! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.23% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title 'GitHub category' is vague and does not clearly summarize the main changes. The changeset includes extensive GitHub integration features (routes, handlers, UI views, API endpoints), removal of 'steps' field across multiple components, and various other updates, but the title only mentions 'GitHub category' which is overly narrow and generic. Consider using a more descriptive title that captures the primary scope, such as 'Add GitHub integration features and remove steps field from features' or 'Implement GitHub API integration with issues and PRs views'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch github-category

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @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

  • GitHub Integration: Introduced new server-side API endpoints and corresponding UI components to display GitHub issues and pull requests directly within the application. This includes functionality to check for GitHub remotes, list issues, and list PRs for the current project.
  • Streamlined Feature/Suggestion Data Model: The 'steps' field has been removed from feature and suggestion data models across the application, simplifying how tasks and recommendations are defined and presented.
  • Enhanced Auto-Mode Verification Logic: Auto-mode now intelligently determines the final status of a completed feature. If automated testing is enabled, features are directly marked as 'verified'; otherwise, they transition to 'waiting_approval' for manual review. Agent prompts have been updated to reflect these verification instructions.
  • Improved Project Creation Flow: Project creation, especially from templates or custom repositories, has been refined to use a new, more robust template cloning API, simplifying the underlying file system operations.
  • Simplified Testing Tab Content: The UI for the 'Testing' tab in feature dialogs has been simplified by removing the manual 'Verification Steps' input, aligning with the new auto-mode verification logic.

🧠 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
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/security-audit.yml
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a 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.

Comment on lines +35 to +36
const httpsMatch = remoteUrl.match(/https:\/\/github\.com\/([^/]+)\/([^/.]+)/);
const sshMatch = remoteUrl.match(/git@github\.com:([^/]+)\/([^/.]+)/);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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.

Suggested change
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
* 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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The state property is typed as a generic string. For better type safety and clarity, it should be a literal type representing the possible values returned by the GitHub CLI.

Suggested change
state: string;
state: 'OPEN' | 'CLOSED';

Comment on lines 58 to 73
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,
}
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The issues field in the response is redundant, as it's just a combination of openIssues and closedIssues. The client can construct this array if needed. Removing this field will simplify the API and reduce the payload size.

export interface GitHubPR {
number: number;
title: string;
state: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The state property is typed as a generic string. For better type safety and clarity, it should be a literal type representing the possible values.

Suggested change
state: string;
state: 'OPEN' | 'MERGED' | 'CLOSED';

isDraft: boolean;
headRefName: string;
reviewDecision: string | null;
mergeable: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The mergeable property is typed as a generic string. Using a literal type with possible values like 'MERGEABLE', 'CONFLICTING', and 'UNKNOWN' would improve type safety.

Suggested change
mergeable: string;
mergeable: 'MERGEABLE' | 'CONFLICTING' | 'UNKNOWN';

Comment on lines 62 to 77
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,
}
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The prs field in the response is redundant, as it's just a combination of openPRs and mergedPRs. The client can construct this array if needed. Removing this field will simplify the API and reduce the payload size.

Comment on lines +81 to +83
} catch {
setHasGitHubRemote(false);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The catch block is empty, which means any errors from checkGitHubRemote will be silently ignored. It's better to log these errors for debugging purposes.

      } catch (error) {
        console.error('Failed to check for GitHub remote:', error);
        setHasGitHubRemote(false);
      }

Copy link

@coderabbitai coderabbitai bot left a 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 in common.ts.

🧹 Nitpick comments (11)
apps/server/src/services/auto-mode-service.ts (1)

1661-1738: Clean bifurcation of verification instructions based on skipTests.

The conditional prompt generation is well-structured:

  • Manual mode (skipTests=true): Straightforward implementation with summary
  • Auto mode (skipTests=false): Includes Playwright verification workflow

One 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 expected
apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts (1)

125-264: Consider extracting shared logic to reduce duplication.

The handleCreateFromTemplate and handleCreateFromCustomUrl functions 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 steps field, aligning with the PR's broader changes. However, line 249 has a potentially confusing comment:

skipTests: true, // As specified, testing mode true

The comment "testing mode true" is misleading because skipTests: true means 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 tests
apps/ui/src/components/layout/sidebar/hooks/use-navigation.ts (1)

3-13: Consider removing unused Zap icon import.

The Zap icon 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.delimiter from Node's path module:

🔎 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: GitHubIssue and GitHubPR.

These types are imported but not used in this file. Only GitHubAPI is 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 like my.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.

AlertCircle is imported but never used in the component.

🔎 Proposed fix
   X,
-  AlertCircle,
 } from 'lucide-react';

251-260: Minor inefficiency: getReviewStatus called 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.

GitHubLabel and GitHubAuthor interfaces are duplicated in both list-prs.ts and list-issues.ts. Extract these shared types to common.ts to 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:

  1. Creating a shared types package (e.g., @automaker/types)
  2. 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

📥 Commits

Reviewing files that changed from the base of the PR and between a85dec6 and 9586589.

📒 Files selected for processing (31)
  • .github/workflows/security-audit.yml
  • apps/server/src/index.ts
  • apps/server/src/routes/github/index.ts
  • apps/server/src/routes/github/routes/check-github-remote.ts
  • apps/server/src/routes/github/routes/common.ts
  • apps/server/src/routes/github/routes/list-issues.ts
  • apps/server/src/routes/github/routes/list-prs.ts
  • apps/server/src/routes/suggestions/generate-suggestions.ts
  • apps/server/src/services/auto-mode-service.ts
  • apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx
  • apps/ui/src/components/layout/sidebar/hooks/use-navigation.ts
  • apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts
  • apps/ui/src/components/views/analysis-view.tsx
  • apps/ui/src/components/views/board-view.tsx
  • apps/ui/src/components/views/board-view/components/kanban-card/card-content-sections.tsx
  • apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx
  • apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx
  • apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx
  • apps/ui/src/components/views/board-view/dialogs/feature-suggestions-dialog.tsx
  • apps/ui/src/components/views/board-view/hooks/use-board-actions.ts
  • apps/ui/src/components/views/board-view/shared/testing-tab-content.tsx
  • apps/ui/src/components/views/github-issues-view.tsx
  • apps/ui/src/components/views/github-prs-view.tsx
  • apps/ui/src/components/views/interview-view.tsx
  • apps/ui/src/lib/electron.ts
  • apps/ui/src/lib/http-api-client.ts
  • apps/ui/src/routes/github-issues.tsx
  • apps/ui/src/routes/github-prs.tsx
  • apps/ui/src/store/app-store.ts
  • libs/types/src/feature.ts
  • package.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 finalStatus is clear and well-documented. The comments accurately explain the two modes:

  • skipTests=false → automated testing completed → verified
  • skipTests=true → manual verification required → waiting_approval

Since feature is already null-checked earlier (lines 512-514), accessing feature.skipTests directly is safe here.


874-883: LGTM!

The optional chaining on feature?.skipTests is appropriate here since feature may be null in followUpFeature. When feature is null or skipTests is undefined, the falsy value correctly defaults to 'verified', maintaining consistency with the main executeFeature logic.

package.json (2)

20-20: The exclusion of apps/server from the main build is intentional.

The codebase deliberately separates server and UI builds. The main build script targets the UI/Electron distribution, while apps/server has its own build:server command. CI workflows confirm this pattern: the PR check only runs build:electron:dir, and server tests run separately with test:server:coverage. During development, dev:full orchestrates 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 -w flags sequentially, not in parallel.

The build:packages command specifies multiple -w flags, 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.writeFile to writeFile aligns with the refactored Electron API structure.


106-106: LGTM: API call updated correctly.

The change from fs.createFolder to mkdir aligns with the refactored Electron API structure.


142-142: LGTM: API calls updated correctly.

The changes from fs.writeFile to writeFile align 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.success and result.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/github under 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 CardContentSections interface 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 steps and includes a clear title field. 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 title field 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@v4 and pinning to a specific major version is recommended.

Verify that the custom action referenced at ./.github/actions/setup-project exists 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 showSteps prop 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 useCallback dependency on currentProject?.path ensures 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 projectPath in the request body. Authentication middleware is properly applied at the /api level, 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: Use validatePathParams middleware to validate projectPath against allowed directories.

The route extracts projectPath from the request body without validating it against the configured allowed root directory. While checkGitHubRemote ensures 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 existing validatePathParams middleware (or call validatePath directly) 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 closed instead of --state merged). Error handling and response structure are consistent.

apps/ui/src/lib/electron.ts (3)

138-159: LGTM!

The GitHubAPI interface 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 github as an optional property is the correct approach, maintaining backward compatibility while extending the API surface.

Comment on lines +132 to +136
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!;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
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.

Comment on lines +204 to +208
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!;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
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.

Comment on lines +276 to +332
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>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Comment on lines +342 to +419
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>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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).

Copy link

@coderabbitai coderabbitai bot left a 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:

  1. Auto-detect the testing framework from package.json scripts or dependencies
  2. Make the verification approach configurable via project settings
  3. Provide framework-agnostic instructions like "run the project's test suite to verify"
  4. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 9586589 and 3a43033.

📒 Files selected for processing (8)
  • apps/server/src/index.ts
  • apps/server/src/services/auto-mode-service.ts
  • apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx
  • apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx
  • apps/ui/src/lib/electron.ts
  • apps/ui/src/lib/http-api-client.ts
  • apps/ui/src/store/app-store.ts
  • libs/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 Omit to 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

Comment on lines +610 to +614
// 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);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 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 -20

Repository: 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 -50

Repository: 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 -20

Repository: 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 -10

Repository: 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 -40

Repository: 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 -n

Repository: 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.

Comment on lines +251 to +252
// Available models for feature execution
export type ClaudeModel = 'opus' | 'sonnet' | 'haiku';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 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.
Copy link

@coderabbitai coderabbitai bot left a 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 toPass for polling the categories.json check, but lines 117-118 use synchronous assertions for features and context directories. 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.

setupMockProject and many other existing functions still use version: 2 directly instead of the centralized STORE_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, and setupMockProjectWithProfiles.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a43033 and 0c508ce.

📒 Files selected for processing (4)
  • apps/ui/tests/e2e-testing-guide.md
  • apps/ui/tests/open-project.spec.ts
  • apps/ui/tests/project-creation.spec.ts
  • apps/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 ./utils are correctly referencing the shared test utilities.


16-30: LGTM!

Good use of beforeAll/afterAll for 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 addInitScript with a parameter object ensures the version constants are properly serialized to the browser context.


97-160: LGTM!

The setupRealProject function follows the same pattern as setupWelcomeView and properly handles the optional setAsCurrent behavior.


756-771: LGTM!

Good refactor of setupComplete to use the centralized STORE_VERSIONS constant.

Comment on lines +100 to +187
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);
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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).

Comment on lines +3 to +10
/**
* 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;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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 -10

Repository: 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 -20

Repository: 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 store

Repository: 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 -40

Repository: 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.ts

Repository: 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 -30

Repository: 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 -25

Repository: 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.
Copy link

@coderabbitai coderabbitai bot left a 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 for state property.

The state property should use a literal type ('OPEN' | 'CLOSED') instead of a generic string for 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

📥 Commits

Reviewing files that changed from the base of the PR and between 0c508ce and edef4c7.

📒 Files selected for processing (3)
  • apps/server/src/routes/github/routes/list-issues.ts
  • apps/server/src/routes/github/routes/list-prs.ts
  • apps/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.all addresses the previous review feedback and will improve response times.

Comment on lines +9 to +27
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;
}
Copy link

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.ts
  • apps/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.

Comment on lines +57 to +71
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,
}
),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants