-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
fix(frontend): validate Windows claude.cmd reliably in GUI #1023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(frontend): validate Windows claude.cmd reliably in GUI #1023
Conversation
Signed-off-by: Umaru <caleb.1331@outlook.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
📝 WalkthroughWalkthroughAdds robust Windows-aware Claude CLI validation: verifies candidate paths via isSecurePath/where.exe, resolves cmd.exe via ComSpec/SystemRoot, preserves quoting with verbatim args, normalizes exec output, and tightens test typing and Windows-specific mocks. (48 words) Changes
Sequence Diagram(s)sequenceDiagram
actor UserCode
participant CLIManager
participant WindowsPaths
participant Security
participant CmdExe
participant Exec
UserCode->>CLIManager: validateClaude(candidatePath)
CLIManager->>WindowsPaths: findWindowsExecutableViaWhereAsync(candidatePath)?
WindowsPaths-->>CLIManager: foundPath | null
CLIManager->>Security: isSecurePath(foundPath)
Security-->>CLIManager: secure / insecure
alt secure
CLIManager->>CmdExe: resolve ComSpec/SystemRoot\cmd.exe
CLIManager->>Exec: execFile/execFileSync(cmd.exe, ['/s','/c', quotedCmd], { env: augmented })
Exec-->>CLIManager: stdout/stderr (normalized)
CLIManager->>UserCode: parse version -> valid
else insecure
CLIManager-->>UserCode: ignore and fallback
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @g1331, 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 robustness and security of Claude CLI detection and validation, especially on Windows. It refines how '.cmd' and '.bat' files are executed to prevent shell injection and correctly handle complex paths, while also introducing a security check for executable locations. The changes are supported by enhanced type safety and more comprehensive, platform-aware tests. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces significant security and robustness improvements for executing CLI tools, particularly for .cmd files on Windows. The changes to use cmd.exe /s /c with windowsVerbatimArguments are excellent for preventing command injection. The added type safety and test enhancements are also valuable. I've identified a couple of areas for improvement: there's a potential bug related to handling already-quoted command paths, and some redundant platform checks that can be cleaned up. Overall, this is a high-quality contribution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/frontend/src/main/__tests__/cli-tool-manager.test.ts (1)
493-519: Observation: Inconsistent use ofcreateDirenthelper.The
sortNvmVersionDirstests still use plain objects{ name: '...', isDirectory: () => true }instead of the newcreateDirenthelper. This is likely intentional sincesortNvmVersionDirsaccepts a simpler interface than fullfs.Dirent, but consider using the helper for consistency if the function signature allows it.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
apps/frontend/src/main/__tests__/cli-tool-manager.test.tsapps/frontend/src/main/__tests__/insights-config.test.tsapps/frontend/src/main/cli-tool-manager.tsapps/frontend/src/main/terminal/__tests__/claude-integration-handler.test.ts
🧰 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/main/__tests__/insights-config.test.tsapps/frontend/src/main/__tests__/cli-tool-manager.test.tsapps/frontend/src/main/terminal/__tests__/claude-integration-handler.test.tsapps/frontend/src/main/cli-tool-manager.ts
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/main/__tests__/insights-config.test.tsapps/frontend/src/main/__tests__/cli-tool-manager.test.tsapps/frontend/src/main/terminal/__tests__/claude-integration-handler.test.tsapps/frontend/src/main/cli-tool-manager.ts
🧬 Code graph analysis (2)
apps/frontend/src/main/__tests__/cli-tool-manager.test.ts (2)
apps/frontend/src/main/env-utils.ts (1)
findExecutable(252-273)apps/frontend/src/main/utils/windows-paths.ts (2)
findWindowsExecutableViaWhere(135-178)isSecurePath(40-56)
apps/frontend/src/main/terminal/__tests__/claude-integration-handler.test.ts (1)
apps/frontend/src/shared/utils/shell-escape.ts (1)
buildCdCommand(48-62)
🪛 ast-grep (0.40.4)
apps/frontend/src/main/terminal/__tests__/claude-integration-handler.test.ts
[warning] 238-238: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^${escapeForRegex(tokenPrefix)}[0-9a-f]{16}$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
[warning] 281-281: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^${escapeForRegex(tokenPrefix)}[0-9a-f]{16}$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
⏰ 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). (3)
- GitHub Check: Seer Code Review
- GitHub Check: CodeQL (python)
- GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (18)
apps/frontend/src/main/terminal/__tests__/claude-integration-handler.test.ts (4)
3-7: LGTM!The new imports align well with the cross-platform test improvements. Using
buildCdCommandfrom shared utils ensures test assertions match the actual implementation's platform-specific behavior, andpathenables proper cross-platform path construction.
105-105: LGTM!Using
buildCdCommanddynamically ensures the test expectation matches the actual implementation's platform-specific output, making this test portable across Windows and Unix environments.
238-239: LGTM - static analysis warning is a false positive here.The ReDoS warning flagged by static analysis doesn't apply in this test context:
tokenPrefixis constructed from the mockedtmpdir()(returns/tmp) and a fixed string literalescapeForRegexproperly neutralizes any regex metacharacters- The pattern is non-backtracking (no nested quantifiers)
Using
path.joinfor path construction is the correct approach for cross-platform compatibility.
281-282: Consistent with the pattern at lines 238-239.Same analysis applies - the static analysis ReDoS warning is a false positive given the controlled test fixtures and proper escaping.
apps/frontend/src/main/__tests__/insights-config.test.ts (2)
89-99: Consistent cross-platform path handling.Both test cases correctly mirror the
path.resolve()pattern from the first test. This ensures consistent expectations across all PYTHONPATH-related tests.Assuming the implementation verification above confirms that
InsightsConfigresolves paths internally, these changes look good.
62-64: No issue found—implementation correctly applies path.resolve().The implementation properly applies
path.resolve()to each PYTHONPATH component (lines 41-52 inapps/frontend/src/main/insights/config.ts) and usespath.delimiterfor joining (line 68), exactly matching the test expectations. Cross-platform consistency is correctly handled.apps/frontend/src/main/__tests__/cli-tool-manager.test.ts (7)
18-23: LGTM!The new imports for
findWindowsExecutableViaWhereAsyncandisSecurePathare correctly added and properly utilized in the mocks and test cases below.
25-39: LGTM!The type aliases and
createDirenthelper improve type safety and reduce boilerplate in tests. The helper correctly implements all requiredDirentinterface methods, and derivingSpawnOptionsfrom the actual function signature ensures the mock stays in sync with production types.
72-104: LGTM!The type safety improvements using
unknownparameters with internal casting are appropriate for test mocks. This approach provides flexibility while maintaining type safety where it matters (callback invocation). The callback signature correctly matches Node.js'schild_processAPI.
115-155: LGTM!The
mockShouldUseShellimplementation correctly emulates the production behavior: returnsfalseon non-Windows platforms andtrueonly for.cmd/.batfiles on Windows. The quote-stripping logic ensures proper handling of Windows paths. Good job wiring it to bothshouldUseShellandgetSpawnOptions.
163-170: LGTM!The expanded mocks correctly cover all Windows path utilities. Default values are sensible (
isSecurePathreturningtrue, async functions returning resolved promises), and tests can easily override withmockReturnValueOnceas demonstrated in the new test case.
208-213: LGTM!The consistent use of
createDirenthelper andMockDirent[]type annotation improves test maintainability and type safety. The refactored tests maintain their original semantics while benefiting from the centralized helper.
377-404: LGTM!This test effectively covers the
isSecurePathguard in Claude CLI detection. The assertions correctly verify that:
- An insecure path is rejected (not found)
- Validation (
execFileSync) is never attempted for insecure pathsisSecurePathis invoked with the correct path argumentThis aligns well with the PR objective to add security path validation coverage.
apps/frontend/src/main/cli-tool-manager.ts (5)
23-31: LGTM!The import changes are clean. The
findHomebrewPythonUtilalias correctly avoids shadowing the privatefindHomebrewPythonmethod in the class.
35-43: LGTM!The custom type definitions properly extend Node.js types with
windowsVerbatimArguments. ThenormalizeExecOutputhelper provides defensive handling for exec output normalization, ensuring consistent string output regardless of the input type.
936-976: Solid security improvements for Windows Claude CLI validation.The implementation correctly:
- Uses
isSecurePathto validate paths before shell execution- Resolves
cmd.exevia absolute path (ComSpecorSystemRoot\System32\cmd.exe) to prevent PATH hijacking- Uses
/d /s /cflags:/ddisables autorun commands,/spreserves inner quotes for paths with spaces- Sets
windowsVerbatimArguments: trueto prevent Node.js from further escaping the command lineThe double-quote pattern
""${claudeCmd}" --version"is correct for cmd.exe with/sflag.
1068-1108: LGTM!The async implementation correctly mirrors the sync version's security measures:
- Same
isSecurePathvalidation for shell execution- Same absolute
cmd.exepath resolution- Same
windowsVerbatimArgumentsand/d /s /cpattern- Consistent environment augmentation
Good consistency between sync and async code paths.
1843-1845: LGTM!Clean public export wrapper that allows the internal
isWrongPlatformPathimplementation to evolve independently of the public API contract.
AndyMik90
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤖 Auto Claude PR Review
Merge Verdict: ✅ READY TO MERGE
✅ Ready to merge - All checks passing, no blocking issues found.
No blocking issues. 3 non-blocking suggestion(s) to consider
Risk Assessment
| Factor | Level | Notes |
|---|---|---|
| Complexity | Medium | Based on lines changed |
| Security Impact | Low | Based on security findings |
| Scope Coherence | Good | Based on structural review |
Findings Summary
- Low: 3 issue(s)
Generated by Auto Claude PR Review
Findings (3 selected of 3 total)
🔵 [40a79fab7c17] [LOW] Redundant platform check inside needsShell block (minor)
📁 apps/frontend/src/main/cli-tool-manager.ts:943
The code checks process.platform === 'win32' inside the if (needsShell) block. Since shouldUseShell() only returns true on Windows (per env-utils.ts), this platform check is technically redundant. However, this is defensive programming that ensures isSecurePath() validation only runs on Windows where shell metacharacters matter.
Suggested fix:
This is intentional defensive code. No fix required, but could add a comment explaining why the platform check exists for clarity.
🔵 [d428c9dcaf9c] [LOW] Security relies on pre-existing isSecurePath() implementation
📁 apps/frontend/src/main/cli-tool-manager.ts:946
The security of the command execution depends on isSecurePath() properly rejecting paths containing shell metacharacters (quotes, ampersands, pipes, carets, percent signs). This function is imported from ./utils/windows-paths and is pre-existing code. The PR correctly uses it as a security gate, but the implementation was not reviewed as part of this PR scope.
Suggested fix:
No action needed for this PR - isSecurePath() is pre-existing, trusted utility code. Future security audit could verify it blocks all cmd.exe metacharacters.
🔵 [9989088257ff] [LOW] AI Comment Triage: Gemini double-quoting concerns are false positives
📁 apps/frontend/src/main/cli-tool-manager.ts:0
Gemini Code Assist raised HIGH priority concerns about claudeCmd potentially being a pre-quoted path. Analysis: This is a false positive because (1) the isSecurePath() check would reject paths containing quote characters, and (2) all sources of claudeCmd (system PATH lookup, NVM detection, platform paths) return unquoted paths.
Suggested fix:
No action required. The AI comments can be dismissed.
This review was generated by Auto Claude.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @apps/frontend/src/main/cli-tool-manager.ts:
- Around line 959-961: The code falls back to a hardcoded
"C:\\Windows\\System32\\cmd.exe" when process.env.ComSpec and
process.env.SystemRoot are missing; update the logic around the cmdExe
assignment (the code that sets const cmdExe using process.env.ComSpec and
path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'cmd.exe')) to
detect when neither ComSpec nor SystemRoot existed and emit a warning via the
existing logger (or console.warn) before using the hardcoded path; keep the same
join behavior but ensure the special-case warning is logged so operators are
alerted to possible non-standard Windows installations.
- Around line 23-31: The import alias findHomebrewPythonUtil is unnecessary;
change the import to use the original name findHomebrewPython and update its
usage in the call site (the invocation currently calling findHomebrewPythonUtil)
to call findHomebrewPython instead; verify there are no naming conflicts in this
module and update any other occurrences of findHomebrewPythonUtil to the
original identifier.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
apps/frontend/src/main/cli-tool-manager.ts
🧰 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/main/cli-tool-manager.ts
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/main/cli-tool-manager.ts
🧠 Learnings (1)
📓 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.
⏰ 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). (3)
- GitHub Check: Seer Code Review
- GitHub Check: CodeQL (python)
- GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (4)
apps/frontend/src/main/cli-tool-manager.ts (4)
35-43: LGTM! Well-structured type scaffolding for Windows verbatim arguments.The custom type extensions properly augment Node's exec options with
windowsVerbatimArguments, andnormalizeExecOutputprovides a clean helper for consistent output handling regardless of whether the result is a string or Buffer.
945-946: Good: CLI directory added to PATH for validation.The environment augmentation ensures that
claude.cmdcan resolve its dependencies during validation, addressing the GUI-launch edge case where PATH might be incomplete.
1089-1122: LGTM! Async implementation correctly mirrors the sync version.The async validation maintains consistency with the sync implementation while properly using
getAugmentedEnvAsyncandexecFileAsync. ThenormalizeExecOutputis correctly applied tostdout(from the result object) rather than the whole result.
950-971: Solid Windows cmd.exe invocation pattern with proper security guards.The implementation correctly:
- Resolves
cmd.exeabsolutely viaComSpecorSystemRoot\System32to avoid PATH dependency- Uses
/d /s /cflags where/spreserves the carefully crafted quoting and/ddisables autorun (security)- Applies
windowsVerbatimArguments: trueto prevent Node from re-escaping- Guards with
isSecurePathbefore shell executionThe edge case of embedded
"characters is properly handled:isSecurePathexplicitly rejects paths containing quotes in its dangerous patterns check, preventing any malformed command lines before construction at line 961.
| import { execFileSync, execFile } from 'child_process'; | ||
| import { existsSync, readdirSync, promises as fsPromises } from 'fs'; | ||
| import path from 'path'; | ||
| import os from 'os'; | ||
| import { promisify } from 'util'; | ||
| import { app } from 'electron'; | ||
| import { findExecutable, findExecutableAsync, getAugmentedEnv, getAugmentedEnvAsync, shouldUseShell, existsAsync } from './env-utils'; | ||
| import type { ToolDetectionResult } from '../shared/types'; | ||
| import { findHomebrewPython as findHomebrewPythonUtil } from './utils/homebrew-python'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Minor: Unused import alias.
The import on line 31 renames findHomebrewPython to findHomebrewPythonUtil, but the function is only called once (line 1717). This alias doesn't add clarity. Consider keeping the original name unless there's a naming conflict.
Optional simplification
-import { findHomebrewPython as findHomebrewPythonUtil } from './utils/homebrew-python';
+import { findHomebrewPython } from './utils/homebrew-python';And update line 1717:
- return findHomebrewPythonUtil(
+ return findHomebrewPython(🤖 Prompt for AI Agents
In @apps/frontend/src/main/cli-tool-manager.ts around lines 23 - 31, The import
alias findHomebrewPythonUtil is unnecessary; change the import to use the
original name findHomebrewPython and update its usage in the call site (the
invocation currently calling findHomebrewPythonUtil) to call findHomebrewPython
instead; verify there are no naming conflicts in this module and update any
other occurrences of findHomebrewPythonUtil to the original identifier.
| const cmdExe = process.env.ComSpec | ||
| || path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'cmd.exe'); | ||
| const cmdLine = `""${unquotedCmd}" --version"`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Verify fallback cmd.exe path on non-standard Windows installations.
The fallback to C:\\Windows\\System32\\cmd.exe assumes a standard Windows installation. While rare, some Windows configurations may have a different SystemRoot. The code correctly tries process.env.SystemRoot first, but if that's also undefined, the hardcoded C:\\Windows fallback could fail on relocated Windows installations.
This is a minor edge case, but consider logging a warning if neither ComSpec nor SystemRoot is defined.
Optional: Add warning for fallback case
const cmdExe = process.env.ComSpec
|| path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'cmd.exe');
+if (!process.env.ComSpec && !process.env.SystemRoot) {
+ console.warn('[Claude CLI] Neither ComSpec nor SystemRoot defined, using hardcoded cmd.exe path');
+}🤖 Prompt for AI Agents
In @apps/frontend/src/main/cli-tool-manager.ts around lines 959 - 961, The code
falls back to a hardcoded "C:\\Windows\\System32\\cmd.exe" when
process.env.ComSpec and process.env.SystemRoot are missing; update the logic
around the cmdExe assignment (the code that sets const cmdExe using
process.env.ComSpec and path.join(process.env.SystemRoot || 'C:\\Windows',
'System32', 'cmd.exe')) to detect when neither ComSpec nor SystemRoot existed
and emit a warning via the existing logger (or console.warn) before using the
hardcoded path; keep the same join behavior but ensure the special-case warning
is logged so operators are alerted to possible non-standard Windows
installations.
* 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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <mludlow000@icloud.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: fix import ordering in test_security.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: format shell_validators.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(merge): remove unnecessary f-string prefixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style(merge): fix ruff formatting for long line Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(terminal): prevent false exit detection for emails and race condition - Update user@host regex to require path indicator after colon, preventing emails like user@example.com: 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: apply ruff formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Test User <test@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> --------- Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 2.7.4 release * changelog 2.7.4 --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com>
…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 <stillknotknown@users.noreply.github.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <mludlow000@icloud.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: fix import ordering in test_security.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: format shell_validators.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(merge): remove unnecessary f-string prefixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style(merge): fix ruff formatting for long line Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(terminal): prevent false exit detection for emails and race condition - Update user@host regex to require path indicator after colon, preventing emails like user@example.com: 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: apply ruff formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Test User <test@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> --------- Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 2.7.4 release * changelog 2.7.4 --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix: ruff format issue in insights_runner.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com>
…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 <stillknotknown@users.noreply.github.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <mludlow000@icloud.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: fix import ordering in test_security.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: format shell_validators.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(merge): remove unnecessary f-string prefixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style(merge): fix ruff formatting for long line Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(terminal): prevent false exit detection for emails and race condition - Update user@host regex to require path indicator after colon, preventing emails like user@example.com: 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: apply ruff formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Test User <test@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> --------- Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 2.7.4 release * changelog 2.7.4 --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix: ruff format issue in insights_runner.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <mludlow000@icloud.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style: fix import ordering in test_security.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* style: format shell_validators.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* fix(merge): remove unnecessary f-string prefixes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style(merge): fix ruff formatting for long line
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* fix(terminal): prevent false exit detection for emails and race condition
- Update user@host regex to require path indicator after colon,
preventing emails like user@example.com: 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style: apply ruff formatting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Test User <test@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
---------
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 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 <caleb.1331@outlook.com>
* test: mock windows-paths exports for isSecurePath
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: make cli env tests platform-aware
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: cover isSecurePath guard in claude detection
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: align env-utils mocks with shouldUseShell
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: assert isSecurePath for cmd path
* fix(frontend): handle quoted claude.cmd paths in validation
---------
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 2.7.4 release
* changelog 2.7.4
---------
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Michael Ludlow <mludlow000@icloud.com>
Co-authored-by: Test User <test@example.com>
Co-authored-by: Umaru <caleb.1331@outlook.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Michael Ludlow <mludlow000@icloud.com>
Co-authored-by: Test User <test@example.com>
Co-authored-by: Umaru <caleb.1331@outlook.com>
…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 <stillknotknown@users.noreply.github.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <mludlow000@icloud.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: fix import ordering in test_security.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: format shell_validators.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(merge): remove unnecessary f-string prefixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style(merge): fix ruff formatting for long line Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(terminal): prevent false exit detection for emails and race condition - Update user@host regex to require path indicator after colon, preventing emails like user@example.com: 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: apply ruff formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Test User <test@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> --------- Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 2.7.4 release * changelog 2.7.4 --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix: ruff format issue in insights_runner.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <mludlow000@icloud.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style: fix import ordering in test_security.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* style: format shell_validators.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* fix(merge): remove unnecessary f-string prefixes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style(merge): fix ruff formatting for long line
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* fix(terminal): prevent false exit detection for emails and race condition
- Update user@host regex to require path indicator after colon,
preventing emails like user@example.com: 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style: apply ruff formatting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Test User <test@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
---------
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 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 <caleb.1331@outlook.com>
* test: mock windows-paths exports for isSecurePath
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: make cli env tests platform-aware
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: cover isSecurePath guard in claude detection
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: align env-utils mocks with shouldUseShell
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: assert isSecurePath for cmd path
* fix(frontend): handle quoted claude.cmd paths in validation
---------
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 2.7.4 release
* changelog 2.7.4
---------
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Michael Ludlow <mludlow000@icloud.com>
Co-authored-by: Test User <test@example.com>
Co-authored-by: Umaru <caleb.1331@outlook.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Michael Ludlow <mludlow000@icloud.com>
Co-authored-by: Test User <test@example.com>
Co-authored-by: Umaru <caleb.1331@outlook.com>
* 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 <stillknotknown@users.noreply.github.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <mludlow000@icloud.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: fix import ordering in test_security.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: format shell_validators.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(merge): remove unnecessary f-string prefixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style(merge): fix ruff formatting for long line Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(terminal): prevent false exit detection for emails and race condition - Update user@host regex to require path indicator after colon, preventing emails like user@example.com: 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: apply ruff formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Test User <test@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> --------- Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 2.7.4 release * changelog 2.7.4 --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com>
…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 <stillknotknown@users.noreply.github.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <mludlow000@icloud.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: fix import ordering in test_security.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: format shell_validators.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(merge): remove unnecessary f-string prefixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style(merge): fix ruff formatting for long line Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(terminal): prevent false exit detection for emails and race condition - Update user@host regex to require path indicator after colon, preventing emails like user@example.com: 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: apply ruff formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Test User <test@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> --------- Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 2.7.4 release * changelog 2.7.4 --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix: ruff format issue in insights_runner.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <mludlow000@icloud.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style: fix import ordering in test_security.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* style: format shell_validators.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* fix(merge): remove unnecessary f-string prefixes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style(merge): fix ruff formatting for long line
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* fix(terminal): prevent false exit detection for emails and race condition
- Update user@host regex to require path indicator after colon,
preventing emails like user@example.com: 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style: apply ruff formatting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Test User <test@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
---------
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 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 <caleb.1331@outlook.com>
* test: mock windows-paths exports for isSecurePath
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: make cli env tests platform-aware
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: cover isSecurePath guard in claude detection
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: align env-utils mocks with shouldUseShell
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: assert isSecurePath for cmd path
* fix(frontend): handle quoted claude.cmd paths in validation
---------
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 2.7.4 release
* changelog 2.7.4
---------
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Michael Ludlow <mludlow000@icloud.com>
Co-authored-by: Test User <test@example.com>
Co-authored-by: Umaru <caleb.1331@outlook.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Michael Ludlow <mludlow000@icloud.com>
Co-authored-by: Test User <test@example.com>
Co-authored-by: Umaru <caleb.1331@outlook.com>
* 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 <stillknotknown@users.noreply.github.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <mludlow000@icloud.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: fix import ordering in test_security.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: format shell_validators.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(merge): remove unnecessary f-string prefixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style(merge): fix ruff formatting for long line Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(terminal): prevent false exit detection for emails and race condition - Update user@host regex to require path indicator after colon, preventing emails like user@example.com: 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: apply ruff formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Test User <test@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> --------- Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 2.7.4 release * changelog 2.7.4 --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com>
* 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 <stillknotknown@users.noreply.github.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <mludlow000@icloud.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: fix import ordering in test_security.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: format shell_validators.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(merge): remove unnecessary f-string prefixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style(merge): fix ruff formatting for long line Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * fix(terminal): prevent false exit detection for emails and race condition - Update user@host regex to require path indicator after colon, preventing emails like user@example.com: 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * style: apply ruff formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Test User <test@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Test User <test@example.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> * 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 <stillknotknown@users.noreply.github.com> --------- Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> * 2.7.4 release * changelog 2.7.4 --------- Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com> Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Michael Ludlow <mludlow000@icloud.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Umaru <caleb.1331@outlook.com>
…#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 <caleb.1331@outlook.com> * test: mock windows-paths exports for isSecurePath Signed-off-by: Umaru <caleb.1331@outlook.com> * test: make cli env tests platform-aware Signed-off-by: Umaru <caleb.1331@outlook.com> * test: cover isSecurePath guard in claude detection Signed-off-by: Umaru <caleb.1331@outlook.com> * test: align env-utils mocks with shouldUseShell Signed-off-by: Umaru <caleb.1331@outlook.com> * test: assert isSecurePath for cmd path * fix(frontend): handle quoted claude.cmd paths in validation --------- Signed-off-by: Umaru <caleb.1331@outlook.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
Signed-off-by: Black Circle Sentinel <mludlow000@icloud.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <mludlow000@icloud.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style: fix import ordering in test_security.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* style: format shell_validators.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* fix(merge): remove unnecessary f-string prefixes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style(merge): fix ruff formatting for long line
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* fix(terminal): prevent false exit detection for emails and race condition
- Update user@host regex to require path indicator after colon,
preventing emails like user@example.com: 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* style: apply ruff formatting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Test User <test@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Test User <test@example.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
* 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 <stillknotknown@users.noreply.github.com>
---------
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 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 <caleb.1331@outlook.com>
* test: mock windows-paths exports for isSecurePath
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: make cli env tests platform-aware
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: cover isSecurePath guard in claude detection
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: align env-utils mocks with shouldUseShell
Signed-off-by: Umaru <caleb.1331@outlook.com>
* test: assert isSecurePath for cmd path
* fix(frontend): handle quoted claude.cmd paths in validation
---------
Signed-off-by: Umaru <caleb.1331@outlook.com>
Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
* 2.7.4 release
* changelog 2.7.4
* fix readme for 2.7.4
* fix(windows): prevent pywintypes import errors before dependency validation (ACS-253) (#1057)
* fix(windows): prevent pywintypes import errors before dependency validation
This fixes ACS-253 where Windows users on Python 3.12+ encounter
ModuleNotFoundError for pywintypes when importing mcp.client.stdio.
The issue occurred because graphiti_config was imported at module level
in cli/utils.py, which triggered the import chain:
graphiti_config → graphiti_core → real_ladybug → pywintypes
This happened BEFORE validate_platform_dependencies() could check for
pywin32 and provide helpful installation instructions.
Changes:
- cli/utils.py: Made graphiti_config import lazy (moved into
validate_environment() function where it's actually used)
- run.py: Added early validate_platform_dependencies() call before
importing cli.main
- runners/spec_runner.py: Added early validate_platform_dependencies()
call before importing cli.utils
Users now get a clear error message with installation instructions
when pywin32 is missing, rather than a cryptic pywintypes import error.
Refs: ACS-253
* test(windows): add comprehensive tests for dependency validator
This adds test coverage for the ACS-253 fix preventing pywintypes import
errors on Windows Python 3.12+.
Test Coverage:
- TestValidatePlatformDependencies (7 tests):
- Windows + Python 3.12+ with pywin32 missing → exits with error
- Windows + Python 3.12+ with pywin32 installed → continues
- Windows + Python < 3.12 → skips validation
- Linux/macOS → skips validation
- Windows + Python 3.13+ → validates
- Windows + Python 3.10 → skips validation
- TestExitWithPywin32Error (3 tests):
- Error message contains helpful instructions
- Error message contains venv path
- Error message contains Python executable
- TestImportOrderPreventsEarlyFailure (3 tests):
- validate_platform_dependencies doesn't import graphiti
- cli/utils.py imports graphiti_config lazily
- Entry points validate before CLI imports
- TestCliUtilsFindSpec (4 tests):
- Find spec by number prefix
- Find spec by full name
- Return None when not found
- Require spec.md to exist
- TestCliUtilsGetProjectDir (2 tests):
- Return provided directory
- Auto-detect from apps/backend directory
- TestCliUtilsSetupEnvironment (2 tests):
- Returns apps/backend directory
- Adds to sys.path
Total: 21 tests, all passing
Refs: ACS-253
* refactor(tests): improve test robustness with AST and fix assertions
Improvements made to test_dependency_validator.py:
1. AST-based function detection: Replace fragile string parsing with
ast.parse() to find the first module-level function, avoiding false
matches in docstrings or multi-line strings.
2. Fix setup_environment test: Remove unused temp_dir fixture and
misleading assertion. Split into two focused tests:
- test_setup_environment_returns_backend_dir: Verifies directory structure
- test_setup_environment_adds_to_path: Verifies sys.path behavior
3. Remove redundant imports: Consolidate builtins imports to module-level,
removing duplicate inner imports that shadow the top-level import.
4. Selective mock for pywintypes: Use selective_mock that returns
MagicMock for pywintypes only, delegating all other imports to the
original __import__ for more realistic test environment.
5. Strengthen venv path assertion: Require both "/path/to/venv" AND
"Scripts" to be present in the error message, not just one or the other.
6. Add ast import: Add AST module import for robust parsing.
All 21 tests pass.
Refs: ACS-253
* fix(tests): address CodeQL and CodeRabbit review feedback
- Remove unused Mock import from unittest.mock
- Remove unused ast import from module level (kept local import in function)
- Initialize validate_env_end_lineno before loop to prevent potential
uninitialized variable use
All 21 tests pass.
Addresses review comments on PR #1057
Refs: ACS-253
* feat(windows): add dependency validation to all entry points for consistency
Add validate_platform_dependencies() to all runner entry points for
consistency with run.py and spec_runner.py. This provides defense-in-depth
and ensures all entry points validate pywin32 on Windows Python 3.12+
before importing from cli.utils.
Changes:
- roadmap_runner.py: Added validate_platform_dependencies() before cli.utils import
- ideation_runner.py: Added validate_platform_dependencies() before cli.utils import
- insights_runner.py: Added validate_platform_dependencies() before cli.utils import
- github/runner.py: Added validate_platform_dependencies() before cli.utils import
- gitlab/runner.py: Added validate_platform_dependencies() before cli.utils import
This completes the consistency improvements suggested by the Auto Claude PR Review.
Refs: ACS-253
---------
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
* fix(agent): ensure Python env is ready before spawning tasks (ACS-254) (#1061)
* fix(agent): ensure Python env is ready before spawning tasks (ACS-254)
Fixes race condition where task creation fails with exit code 127
when Python environment initialization hasn't completed.
The issue occurred because AgentManager.startSpecCreation() and
startTaskExecution() spawned Python processes without ensuring
pythonEnvManager.isEnvReady() was true. This caused getPythonPath()
to fall back to findPythonCommand() which could return an invalid
path during the async initialization window.
Changes:
- Add pythonEnvManager import to agent-manager.ts
- Add ensurePythonEnvReady() private method (mirrors agent-queue.ts pattern)
- Call ensurePythonEnvReady() in startSpecCreation() before spawning
- Call ensurePythonEnvReady() in startTaskExecution() before spawning
The fix ensures that if a task is started before Python venv is
ready, the task will wait for initialization to complete rather
than failing with "command not found" (exit code 127).
Refs: https://linear.app/stillknotknown/issue/ACS-254
* refactor(agent): extract shared ensurePythonEnvReady to AgentProcessManager
Address PR review feedback about code duplication between AgentManager
and AgentQueueManager.ensurePythonEnvReady().
Changes:
- Add AgentProcessManager.ensurePythonEnvReady() as shared method
- Remove duplicated private method from AgentManager
- Update AgentManager to use processManager.ensurePythonEnvReady()
- Simplify AgentQueueManager.ensurePythonEnvReady() to delegate to shared method
- Add unit tests for ensurePythonEnvReady covering all scenarios
The shared method returns { ready: boolean; error?: string } to allow
callers to handle error emission in their own way (AgentManager emits
'error' event, AgentQueueManager emits specific event types).
Test coverage added for:
- Python environment already ready (no initialization needed)
- Python environment not ready (initializes successfully)
- autoBuildSource not found (returns error)
- Python initialization fails with error message
- Python initialization fails without error message
Reduces code duplication by ~55 lines while maintaining same behavior.
Refs: https://linear.app/stillknotknown/issue/ACS-254
* refactor(agent): add Python env check to startQAProcess for consistency
Address CodeRabbit review suggestion to add ensurePythonEnvReady check
to startQAProcess, providing consistent protection against the race
condition for all Python process spawning methods.
Now all three process-spawning methods in AgentManager have the check:
- startSpecCreation
- startTaskExecution
- startQAProcess (newly added)
This prevents edge-case failures where QA might be triggered before
Python environment initialization completes.
Refs: https://linear.app/stillknotknown/issue/ACS-254
* test: fix pythonEnvManager mock to include getPythonEnv method
The test mock was missing the getPythonEnv() method that spawnProcess()
calls, causing 14 test failures. Added getPythonEnv mock returning empty
object to match production usage.
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
* test: add python-env-manager mock for integration tests
Integration tests were timing out because python-env-manager wasn't mocked.
The ensurePythonEnvReady changes added calls to pythonEnvManager.isEnvReady()
and getPythonEnv() which weren't mocked in the integration test suite.
Fixes 13 timeout failures in subprocess-spawn.test.ts
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
---------
Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com>
* fix(github-review): refresh CI status before returning cached verdict (#1083)
* fix(github-review): refresh CI status before returning cached verdict
When follow-up PR review runs with no code changes, it was returning the
cached previous verdict without checking current CI status. This caused
"CI failing" messages to persist even after CI checks recovered.
Changes:
- Move CI status fetch before the early-return check
- Detect CI recovery (was failing, now passing) and update verdict
- Remove stale CI blockers when CI passes
- Update summary message to reflect current CI status
Fixes issue where PRs showed "1 CI check(s) failing" when all GitHub
checks had actually passed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address PR review feedback for CI recovery logic
- Remove unnecessary f-string prefix (lint F541 fix)
- Replace invalid MergeVerdict.REVIEWED_PENDING_POST with NEEDS_REVISION
- Fix CI blocker filtering to use startswith("CI Failed:") instead of broad "CI" check
- Always filter out CI blockers first, then add back only currently failing checks
- Derive overall_status from updated_verdict using consistent mapping
- Check for remaining non-CI blockers when CI recovers before updating verdict
Co-authored-by: CodeRabbit <coderabbit@users.noreply.github.com>
Co-authored-by: Gemini <gemini@google.com>
* fix: handle workflows pending and finding severity in CI recovery
Addresses additional review feedback from Cursor:
1. Workflows Pending handling:
- Include "Workflows Pending:" in CI-related blocker detection
- Add is_ci_blocker() helper for consistent detection
- Filter and re-add workflow blockers like CI blockers
2. Finding severity levels:
- Check finding severity when CI recovers
- Only HIGH/MEDIUM/CRITICAL findings trigger NEEDS_REVISION
- LOW severity findings allow READY_TO_MERGE (non-blocking)
Co-authored-by: Cursor <cursor@cursor.com>
---------
Co-authored-by: Test User <test@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: CodeRabbit <coderabbit@users.noreply.github.com>
Co-authored-by: Gemini <gemini@google.com>
Co-authored-by: Cursor <cursor@cursor.com>
* fix(pr-review): properly capture structured output from SDK ResultMessage (#1133)
* fix(pr-review): properly capture structured output from SDK ResultMessage
Fixes critical bug where PR follow-up reviews showed "0 previous findings
addressed" despite AI correctly analyzing resolution status.
Root Causes Fixed:
1. sdk_utils.py - ResultMessage handling
- Added proper check for msg.type == "result" per Anthropic SDK docs
- Handle msg.subtype == "success" for structured output capture
- Handle error_max_structured_output_retries error case
- Added visible logging when structured output is captured
2. parallel_followup_reviewer.py - Silent fallback prevention
- Added warning logging when structured output is missing
- Added _extract_partial_data() to recover data when Pydantic fails
- Prevents complete data loss when schema validation has minor issues
3. parallel_followup_reviewer.py - CI status enforcement
- Added code enforcement for failing CI (override to BLOCKED)
- Added enforcement for pending CI (downgrade READY_TO_MERGE)
- AI prompt compliance is no longer the only safeguard
4. test_dependency_validator.py - macOS compatibility fixes
- Fixed symlink comparison issue (/var vs /private/var)
- Fixed case-sensitivity comparison for filesystem
Impact:
Before: AI analysis showed "3/4 resolved" but summary showed "0 resolved"
After: Structured output properly captured, fallback extraction if needed
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(pr-review): rescan related files after worktree creation
Related files were always returning 0 because context gathering
happened BEFORE the worktree was created. For fork PRs or PRs with
new files, the files don't exist in the local checkout, so the
related files lookup failed.
This fix:
- Adds `find_related_files_for_root()` static method to ContextGatherer
that can search for related files using any project root path
- Restructures ParallelOrchestratorReviewer.review() to create the
worktree FIRST, then rescan for related files using the worktree
path, then build the prompt with the updated context
Now the PR review will correctly find related test files, config
files, and type definitions that exist in the PR.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(pr-review): add visible logging for worktree creation and rescan
Add always-visible logs (not gated by DEBUG_MODE) to show:
- When worktree is created for PR review
- Result of related files rescan in worktree
This helps verify the fix is working and diagnose issues.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(pr-review): show model name when invoking specialist agents
Add model information to agent invocation logs so users can see which
model each agent is using. This helps with debugging and monitoring.
Example log output:
[ParallelOrchestrator] Invoking agent: logic-reviewer [sonnet-4.5]
[ParallelOrchestrator] Invoking agent: quality-reviewer [sonnet-4.5]
Added _short_model_name() helper to convert full model names like
"claude-sonnet-4-5-20250929" to short display names like "sonnet-4.5".
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(sdk-utils): add model info to AssistantMessage tool invocation logs
The agent invocation log was missing the model info when tool calls
came through AssistantMessage content blocks (vs standalone ToolUseBlock).
Now both code paths show the model name consistently.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(sdk-utils): add user-visible progress and activity logging
Previously, most SDK stream activity was hidden behind DEBUG_MODE,
making it hard for users to see what's happening during PR reviews.
Changes:
- Add periodic progress logs every 10 messages showing agent count
- Show tool usage (Read, Grep, etc.) not just Task calls
- Show tool completion results with brief preview
- Model info now shown for all agent invocation paths
Users will now see:
- "[ParallelOrchestrator] Processing... (20 messages, 4 agents working)"
- "[ParallelOrchestrator] Using tool: Read"
- "[ParallelOrchestrator] Tool result [done]: ..."
- "[ParallelOrchestrator] Invoking agent: logic-reviewer [opus-4.5]"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(pr-review): improve worktree visibility and fix log categorization
1. Frontend log categorization:
- Add "PRReview" and "ClientCache" to analysisSources
- [PRReview] logs now appear in "AI Analysis" section instead of "Synthesis"
2. Enhanced worktree logging:
- Show file count in worktree creation log
- Display PR branch HEAD SHA for verification
- Format: "[PRReview] Created temporary worktree: pr-xxx (1,234 files)"
3. Structured output detection:
- Also check for msg_type == "ResultMessage" (SDK class name)
- Add diagnostic logging in DEBUG mode to trace ResultMessage handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(deps): update claude-agent-sdk to >=0.1.19
Update to latest SDK version for structured output improvements.
Previous: >=0.1.16
Latest available: 0.1.19
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor(sdk-utils): consolidate structured output capture to single location
BREAKING: Simplified structured output handling to follow official Python SDK pattern.
Before: 5 different capture locations causing "Multiple StructuredOutput blocks" warnings
After: 1 capture location using hasattr(msg, 'structured_output') per official docs
Changes:
- Remove 4 redundant capture paths (ToolUseBlock, AssistantMessage content, legacy, ResultMessage)
- Single capture point: if hasattr(msg, 'structured_output') and msg.structured_output
- Skip duplicates silently (only capture first one)
- Keep error handling for error_max_structured_output_retries
- Skip logging StructuredOutput tool calls (handled separately)
- Cleaner, more maintainable code following official SDK pattern
Reference: https://platform.claude.com/docs/en/agent-sdk/structured-outputs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(pr-logs): enhance log visibility and organization for agent activities
- Introduced a new logging structure to categorize agent logs into groups, improving readability and user experience.
- Added functionality to toggle visibility of agent logs and orchestrator tool activities, allowing users to focus on relevant information.
- Implemented helper functions to identify tool activity logs and group entries by agent, enhancing log organization.
- Updated UI components to support the new log grouping and toggling features, ensuring a seamless user interface.
This update aims to provide clearer insights into agent activities during PR reviews, making it easier for users to track progress and actions taken by agents.
* fix(pr-review): address PR review findings for reliability and UX
- Fix CI pending check asymmetry: check MERGE_WITH_CHANGES verdict
- Add file count limit (10k) to prevent slow rglob on large repos
- Extract CONFIG_FILE_NAMES constant to fix DRY violation
- Fix misleading "agents working" count by tracking completed agents
- Add i18n translations for agent activity logs (en/fr)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(pr-logs): categorize Followup logs to context phase for follow-up reviews
The Followup source logs context gathering work (comparing commits, finding
changed files, gathering feedback) not analysis. Move from analysisSources
to contextSources so follow-up review logs appear in the correct phase.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix(runners): correct roadmap import path in roadmap_runner.py (ACS-264) (#1091)
* fix(runners): correct roadmap import path in roadmap_runner.py (ACS-264)
The import statement `from roadmap import RoadmapOrchestrator` was trying
to import from a non-existent top-level roadmap module. The roadmap package
is actually located at runners/roadmap/, so the correct import path is
`from runners.roadmap import RoadmapOrchestrator`.
This fixes the ImportError that occurred when attempting to use the runners
module.
Fixes # (to be linked from Linear ticket AC…
Base Branch
developbranch (required for all feature/fix PRs)main(hotfix only - maintainers)Description
Fixes a Windows GUI false-negative where
wherefindsclaude.cmd(e.g. NVM4W underD:\Program Files\...) but frontend validation fails, causing Claude Code detection to fall back to “not found” and the UI to showInstalled version: null. This alignsapps/frontend/src/main/cli-tool-manager.tsvalidation for.cmd/.batwith the safer absolute-cmd.exe+ proper quoting approach.Related Issue
Closes #1001
Type of Change
Area
Commit Message Format
Follow conventional commits:
<type>: <subject>Types: feat, fix, docs, style, refactor, test, chore
Example:
feat: add user authentication systemChecklist
developbranchCI/Testing Requirements
Screenshots
Feature Toggle
Breaking Changes
Breaking: No
Details: N/A
Summary by CodeRabbit
New Features
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.