Skip to content

Conversation

@webdevcody
Copy link
Collaborator

@webdevcody webdevcody commented Dec 20, 2025

Summary

This PR adds automatic title generation for features using Claude Haiku.

Changes

  • New API endpoint: POST /features/generate-title that generates concise titles (5-10 words) from feature descriptions
  • UI updates:
    • Display titles in kanban cards with loading state indicator
    • Add optional title field to add/edit feature dialogs
    • Auto-generate titles when description is provided but title is empty
  • Additional improvements:
    • Add 'Pull & Resolve Conflicts' action to worktree dropdown
    • Show running agents count in board header (X / Y format)
  • Type updates: Feature interface now includes title and titleGenerating fields

Technical Details

  • Uses Claude Haiku model for fast, cost-effective title generation
  • Non-blocking title generation - features can be created immediately while title generates in background
  • Graceful error handling with fallback to description if generation fails

Summary by CodeRabbit

  • New Features
    • Added automatic title generation for features based on descriptions
    • Added optional title field to feature creation and editing dialogs
    • Added "Pull & Resolve Conflicts" action for managing git conflicts in worktrees
    • Added visual counter displaying active agents running in the board header
    • Added loading indicator when feature titles are being generated

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

- Add POST /features/generate-title endpoint using Claude Haiku
- Generate concise titles (5-10 words) from feature descriptions
- Display titles in kanban cards with loading state
- Add optional title field to add/edit feature dialogs
- Auto-generate titles when description provided but title empty
- Add 'Pull & Resolve Conflicts' action to worktree dropdown
- Show running agents count in board header (X / Y format)
- Update Feature interface to include title and titleGenerating fields
@coderabbitai
Copy link

coderabbitai bot commented Dec 20, 2025

Walkthrough

This PR introduces a title generation feature for features, allowing automatic or manual title creation via Claude Haiku. It adds a new server route endpoint, UI components for managing titles, Electron/HTTP API integrations, and conflict resolution handling with running agents count display.

Changes

Cohort / File(s) Summary
Title Generation Server Route
apps/server/src/routes/features/index.ts, apps/server/src/routes/features/routes/generate-title.ts
New POST /generate-title endpoint with Claude Haiku integration, streaming parser, input validation, and error handling. Route registration added to features router.
Feature Model & Store
apps/server/src/services/feature-loader.ts, apps/ui/src/store/app-store.ts
Feature interface extended with title?: string and titleGenerating?: boolean fields across server and UI store layers.
Feature Dialog Components
apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx, apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx
Title input field added to both create and edit feature dialogs; onAdd/onUpdate callback signatures updated to include title.
Kanban Card Rendering
apps/ui/src/components/views/board-view/components/kanban-card.tsx
Title display with conditional rendering for generating state (loader + "Generating title..." text); description moved to CardDescription with adjusted typography.
Board Actions Hook
apps/ui/src/components/views/board-view/hooks/use-board-actions.ts
Title generation integration via Electron API with async non-blocking execution; title field threaded through handleAddFeature and handleUpdateFeature; titleGenerating state managed on feature creation and update.
API Clients
apps/ui/src/lib/electron.ts, apps/ui/src/lib/http-api-client.ts
New generateTitle method in FeaturesAPI interface with mock and HTTP implementations; mock returns title with "Add " prefix and truncated description.
Board Header & Agent Count
apps/ui/src/components/views/board-view.tsx, apps/ui/src/components/views/board-view/board-header.tsx
runningAgentsCount prop added to BoardHeader; Users icon replaced with Bot icon and "Agents" label; display width adjusted to accommodate agents/max format.
Worktree Conflict Resolution
apps/ui/src/components/views/board-view.tsx, apps/ui/src/components/views/board-view/worktree-panel/types.ts, apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx, apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx, apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx
onResolveConflicts callback added throughout worktree component hierarchy; new "Pull & Resolve Conflicts" menu item with GitMerge icon in dropdown; handleResolveConflicts handler in board-view creates Maintenance feature and initiates it.

Sequence Diagram

sequenceDiagram
    participant UI as AddFeatureDialog
    participant Hook as use-board-actions
    participant Electron as Electron API
    participant HttpClient as HTTP Client
    participant Server as Server Handler
    participant Claude as Claude API
    participant Store as App Store

    UI->>Hook: onAdd(feature with description)
    Hook->>Store: Create feature with titleGenerating=true
    alt Title provided by user
        Hook->>Store: Use provided title
    else No title provided
        Hook->>Electron: generateTitle(description)
        Electron->>HttpClient: POST /features/generate-title
        HttpClient->>Server: Send description payload
        Server->>Claude: Stream request for title
        Claude-->>Server: Streaming response
        Server->>Server: Parse & extract title
        Server-->>HttpClient: Return title JSON
        HttpClient-->>Electron: Title response
        Electron-->>Hook: { success, title }
    end
    Hook->>Store: Update feature with title, titleGenerating=false
    Store->>UI: Feature updated, display title in KanbanCard
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • use-board-actions.ts: Async title generation flow with Electron API integration and state management requires careful review for race conditions and error handling
  • generate-title.ts: Claude Haiku streaming integration, request validation, and response parsing logic should be verified for correctness
  • Worktree callback threading: onResolveConflicts prop passed through multiple component layers—verify complete wiring and no missing integrations
  • Feature interface consistency: title and titleGenerating fields added across server/store/UI; verify all components properly initialize and handle these fields

Possibly related PRs

Poem

🐰 A title to call every feature by name,
With Claude's quick whisper, they're never the same,
When conflicts arise, we pull and we mend,
While agents run swift, from start until end! 🚀

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: adding auto-generated titles for features via Claude Haiku API integration throughout the codebase.
✨ 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 generate-titles

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 introduces a significant enhancement by integrating AI-powered title generation for features, leveraging the Claude Haiku model. This allows for more descriptive and concise feature titles to be automatically created from their descriptions, improving clarity and organization. Alongside this core functionality, the PR also adds a convenient "Pull & Resolve Conflicts" action for worktrees and enhances the board header with a real-time display of running agents, contributing to a more efficient and informative user experience.

Highlights

  • AI-Powered Title Generation: Features can now have their titles automatically generated using the Claude Haiku model, based on their description. This improves clarity and organization on kanban cards.
  • New API Endpoint: A new POST /features/generate-title endpoint has been added to the server to handle the AI-driven title generation requests.
  • Enhanced UI for Features: Kanban cards now display the generated titles, including a loading state indicator while the title is being generated. Feature add/edit dialogs include an optional title field, allowing manual input or automatic generation.
  • Non-Blocking Title Generation: Titles are generated asynchronously in the background, ensuring that users can create features immediately without waiting for the AI process to complete.
  • "Pull & Resolve Conflicts" Action: A new action has been added to the worktree dropdown, enabling users to quickly create and start a maintenance feature specifically designed to pull from origin/main and resolve any merge conflicts.
  • Running Agents Count Display: The board header now shows the number of currently running agents in an "X / Y" format, where X represents the active agents and Y is the maximum allowed concurrency.
  • Feature Interface Update: The Feature interface has been extended to include title (optional string) and titleGenerating (optional boolean) fields to support the new title management functionality.

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

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 automatic title generation for features using Claude Haiku, which is a great enhancement for user experience. It adds a new API endpoint and updates the UI to display titles and their generation status. The changes are well-implemented, with non-blocking title generation and graceful error handling. Additionally, the PR includes some nice UI improvements like showing the running agent count and adding a 'Pull & Resolve Conflicts' action.

I've identified a critical issue where some new function calls are missing a required property, which will lead to runtime errors. I've also suggested a refactoring to improve code robustness by removing a fragile setTimeout pattern, and another to improve maintainability by reducing code duplication.

Comment on lines +470 to +508
const handleResolveConflicts = useCallback(
async (worktree: WorktreeInfo) => {
const description = `Pull latest from origin/main and resolve conflicts. Merge origin/main into the current branch (${worktree.branch}), resolving any merge conflicts that arise. After resolving conflicts, ensure the code compiles and tests pass.`;

// Create the feature
const featureData = {
category: "Maintenance",
description,
steps: [],
images: [],
imagePaths: [],
skipTests: defaultSkipTests,
model: "opus" as const,
thinkingLevel: "none" as const,
branchName: worktree.branch,
priority: 1, // High priority for conflict resolution
planningMode: "skip" as const,
requirePlanApproval: false,
};

await handleAddFeature(featureData);

// Find the newly created feature and start it
setTimeout(async () => {
const latestFeatures = useAppStore.getState().features;
const newFeature = latestFeatures.find(
(f) =>
f.branchName === worktree.branch &&
f.status === "backlog" &&
f.description.includes("Pull latest from origin/main")
);

if (newFeature) {
await handleStartImplementation(newFeature);
}
}, FEATURE_CREATION_SETTLE_DELAY_MS);
},
[handleAddFeature, handleStartImplementation, defaultSkipTests]
);
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

This handler has a couple of critical issues:

  1. Missing Property: featureData is missing the new title property, which is now required by handleAddFeature. This will cause a runtime error.
  2. Fragile Logic: Using setTimeout and find to retrieve the newly created feature is unreliable and depends on timing.

A more robust approach would be to modify handleAddFeature in use-board-actions.ts to return the newly created feature, and then use that return value here.

Recommended Fix:

  1. In use-board-actions.ts, change handleAddFeature to return the createdFeature:

    const handleAddFeature = useCallback(
      async (featureData: { ... }): Promise<Feature> => { // Add return type
        // ...
        const createdFeature = addFeature(newFeatureData);
        await persistFeatureCreate(createdFeature);
        // ... title generation logic
        return createdFeature; // Return the created feature
      },
      // ...
    );
  2. Here in board-view.tsx, update handleResolveConflicts to use the returned feature.

Note: The handleAddressPRComments function has the same issues and should be updated similarly.

  const handleResolveConflicts = useCallback(
    async (worktree: WorktreeInfo) => {
      const description = `Pull latest from origin/main and resolve conflicts. Merge origin/main into the current branch (${worktree.branch}), resolving any merge conflicts that arise. After resolving conflicts, ensure the code compiles and tests pass.`;

      // Create the feature
      const featureData = {
        title: "", // Pass an empty title to trigger auto-generation
        category: "Maintenance",
        description,
        steps: [],
        images: [],
        imagePaths: [],
        skipTests: defaultSkipTests,
        model: "opus" as const,
        thinkingLevel: "none" as const,
        branchName: worktree.branch,
        priority: 1, // High priority for conflict resolution
        planningMode: "skip" as const,
        requirePlanApproval: false,
      };

      // This assumes handleAddFeature is modified to return the created feature
      const newFeature = await handleAddFeature(featureData);

      if (newFeature) {
        await handleStartImplementation(newFeature);
      }
    },
    [handleAddFeature, handleStartImplementation, defaultSkipTests]
  );

Comment on lines +160 to +185
// Generate title in the background if needed (non-blocking)
if (needsTitleGeneration) {
const api = getElectronAPI();
if (api?.features?.generateTitle) {
api.features.generateTitle(featureData.description)
.then((result) => {
if (result.success && result.title) {
const titleUpdates = { title: result.title, titleGenerating: false };
updateFeature(createdFeature.id, titleUpdates);
persistFeatureUpdate(createdFeature.id, titleUpdates);
} else {
// Clear generating flag even if failed
const titleUpdates = { titleGenerating: false };
updateFeature(createdFeature.id, titleUpdates);
persistFeatureUpdate(createdFeature.id, titleUpdates);
}
})
.catch((error) => {
console.error("[Board] Error generating title:", error);
// Clear generating flag on error
const titleUpdates = { titleGenerating: false };
updateFeature(createdFeature.id, titleUpdates);
persistFeatureUpdate(createdFeature.id, titleUpdates);
});
}
}
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 logic for updating the feature after title generation has some code duplication in the .then() and .catch() blocks. This can be refactored for better maintainability by using an async IIFE and a finally block to handle updating the feature state, regardless of whether the title generation succeeds or fails.

      // Generate title in the background if needed (non-blocking)
      if (needsTitleGeneration) {
        const api = getElectronAPI();
        if (api?.features?.generateTitle) {
          (async () => {
            const titleUpdates: Partial<Feature> = { titleGenerating: false };
            try {
              const result = await api.features.generateTitle(featureData.description);
              if (result.success && result.title) {
                titleUpdates.title = result.title;
              }
            } catch (error) {
              console.error("[Board] Error generating title:", error);
            } finally {
              updateFeature(createdFeature.id, titleUpdates);
              persistFeatureUpdate(createdFeature.id, titleUpdates);
            }
          })();
        }
      }

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 (5)
apps/ui/src/lib/electron.ts (1)

613-619: Consider improving mock title generation logic.

The current mock implementation has a few inconsistencies:

  1. It takes the first 6 words, then checks if the result is > 40 characters and truncates. This could create awkward titles like "Add Fix the issue with the login..."
  2. It always prefixes with "Add" but the real system prompt uses various verbs (Fix, Update, Implement, Create, etc.)
  3. The logic doesn't simulate the variety and quality of Claude-generated titles
💡 Suggested improvement for more realistic mock behavior
 generateTitle: async (description: string) => {
   console.log("[Mock] Generating title for:", description.substring(0, 50));
-  // Mock title generation - just take first few words
-  const words = description.split(/\s+/).slice(0, 6).join(" ");
-  const title = words.length > 40 ? words.substring(0, 40) + "..." : words;
-  return { success: true, title: `Add ${title}` };
+  // Mock title generation - create action-oriented title
+  const words = description.split(/\s+/);
+  const verbs = ["Add", "Fix", "Update", "Implement", "Create"];
+  const verb = verbs[Math.floor(Math.random() * verbs.length)];
+  
+  // Take 5-9 words after the verb (to simulate 5-10 word titles)
+  const titleWords = words.slice(0, Math.min(8, words.length)).join(" ");
+  const title = titleWords.length > 50 ? titleWords.substring(0, 50) + "..." : titleWords;
+  return { success: true, title: `${verb} ${title}` };
 },

This better simulates the variety of Claude-generated titles while staying within the 5-10 word guideline.

apps/server/src/routes/features/routes/generate-title.ts (2)

37-62: Consider more robust stream parsing.

The current implementation assumes specific message structure from the Claude SDK. Consider adding defensive checks to handle unexpected message formats gracefully.

🔎 Suggested improvement for robustness
 async function extractTextFromStream(
   stream: AsyncIterable<{
     type: string;
     subtype?: string;
     result?: string;
     message?: {
       content?: Array<{ type: string; text?: string }>;
     };
   }>
 ): Promise<string> {
   let responseText = "";
 
   for await (const msg of stream) {
+    if (!msg || typeof msg !== 'object') continue;
+    
     if (msg.type === "assistant" && msg.message?.content) {
       for (const block of msg.message.content) {
-        if (block.type === "text" && block.text) {
+        if (block && block.type === "text" && typeof block.text === "string") {
           responseText += block.text;
         }
       }
     } else if (msg.type === "result" && msg.subtype === "success") {
-      responseText = msg.result || responseText;
+      if (typeof msg.result === "string") {
+        responseText = msg.result;
+      }
     }
   }
 
   return responseText;
 }

95-116: Add timeout and validate generated title.

The title generation call to Claude has two gaps:

  1. No timeout handling: If Claude takes too long or hangs, the request will wait indefinitely. This could impact user experience.
  2. No validation of generated title: The system prompt requests 5-10 words, but there's no verification that the result matches this constraint.
🔎 Suggested improvements

Add timeout handling:

// At the top of the file, add a constant
const TITLE_GENERATION_TIMEOUT_MS = 30000; // 30 seconds

// In the handler, wrap the query call
const timeoutPromise = new Promise<never>((_, reject) => {
  setTimeout(() => reject(new Error("Title generation timed out")), TITLE_GENERATION_TIMEOUT_MS);
});

const titlePromise = (async () => {
  const stream = query({
    prompt: userPrompt,
    options: {
      model: CLAUDE_MODEL_MAP.haiku,
      systemPrompt: SYSTEM_PROMPT,
      maxTurns: 1,
      allowedTools: [],
      permissionMode: "acceptEdits",
    },
  });
  return await extractTextFromStream(stream);
})();

const title = await Promise.race([titlePromise, timeoutPromise]);

Add title validation:

const trimmedTitle = title.trim();
if (!trimmedTitle) {
  logger.warn("Received empty response from Claude");
  const response: GenerateTitleErrorResponse = {
    success: false,
    error: "Failed to generate title - empty response",
  };
  res.status(500).json(response);
  return;
}

// Validate word count (5-10 words as specified in system prompt)
const wordCount = trimmedTitle.split(/\s+/).length;
if (wordCount > 15) {
  logger.warn(`Generated title too long: ${wordCount} words`);
  // Truncate to approximately 10 words
  const truncated = trimmedTitle.split(/\s+/).slice(0, 10).join(" ");
  logger.info(`Truncated title: ${truncated}`);
  return res.json({ success: true, title: truncated });
}
apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx (1)

317-331: Consider adding title generation on edit when title is cleared.

The title input is properly integrated, but unlike the add feature flow, clearing the title in edit mode won't trigger auto-generation. This asymmetry might confuse users who expect the same behavior in both dialogs.

If auto-generation on edit is desired, you could add logic similar to handleAddFeature in use-board-actions.ts to the handleUpdateFeature function to check if the title is empty and description exists, then trigger generation.

apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx (1)

358-368: Add data-testid for consistency and testability.

The title input in the edit dialog has data-testid="edit-feature-title" (line 329 in edit-feature-dialog.tsx), but this input lacks a corresponding test identifier. This inconsistency makes automated testing harder.

🔧 Add test identifier
             <Input
               id="title"
               value={newFeature.title}
               onChange={(e) =>
                 setNewFeature({ ...newFeature, title: e.target.value })
               }
               placeholder="Leave blank to auto-generate"
+              data-testid="add-feature-title"
             />
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36e007e and fcb2e90.

📒 Files selected for processing (16)
  • apps/server/src/routes/features/index.ts (2 hunks)
  • apps/server/src/routes/features/routes/generate-title.ts (1 hunks)
  • apps/server/src/services/feature-loader.ts (1 hunks)
  • apps/ui/src/components/views/board-view.tsx (3 hunks)
  • apps/ui/src/components/views/board-view/board-header.tsx (4 hunks)
  • apps/ui/src/components/views/board-view/components/kanban-card.tsx (1 hunks)
  • apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx (6 hunks)
  • apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx (4 hunks)
  • apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (3 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx (4 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx (3 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/types.ts (1 hunks)
  • apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx (2 hunks)
  • apps/ui/src/lib/electron.ts (2 hunks)
  • apps/ui/src/lib/http-api-client.ts (1 hunks)
  • apps/ui/src/store/app-store.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
apps/ui/src/components/views/board-view/worktree-panel/types.ts (2)
apps/ui/src/lib/electron.ts (1)
  • WorktreeInfo (52-52)
apps/ui/src/types/electron.d.ts (1)
  • WorktreeInfo (578-583)
apps/server/src/routes/features/routes/generate-title.ts (2)
apps/server/src/lib/logger.ts (1)
  • createLogger (32-60)
apps/server/src/lib/model-resolver.ts (1)
  • CLAUDE_MODEL_MAP (13-17)
apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx (1)
apps/ui/src/components/views/board-view/worktree-panel/types.ts (1)
  • WorktreeInfo (9-18)
apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx (3)
apps/ui/src/components/views/board-view/worktree-panel/types.ts (1)
  • WorktreeInfo (9-18)
apps/ui/src/lib/electron.ts (1)
  • WorktreeInfo (52-52)
apps/ui/src/types/electron.d.ts (1)
  • WorktreeInfo (578-583)
apps/ui/src/components/views/board-view.tsx (3)
apps/ui/src/components/views/board-view/worktree-panel/types.ts (1)
  • WorktreeInfo (9-18)
apps/ui/src/lib/electron.ts (1)
  • WorktreeInfo (52-52)
apps/ui/src/types/electron.d.ts (1)
  • WorktreeInfo (578-583)
apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (1)
apps/ui/src/lib/electron.ts (1)
  • getElectronAPI (555-564)
apps/server/src/routes/features/index.ts (1)
apps/server/src/routes/features/routes/generate-title.ts (1)
  • createGenerateTitleHandler (64-137)
⏰ 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 (19)
apps/server/src/services/feature-loader.ts (1)

17-18: LGTM! Clean interface extension.

The addition of optional title and titleGenerating fields to the Feature interface is well-designed and supports the new title generation workflow without breaking existing features.

apps/ui/src/lib/http-api-client.ts (1)

515-516: LGTM! Consistent API pattern.

The generateTitle method follows the established pattern for feature API methods and properly integrates with the HTTP client architecture.

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

206-208: LGTM! Interface definition is correct.

The generateTitle method signature properly matches the expected API contract.

apps/server/src/routes/features/routes/generate-title.ts (1)

28-35: LGTM! Clear and specific system prompt.

The system prompt provides excellent guidance for title generation with concrete examples and clear constraints.

apps/server/src/routes/features/index.ts (2)

13-13: LGTM! Proper import.

The import follows the established pattern for route handlers in this file.


24-24: LGTM! Consistent route registration.

The route registration follows the same pattern as other feature routes.

apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx (1)

24-24: LGTM! Clean prop threading.

The onResolveConflicts callback is properly threaded through the component hierarchy to enable the conflict resolution UI flow.

Also applies to: 152-152

apps/ui/src/components/views/board-view/worktree-panel/types.ts (1)

70-70: LGTM! Proper callback type definition.

The onResolveConflicts callback is properly typed and consistent with other worktree action callbacks in the interface.

apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx (1)

48-48: LGTM! Proper callback propagation.

The onResolveConflicts callback is correctly threaded through WorktreeTab to WorktreeActionsDropdown, following the established pattern for other action callbacks.

Also applies to: 88-88, 348-348

apps/ui/src/store/app-store.ts (1)

283-284: LGTM! Clean interface extension for title support.

The new optional title and titleGenerating fields are appropriately typed and follow the existing pattern for optional Feature properties. These fields integrate well with the persistence layer since features is already included in partialize.

apps/ui/src/components/views/board-view/components/kanban-card.tsx (1)

650-667: LGTM! Clean conditional rendering for title states.

The three-way conditional (generating → title → null) handles all states correctly. The loading indicator with spinner provides good UX feedback during async title generation. The styling hierarchy with CardTitle for the title and CardDescription for the description is appropriate.

apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx (1)

166-174: LGTM! Well-integrated conflict resolution action.

The new "Pull & Resolve Conflicts" menu item is appropriately:

  • Conditionally rendered only for non-main worktrees
  • Styled distinctively with purple to indicate it's a special/advanced action
  • Placed logically after pull/push operations in the menu flow
apps/ui/src/components/views/board-view/board-header.tsx (1)

57-62: LGTM! Improved agents display with running count.

The "X / Y" format showing running agents vs. max concurrency is a good UX improvement. The min-w-[5ch] should handle typical values, though for edge cases like "10 / 10" you might consider min-w-[7ch] to prevent layout shift.

apps/ui/src/components/views/board-view.tsx (3)

469-508: LGTM! Conflict resolution handler follows established pattern.

The implementation mirrors handleAddressPRComments with appropriate differences (category: "Maintenance", conflict-specific description). The setTimeout + feature lookup pattern is consistent with existing code.

One consideration: the feature lookup using .includes("Pull latest from origin/main") could theoretically match user-created features with similar text. This is the same pattern used in handleAddressPRComments, so it's consistent, but if you want more robust matching, consider adding a transient marker field or using a more unique identifier in the lookup.


930-930: LGTM! Correct wiring of running agents count.

The runningAutoTasks.length correctly reflects the number of currently running agent tasks, which aligns with what BoardHeader expects for the runningAgentsCount prop.


971-971: LGTM! Handler correctly wired to WorktreePanel.

The onResolveConflicts prop is properly connected, enabling the conflict resolution flow from the worktree dropdown menu.

apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (2)

145-146: LGTM!

The condition properly checks for both an empty title and a non-empty description before triggering generation. The trim() calls ensure whitespace-only values are handled correctly.


187-187: No action required. Both persistFeatureUpdate and updateFeature are already stable references. updateFeature is a Zustand store action, which by design are static and never change. persistFeatureUpdate is properly memoized with useCallback, with appropriate dependencies. Including them in the dependency array is correct and poses no performance risk.

apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx (1)

104-104: LGTM!

The title field is properly initialized to an empty string and correctly reset after form submission, maintaining consistent state management throughout the component lifecycle.

Also applies to: 209-209

Comment on lines +160 to +185
// Generate title in the background if needed (non-blocking)
if (needsTitleGeneration) {
const api = getElectronAPI();
if (api?.features?.generateTitle) {
api.features.generateTitle(featureData.description)
.then((result) => {
if (result.success && result.title) {
const titleUpdates = { title: result.title, titleGenerating: false };
updateFeature(createdFeature.id, titleUpdates);
persistFeatureUpdate(createdFeature.id, titleUpdates);
} else {
// Clear generating flag even if failed
const titleUpdates = { titleGenerating: false };
updateFeature(createdFeature.id, titleUpdates);
persistFeatureUpdate(createdFeature.id, titleUpdates);
}
})
.catch((error) => {
console.error("[Board] Error generating title:", error);
// Clear generating flag on error
const titleUpdates = { titleGenerating: false };
updateFeature(createdFeature.id, titleUpdates);
persistFeatureUpdate(createdFeature.id, titleUpdates);
});
}
}
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

Silent error handling may confuse users.

When title generation fails (lines 171-174, 177-183), the titleGenerating flag is cleared silently without notifying the user. This could leave users wondering why no title appeared, especially if the generation takes several seconds before failing.

💡 Suggested improvement

Consider adding a subtle toast notification on failure:

           .catch((error) => {
             console.error("[Board] Error generating title:", error);
+            toast.error("Title generation failed", {
+              description: "You can manually enter a title or try again."
+            });
             // Clear generating flag on error
             const titleUpdates = { titleGenerating: false };

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/ui/src/components/views/board-view/hooks/use-board-actions.ts around
lines 160 to 185, the title-generation failure branches clear the
titleGenerating flag silently; update those failure and catch branches to also
surface a subtle user-facing notification (e.g., call the app's
toast/notification helper with a brief non-blocking message like "Title
generation failed" and optional retry hint) while still clearing titleGenerating
and persisting the update so the UI is consistent; ensure the notification call
is guarded (check for the toast API or import the app's notification helper) and
does not block the existing promise flow.

Comment on lines +164 to +183
api.features.generateTitle(featureData.description)
.then((result) => {
if (result.success && result.title) {
const titleUpdates = { title: result.title, titleGenerating: false };
updateFeature(createdFeature.id, titleUpdates);
persistFeatureUpdate(createdFeature.id, titleUpdates);
} else {
// Clear generating flag even if failed
const titleUpdates = { titleGenerating: false };
updateFeature(createdFeature.id, titleUpdates);
persistFeatureUpdate(createdFeature.id, titleUpdates);
}
})
.catch((error) => {
console.error("[Board] Error generating title:", error);
// Clear generating flag on error
const titleUpdates = { titleGenerating: false };
updateFeature(createdFeature.id, titleUpdates);
persistFeatureUpdate(createdFeature.id, titleUpdates);
});
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

Potential race condition with concurrent feature updates.

If a user edits the feature (e.g., updates the description or other fields) while title generation is in progress, the generated title update (lines 168-169) could overwrite or conflict with the user's changes. The updates are applied independently without coordination.

Consider one of these approaches:

  • Check if the feature's titleGenerating flag is still true before applying the update (to detect if user cleared it manually)
  • Use a versioning or timestamp mechanism to detect stale updates
  • Queue updates instead of applying them immediately

This is a low-probability edge case but could affect UX in slower network conditions or with slower AI responses.

🤖 Prompt for AI Agents
In apps/ui/src/components/views/board-view/hooks/use-board-actions.ts around
lines 164-183, the title-generation promise unconditionally applies updates
which can overwrite concurrent user edits; change the flow to avoid races by
first fetching the current feature state (or using the latest local feature
object) and verifying that titleGenerating is still true and the feature's
updatedAt/version hasn't changed before applying the generated title, and if it
has changed skip or merge the update (or prompt re-check); ensure both
updateFeature and persistFeatureUpdate are only called when the checks pass,
otherwise just clear the titleGenerating flag conditionally or abort the title
write so user edits are not lost.

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