Skip to content

Conversation

@AndyMik90
Copy link
Owner

@AndyMik90 AndyMik90 commented Jan 13, 2026

This task enhances the Auto-Claude UI to make worktree-based task isolation more visible to users. Currently, explanatory text about worktree isolation is hidden in a collapsed "Git Options (optional)" section, causing confusion about where code changes occur and what the "Merge with AI" button does. The solution surfaces existing i18n content to prominent locations in the task creation modal and merge UI, following the pattern already established by the terminal creation flow.

Summary by CodeRabbit

  • New Features

    • Added an informational banner in the task creation wizard explaining worktree isolation.
    • Added a contextual tooltip to the merge/stage action button with guidance on merging from the worktree back to the base branch.
  • Localization

    • Added English and French translations for the new banner and tooltip text.

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

AndyMik90 and others added 5 commits January 13, 2026 08:56
…ice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json
…orkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file
Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 13, 2026

📝 Walkthrough

Walkthrough

Adds two presentational UI elements: a worktree/isolation info banner in the TaskCreationWizard and a tooltip for the merge action in WorkspaceStatus, plus corresponding English and French i18n keys.

Changes

Cohort / File(s) Summary
Task Creation Wizard UI
apps/frontend/src/renderer/components/TaskCreationWizard.tsx
Imported Info icon and inserted a worktree isolation info banner at the top of the wizard main content using i18n title/description.
Task Review UI
apps/frontend/src/renderer/components/task-detail/task-review/WorkspaceStatus.tsx
Added Tooltip, TooltipTrigger, TooltipContent around the merge/stage button and extended translation namespaces to include tasks for the merge tooltip.
Internationalization
apps/frontend/src/shared/i18n/locales/en/tasks.json, apps/frontend/src/shared/i18n/locales/fr/tasks.json
Added wizard.worktreeNotice (title, description) and top-level review.mergeTooltip translation keys in English and French.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Possibly related PRs

Suggested labels

feature, area/frontend, size/S

Suggested reviewers

  • AlexMadera
  • MikeeBuilds

Poem

🐰 A little banner, calm and bright,
I nibble code by morning light.
An Info icon, tooltip too,
Guiding merges — voilà, that's new! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 'Make worktree isolation prominent in UI' directly and accurately summarizes the main objective of the changeset: surfacing worktree isolation information into prominent UI locations (task creation modal and merge UI).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aff156f and 17ae69d.

📒 Files selected for processing (2)
  • apps/frontend/src/renderer/components/TaskCreationWizard.tsx
  • apps/frontend/src/renderer/components/task-detail/task-review/WorkspaceStatus.tsx
🧰 Additional context used
📓 Path-based instructions (2)
apps/frontend/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/frontend/src/**/*.{tsx,ts}: Use i18n translation keys for all user-facing text in the frontend. All labels, buttons, messages must use translation keys from react-i18next with namespace:section.key format (e.g., 'navigation:items.githubPRs').
Never use hardcoded strings for UI text in JSX/TSX files. Always use translation keys via useTranslation() hook.

Files:

  • apps/frontend/src/renderer/components/task-detail/task-review/WorkspaceStatus.tsx
  • apps/frontend/src/renderer/components/TaskCreationWizard.tsx
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/renderer/components/task-detail/task-review/WorkspaceStatus.tsx
  • apps/frontend/src/renderer/components/TaskCreationWizard.tsx
🧠 Learnings (4)
📓 Common learnings
Learnt from: MikeeBuilds
Repo: AndyMik90/Auto-Claude PR: 661
File: apps/frontend/src/renderer/components/onboarding/OllamaModelSelector.tsx:176-189
Timestamp: 2026-01-04T23:59:48.743Z
Learning: In the AndyMik90/Auto-Claude repository, pre-existing i18n issues (hardcoded user-facing strings that should be localized) can be deferred to future i18n cleanup passes rather than requiring immediate fixes in PRs that don't introduce new i18n violations.
Learnt from: CR
Repo: AndyMik90/Auto-Claude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T13:47:32.539Z
Learning: When submitting PRs to AndyMik90/Auto-Claude upstream, always target the develop branch, NOT main. Commits must include sign-off (git commit -s).
Learnt from: CR
Repo: AndyMik90/Auto-Claude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T13:47:32.539Z
Learning: Use git worktrees for isolated spec builds with branch naming convention auto-claude/{spec-name}. Keep all branches LOCAL until user explicitly pushes.
📚 Learning: 2026-01-12T13:47:32.539Z
Learnt from: CR
Repo: AndyMik90/Auto-Claude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T13:47:32.539Z
Learning: Applies to apps/frontend/src/**/*.{tsx,ts} : Use i18n translation keys for all user-facing text in the frontend. All labels, buttons, messages must use translation keys from react-i18next with namespace:section.key format (e.g., 'navigation:items.githubPRs').

Applied to files:

  • apps/frontend/src/renderer/components/task-detail/task-review/WorkspaceStatus.tsx
  • apps/frontend/src/renderer/components/TaskCreationWizard.tsx
📚 Learning: 2026-01-12T13:47:32.539Z
Learnt from: CR
Repo: AndyMik90/Auto-Claude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T13:47:32.539Z
Learning: Applies to apps/frontend/src/**/*.{tsx,ts} : Never use hardcoded strings for UI text in JSX/TSX files. Always use translation keys via useTranslation() hook.

Applied to files:

  • apps/frontend/src/renderer/components/task-detail/task-review/WorkspaceStatus.tsx
  • apps/frontend/src/renderer/components/TaskCreationWizard.tsx
📚 Learning: 2026-01-04T23:59:45.209Z
Learnt from: MikeeBuilds
Repo: AndyMik90/Auto-Claude PR: 661
File: apps/frontend/src/renderer/components/onboarding/OllamaModelSelector.tsx:176-189
Timestamp: 2026-01-04T23:59:45.209Z
Learning: In the AndyMik90/Auto-Claude repository, pre-existing i18n issues (hardcoded user-facing strings) can be deferred for future i18n cleanup passes. Do not fix such issues in PRs that do not introduce new i18n violations, especially in frontend TSX components (e.g., apps/frontend/**/*.tsx). If a PR adds new i18n violations, address them in that PR.

Applied to files:

  • apps/frontend/src/renderer/components/task-detail/task-review/WorkspaceStatus.tsx
  • apps/frontend/src/renderer/components/TaskCreationWizard.tsx
🧬 Code graph analysis (1)
apps/frontend/src/renderer/components/task-detail/task-review/WorkspaceStatus.tsx (1)
apps/frontend/src/renderer/components/ui/button.tsx (1)
  • Button (64-64)
⏰ 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). (4)
  • GitHub Check: Seer Code Review
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (4)
apps/frontend/src/renderer/components/TaskCreationWizard.tsx (2)

15-15: LGTM!

The Info icon import is appropriate for the new banner component.


524-535: LGTM!

The worktree isolation info banner correctly uses i18n translation keys (tasks:wizard.worktreeNotice.title and tasks:wizard.worktreeNotice.description) and applies theme-aware semantic colors for dark-mode support. This addresses the PR objective of making worktree isolation more prominent without cluttering the UI.

apps/frontend/src/renderer/components/task-detail/task-review/WorkspaceStatus.tsx (2)

21-21: LGTM!

The Tooltip imports and the extended translation namespace array ('tasks') are correctly added to support the new merge tooltip functionality.

Also applies to: 104-104


422-456: Tooltip and i18n implementation is correct.

The tooltip properly uses the Radix asChild pattern with TooltipTrigger, and all i18n keys (taskReview:merge.buttons.* and tasks:review.mergeTooltip) are correctly defined in the translation files. TooltipProvider is configured at the app root level in App.tsx, ensuring the component tree has proper tooltip support.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @AndyMik90, 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 improves the user experience of Auto-Claude by making the concept of Git worktree isolation more transparent. Previously, crucial information about isolated task environments was hidden, leading to user confusion. This change surfaces that information prominently in the task creation modal via a new banner and provides a clear explanation for the "Merge with AI" button through a tooltip in the task review interface, ensuring users better understand the isolation mechanism and the merging process.

Highlights

  • Enhanced Worktree Isolation Visibility: The UI now prominently displays information about worktree-based task isolation, addressing previous user confusion.
  • New Informational Banner: An 'Isolated Workspace' info banner has been added to the task creation wizard, explaining the concept of worktree isolation upfront.
  • Merge Button Tooltip: A descriptive tooltip has been added to the 'Merge with AI' button in the task review section, clarifying its functionality and the role of AI in conflict resolution.
  • Internationalization Updates: New translation keys have been added to the English and French tasks.json files to support the new UI texts.
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 effectively enhances the UI to make worktree isolation more prominent, as described. The changes are well-implemented, adding an informational banner in the task creation wizard and a helpful tooltip on the merge button. The use of i18n for the new text is also correctly handled.

I have one suggestion to improve maintainability by extracting the new info banner into a reusable component, which would be consistent with other banner-like elements in the application. Overall, this is a solid contribution that improves user experience.

Comment on lines 525 to 535
<div className="flex items-start gap-3 p-4 bg-blue-50 border border-blue-200 rounded-lg">
<Info className="h-5 w-5 text-blue-600 flex-shrink-0 mt-0.5" />
<div className="flex-1 min-w-0">
<h4 className="text-sm font-medium text-blue-900 mb-1">
{t('tasks:wizard.worktreeNotice.title')}
</h4>
<p className="text-sm text-blue-700">
{t('tasks:wizard.worktreeNotice.description')}
</p>
</div>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This info banner is a great addition for user clarity. To improve maintainability and promote reusability, consider extracting this banner into a dedicated component. This would be consistent with other banner-like elements in the application (e.g., for warnings and errors in WorkspaceStatus.tsx).

A reusable InfoBanner component could look like this:

// In a new file like 'apps/frontend/src/renderer/components/ui/InfoBanner.tsx'
import { Info } from 'lucide-react';
import type { ReactNode } from 'react';

interface InfoBannerProps {
  title: ReactNode;
  description: ReactNode;
}

export function InfoBanner({ title, description }: InfoBannerProps) {
  return (
    <div className="flex items-start gap-3 p-4 bg-blue-50 border border-blue-200 rounded-lg">
      <Info className="h-5 w-5 text-blue-600 flex-shrink-0 mt-0.5" />
      <div className="flex-1 min-w-0">
        <h4 className="text-sm font-medium text-blue-900 mb-1">
          {title}
        </h4>
        <p className="text-sm text-blue-700">
          {description}
        </p>
      </div>
    </div>
  );
}

You could then use it as follows:

<InfoBanner
  title={t('tasks:wizard.worktreeNotice.title')}
  description={t('tasks:wizard.worktreeNotice.description')}
/>

@AndyMik90 AndyMik90 self-assigned this Jan 13, 2026
Copy link
Owner Author

@AndyMik90 AndyMik90 left a comment

Choose a reason for hiding this comment

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

🤖 Auto Claude PR Review

Merge Verdict: 🔴 BLOCKED

🔴 Blocked - Merge conflicts must be resolved before merge.

Blocked: PR has merge conflicts with base branch. Resolve conflicts before merge.

Risk Assessment

Factor Level Notes
Complexity Low Based on lines changed
Security Impact None Based on security findings
Scope Coherence Good Based on structural review

🚨 Blocking Issues (Must Fix)

  • Merge Conflicts: PR has conflicts with base branch that must be resolved

Findings Summary

  • Medium: 1 issue(s)
  • Low: 1 issue(s)

Generated by Auto Claude PR Review

Findings (2 selected of 2 total)

🟡 [b8e9af03d21b] [MEDIUM] Hardcoded blue colors will break dark mode styling

📁 apps/frontend/src/renderer/components/TaskCreationWizard.tsx:523

The new info banner uses hardcoded Tailwind color classes (bg-blue-50, border-blue-200, text-blue-600, text-blue-900, text-blue-700) that only work in light mode. The ai-triage-reviewer confirmed the project has robust dark mode support via CSS custom properties (--info, --primary, etc.) with proper .dark theme variants. These hardcoded colors will appear jarring or unreadable when users enable dark mode.

Suggested fix:

Replace hardcoded blue colors with theme-aware semantic classes that the project already uses elsewhere:

Change:
  bg-blue-50 → bg-info/10
  border-blue-200 → border-info/50
  text-blue-600 → text-info
  text-blue-900 → text-info (or text-foreground)
  text-blue-700 → text-muted-foreground

This matches the pattern seen in other parts of the codebase (e.g., bg-info/10 text-info in TaskCreationWizard line 474).

🔵 [fa4845f627d7] [LOW] Consider extracting info banner to reusable component

📁 apps/frontend/src/renderer/components/TaskCreationWizard.tsx:523

The info banner is implemented inline with 13 lines of markup. If similar info banners are used elsewhere in the codebase (or will be needed in the future), extracting this to a reusable InfoBanner component would improve maintainability and ensure consistent styling across the app.

Suggested fix:

Consider creating a reusable InfoBanner component:
<InfoBanner
  variant="info"
  title={t('tasks:wizard.worktreeNotice.title')}
  description={t('tasks:wizard.worktreeNotice.description')}
/>

However, for a single-use component, the current inline implementation is acceptable.

This review was generated by Auto Claude.

AndyMik90 and others added 2 commits January 13, 2026 18:18
Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@AndyMik90 AndyMik90 force-pushed the auto-claude/112-docs-ux-make-worktree-isolation-more-prominent-in- branch from aff156f to 17ae69d Compare January 13, 2026 17:18
@github-actions github-actions bot added area/frontend This is frontend only size/S Small (10-99 lines) 🔄 Checking Checking PR Status and removed 🔄 Checking Checking PR Status labels Jan 13, 2026
Copy link
Owner Author

@AndyMik90 AndyMik90 left a comment

Choose a reason for hiding this comment

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

✅ Auto Claude Review - APPROVED

Status: Ready to Merge

Summary: ## ✅ Follow-up Review: Ready To Merge

✅ Ready to merge - All checks passing and findings addressed.

Resolution Status

  • Resolved: 1 previous findings addressed
  • Unresolved: 1 previous findings remain
  • 🆕 New Issues: 0 new findings in recent changes

Finding Validation

  • 🔍 Dismissed as False Positives: 0 findings were re-investigated and found to be incorrect
  • Confirmed Valid: 1 findings verified as genuine issues
  • 👤 Needs Human Review: 0 findings require manual verification

Verdict

All CI checks passing (18/18). The medium-severity dark mode styling issue (b8e9af03d21b) has been fully RESOLVED - the hardcoded blue colors are now replaced with theme-aware semantic tokens (bg-info/10, text-info, etc.). The only remaining finding (fa4845f627d7) is LOW severity - a maintainability suggestion to extract the info banner pattern to a reusable component. While validated as a genuine improvement opportunity (pattern exists in 4+ files), LOW severity suggestions do not block merge per review guidelines. No new issues were introduced by the changes. The PR successfully addresses the blocking issue from the previous review.

Review Process

Agents invoked: resolution-verifier, new-code-reviewer, finding-validator


This is an AI-generated follow-up review using parallel specialist analysis with finding validation.


💡 Suggestions (1)

These are non-blocking suggestions for consideration:

🔵 [fa4845f627d7] [LOW] [UNRESOLVED] Consider extracting info banner to reusable component

📁 apps/frontend/src/renderer/components/TaskCreationWizard.tsx:523

The info banner is implemented inline with 13 lines of markup. If similar info banners are used elsewhere in the codebase (or will be needed in the future), extracting this to a reusable InfoBanner component would improve maintainability and ensure consistent styling across the app.

Resolution note:

...

Similar patterns found in: OllamaModelSelector.tsx:325, MemoryStep.tsx:492, App.tsx:973, RateLimitIndicator.tsx:36

Suggested fix:

Consider creating a reusable InfoBanner component:
<InfoBanner
  variant="info"
  title={t('tasks:wizard.worktreeNotice.title')}
  description={t('tasks:wizard.worktreeNotice.description')}
/>

However, for a single-use component, the current inline implementation is acceptable.

This automated review found no blocking issues. The PR can be safely merged.

Generated by Auto Claude

@AndyMik90 AndyMik90 merged commit 7414811 into develop Jan 13, 2026
18 checks passed
@AndyMik90 AndyMik90 deleted the auto-claude/112-docs-ux-make-worktree-isolation-more-prominent-in- branch January 13, 2026 17:56
AndyMik90 added a commit that referenced this pull request Jan 13, 2026
* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
@AndyMik90 AndyMik90 mentioned this pull request Jan 13, 2026
AndyMik90 added a commit that referenced this pull request Jan 13, 2026
* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes #1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
AndyMik90 added a commit that referenced this pull request Jan 15, 2026
…frontend settings (#1082)

* Version 2.7.4 (#1040)

* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes #1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>

* fix(docs): update README download links to v2.7.4

The stable version badge was updated to 2.7.4 but the download links
were still pointing to 2.7.3 artifacts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: update all model versions to Claude 4.5 and connect insights to frontend settings

- Update outdated model versions across entire codebase:
  - claude-sonnet-4-20250514 → claude-sonnet-4-5-20250929
  - claude-opus-4-20250514 → claude-opus-4-5-20251101
  - claude-haiku-3-5-20241022 → claude-haiku-4-5-20251001
  - claude-sonnet-3-5-20241022 removed from pricing table

- Fix insight extractor crash with Haiku + extended thinking:
  - Set thinking_default to "none" for insights agent type
  - Haiku models don't support extended thinking

- Connect Insights Chat to frontend Agent Settings:
  - Add getInsightsFeatureSettings() to read featureModels/featureThinking
  - Merge frontend settings with any explicit modelConfig
  - Follow same pattern as ideation handlers

- Update rate limiter pricing table with current models only

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review findings for insights feature

- Fix incorrect comment about Haiku extended thinking support
  (Haiku 4.5 does NOT support extended thinking, only Sonnet 4.5 and Opus 4.5)
- Use standard path import pattern consistent with codebase
- Replace console.error with debugError for consistent logging
- Add pydantic to test requirements (fixes CI test collection error)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: ruff format issue in insights_runner.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address follow-up PR review findings

- Fix HIGH: Make max_thinking_tokens conditional in simple_client.py
  (prevents passing None to SDK, which may cause issues with Haiku)
- Fix MEDIUM: Use nullish coalescing at property level for featureModels.insights
  (handles partial settings objects where insights key may be missing)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
StillKnotKnown added a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
…frontend settings (AndyMik90#1082)

* Version 2.7.4 (AndyMik90#1040)

* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (AndyMik90#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (AndyMik90#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (AndyMik90#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (AndyMik90#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (AndyMik90#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (AndyMik90#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (AndyMik90#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (AndyMik90#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (AndyMik90#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (AndyMik90#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (AndyMik90#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (AndyMik90#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes AndyMik90#1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (AndyMik90#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (AndyMik90#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (AndyMik90#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (AndyMik90#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (AndyMik90#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (AndyMik90#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (AndyMik90#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (AndyMik90#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (AndyMik90#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (AndyMik90#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (AndyMik90#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (AndyMik90#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (AndyMik90#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (AndyMik90#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>

* fix(docs): update README download links to v2.7.4

The stable version badge was updated to 2.7.4 but the download links
were still pointing to 2.7.3 artifacts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: update all model versions to Claude 4.5 and connect insights to frontend settings

- Update outdated model versions across entire codebase:
  - claude-sonnet-4-20250514 → claude-sonnet-4-5-20250929
  - claude-opus-4-20250514 → claude-opus-4-5-20251101
  - claude-haiku-3-5-20241022 → claude-haiku-4-5-20251001
  - claude-sonnet-3-5-20241022 removed from pricing table

- Fix insight extractor crash with Haiku + extended thinking:
  - Set thinking_default to "none" for insights agent type
  - Haiku models don't support extended thinking

- Connect Insights Chat to frontend Agent Settings:
  - Add getInsightsFeatureSettings() to read featureModels/featureThinking
  - Merge frontend settings with any explicit modelConfig
  - Follow same pattern as ideation handlers

- Update rate limiter pricing table with current models only

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review findings for insights feature

- Fix incorrect comment about Haiku extended thinking support
  (Haiku 4.5 does NOT support extended thinking, only Sonnet 4.5 and Opus 4.5)
- Use standard path import pattern consistent with codebase
- Replace console.error with debugError for consistent logging
- Add pydantic to test requirements (fixes CI test collection error)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: ruff format issue in insights_runner.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address follow-up PR review findings

- Fix HIGH: Make max_thinking_tokens conditional in simple_client.py
  (prevents passing None to SDK, which may cause issues with Haiku)
- Fix MEDIUM: Use nullish coalescing at property level for featureModels.insights
  (handles partial settings objects where insights key may be missing)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
AndyMik90 added a commit that referenced this pull request Jan 16, 2026
* Version 2.7.4 (#1040)

* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes #1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>

* fix(docs): update README download links to v2.7.4

The stable version badge was updated to 2.7.4 but the download links
were still pointing to 2.7.3 artifacts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-1 - Add fsPromises import and saveAsync() method to TerminalSessionStore

* auto-claude: subtask-1-2 - Add public saveSessionAsync() method

Add public saveSessionAsync() method that wraps the private saveAsync()
method. This enables external callers (like Electron app-quit handlers)
to perform non-blocking async saves to disk.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-2-1 - Add persistSessionAsync() function to session-handler.ts

- Added persistSessionAsync() to session-handler.ts that builds the session
  object and calls store.saveSessionAsync() with fire-and-forget pattern
- Fixed saveSessionAsync() in terminal-session-store.ts to properly accept
  a session parameter and mirror saveSession() logic with async disk writes
- This enables non-blocking session persistence to prevent main process freezing

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-3-1 - Convert persistSession() calls to async

Convert all 4 persistSession() calls in claude-integration-handler.ts
to use persistSessionAsync() for fire-and-forget async file persistence.

This prevents the Electron main process from blocking on synchronous
disk writes, which was causing the Mac crash on "Invoke Claude" button.

Converted locations:
- Line 180: finalizeClaudeInvoke()
- Line 389: handleClaudeExit()
- Line 567: resumeClaude()
- Line 743: resumeClaudeAsync()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-3-3 - Convert persistSession() calls in resumeClaude() and resumeClaudeAsync() to async

Updated comments in resumeClaude() and resumeClaudeAsync() to reference
persistSessionAsync() instead of persistSession() for consistency with
the actual code that was already using the async version.

* auto-claude: subtask-4-1 - Convert persistSession() calls in createTerminal()

Changed all 3 synchronous persistSession() calls in terminal-lifecycle.ts
to use the async persistSessionAsync() variant to prevent UI freezing:
- createTerminal(): persist after terminal setup
- restoreTerminal(): persist after title/worktreeConfig restore
- restoreTerminal(): persist after Claude mode and pending resume state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-5-1 - Convert persistSession() call in setWorktreeConfig

Migrated the synchronous persistSession() call to persistSessionAsync() in
the setWorktreeConfig() method to avoid blocking the main process when
persisting terminal session data after worktree config changes.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-6-3 - Fix test mock for persistSessionAsync

Update claude-integration-handler.test.ts to mock persistSessionAsync
which is now used instead of the sync persistSession. This fixes the
16 failing tests that were missing the mock export.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: Address PR review issues for async session persistence

**HIGH priority fix:**
- Add pendingDelete set to prevent async writes from resurrecting deleted
  sessions. When removeSession() is called, the session ID is tracked to
  prevent in-flight saveSessionAsync() calls from re-adding the session.

**MEDIUM priority fixes:**
- Extract shared session update logic into updateSessionInMemory() to
  eliminate code duplication between saveSession() and saveSessionAsync()
- Extract createSessionObject() helper to eliminate duplication between
  persistSession() and persistSessionAsync() in session-handler.ts
- Add write serialization (writeInProgress/writePending flags) to prevent
  concurrent saveAsync() calls from interleaving and losing data

**LOW priority fixes:**
- Add failure tracking (consecutiveFailures counter) with warnings for
  persistent write failures in fire-and-forget scenarios
- Add persistAllSessionsAsync() for non-blocking batch saves
- Update callers (destroyAllTerminals, periodic save timer) to use async
  version, deprecate blocking persistAllSessions()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
StillKnotKnown added a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
…frontend settings (AndyMik90#1082)

* Version 2.7.4 (AndyMik90#1040)

* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (AndyMik90#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (AndyMik90#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (AndyMik90#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (AndyMik90#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (AndyMik90#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (AndyMik90#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (AndyMik90#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (AndyMik90#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (AndyMik90#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (AndyMik90#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (AndyMik90#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (AndyMik90#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes AndyMik90#1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (AndyMik90#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (AndyMik90#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (AndyMik90#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (AndyMik90#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (AndyMik90#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (AndyMik90#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (AndyMik90#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (AndyMik90#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (AndyMik90#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (AndyMik90#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (AndyMik90#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (AndyMik90#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (AndyMik90#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (AndyMik90#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>

* fix(docs): update README download links to v2.7.4

The stable version badge was updated to 2.7.4 but the download links
were still pointing to 2.7.3 artifacts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: update all model versions to Claude 4.5 and connect insights to frontend settings

- Update outdated model versions across entire codebase:
  - claude-sonnet-4-20250514 → claude-sonnet-4-5-20250929
  - claude-opus-4-20250514 → claude-opus-4-5-20251101
  - claude-haiku-3-5-20241022 → claude-haiku-4-5-20251001
  - claude-sonnet-3-5-20241022 removed from pricing table

- Fix insight extractor crash with Haiku + extended thinking:
  - Set thinking_default to "none" for insights agent type
  - Haiku models don't support extended thinking

- Connect Insights Chat to frontend Agent Settings:
  - Add getInsightsFeatureSettings() to read featureModels/featureThinking
  - Merge frontend settings with any explicit modelConfig
  - Follow same pattern as ideation handlers

- Update rate limiter pricing table with current models only

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review findings for insights feature

- Fix incorrect comment about Haiku extended thinking support
  (Haiku 4.5 does NOT support extended thinking, only Sonnet 4.5 and Opus 4.5)
- Use standard path import pattern consistent with codebase
- Replace console.error with debugError for consistent logging
- Add pydantic to test requirements (fixes CI test collection error)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: ruff format issue in insights_runner.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address follow-up PR review findings

- Fix HIGH: Make max_thinking_tokens conditional in simple_client.py
  (prevents passing None to SDK, which may cause issues with Haiku)
- Fix MEDIUM: Use nullish coalescing at property level for featureModels.insights
  (handles partial settings objects where insights key may be missing)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
StillKnotKnown added a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
* Version 2.7.4 (#1040)

* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes #1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>

* fix(docs): update README download links to v2.7.4

The stable version badge was updated to 2.7.4 but the download links
were still pointing to 2.7.3 artifacts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-1 - Add fsPromises import and saveAsync() method to TerminalSessionStore

* auto-claude: subtask-1-2 - Add public saveSessionAsync() method

Add public saveSessionAsync() method that wraps the private saveAsync()
method. This enables external callers (like Electron app-quit handlers)
to perform non-blocking async saves to disk.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-2-1 - Add persistSessionAsync() function to session-handler.ts

- Added persistSessionAsync() to session-handler.ts that builds the session
  object and calls store.saveSessionAsync() with fire-and-forget pattern
- Fixed saveSessionAsync() in terminal-session-store.ts to properly accept
  a session parameter and mirror saveSession() logic with async disk writes
- This enables non-blocking session persistence to prevent main process freezing

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-3-1 - Convert persistSession() calls to async

Convert all 4 persistSession() calls in claude-integration-handler.ts
to use persistSessionAsync() for fire-and-forget async file persistence.

This prevents the Electron main process from blocking on synchronous
disk writes, which was causing the Mac crash on "Invoke Claude" button.

Converted locations:
- Line 180: finalizeClaudeInvoke()
- Line 389: handleClaudeExit()
- Line 567: resumeClaude()
- Line 743: resumeClaudeAsync()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-3-3 - Convert persistSession() calls in resumeClaude() and resumeClaudeAsync() to async

Updated comments in resumeClaude() and resumeClaudeAsync() to reference
persistSessionAsync() instead of persistSession() for consistency with
the actual code that was already using the async version.

* auto-claude: subtask-4-1 - Convert persistSession() calls in createTerminal()

Changed all 3 synchronous persistSession() calls in terminal-lifecycle.ts
to use the async persistSessionAsync() variant to prevent UI freezing:
- createTerminal(): persist after terminal setup
- restoreTerminal(): persist after title/worktreeConfig restore
- restoreTerminal(): persist after Claude mode and pending resume state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-5-1 - Convert persistSession() call in setWorktreeConfig

Migrated the synchronous persistSession() call to persistSessionAsync() in
the setWorktreeConfig() method to avoid blocking the main process when
persisting terminal session data after worktree config changes.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-6-3 - Fix test mock for persistSessionAsync

Update claude-integration-handler.test.ts to mock persistSessionAsync
which is now used instead of the sync persistSession. This fixes the
16 failing tests that were missing the mock export.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: Address PR review issues for async session persistence

**HIGH priority fix:**
- Add pendingDelete set to prevent async writes from resurrecting deleted
  sessions. When removeSession() is called, the session ID is tracked to
  prevent in-flight saveSessionAsync() calls from re-adding the session.

**MEDIUM priority fixes:**
- Extract shared session update logic into updateSessionInMemory() to
  eliminate code duplication between saveSession() and saveSessionAsync()
- Extract createSessionObject() helper to eliminate duplication between
  persistSession() and persistSessionAsync() in session-handler.ts
- Add write serialization (writeInProgress/writePending flags) to prevent
  concurrent saveAsync() calls from interleaving and losing data

**LOW priority fixes:**
- Add failure tracking (consecutiveFailures counter) with warnings for
  persistent write failures in fire-and-forget scenarios
- Add persistAllSessionsAsync() for non-blocking batch saves
- Update callers (destroyAllTerminals, periodic save timer) to use async
  version, deprecate blocking persistAllSessions()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
StillKnotKnown added a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (AndyMik90#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (AndyMik90#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (AndyMik90#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (AndyMik90#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (AndyMik90#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (AndyMik90#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (AndyMik90#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (AndyMik90#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (AndyMik90#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (AndyMik90#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (AndyMik90#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (AndyMik90#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes AndyMik90#1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (AndyMik90#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (AndyMik90#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (AndyMik90#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (AndyMik90#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (AndyMik90#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (AndyMik90#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (AndyMik90#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (AndyMik90#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (AndyMik90#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (AndyMik90#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (AndyMik90#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (AndyMik90#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (AndyMik90#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (AndyMik90#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
StillKnotKnown added a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
…frontend settings (AndyMik90#1082)

* Version 2.7.4 (AndyMik90#1040)

* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (AndyMik90#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (AndyMik90#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (AndyMik90#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (AndyMik90#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (AndyMik90#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (AndyMik90#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (AndyMik90#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (AndyMik90#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (AndyMik90#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (AndyMik90#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (AndyMik90#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (AndyMik90#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes AndyMik90#1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (AndyMik90#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (AndyMik90#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (AndyMik90#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (AndyMik90#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (AndyMik90#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (AndyMik90#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (AndyMik90#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (AndyMik90#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (AndyMik90#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (AndyMik90#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (AndyMik90#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (AndyMik90#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (AndyMik90#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (AndyMik90#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>

* fix(docs): update README download links to v2.7.4

The stable version badge was updated to 2.7.4 but the download links
were still pointing to 2.7.3 artifacts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: update all model versions to Claude 4.5 and connect insights to frontend settings

- Update outdated model versions across entire codebase:
  - claude-sonnet-4-20250514 → claude-sonnet-4-5-20250929
  - claude-opus-4-20250514 → claude-opus-4-5-20251101
  - claude-haiku-3-5-20241022 → claude-haiku-4-5-20251001
  - claude-sonnet-3-5-20241022 removed from pricing table

- Fix insight extractor crash with Haiku + extended thinking:
  - Set thinking_default to "none" for insights agent type
  - Haiku models don't support extended thinking

- Connect Insights Chat to frontend Agent Settings:
  - Add getInsightsFeatureSettings() to read featureModels/featureThinking
  - Merge frontend settings with any explicit modelConfig
  - Follow same pattern as ideation handlers

- Update rate limiter pricing table with current models only

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review findings for insights feature

- Fix incorrect comment about Haiku extended thinking support
  (Haiku 4.5 does NOT support extended thinking, only Sonnet 4.5 and Opus 4.5)
- Use standard path import pattern consistent with codebase
- Replace console.error with debugError for consistent logging
- Add pydantic to test requirements (fixes CI test collection error)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: ruff format issue in insights_runner.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address follow-up PR review findings

- Fix HIGH: Make max_thinking_tokens conditional in simple_client.py
  (prevents passing None to SDK, which may cause issues with Haiku)
- Fix MEDIUM: Use nullish coalescing at property level for featureModels.insights
  (handles partial settings objects where insights key may be missing)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
StillKnotKnown added a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
* Version 2.7.4 (#1040)

* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes #1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>

* fix(docs): update README download links to v2.7.4

The stable version badge was updated to 2.7.4 but the download links
were still pointing to 2.7.3 artifacts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-1 - Add fsPromises import and saveAsync() method to TerminalSessionStore

* auto-claude: subtask-1-2 - Add public saveSessionAsync() method

Add public saveSessionAsync() method that wraps the private saveAsync()
method. This enables external callers (like Electron app-quit handlers)
to perform non-blocking async saves to disk.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-2-1 - Add persistSessionAsync() function to session-handler.ts

- Added persistSessionAsync() to session-handler.ts that builds the session
  object and calls store.saveSessionAsync() with fire-and-forget pattern
- Fixed saveSessionAsync() in terminal-session-store.ts to properly accept
  a session parameter and mirror saveSession() logic with async disk writes
- This enables non-blocking session persistence to prevent main process freezing

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-3-1 - Convert persistSession() calls to async

Convert all 4 persistSession() calls in claude-integration-handler.ts
to use persistSessionAsync() for fire-and-forget async file persistence.

This prevents the Electron main process from blocking on synchronous
disk writes, which was causing the Mac crash on "Invoke Claude" button.

Converted locations:
- Line 180: finalizeClaudeInvoke()
- Line 389: handleClaudeExit()
- Line 567: resumeClaude()
- Line 743: resumeClaudeAsync()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-3-3 - Convert persistSession() calls in resumeClaude() and resumeClaudeAsync() to async

Updated comments in resumeClaude() and resumeClaudeAsync() to reference
persistSessionAsync() instead of persistSession() for consistency with
the actual code that was already using the async version.

* auto-claude: subtask-4-1 - Convert persistSession() calls in createTerminal()

Changed all 3 synchronous persistSession() calls in terminal-lifecycle.ts
to use the async persistSessionAsync() variant to prevent UI freezing:
- createTerminal(): persist after terminal setup
- restoreTerminal(): persist after title/worktreeConfig restore
- restoreTerminal(): persist after Claude mode and pending resume state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-5-1 - Convert persistSession() call in setWorktreeConfig

Migrated the synchronous persistSession() call to persistSessionAsync() in
the setWorktreeConfig() method to avoid blocking the main process when
persisting terminal session data after worktree config changes.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-6-3 - Fix test mock for persistSessionAsync

Update claude-integration-handler.test.ts to mock persistSessionAsync
which is now used instead of the sync persistSession. This fixes the
16 failing tests that were missing the mock export.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: Address PR review issues for async session persistence

**HIGH priority fix:**
- Add pendingDelete set to prevent async writes from resurrecting deleted
  sessions. When removeSession() is called, the session ID is tracked to
  prevent in-flight saveSessionAsync() calls from re-adding the session.

**MEDIUM priority fixes:**
- Extract shared session update logic into updateSessionInMemory() to
  eliminate code duplication between saveSession() and saveSessionAsync()
- Extract createSessionObject() helper to eliminate duplication between
  persistSession() and persistSessionAsync() in session-handler.ts
- Add write serialization (writeInProgress/writePending flags) to prevent
  concurrent saveAsync() calls from interleaving and losing data

**LOW priority fixes:**
- Add failure tracking (consecutiveFailures counter) with warnings for
  persistent write failures in fire-and-forget scenarios
- Add persistAllSessionsAsync() for non-blocking batch saves
- Update callers (destroyAllTerminals, periodic save timer) to use async
  version, deprecate blocking persistAllSessions()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
StillKnotKnown added a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (AndyMik90#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (AndyMik90#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (AndyMik90#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (AndyMik90#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (AndyMik90#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (AndyMik90#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (AndyMik90#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (AndyMik90#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (AndyMik90#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (AndyMik90#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (AndyMik90#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (AndyMik90#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes AndyMik90#1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (AndyMik90#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (AndyMik90#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (AndyMik90#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (AndyMik90#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (AndyMik90#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (AndyMik90#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (AndyMik90#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (AndyMik90#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (AndyMik90#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (AndyMik90#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (AndyMik90#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (AndyMik90#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (AndyMik90#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (AndyMik90#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
StillKnotKnown added a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
* ci: add Azure auth test workflow

* fix(worktree): handle "already up to date" case correctly (ACS-226) (AndyMik90#961)

* fix(worktree): handle "already up to date" case correctly (ACS-226)

When git merge returns non-zero for "Already up to date", the merge
code incorrectly treated this as a conflict and aborted. Now checks
git output to distinguish between:
- "Already up to date" - treat as success (nothing to merge)
- Actual conflicts - abort as before
- Other errors - show actual error message

Also added comprehensive tests for edge cases:
- Already up to date with no_commit=True
- Already up to date with delete_after=True
- Actual merge conflict detection
- Merge conflict with no_commit=True

* test: strengthen merge conflict abort verification

Improve assertions in conflict detection tests to explicitly verify:
- MERGE_HEAD does not exist after merge abort
- git status returns clean (no staged/unstaged changes)

This is more robust than just checking for absence of "CONFLICT"
string, as git status --porcelain uses status codes, not literal words.

* test: add git command success assertions and branch deletion verification

- Add explicit returncode assertions for all subprocess.run git add/commit calls
- Add branch deletion verification in test_merge_worktree_already_up_to_date_with_delete_after
- Ensures tests fail early if git commands fail rather than continuing silently

---------

Co-authored-by: StillKnotKnown <[email protected]>

* fix(terminal): add collision detection for terminal drag and drop reordering (AndyMik90#985)

* fix(terminal): add collision detection for terminal drag and drop reordering

Add closestCenter collision detection to DndContext to fix terminal
drag and drop swapping not detecting valid drop targets. The default
rectIntersection algorithm required too much overlap for grid layouts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): handle file drops when closestCenter returns sortable ID

Address PR review feedback:
- Fix file drop handling to work when closestCenter collision detection
  returns the sortable ID instead of the droppable ID
- Add terminals to useCallback dependency array to prevent stale state

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): enable auto-switch on 401 auth errors & OAuth-only profiles (AndyMik90#900)

* fix(ACS-181): enable auto-switch for OAuth-only profiles

Add OAuth token check at the start of isProfileAuthenticated() so that
profiles with only an oauthToken (no configDir) are recognized as
authenticated. This allows the profile scorer to consider OAuth-only
profiles as valid alternatives for proactive auto-switching.

Previously, isProfileAuthenticated() immediately returned false if
configDir was missing, causing OAuth-only profiles to receive a -500
penalty in the scorer and never be selected for auto-switch.

Fixes: ACS-181

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

* fix(ACS-181): detect 'out of extra usage' rate limit messages

The previous patterns only matched "Limit reached · resets ..." but
Claude Code also shows "You're out of extra usage · resets ..." which
wasn't being detected. This prevented auto-switch from triggering.

Added new patterns to both output-parser.ts (terminal) and
rate-limit-detector.ts (agent processes) to detect:
- "out of extra usage · resets ..."
- "You're out of extra usage · resets ..."

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ACS-181): add real-time rate limit detection and debug logging

- Add real-time rate limit detection in agent-process.ts processLog()
  so rate limits are detected immediately as output appears, not just
  when the process exits
- Add clear warning message when auto-switch is disabled in settings
- Add debug logging to profile-scorer.ts to trace profile evaluation
- Add debug logging to rate-limit-detector.ts to trace pattern matching

This enables immediate detection and auto-switch when rate limits occur
during task execution.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): enable auto-switch on 401 auth errors

- Propagate 401/403 errors from fetchUsageViaAPI to checkUsageAndSwap in UsageMonitor to trigger proactive profile swapping.
- Fix usage monitor race condition by ensuring it waits for ClaudeProfileManager initialization.
- Fix isProfileAuthenticated to correctly validate OAuth-only profiles.

* fix(ACS-181): address PR review feedback

- Revert unrelated files (rate-limit-detector, output-parser, agent-process) to upstream state
- Gate profile-scorer logging behind DEBUG flag
- Fix usage-monitor type safety and correct catch block syntax
- Fix misleading indentation in index.ts app updater block

* fix(frontend): enforce eslint compliance for logs in profile-scorer

- Replace all console.log with console.warn (per linter rules)
- Strictly gate all debug logs behind isDebug check to prevent production noise

* fix(ACS-181): add swap loop protection for auth failures

- Add authFailedProfiles Map to track profiles with recent auth failures
- Implement 5-minute cooldown before retrying failed profiles
- Exclude failed profiles from swap candidates to prevent infinite loops
- Gate TRACE logs behind DEBUG flag to reduce production noise
- Change console.log to console.warn for ESLint compliance

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add Claude Code version rollback feature (AndyMik90#983)

* feat(frontend): add Claude Code version rollback feature

Add ability for users to switch to any of the last 20 Claude Code CLI versions
directly from the Claude Code popup in the sidebar.

Changes:
- Add IPC channels for fetching available versions and installing specific version
- Add backend handlers to fetch versions from npm registry (with 1-hour cache)
- Add version selector dropdown in ClaudeCodeStatusBadge component
- Add warning dialog before switching versions (warns about closing sessions)
- Add i18n support for English and French translations

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address PR review feedback for Claude Code version rollback

- Add validation after semver filtering to handle empty version list
- Add error state and UI feedback for installation/version switch failures
- Extract magic number 5000ms to VERSION_RECHECK_DELAY_MS constant
- Bind Select value prop to selectedVersion state
- Normalize version comparison to handle 'v' prefix consistently
- Use normalized version comparison in SelectItem disabled check

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(security): inherit security profiles in worktrees and validate shell -c commands (AndyMik90#971)

* fix(security): inherit security profiles in worktrees and validate shell -c commands

- Add inherited_from field to SecurityProfile to mark profiles copied from parent projects
- Skip hash-based re-analysis for inherited profiles (fixes worktrees losing npm/npx etc.)
- Add shell_validators.py to validate commands inside bash/sh/zsh -c strings
- Register shell validators to close security bypass via bash -c "arbitrary_command"
- Add 13 new tests for inherited profiles and shell -c validation

Fixes worktree security config not being inherited, which caused agents to be
blocked from running npm/npx commands in isolated workspaces.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(security): close shell -c bypass vectors and validate inherited profiles

- Fix combined shell flags bypass (-xc, -ec, -ic) in _extract_c_argument()
  Shell allows combining flags like `bash -xc 'cmd'` which bypassed -c detection
- Add recursive validation for nested shell invocations
  Prevents bypass via `bash -c "bash -c 'evil_cmd'"`
- Validate inherited_from path in should_reanalyze() with defense-in-depth
  - Must exist and be a directory
  - Must be an ancestor of current project
  - Must contain valid security profile
- Add comprehensive test coverage for all security fixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: fix import ordering in test_security.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: format shell_validators.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(frontend): add searchable branch combobox to worktree creation dialog (AndyMik90#979)

* feat(frontend): add searchable branch combobox to worktree creation dialog

- Replace limited Select dropdown with searchable Combobox for branch selection
- Add new Combobox UI component with search filtering and scroll support
- Remove 15-branch limit - now shows all branches with search
- Improve worktree name validation to allow dots and underscores
- Better sanitization: spaces become hyphens, preserve valid characters
- Add i18n keys for branch search UI in English and French

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review feedback for worktree dialog

- Extract sanitizeWorktreeName utility function to avoid duplication
- Replace invalid chars with hyphens instead of removing them (feat/new → feat-new)
- Trim trailing hyphens and dots from sanitized names
- Add validation to forbid '..' in names (invalid for Git branch names)
- Refactor branchOptions to use map/spread instead of forEach/push
- Add ARIA accessibility: listboxId, aria-controls, role="listbox"

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): align worktree name validation with backend regex

- Fix frontend validation to match backend WORKTREE_NAME_REGEX (no dots,
  must end with alphanumeric)
- Update sanitizeWorktreeName to exclude dots from allowed characters
- Update i18n messages (en/fr) to remove mention of dots
- Add displayName to Combobox component for React DevTools
- Export Combobox from UI component index.ts
- Add aria-label to Combobox listbox for accessibility

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): address PR review accessibility and cleanup issues

- Add forwardRef pattern to Combobox for consistency with other UI components
- Add keyboard navigation (ArrowUp/Down, Enter, Escape, Home, End)
- Add aria-activedescendant for screen reader focus tracking
- Add unique option IDs for ARIA compliance
- Add cleanup for async branch fetching to prevent state updates on unmounted component

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(frontend): sync worktree config to renderer on terminal restoration (AndyMik90#982)

* fix(frontend): sync worktree config to renderer on terminal restoration

When terminals are restored after app restart, the worktree config
was not being synced to the renderer, causing the worktree label
to not appear. This adds a new IPC channel to send worktree config
during restoration and a listener in useTerminalEvents to update
the terminal store.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(frontend): always sync worktreeConfig to handle deleted worktrees

Addresses PR review feedback: send worktreeConfig IPC message
unconditionally so the renderer can clear stale worktree labels
when a worktree is deleted while the app is closed.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(merge): include files with content changes even when semantic analysis is empty (AndyMik90#986)

* fix(merge): include files with content changes even when semantic analysis is empty

The merge system was discarding files that had real code changes but no
detected semantic changes. This happened because:

1. The semantic analyzer only detects imports and function additions/removals
2. Files with only function body modifications returned semantic_changes=[]
3. The filter used Python truthiness (empty list = False), excluding these files
4. This caused merges to fail with "0 files to merge" despite real changes

The fix uses content hash comparison as a fallback check. If the file content
actually changed (hash_before != hash_after), include it for merge regardless
of whether the semantic analyzer could parse the specific change types.

This fixes merging for:
- Files with function body modifications (most common case)
- Unsupported file types (Rust, Go, etc.) where semantic analysis returns empty
- Any file where the analyzer fails to detect the specific change pattern

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor(merge): add TaskSnapshot.has_modifications property and handle DIRECT_COPY

Address PR review feedback:

1. DRY improvement: Add `has_modifications` property to TaskSnapshot
   - Centralizes the modification detection logic
   - Checks semantic_changes first, falls back to content hash comparison
   - Handles both complete tasks and in-progress tasks safely

2. Fix for files with empty semantic_changes (Cursor issue #2):
   - Add DIRECT_COPY MergeDecision for files that were modified but
     couldn't be semantically analyzed (body changes, unsupported languages)
   - MergePipeline returns DIRECT_COPY when has_modifications=True but
     semantic_changes=[] (single task case)
   - Orchestrator handles DIRECT_COPY by reading file directly from worktree
   - This prevents silent data loss where apply_single_task_changes would
     return baseline content unchanged

3. Update _update_stats to count DIRECT_COPY as auto-merged

The combination ensures:
- Files ARE detected for merge (has_modifications check)
- Files ARE properly merged (DIRECT_COPY reads from worktree)
- No silent data loss (worktree content used instead of baseline)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): handle DIRECT_COPY in merge_tasks() and log missing files

- Add DIRECT_COPY handling to merge_tasks() for multi-task merges
  (was only handled in merge_task() for single-task merges)
- Add warning logging when worktree file doesn't exist during DIRECT_COPY
  in both merge_task() and merge_tasks()

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): remove unnecessary f-string prefixes

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(merge): properly fail DIRECT_COPY when worktree file missing

- Extract _read_worktree_file_for_direct_copy() helper to DRY up logic
- Set decision to FAILED when worktree file not found (was silent success)
- Add warning when worktree_path is None in merge_tasks
- Use `is not None` check for merged_content to allow empty files
- Fix has_modifications for new files with empty hash_before
- Add debug_error() to merge_tasks exception handling for consistency

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style(merge): fix ruff formatting for long line

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(terminal): detect Claude exit and reset label when user closes Claude (AndyMik90#990)

* fix(terminal): detect Claude exit and reset label when user closes Claude

Previously, the "Claude" label on terminals would persist even after the
user closed Claude (via /exit, Ctrl+D, etc.) because the system only
reset isClaudeMode when the entire terminal process exited.

This change adds robust Claude exit detection by:
- Adding shell prompt patterns to detect when Claude exits and returns
  to shell (output-parser.ts)
- Adding new IPC channel TERMINAL_CLAUDE_EXIT for exit notifications
- Adding handleClaudeExit() to reset terminal state in main process
- Adding onClaudeExit callback in terminal event handler
- Adding onTerminalClaudeExit listener in preload API
- Handling exit event in renderer to update terminal store

Now when a user closes Claude within a terminal, the label is removed
immediately while the terminal continues running.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): add line-start anchors to exit detection regex patterns

Address PR review findings:
- Add ^ anchors to CLAUDE_EXIT_PATTERNS to prevent false positive exit
  detection when Claude outputs paths, array access, or Unicode arrows
- Add comprehensive unit tests for detectClaudeExit and related functions
- Remove duplicate debugLog call in handleClaudeExit (keep console.warn)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): prevent false exit detection for emails and race condition

- Update user@host regex to require path indicator after colon,
  preventing emails like [email protected]: from triggering exit detection
- Add test cases for emails at line start to ensure they don't match
- Add guard in onTerminalClaudeExit to prevent setting status to 'running'
  if terminal has already exited (fixes potential race condition)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(app-update): persist downloaded update state for Install button visibility (AndyMik90#992)

* fix(app-update): persist downloaded update state for Install button visibility

When updates auto-download in background, users miss the update-downloaded
event if not on Settings page. This causes "Install and Restart" button
to never appear.

Changes:
- Add downloadedUpdateInfo state in app-updater.ts to persist downloaded info
- Add APP_UPDATE_GET_DOWNLOADED IPC handler to query downloaded state
- Add getDownloadedAppUpdate API method in preload
- Update AdvancedSettings to check for already-downloaded updates on mount

Now when user opens Settings after background download, the component
queries persisted state and shows "Install and Restart" correctly.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): resolve race condition and type safety issues

- Fix race condition where checkForAppUpdates() could overwrite downloaded
  update info with null, causing 'Unknown' version display
- Add proper type guard for releaseNotes (can be string | array | null)
  instead of unsafe type assertion

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(app-update): clear downloaded update state on channel change and add useEffect cleanup

- Clear downloadedUpdateInfo when update channel changes to prevent showing
  Install button for updates from a different channel (e.g., beta update
  showing after switching to stable channel)
- Add isCancelled flag to useEffect async operations in AdvancedSettings
  to prevent React state updates on unmounted components

Addresses CodeRabbit review findings.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(backend): add Sentry integration and fix broken pipe errors (AndyMik90#991)

* fix(backend): add Sentry integration and fix broken pipe errors

- Add sentry-sdk to Python backend for error tracking
- Create safe_print() utility to handle BrokenPipeError gracefully
- Initialize Sentry in CLI, GitHub runner, and spec runner entry points
- Use same SENTRY_DSN environment variable as Electron frontend
- Apply privacy path masking (usernames removed from stack traces)

Fixes "Review Failed: [Errno 32] Broken pipe" error in PR review

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address PR review findings for Sentry integration

- Fix ruff linting errors (unused imports, import sorting)
- Add path masking to set_context() and set_tag() for privacy
- Add defensive path masking to capture_exception() kwargs
- Add debug logging for bare except clauses in sentry.py
- Add top-level error handler in cli/main.py with Sentry capture
- Add error handling with Sentry capture in spec_runner.py
- Move safe_print to core/io_utils.py for broader reuse
- Migrate GitLab runner files to use safe_print()
- Add fallback import pattern in sdk_utils.py

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* style: apply ruff formatting

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(backend): address CodeRabbit review findings for Sentry and io_utils

- Add path masking to capture_message() kwargs for privacy consistency
- Add recursion depth limit (50) to _mask_object_paths() to prevent stack overflow
- Add WSL path masking support (/mnt/[a-z]/Users/...)
- Add consistent ImportError debug logging across Sentry wrapper functions
- Add ValueError handling in safe_print() for closed stdout scenarios
- Improve reset_pipe_state() documentation with usage warnings

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix: improve Claude CLI detection and add installation selector (AndyMik90#1004)

* fix: improve Claude CLI detection and add installation selector

This PR addresses the "Claude Code not found" error when starting tasks by
improving CLI path detection across all platforms.

Backend changes:
- Add cross-platform `find_claude_cli()` function in `client.py` that checks:
  - CLAUDE_CLI_PATH environment variable for user override
  - System PATH via shutil.which()
  - Homebrew paths on macOS
  - NVM paths for Node.js version manager installations
  - Platform-specific standard locations (Windows: AppData, Program Files; Unix: .local/bin)
- Pass detected `cli_path` to ClaudeAgentOptions in both `create_client()` and `create_simple_client()`
- Improve Windows .cmd/.bat file execution using proper cmd.exe flags (/d, /s, /c)
  and correct quoting for paths with spaces

Frontend changes:
- Add IPC handlers for scanning all Claude CLI installations and switching active path
- Update ClaudeCodeStatusBadge to show current CLI path and allow selection when
  multiple installations are detected
- Add `writeSettingsFile()` to settings-utils for persisting CLI path selection
- Add translation keys for new UI elements (English and French)

Closes AndyMik90#1001

* fix: address PR review findings for Claude CLI detection

Addresses all 8 findings from Auto Claude PR Review:

Security improvements:
- Add path sanitization (_is_secure_path) to backend CLI validation
  to prevent command injection via malicious paths
- Add isSecurePath validation in frontend IPC handler before CLI execution
- Normalize paths with path.resolve() before execution

Architecture improvements:
- Refactor scanClaudeInstallations to use getClaudeDetectionPaths() from
  cli-tool-manager.ts as single source of truth (addresses code duplication)
- Add cross-reference comments between backend _get_claude_detection_paths()
  and frontend getClaudeDetectionPaths() to keep them in sync

Bug fixes:
- Fix path display truncation to use regex /[/\\]/ for cross-platform
  compatibility (Windows uses backslashes)
- Add null check for version in UI rendering (shows "version unknown"
  instead of "vnull")
- Use DEFAULT_APP_SETTINGS merge pattern for settings persistence

Debugging improvements:
- Add error logging in validateClaudeCliAsync catch block for better
  debugging of CLI detection issues

Translation additions:
- Add "versionUnknown" key to English and French navigation.json

* ci(release): move VirusTotal scan to separate post-release workflow (AndyMik90#980)

* ci(release): move VirusTotal scan to separate post-release workflow

VirusTotal scans were blocking release creation, taking 5+ minutes per
file. This change moves the scan to a separate workflow that triggers
after the release is published, allowing releases to be available
immediately.

- Create virustotal-scan.yml workflow triggered on release:published
- Remove blocking VirusTotal step from release.yml
- Scan results are appended to release notes after completion
- Add manual trigger option for rescanning old releases

* fix(ci): address PR review issues in VirusTotal scan workflow

- Add error checking on gh release view to prevent wiping release notes
- Replace || true with proper error handling to distinguish "no assets" from real errors
- Use file-based approach for release notes to avoid shell expansion issues
- Use env var pattern consistently for secret handling
- Remove placeholder text before appending VT results
- Document 32MB threshold with named constant
- Add HTTP status code validation on all curl requests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): add concurrency control and remove dead code in VirusTotal workflow

- Add concurrency group to prevent TOCTOU race condition when multiple
  workflow_dispatch runs target the same release tag
- Remove unused analysis_failed variable declaration

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): improve error handling in VirusTotal workflow

- Fail workflow when download errors occur but scannable assets exist
- Add explicit timeout handling for analysis polling loop
- Use portable sed approach (works on both GNU and BSD sed)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(ui): display actual base branch name instead of hardcoded main (AndyMik90#969)

* fix(ui): display actual base branch name instead of hardcoded "main"

The merge conflict UI was showing "Main branch has X new commits"
regardless of the actual base branch. Now it correctly displays
the dynamic branch name (e.g., "develop branch has 40 new commits")
using the baseBranch value from gitConflicts.

* docs: update README download links to v2.7.3 (AndyMik90#976)

- Update all stable download links from 2.7.2 to 2.7.3
- Add Flatpak download link (new in 2.7.3)

* fix(i18n): add translation keys for branch divergence messages

- Add merge section to taskReview.json with pluralized translations
- Update WorkspaceStatus.tsx to use i18n for branch behind message
- Update MergePreviewSummary.tsx to use i18n for branch divergence text
- Add French translations for all new keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): add missing translation keys for branch behind details

- Add branchHasNewCommitsSinceBuild for build started message
- Add filesNeedAIMergeDueToRenames for path-mapped files
- Add fileRenamesDetected for rename detection message
- Add filesRenamedOrMoved for generic rename/move message
- Update WorkspaceStatus.tsx to use all new i18n keys

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): correct pluralization for rename count in AI merge message

The filesNeedAIMergeDueToRenames translation has two values that need
independent pluralization (fileCount and renameCount). Since i18next
only supports one count parameter, added separate translation keys
for singular/plural renames and select the correct key based on
renameCount value.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(i18n): use translation keys for merge button labels with dynamic branch

Replace hardcoded 'Stage to Main' and 'Merge to Main' button labels with
i18n translation keys that interpolate the actual target branch name.
Also adds translations for loading states (Resolving, Staging, Merging).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* fix(github-prs): prevent preloading of PRs currently under review (AndyMik90#1006)

- Updated logic to skip PRs that are currently being reviewed when determining which PRs need preloading.
- Enhanced condition to only fetch existing review data from disk if no review is in progress, ensuring that ongoing reviews are not overwritten by stale data.

* chore: bump version to 2.7.4

* hotfix/sentry-backend-build

* fix(github): resolve circular import issues in context_gatherer and services (AndyMik90#1026)

- Updated import statements in context_gatherer.py to import safe_print from core.io_utils to avoid circular dependencies with the services package.
- Introduced lazy imports in services/__init__.py to prevent circular import issues, detailing the import chain in comments for clarity.
- Added a lazy import handler to load classes on first access, improving module loading efficiency.

* feat(sentry): embed Sentry DSN at build time for packaged apps (AndyMik90#1025)

* feat(sentry): integrate Sentry configuration into Electron build

- Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts.
- Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses.
- Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends.
- Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability.

This integration ensures that Sentry is properly configured for both local development and CI environments.

* fix(sentry): add typeof guards for build-time constants in tests

The __SENTRY_*__ constants are only defined when Vite's define plugin runs
during build. In test environments (vitest), these constants are undefined
and cause ReferenceError. Added typeof guards to safely handle both cases.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Fix Duplicate Kanban Task Creation on Rapid Button Clicks (AndyMik90#1021)

* auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook

* auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop

* auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c

* auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task

- Fixed missing convertingIdeas prop connection in Ideation.tsx
- Added convertingIdeas to destructured hook values
- Added isConverting prop to IdeaDetailPanel component
- Created detailed manual-test-report.md with code review and E2E testing instructions
- All code implementation verified via TypeScript checks (no errors)
- Multi-layer protection confirmed: UI disabled, guard check, backend idempotency
- Manual E2E testing required for final verification

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: address PR review findings for duplicate task prevention

- Fix TOCTOU race condition by moving idempotency check inside lock
- Fix React state closure by using ref for synchronous tracking
- Add i18n translations for ideation UI (EN + FR)
- Add error handling with toast notifications for conversion failures

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (AndyMik90#1016)

* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions

Add a toggle in Developer Tools settings that enables "YOLO Mode" which
starts Claude with the --dangerously-skip-permissions flag, bypassing
all safety prompts.

Changes:
- Add dangerouslySkipPermissions setting to AppSettings interface
- Add translation keys for YOLO mode (en/fr)
- Modify claude-integration-handler to accept and append extra flags
- Update terminal-manager and terminal-handlers to read and forward the setting
- Add Switch toggle with warning styling in DevToolsSettings UI

The toggle includes visual warnings (amber colors, AlertTriangle icon) to
clearly indicate this is a dangerous option that bypasses Claude's
permission system.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review issues for YOLO mode implementation

- Add async readSettingsFileAsync to avoid blocking main process during settings read
- Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings
- Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches
- Update switchClaudeProfile callback to pass stored YOLO mode setting

These fixes address:
- LOW: Synchronous file I/O in IPC handler
- LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync
- MEDIUM: YOLO mode not persisting when switching Claude profiles

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>

* Make worktree isolation prominent in UI (AndyMik90#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>

* fix(terminal): improve worktree name input UX (AndyMik90#1012)

* fix(terminal): improve worktree name input to not strip trailing characters while typing

- Allow trailing hyphens/underscores during input (only trim on submit)
- Add preview name that shows the final sanitized value for branch preview
- Remove invalid characters instead of replacing with hyphens
- Collapse consecutive underscores in addition to hyphens
- Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review findings for worktree name validation

- Fix submit button disabled check to use sanitized name instead of raw input
- Simplify trailing trim logic (apply once after all transformations)
- Apply lowercase in handleNameChange to reduce input/preview gap
- Internationalize 'name' fallback using existing translation key

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): improve header responsiveness for multiple terminals

- Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only
- Add dynamic max-width to worktree name badge with truncation
- Add tooltips to all icon-only elements for accessibility
- Maintain full functionality while reducing header width requirements

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(terminal): enhance terminal recreation logic with retry mechanism (AndyMik90#1013)

* fix(terminal): enhance terminal recreation logic with retry mechanism

- Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready.
- Added cleanup for retry timers on component unmount to prevent memory leaks.
- Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup.

* fix(terminal): address PR review feedback for retry mechanism

- Fix race condition: clear pending retry timer at START of effect
  to prevent multiple timers when dependencies change mid-retry
- Fix isCreatingRef: keep it true during retry window to prevent
  duplicate creation attempts from concurrent effect runs
- Extract duplicated retry logic into scheduleRetryOrFail helper
  (consolidated 5 duplicate instances into 1 reusable function)
- Add handleSuccess/handleError helpers to reduce code duplication
- Reduce file from 295 to 237 lines (~20% reduction)

Addresses review feedback from CodeRabbit, Gemini, and Auto Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>

* feat(terminal): add task worktrees section and remove terminal limit (AndyMik90#1033)

* feat(terminal): add task worktrees section and remove terminal limit

- Remove 12 terminal worktree limit (now unlimited)
- Add "Task Worktrees" section in worktree dropdown below terminal worktrees
- Task worktrees (created by kanban) now accessible for manual work
- Update translations for new section labels (EN + FR)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Clear taskWorktrees state when project is null or changes
- Parallelize API calls with Promise.all for better performance
- Use consistent path-based filtering for both worktree types
- Add clarifying comment for createdAt timestamp

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* Add file/screenshot upload to QA feedback interface (AndyMik90#1018)

* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail

- Add feedbackImages state as ImageAttachment[] for storing feedback images
- Add setFeedbackImages setter for direct state updates
- Add addFeedbackImage handler for adding a single image
- Add addFeedbackImages handler for adding multiple images at once
- Add removeFeedbackImage handler for removing an image by ID
- Add clearFeedbackImages handler for clearing all images
- Import ImageAttachment type from shared/types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview

- Add ImageAttachment import from ./task types
- Update submitReview signature to include optional images parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images

* auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa

- Add paste event handler for screenshot/image clipboard support
- Add drag-over and drag-leave handlers for visual feedback during drag
- Add drop handler for image file drops
- Add image thumbnail display (64x64) with remove button on hover
- Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.)
- Add i18n support for all new UI text
- Make new props optional for backward compatibility during incremental rollout
- Allow submission with either text feedback or images (not both required)
- Add visual drag feedback with border/background color change

* auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection

* auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview

- Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview
- Update handleReject to include images in submitReview call
- Allow submission with images only (no text required)
- Clear images after successful submission

* auto-claude: subtask-3-1 - Add English translations for feedback image UI

* auto-claude: subtask-3-2 - Add French translations for feedback image UI

* fix(security): sanitize image filename to prevent path traversal

- Use path.basename() to strip directory components from filenames
- Validate sanitized filename is not empty, '.', or '..'
- Add defense-in-depth check verifying resolved path stays within target directory
- Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: add MIME type validation and fix SVG file extension

- Add server-side MIME type validation for image uploads (defense in depth)
- Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml'
- Add MIME-to-extension mapping for all allowed image types

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: require mimeType and apply SVG extension fix to drop handler

- Change MIME validation to reject missing mimeType (prevents bypass)
- Add 'image/jpg' to server-side allowlist for consistency
- Apply mimeToExtension mapping to drop handler (was only in paste handler)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Test User <[email protected]>

* fix(auth): await profile manager initialization before auth check (AndyMik90#1010)

* fix(auth): await profile manager initialization before auth check

Fixes race condition where hasValidAuth() was called before the
ClaudeProfileManager finished async initialization from disk.

The getClaudeProfileManager() returns a singleton immediately with
default profile data (no OAuth token). When hasValidAuth() runs
before initialization completes, it returns false even when valid
credentials exist.

Changed all pre-flight auth checks to use
await initializeClaudeProfileManager() which ensures initialization
completes via promise caching.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add error handling for profile manager initialization

Prevents unhandled promise rejections when initializeClaudeProfileManager()
throws due to filesystem errors (permissions, disk full, corrupt JSON).

The ipcMain.on handler for TASK_START doesn't await promises, so
unhandled rejections could crash the main process. Wrapped all
await initializeClaudeProfileManager() calls in try-catch blocks.

Found via automated code review.

Signed-off-by: StillKnotKnown <[email protected]>

* test: mock initializeClaudeProfileManager in subprocess tests

The test mock was only mocking getClaudeProfileManager, but now we
also use initializeClaudeProfileManager which wasn't mocked, causing
test failures.

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers

Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK
handlers were missing try-catch blocks for initializeClaudeProfileManager(),
inconsistent with TASK_START handler.

If initialization fails, users now get specific file permissions guidance
instead of generic error messages.

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(auth): extract profile manager initialization into helper

Extract the repeated initializeClaudeProfileManager() + try/catch pattern
into a helper function ensureProfileManagerInitialized() that returns
a discriminated union for type-safe error handling.

This reduces code duplication across TASK_START, TASK_UPDATE_STATUS,
and TASK_RECOVER_STUCK handlers while preserving context-specific
error handling behavior.

The helper returns:
- { success: true, profileManager } on success
- { success: false, error } on failure

Signed-off-by: StillKnotKnown <[email protected]>

* fix(auth): improve error details and allow retry after transient failures

Two improvements to profile manager initialization:

1. Include actual error details in failure response for better debugging.
   Previously, only a generic message was returned to users, making it
   hard to diagnose the root cause. Now the error message is appended.

2. Reset cached promise on failure to allow retries after transient errors.
   Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected
   promise was cached forever, requiring app restart to recover. Now the
   cached promise is reset on failure, allowing subsequent calls to retry.

Signed-off-by: StillKnotKnown <[email protected]>

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>

* fix(frontend): validate Windows claude.cmd reliably in GUI (AndyMik90#1023)

* fix: use absolute cmd.exe for Claude CLI validation

* fix: make cmd.exe validation type-safe for tests

* fix: satisfy frontend typecheck for cli tool tests

Signed-off-by: Umaru <[email protected]>

* test: mock windows-paths exports for isSecurePath

Signed-off-by: Umaru <[email protected]>

* test: make cli env tests platform-aware

Signed-off-by: Umaru <[email protected]>

* test: cover isSecurePath guard in claude detection

Signed-off-by: Umaru <[email protected]>

* test: align env-utils mocks with shouldUseShell

Signed-off-by: Umaru <[email protected]>

* test: assert isSecurePath for cmd path

* fix(frontend): handle quoted claude.cmd paths in validation

---------

Signed-off-by: Umaru <[email protected]>
Co-authored-by: Andy <[email protected]>

* 2.7.4 release

* changelog 2.7.4

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Signed-off-by: StillKnotKnown <[email protected]>
Signed-off-by: Umaru <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Michael Ludlow <[email protected]>
Co-authored-by: Test User <[email protected]>
Co-authored-by: Umaru <[email protected]>
xinzhuzi pushed a commit to xinzhuzi/Auto-Claude that referenced this pull request Jan 17, 2026
* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/frontend This is frontend only 🔄 Checking Checking PR Status size/S Small (10-99 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants