Skip to content

feat(i18n): add prd namespace translations + register missing tasks for zh-CN/ko#983

Open
WenhuaXia wants to merge 1 commit into
siteboon:mainfrom
WenhuaXia:fix/tasks-i18n-small
Open

feat(i18n): add prd namespace translations + register missing tasks for zh-CN/ko#983
WenhuaXia wants to merge 1 commit into
siteboon:mainfrom
WenhuaXia:fix/tasks-i18n-small

Conversation

@WenhuaXia

@WenhuaXia WenhuaXia commented Jul 10, 2026

Copy link
Copy Markdown

feat(i18n): add prd namespace translations + register missing tasks for zh-CN/ko

  • Add prd.json translations for en/de/it/ja/ko/ru/tr/zh-CN/zh-TW
  • Add tasks.json for zh-CN/ko
  • Translate git panel error messages and confirmation dialogs
  • Fix hardcoded English strings in sidebar, reasoning, settings
  • Add plugin settings translations (browser, MCP, agent connections)
  • Fix chat namespace prefix for thinking display
  • Translate NextTaskBanner and TaskMaster modals
  • Add missing sidebar tooltips (running/archived/search)
  • Register prd namespace in i18n config

Summary by CodeRabbit

  • New Features

    • Added localized PRD editor, browser monitoring, Git, task, settings, chat, and session interfaces across supported languages.
    • Added password settings translations, bookmark actions, expanded session navigation, and localized model-selection prompts.
    • Added localized runtime setup, error messages, accessibility labels, and empty states.
  • Improvements

    • Quick Settings can now be toggled through application events.
    • Settings commands and tab labels now adapt to the selected language.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR internationalizes Browser Use, Git, PRD, chat, settings, TaskMaster, and sidebar interfaces, adds PRD translation namespace resources, updates reasoning text localization, and wires quick-settings toggling through a window event.

Changes

Browser Use localization

Layer / File(s) Summary
Browser session and runtime text
src/components/browser-use/view/BrowserUsePanel.tsx, src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx
Browser session states, prompts, timestamps, actions, screenshots, controls, runtime labels, installation messages, and errors now use translations.

Git panel localization

Layer / File(s) Summary
Git panel controls and feedback
src/components/git-panel/view/*
Git tabs, repository errors, status legend, commit composer, and new-branch modal text now use localized strings.

PRD localization

Layer / File(s) Summary
PRD namespace and components
src/i18n/config.js, src/i18n/locales/*/prd.json, src/components/prd-editor/view/*
The prd namespace is registered for supported locales, and PRD editor and task-generation modal text is localized.

Chat and reasoning localization

Layer / File(s) Summary
Chat navigation and reasoning text
src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx, src/shared/view/ui/Reasoning.tsx, src/i18n/locales/*/chat.json
Model-selection prompts, message navigation labels, streaming reasoning text, and thought-process labels now use translations.

Settings, TaskMaster, and sidebar updates

Layer / File(s) Summary
Settings metadata and localized content
src/components/settings/constants/constants.ts, src/components/command-palette/CommandPalette.tsx, src/components/settings/view/tabs/*, src/i18n/locales/*/settings.json
Settings tab metadata now stores translation keys, command-palette entries translate those keys, and settings content gains localized browser, About, password, and quick-settings strings.
TaskMaster and sidebar behavior
src/components/task-master/view/*, src/components/sidebar/view/subcomponents/SidebarProjectSessions.tsx, src/components/quick-settings-panel/view/QuickSettingsPanelView.tsx, src/i18n/locales/*/tasks.json, src/i18n/locales/*/sidebar.json
TaskMaster copy and locale resources are localized, session bookmark props are forwarded, load-more labels use translations, and quick settings listens for a toggle event.

Possibly related PRs

Suggested reviewers: blackmammoth, viper151

Poem

A rabbit hops through keys of light,
Translating panels left and right.
Git and browser, tasks in tune,
PRD words bloom beneath the moon.
“t(...)!” it cheers, with paws held high—
New languages dance by.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.07% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main i18n additions: new PRD namespace translations and missing tasks translations for zh-CN/ko.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
src/components/git-panel/view/GitPanelHeader.tsx (1)

77-107: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Confirmation messages remain hardcoded English despite PR objective.

The PR summary states it translates "confirmation dialogs," but the confirmation message bodies (lines 80, 88, 96, 104) are still hardcoded English with manual pluralization (commit${behindCount !== 1 ? 's' : ''}). These messages are the primary content shown to users in ConfirmActionModal, and manual pluralization won't work for locales with different plural rules (e.g., Russian, Japanese).

Consider passing an error_key or message key from the caller and translating in ConfirmActionModal, or use i18next's interpolation/pluralization: t('gitPanel.confirmation.messages.pull', { count: behindCount, remote: remoteName }).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/git-panel/view/GitPanelHeader.tsx` around lines 77 - 107, The
confirmation messages in requestPullConfirmation, requestPushConfirmation,
requestPublishConfirmation, and requestRevertLocalCommitConfirmation are
hardcoded English with manual pluralization. Replace these message bodies with
localized translation keys using the existing i18n approach, passing count and
remoteName interpolation values where needed, or pass message keys and
parameters for ConfirmActionModal to translate; ensure all locales use proper
pluralization.
src/components/git-panel/view/modals/NewBranchModal.tsx (1)

2-20: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add gitPanel.newBranchModal translations to the missing locale files
Only en and zh-CN define this block; de, it, ja, ko, ru, tr, and zh-TW fall back to English, and fr is not wired into src/i18n/config.js.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/git-panel/view/modals/NewBranchModal.tsx` around lines 2 - 20,
Add the gitPanel.newBranchModal translation block to the missing locale resource
files for de, it, ja, ko, ru, tr, and zh-TW, matching the keys used by
NewBranchModal. Also register the fr locale in src/i18n/config.js so its
translations are loaded.
src/components/git-panel/view/modals/ConfirmActionModal.tsx (1)

76-94: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Localize the confirmation body text
The title/label keys already exist, and the missing locale copies fall back to English, so the raw-key risk isn’t the issue here. action.message is still passed in as a prebuilt English string from callers, which leaves these dialogs partly untranslated; pass a translation key plus params into ConfirmationRequest and translate it in ConfirmActionModal.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/git-panel/view/modals/ConfirmActionModal.tsx` around lines 76
- 94, Update ConfirmationRequest and all callers to carry a confirmation-message
translation key with any interpolation parameters instead of a prebuilt
action.message string, then have ConfirmActionModal translate that key via t
with the provided params when rendering the body. Preserve the existing title
and label behavior and update each action type’s callers and typings
consistently.
src/components/git-panel/view/changes/ChangesView.tsx (1)

10-27: 🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

Restore the missing onStageFiles / onUnstageFiles props GitPanel.tsx still passes both callbacks into <ChangesView>, but ChangesViewProps no longer declares them, so the JSX type check fails. Add them back to the props type or remove the caller props.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/git-panel/view/changes/ChangesView.tsx` around lines 10 - 27,
Add onStageFiles and onUnstageFiles to ChangesViewProps with the same callback
signatures passed by GitPanel.tsx, and ensure ChangesView accepts and uses or
forwards them consistently. Alternatively, remove those props from the
ChangesView invocation if staging is no longer supported.
server/routes/taskmaster.js (1)

515-563: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Handle initProcess spawn failures here. task-master is invoked directly without an installation guard, but there’s no initProcess.on('error', ...). If the binary is missing, the child emits ENOENT and the unhandled error event can take down the server instead of failing this request.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/routes/taskmaster.js` around lines 515 - 563, Add an initProcess error
handler immediately after spawning the child in the task-master initialization
flow. Handle spawn failures such as ENOENT by logging the error and returning a
500 response with an appropriate failure message and error details, while
preventing duplicate responses if the close handler also fires. Ensure the
existing successful close handling remains unchanged.
src/i18n/locales/zh-CN/sidebar.json (1)

37-53: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restore tooltips.attentionRequiredIndicator in src/i18n/locales/zh-CN/sidebar.json.
SidebarSessionItem.tsx still reads this key, so zh-CN falls back to the English default text (Session needs attention) until the translation is added back.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/zh-CN/sidebar.json` around lines 37 - 53, Restore the
missing tooltips.attentionRequiredIndicator entry in the sidebar locale data,
using an appropriate Simplified Chinese translation consistent with the other
tooltip values so SidebarSessionItem.tsx does not fall back to English.
🟡 Minor comments (20)
src/components/git-panel/view/branches/BranchesView.tsx-94-94 (1)

94-94: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Hardcoded title attributes on branch action buttons.

title={Switch to ${name}} (line 94) and title={Delete ${name}} (line 101) are still hardcoded English. These should be localized: t('gitPanel.branches.switchTo', { name }) and t('gitPanel.branches.deleteBranchName', { name }).

Also applies to: 101-101

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/git-panel/view/branches/BranchesView.tsx` at line 94, Replace
the hardcoded branch action titles in the branches view with localized
translations: use t('gitPanel.branches.switchTo', { name }) for the switch
action and t('gitPanel.branches.deleteBranchName', { name }) for the delete
action, preserving the existing name interpolation.
src/components/git-panel/view/GitPanelHeader.tsx-195-195 (1)

195-195: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remaining hardcoded English strings in tooltips and aria-labels.

Several user-facing strings are still hardcoded: button title attributes (lines 195, 207, 218, 230) and aria-label="Dismiss error" (line 271). These should be localized for full i18n coverage.

Also applies to: 207-207, 218-218, 230-230, 271-271

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/git-panel/view/GitPanelHeader.tsx` at line 195, Replace the
hardcoded tooltip titles in the GitPanelHeader controls and the “Dismiss error”
aria-label with localized translation keys, using the component’s existing i18n
mechanism and preserving dynamic values such as currentBranch and remoteName.
server/modules/providers/list/claude/claude-sessions.provider.ts-400-428 (1)

400-428: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard against undefined raw.event for stream_event type.

If the SDK emits a stream_event with a missing event property, innerEvent is undefined and innerEvent.type on the next line throws a TypeError. Add an early return for malformed stream events.

🛡️ Proposed null guard
-    const innerEvent = raw.type === 'stream_event' ? raw.event : raw;
+    if (raw.type === 'stream_event' && !raw.event) {
+      return [];
+    }
+    const innerEvent = raw.type === 'stream_event' ? raw.event : raw;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/claude/claude-sessions.provider.ts` around
lines 400 - 428, Add an early guard after assigning innerEvent in the
stream-event normalization logic: when raw.type is 'stream_event' and raw.event
is missing or undefined, return an empty message list before accessing
innerEvent.type. Update the relevant handler containing innerEvent to safely
discard malformed events without throwing.
src/i18n/locales/zh-TW/chat.json-258-269 (1)

258-269: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add missing thoughtProcess translation key.

The English chat.json includes "thoughtProcess": "Thought process" (line 251), but the zh-TW file ends at scrollNav without this key. Users in zh-TW will see the English fallback or raw key. Add the translation after the scrollNav object.

💚 Proposed fix
   "last": "底部"
   },
+  "thoughtProcess": "思考過程"
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/zh-TW/chat.json` around lines 258 - 269, Add the missing
thoughtProcess key after the scrollNav object in the zh-TW chat locale, using an
appropriate Traditional Chinese translation consistent with the English
chat.json key.
src/i18n/locales/zh-TW/chat.json-195-196 (1)

195-196: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix "加載" to "載入" for Traditional Chinese consistency.

The loadMore value uses "加載" (simplified Chinese), while the rest of the file consistently uses "載入" (traditional Chinese) — e.g., lines 184, 189, 191–194. The scrollNav.loadAll at line 263 also uses "載入".

💚 Proposed fix
-      "loadMore": "加載更多({{count}}條)"
+      "loadMore": "載入更多({{count}}條)"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/zh-TW/chat.json` around lines 195 - 196, Update the
`loadMore` translation in the Traditional Chinese chat locale from
“加載更多({{count}}條)” to use “載入” for consistency with the surrounding translations
and `scrollNav.loadAll`.
src/i18n/locales/tr/sidebar.json-145-148 (1)

145-148: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align bookmarks.pin with the source label.
src/i18n/locales/tr/sidebar.json:147 uses “Sohbeti sabitle” (“pin chat”), but the English source is “Pin session” and the other locales follow that meaning.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/tr/sidebar.json` around lines 145 - 148, Update the
bookmarks.pin translation in the Turkish sidebar locale to match the English
source meaning “Pin session” rather than “Pin chat,” while leaving
bookmarks.title and bookmarks.unpin unchanged.
src/components/task-master/view/NextTaskBanner.tsx-105-105 (1)

105-105: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Translate the expanded-state label.

Line 105 displays hardcoded Chinese whenever details are open, regardless of the selected locale. Add a notConfigured.hideDetails key to every tasks locale.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/task-master/view/NextTaskBanner.tsx` at line 105, Replace the
hardcoded “隐藏详情” in the expanded-state branch of NextTaskBanner with
t('notConfigured.hideDetails'), and add the corresponding
notConfigured.hideDetails translation key to every tasks locale.
src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx-147-147 (1)

147-147: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Translate the status prefix too.

Line 147 localizes the value but leaves Status: in English. Use an interpolated translation such as browserSettings.statusLabel so locales can control the complete sentence and word order.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx`
at line 147, Translate the full status label in the `BrowserUseSettingsTab`
render, replacing the hardcoded “Status:” prefix and localized status value with
an interpolated `browserSettings.statusLabel` translation that accepts the
computed status text, allowing locales to control wording and order.
src/i18n/locales/fr/chat.json-140-142 (1)

140-142: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix French grammar in pressToSearch.

"pour rechercher sessions" is missing the partitive article. In French, the transitive verb rechercher requires des before indefinite plural nouns.

🛡️ Proposed fix
-    "pressToSearch": "Appuyez sur <kbd>{{shortcut}}</kbd> pour rechercher sessions, fichiers et commits",
+    "pressToSearch": "Appuyez sur <kbd>{{shortcut}}</kbd> pour rechercher des sessions, des fichiers et des commits",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/fr/chat.json` around lines 140 - 142, Correct the French
grammar in the pressToSearch locale string by adding the required “des” before
“sessions,” while preserving the existing shortcut placeholder and remaining
text.
src/i18n/locales/zh-CN/settings.json-486-586 (1)

486-586: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Replace voiceSettings.apiKey with a real label
src/i18n/locales/zh-CN/settings.json uses *** here, but the English source is API key; this should be translated as API 密钥.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/zh-CN/settings.json` around lines 486 - 586, Replace the
"***" value for voiceSettings.apiKey in the voiceSettings translation block with
the Chinese label "API 密钥", matching the English source meaning.
src/i18n/locales/tr/settings.json-501-508 (1)

501-508: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Hardcoded minimum length in error.minLength diverges from minLengthHelp interpolation.

Same pattern as the German locale: minLengthHelp uses {{min}} (line 501) but error.minLength hardcodes "6" (line 507). Use {{min}} for consistency.

♻️ Suggested fix
-      "minLength": "Şifre en az 6 karakter olmalıdır",
+      "minLength": "Şifre en az {{min}} karakter olmalıdır",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/tr/settings.json` around lines 501 - 508, The Turkish
locale’s error.minLength message hardcodes “6” while minLengthHelp uses
interpolation. Update error.minLength to use the {{min}} placeholder, matching
minLengthHelp and the locale’s dynamic minimum-length value.
src/i18n/locales/en/settings.json-599-606 (1)

599-606: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Hardcoded minimum length in error.minLength diverges from minLengthHelp interpolation.

minLengthHelp (line 599) uses {{min}} but error.minLength (line 605) hardcodes "6". If the minimum length is ever changed, the error message will be stale. Use {{min}} in the error string for consistency.

♻️ Suggested fix
-      "minLength": "Password must be at least 6 characters",
+      "minLength": "Password must be at least {{min}} characters",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/en/settings.json` around lines 599 - 606, Replace the
hardcoded “6” in the `error.minLength` localization string with the `{{min}}`
interpolation token, matching `minLengthHelp` so both messages reflect the
configured minimum.
src/i18n/locales/de/settings.json-494-501 (1)

494-501: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Hardcoded minimum length in error.minLength diverges from minLengthHelp interpolation.

minLengthHelp uses {{min}} interpolation (line 494) but error.minLength hardcodes "6" (line 500). If the minimum length ever changes, the error message will be stale. Consider using {{min}} in the error string as well for consistency.

♻️ Suggested fix
-      "minLength": "Passwort muss mindestens 6 Zeichen lang sein",
+      "minLength": "Passwort muss mindestens {{min}} Zeichen lang sein",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/de/settings.json` around lines 494 - 501, Update the
error.minLength translation to use the {{min}} interpolation instead of the
hardcoded “6”, matching minLengthHelp and keeping both messages consistent when
the requirement changes.
src/i18n/locales/de/settings.json-484-506 (1)

484-506: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the missing browserSettings block to src/i18n/locales/de/settings.json. The German locale currently has password but no browserSettings, so browser settings strings will fall back to English.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/de/settings.json` around lines 484 - 506, Add the missing
browserSettings translation block to the German settings locale, matching the
structure and keys used by the other locales and providing German translations
for each browser settings string. Place it alongside the existing password
section without altering the password translations.
src/i18n/locales/tr/settings.json-491-513 (1)

491-513: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add browserSettings to src/i18n/locales/tr/settings.json
This locale is missing the new browserSettings block, so browser-related settings will fall back to English for Turkish users.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/tr/settings.json` around lines 491 - 513, Add the missing
browserSettings translation block to the Turkish settings locale, matching the
keys and structure used by the other locales and providing Turkish translations
for every browser-related setting string.
src/stores/useBookmarkStore.ts-14-21 (1)

14-21: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Validate parsed bookmark data shape.

load() returns JSON.parse(raw) without verifying the result is an array of valid BookmarkedSession objects. Corrupted or legacy localStorage data could cause runtime errors in consumers (e.g., .some() on a non-array).

🛡️ Proposed fix
 function load(): BookmarkedSession[] {
   try {
     const raw = typeof localStorage !== 'undefined' ? localStorage.getItem(STORAGE_KEY) : null;
-    return raw ? JSON.parse(raw) : [];
+    if (!raw) return [];
+    const parsed = JSON.parse(raw);
+    return Array.isArray(parsed) ? parsed : [];
   } catch {
     return [];
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/stores/useBookmarkStore.ts` around lines 14 - 21, Update load() to
validate the parsed localStorage value before returning it: ensure the result is
an array and each entry matches the expected BookmarkedSession shape, including
required fields and types. Return only validated bookmarks or [] for
invalid/corrupted data, while preserving the existing error fallback.
server/modules/browser-use/browser-use.service.ts-257-257 (1)

257-257: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Log the effective cwd, not process.cwd().

This change exists to move the command's working directory off process.cwd() (to INSTALL_ROOT or a caller-supplied cwd), yet the diagnostic still prints process.cwd(). The log will misreport the directory the command actually ran in.

Proposed fix
-    console.info('[Browser] Running:', command, args.join(' '), '| cwd:', process.cwd());
+    console.info('[Browser] Running:', command, args.join(' '), '| cwd:', cwd);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/browser-use/browser-use.service.ts` at line 257, Update the
diagnostic log in the command execution logic to print the effective working
directory selected for the command, such as the resolved INSTALL_ROOT or
caller-supplied cwd, instead of process.cwd(). Use the same cwd value passed to
the spawned process so the log in the browser-use service accurately reflects
where the command runs.
server/modules/providers/list/claude/claude-session-synchronizer.provider.ts-179-197 (1)

179-197: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Send API keys with x-api-key, not Bearer
resolveAnthropicConfig() collapses ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN and OAuth access tokens into one key, but /v1/messages expects x-api-key for direct API-key auth and Authorization: Bearer only for OAuth/WIF tokens. As written, the API-key path will 401 and always fall back to truncateToTitle; split the header by credential type.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`
around lines 179 - 197, The Claude request in the session title generation flow
uses Bearer authentication for all credentials, causing direct API keys to fail.
Update resolveAnthropicConfig and the request construction in the relevant
synchronizer method to preserve credential type and send API keys via x-api-key,
while retaining Authorization: Bearer for OAuth or WIF tokens.
src/i18n/locales/ru/settings.json-498-502 (1)

498-502: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use {{min}} interpolation in error.minLength instead of hardcoding "6".

minLengthHelp uses {{min}} interpolation but error.minLength hardcodes "6". If the minimum password length ever changes, the error message would be stale.

🔧 Proposed fix
     "minLength": "Пароль должен содержать не менее {{min}} символов",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/ru/settings.json` around lines 498 - 502, Update the
`error.minLength` translation in the settings locale to use `{{min}}` instead of
the hardcoded “6”, matching the interpolation used by `minLengthHelp`.
src/components/sidebar/view/subcomponents/SidebarSessionItem.tsx-211-211 (1)

211-211: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

isCursorSession needs to be part of the session view model

SessionViewModel doesn’t declare isCursorSession, and createSessionViewModel never sets it, so this guard always falls through. Either add the field to the model or remove the check if it isn’t needed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/sidebar/view/subcomponents/SidebarSessionItem.tsx` at line
211, Add isCursorSession to the SessionViewModel type and initialize it in
createSessionViewModel so SidebarSessionItem can access it without an any cast;
otherwise remove the guard from the rendering logic if cursor-session handling
is unnecessary.
🧹 Nitpick comments (6)
src/components/git-panel/view/GitRepositoryErrorState.tsx (1)

13-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the not_git_repo_details sentinel with a typed detail key
src/components/git-panel/view/GitRepositoryErrorState.tsx:13-16
These keys are only present in en/common.json and zh-CN/common.json, so the rest of the locales fall back to English. The details === 'not_git_repo_details' check still hard-codes a backend string; a details_key (or shared enum) would make this contract safer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/git-panel/view/GitRepositoryErrorState.tsx` around lines 13 -
16, The not_git_repo_details sentinel is hard-coded in GitRepositoryErrorState.
Replace it with a typed details_key contract or shared enum, update the producer
and consumers to pass that key, and resolve it through the existing translation
function while preserving fallback behavior for other locales and raw detail
text.
src/components/git-panel/view/GitPanelHeader.tsx (1)

152-168: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Add branch filtering to the branch dropdown
The menu renders every entry in branches and only limits height with max-h-64, so larger repos will require a lot of scrolling. A small search/filter field would make branch switching easier.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/git-panel/view/GitPanelHeader.tsx` around lines 152 - 168, Add
a controlled search input to the branch dropdown rendered by GitPanelHeader and
filter the branches mapped in the dropdown using a case-insensitive match
against the query, while preserving current-branch highlighting and switching
behavior. Add appropriate state and handle the empty filtered-results case.
src/components/git-panel/view/changes/CommitComposer.tsx (1)

106-116: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Standardize pluralization key naming convention.

The file uses two different pluralization patterns: commitFile/commitFiles (line 107) vs filesSelected/filesSelected_plural (line 158). The _plural suffix is the i18next convention; the distinct-key approach is non-standard and may confuse translators managing locale files.

♻️ Align to i18next _plural convention
-              {selectedFileCount === 1 ? t('gitPanel.composer.commitFile', { count: selectedFileCount }) : t('gitPanel.composer.commitFiles', { count: selectedFileCount })}
+              {t('gitPanel.composer.commitFile', { count: selectedFileCount })}

Then in locale files, add the plural form:

"gitPanel": {
  "composer": {
    "commitFile": "Commit {{count}} file",
    "commitFile_plural": "Commit {{count}} files"
  }
}

Also applies to: 158-166

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/git-panel/view/changes/CommitComposer.tsx` around lines 106 -
116, Standardize the commit count translation keys to i18next pluralization. In
CommitComposer, update the selectedFileCount === 1 ternary to always use
gitPanel.composer.commitFile with the count, and add/update the
commitFile_plural locale entry for the plural text; preserve the existing
filesSelected/filesSelected_plural convention elsewhere.
src/components/settings/view/SettingsMainTabs.tsx (1)

52-52: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Drop the stale tab.label fallback. MainTabConfig still allows label, but every TAB_CONFIG entry now uses labelKey, so this branch is unreachable and can be removed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/settings/view/SettingsMainTabs.tsx` at line 52, Remove the
stale tab.label fallback in the SettingsMainTabs tab rendering expression, using
only t(tab.labelKey) since every TAB_CONFIG entry provides labelKey; update any
related MainTabConfig typing if needed to reflect that label is no longer
supported.
src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx (1)

24-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unused expandedProjects prop.

expandedProjects is declared in the props type (line 24) and destructured (line 199), but never referenced in the component body. Remove it to keep the API surface clean.

♻️ Proposed refactor
 type SidebarBookmarksProps = {
   bookmarks: BookmarkedSession[];
   selectedSessionId: string | null;
   onSelectSession: (projectId: string, sessionId: string, provider: string) => void;
   onRemoveBookmark: (session: { sessionId: string; projectId: string; provider: string }) => void;
   onDeleteSession: (projectId: string, sessionId: string, sessionTitle: string, provider: string) => void;
   editingSession: string | null;
   editingSessionName: string;
   onStartEditingSession: (sessionId: string, initialName: string) => void;
   onCancelEditingSession: () => void;
   onEditingSessionNameChange: (value: string) => void;
   onSaveEditingSession: (projectId: string, sessionId: string, summary: string, provider: string) => void;
-  expandedProjects: Set<string>;
   onCollapseAllProjects: () => void;
   t: TFunction;
 };

And remove from the destructuring:

   onSaveEditingSession,
-  expandedProjects,
   onCollapseAllProjects,
   t,

Also applies to: 199-199

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx` at line 24,
Remove the unused expandedProjects prop from the SidebarBookmarks props type and
from its destructuring in the component, and update any callers to stop passing
it.
server/modules/providers/list/claude/claude-session-synchronizer.provider.ts (1)

92-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Redundant subagent check — already handled two lines above.

Lines 88-90 already call this.isSubagentTranscript(filePath) (which normalizes and checks for a subagents segment) and return null. This inline re-check is dead code and can be removed.

Proposed fix
     if (this.isSubagentTranscript(filePath)) {
       return null;
     }
-
-    // Skip subagent JSONL files — they share the parent session's sessionId
-    // and would overwrite the correct jsonl_path with the subagent path
-    const pathSegments = path.normalize(filePath).split(path.sep);
-    if (pathSegments.includes('subagents')) {
-      return null;
-    }
-
     const nameMap = await buildLookupMap(path.join(this.claudeHome, 'history.jsonl'), 'sessionId', 'display');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`
around lines 92 - 97, Remove the redundant inline `pathSegments` normalization
and `subagents` check from the transcript processing method, since
`this.isSubagentTranscript(filePath)` already performs this check and returns
`null`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/modules/providers/list/claude/claude-sessions.provider.ts`:
- Around line 470-489: Use the cleaned text consistently in the message created
within the human-origin branch of the session parsing logic. In the block using
stripImageAnnotation and isSubagentPromptEcho, change the normalized message
content from the original text to cleanText so image annotations do not reach
the UI.

In `@server/routes/git.js`:
- Line 171: Update the `/status` error handling to recognize the
`'not_git_repo'` sentinel thrown by `validateGitRepository` instead of checking
only the old human-readable substrings. Preserve any necessary legacy checks,
and ensure matching this sentinel sets `error_key` to
`'gitPanel.errors.notGitRepo'`.

In `@src/components/settings/constants/constants.ts`:
- Around line 30-39: SETTINGS_MAIN_TABS is missing the password tab metadata,
preventing command-palette navigation to password settings. Add a password entry
to the SETTINGS_MAIN_TABS array using the matching password tab identifier,
label key, search keywords, and icon conventions used by SettingsSidebar and
SettingsMainTabs.

In `@src/components/shell/hooks/useShellConnection.ts`:
- Around line 151-156: Update the init payload in the socket connection logic to
avoid reusing a stale session path for plain-shell mode. In the
sendSocketMessage call, make resolveShellProjectPath use currentProject directly
when isPlainShellRef.current is true; otherwise retain the existing
selected-session path behavior.

In `@src/components/sidebar/view/Sidebar.tsx`:
- Around line 318-333: Thread the bookmark provider through the entire selection
callback: update SidebarContent and Sidebar’s onSelectBookmarkedSession handler
to accept the provider argument, then use it for the fallback session’s
__provider instead of hardcoding 'claude'. Preserve the provider when invoking
handleSessionClick for unloaded bookmarked sessions.

In `@src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx`:
- Around line 276-296: Update the React key in the bookmarks map within
SidebarBookmarks to use a composite identifier matching bookmarkKey, including
bm.projectId, bm.sessionId, and bm.provider, instead of bm.sessionId alone.
Ensure the key remains unique for bookmarks across different projects or
providers.

In `@src/i18n/locales/en/chat.json`:
- Line 62: The `thinking` translation has inconsistent shapes across locale
files, causing `ReasoningTrigger`’s `t('thinking')` call to return undefined for
object-based locales. Update every remaining `src/i18n/locales/*/chat.json`
`thinking` entry from `{ title, emoji }` to the same string form used by the
English locale, preserving the translated wording.

In `@src/stores/useBookmarkStore.ts`:
- Around line 60-88: Remove the side-effecting save() calls from the
setBookmarks updater callbacks in bookmarkSession, removeBookmark, and
toggleBookmark. Compute the next bookmark list from current state, persist it
with save(next), then update state with setBookmarks(next); alternatively, sync
persistence from a bookmarks-dependent effect while keeping updater callbacks
pure.

---

Outside diff comments:
In `@server/routes/taskmaster.js`:
- Around line 515-563: Add an initProcess error handler immediately after
spawning the child in the task-master initialization flow. Handle spawn failures
such as ENOENT by logging the error and returning a 500 response with an
appropriate failure message and error details, while preventing duplicate
responses if the close handler also fires. Ensure the existing successful close
handling remains unchanged.

In `@src/components/git-panel/view/changes/ChangesView.tsx`:
- Around line 10-27: Add onStageFiles and onUnstageFiles to ChangesViewProps
with the same callback signatures passed by GitPanel.tsx, and ensure ChangesView
accepts and uses or forwards them consistently. Alternatively, remove those
props from the ChangesView invocation if staging is no longer supported.

In `@src/components/git-panel/view/GitPanelHeader.tsx`:
- Around line 77-107: The confirmation messages in requestPullConfirmation,
requestPushConfirmation, requestPublishConfirmation, and
requestRevertLocalCommitConfirmation are hardcoded English with manual
pluralization. Replace these message bodies with localized translation keys
using the existing i18n approach, passing count and remoteName interpolation
values where needed, or pass message keys and parameters for ConfirmActionModal
to translate; ensure all locales use proper pluralization.

In `@src/components/git-panel/view/modals/ConfirmActionModal.tsx`:
- Around line 76-94: Update ConfirmationRequest and all callers to carry a
confirmation-message translation key with any interpolation parameters instead
of a prebuilt action.message string, then have ConfirmActionModal translate that
key via t with the provided params when rendering the body. Preserve the
existing title and label behavior and update each action type’s callers and
typings consistently.

In `@src/components/git-panel/view/modals/NewBranchModal.tsx`:
- Around line 2-20: Add the gitPanel.newBranchModal translation block to the
missing locale resource files for de, it, ja, ko, ru, tr, and zh-TW, matching
the keys used by NewBranchModal. Also register the fr locale in
src/i18n/config.js so its translations are loaded.

In `@src/i18n/locales/zh-CN/sidebar.json`:
- Around line 37-53: Restore the missing tooltips.attentionRequiredIndicator
entry in the sidebar locale data, using an appropriate Simplified Chinese
translation consistent with the other tooltip values so SidebarSessionItem.tsx
does not fall back to English.

---

Minor comments:
In `@server/modules/browser-use/browser-use.service.ts`:
- Line 257: Update the diagnostic log in the command execution logic to print
the effective working directory selected for the command, such as the resolved
INSTALL_ROOT or caller-supplied cwd, instead of process.cwd(). Use the same cwd
value passed to the spawned process so the log in the browser-use service
accurately reflects where the command runs.

In
`@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`:
- Around line 179-197: The Claude request in the session title generation flow
uses Bearer authentication for all credentials, causing direct API keys to fail.
Update resolveAnthropicConfig and the request construction in the relevant
synchronizer method to preserve credential type and send API keys via x-api-key,
while retaining Authorization: Bearer for OAuth or WIF tokens.

In `@server/modules/providers/list/claude/claude-sessions.provider.ts`:
- Around line 400-428: Add an early guard after assigning innerEvent in the
stream-event normalization logic: when raw.type is 'stream_event' and raw.event
is missing or undefined, return an empty message list before accessing
innerEvent.type. Update the relevant handler containing innerEvent to safely
discard malformed events without throwing.

In `@src/components/git-panel/view/branches/BranchesView.tsx`:
- Line 94: Replace the hardcoded branch action titles in the branches view with
localized translations: use t('gitPanel.branches.switchTo', { name }) for the
switch action and t('gitPanel.branches.deleteBranchName', { name }) for the
delete action, preserving the existing name interpolation.

In `@src/components/git-panel/view/GitPanelHeader.tsx`:
- Line 195: Replace the hardcoded tooltip titles in the GitPanelHeader controls
and the “Dismiss error” aria-label with localized translation keys, using the
component’s existing i18n mechanism and preserving dynamic values such as
currentBranch and remoteName.

In
`@src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx`:
- Line 147: Translate the full status label in the `BrowserUseSettingsTab`
render, replacing the hardcoded “Status:” prefix and localized status value with
an interpolated `browserSettings.statusLabel` translation that accepts the
computed status text, allowing locales to control wording and order.

In `@src/components/sidebar/view/subcomponents/SidebarSessionItem.tsx`:
- Line 211: Add isCursorSession to the SessionViewModel type and initialize it
in createSessionViewModel so SidebarSessionItem can access it without an any
cast; otherwise remove the guard from the rendering logic if cursor-session
handling is unnecessary.

In `@src/components/task-master/view/NextTaskBanner.tsx`:
- Line 105: Replace the hardcoded “隐藏详情” in the expanded-state branch of
NextTaskBanner with t('notConfigured.hideDetails'), and add the corresponding
notConfigured.hideDetails translation key to every tasks locale.

In `@src/i18n/locales/de/settings.json`:
- Around line 494-501: Update the error.minLength translation to use the {{min}}
interpolation instead of the hardcoded “6”, matching minLengthHelp and keeping
both messages consistent when the requirement changes.
- Around line 484-506: Add the missing browserSettings translation block to the
German settings locale, matching the structure and keys used by the other
locales and providing German translations for each browser settings string.
Place it alongside the existing password section without altering the password
translations.

In `@src/i18n/locales/en/settings.json`:
- Around line 599-606: Replace the hardcoded “6” in the `error.minLength`
localization string with the `{{min}}` interpolation token, matching
`minLengthHelp` so both messages reflect the configured minimum.

In `@src/i18n/locales/fr/chat.json`:
- Around line 140-142: Correct the French grammar in the pressToSearch locale
string by adding the required “des” before “sessions,” while preserving the
existing shortcut placeholder and remaining text.

In `@src/i18n/locales/ru/settings.json`:
- Around line 498-502: Update the `error.minLength` translation in the settings
locale to use `{{min}}` instead of the hardcoded “6”, matching the interpolation
used by `minLengthHelp`.

In `@src/i18n/locales/tr/settings.json`:
- Around line 501-508: The Turkish locale’s error.minLength message hardcodes
“6” while minLengthHelp uses interpolation. Update error.minLength to use the
{{min}} placeholder, matching minLengthHelp and the locale’s dynamic
minimum-length value.
- Around line 491-513: Add the missing browserSettings translation block to the
Turkish settings locale, matching the keys and structure used by the other
locales and providing Turkish translations for every browser-related setting
string.

In `@src/i18n/locales/tr/sidebar.json`:
- Around line 145-148: Update the bookmarks.pin translation in the Turkish
sidebar locale to match the English source meaning “Pin session” rather than
“Pin chat,” while leaving bookmarks.title and bookmarks.unpin unchanged.

In `@src/i18n/locales/zh-CN/settings.json`:
- Around line 486-586: Replace the "***" value for voiceSettings.apiKey in the
voiceSettings translation block with the Chinese label "API 密钥", matching the
English source meaning.

In `@src/i18n/locales/zh-TW/chat.json`:
- Around line 258-269: Add the missing thoughtProcess key after the scrollNav
object in the zh-TW chat locale, using an appropriate Traditional Chinese
translation consistent with the English chat.json key.
- Around line 195-196: Update the `loadMore` translation in the Traditional
Chinese chat locale from “加載更多({{count}}條)” to use “載入” for consistency with the
surrounding translations and `scrollNav.loadAll`.

In `@src/stores/useBookmarkStore.ts`:
- Around line 14-21: Update load() to validate the parsed localStorage value
before returning it: ensure the result is an array and each entry matches the
expected BookmarkedSession shape, including required fields and types. Return
only validated bookmarks or [] for invalid/corrupted data, while preserving the
existing error fallback.

---

Nitpick comments:
In
`@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`:
- Around line 92-97: Remove the redundant inline `pathSegments` normalization
and `subagents` check from the transcript processing method, since
`this.isSubagentTranscript(filePath)` already performs this check and returns
`null`.

In `@src/components/git-panel/view/changes/CommitComposer.tsx`:
- Around line 106-116: Standardize the commit count translation keys to i18next
pluralization. In CommitComposer, update the selectedFileCount === 1 ternary to
always use gitPanel.composer.commitFile with the count, and add/update the
commitFile_plural locale entry for the plural text; preserve the existing
filesSelected/filesSelected_plural convention elsewhere.

In `@src/components/git-panel/view/GitPanelHeader.tsx`:
- Around line 152-168: Add a controlled search input to the branch dropdown
rendered by GitPanelHeader and filter the branches mapped in the dropdown using
a case-insensitive match against the query, while preserving current-branch
highlighting and switching behavior. Add appropriate state and handle the empty
filtered-results case.

In `@src/components/git-panel/view/GitRepositoryErrorState.tsx`:
- Around line 13-16: The not_git_repo_details sentinel is hard-coded in
GitRepositoryErrorState. Replace it with a typed details_key contract or shared
enum, update the producer and consumers to pass that key, and resolve it through
the existing translation function while preserving fallback behavior for other
locales and raw detail text.

In `@src/components/settings/view/SettingsMainTabs.tsx`:
- Line 52: Remove the stale tab.label fallback in the SettingsMainTabs tab
rendering expression, using only t(tab.labelKey) since every TAB_CONFIG entry
provides labelKey; update any related MainTabConfig typing if needed to reflect
that label is no longer supported.

In `@src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx`:
- Line 24: Remove the unused expandedProjects prop from the SidebarBookmarks
props type and from its destructuring in the component, and update any callers
to stop passing it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 667a6b5d-9761-4d84-b36e-a0f882a73d22

📥 Commits

Reviewing files that changed from the base of the PR and between 5884573 and b979be3.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (104)
  • .gitignore
  • pnpm-workspace.yaml
  • server/claude-sdk.js
  • server/modules/browser-use/browser-use.service.ts
  • server/modules/database/repositories/sessions.db.ts
  • server/modules/projects/services/projects-with-sessions-fetch.service.ts
  • server/modules/providers/list/claude/claude-session-synchronizer.provider.ts
  • server/modules/providers/list/claude/claude-sessions.provider.ts
  • server/modules/providers/provider.routes.ts
  • server/modules/providers/services/sessions-watcher.service.ts
  • server/modules/providers/services/sessions.service.ts
  • server/routes/git.js
  • server/routes/taskmaster.js
  • server/shared/interfaces.ts
  • src/components/browser-use/view/BrowserUsePanel.tsx
  • src/components/chat/hooks/useChatMessages.ts
  • src/components/chat/hooks/useChatSessionState.ts
  • src/components/chat/utils/exportSession.ts
  • src/components/chat/view/ChatInterface.tsx
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx
  • src/components/chat/view/subcomponents/ScrollNavigation.tsx
  • src/components/command-palette/CommandPalette.tsx
  • src/components/git-panel/hooks/useGitPanelController.ts
  • src/components/git-panel/types/types.ts
  • src/components/git-panel/view/GitPanel.tsx
  • src/components/git-panel/view/GitPanelHeader.tsx
  • src/components/git-panel/view/GitRepositoryErrorState.tsx
  • src/components/git-panel/view/GitViewTabs.tsx
  • src/components/git-panel/view/branches/BranchesView.tsx
  • src/components/git-panel/view/changes/ChangesView.tsx
  • src/components/git-panel/view/changes/CommitComposer.tsx
  • src/components/git-panel/view/changes/FileStatusLegend.tsx
  • src/components/git-panel/view/history/HistoryView.tsx
  • src/components/git-panel/view/modals/ConfirmActionModal.tsx
  • src/components/git-panel/view/modals/NewBranchModal.tsx
  • src/components/main-content/view/subcomponents/MainContentTitle.tsx
  • src/components/prd-editor/view/GenerateTasksModal.tsx
  • src/components/prd-editor/view/PrdEditorHeader.tsx
  • src/components/settings/constants/constants.ts
  • src/components/settings/types/types.ts
  • src/components/settings/view/Settings.tsx
  • src/components/settings/view/SettingsMainTabs.tsx
  • src/components/settings/view/SettingsSidebar.tsx
  • src/components/settings/view/tabs/AboutTab.tsx
  • src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx
  • src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx
  • src/components/shell/hooks/useShellConnection.ts
  • src/components/sidebar/view/Sidebar.tsx
  • src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx
  • src/components/sidebar/view/subcomponents/SidebarContent.tsx
  • src/components/sidebar/view/subcomponents/SidebarProjectItem.tsx
  • src/components/sidebar/view/subcomponents/SidebarProjectList.tsx
  • src/components/sidebar/view/subcomponents/SidebarProjectSessions.tsx
  • src/components/sidebar/view/subcomponents/SidebarSessionItem.tsx
  • src/components/task-master/view/NextTaskBanner.tsx
  • src/components/task-master/view/modals/CreateTaskModal.tsx
  • src/components/task-master/view/modals/TaskMasterSetupModal.tsx
  • src/hooks/useProjectsState.ts
  • src/i18n/config.js
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/de/prd.json
  • src/i18n/locales/de/settings.json
  • src/i18n/locales/de/sidebar.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/en/common.json
  • src/i18n/locales/en/prd.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/en/sidebar.json
  • src/i18n/locales/fr/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/it/prd.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/it/sidebar.json
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/ja/prd.json
  • src/i18n/locales/ja/settings.json
  • src/i18n/locales/ja/sidebar.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ko/prd.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/ko/sidebar.json
  • src/i18n/locales/ko/tasks.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/ru/prd.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/ru/sidebar.json
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/tr/prd.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/tr/sidebar.json
  • src/i18n/locales/zh-CN/chat.json
  • src/i18n/locales/zh-CN/common.json
  • src/i18n/locales/zh-CN/prd.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-CN/sidebar.json
  • src/i18n/locales/zh-CN/tasks.json
  • src/i18n/locales/zh-TW/chat.json
  • src/i18n/locales/zh-TW/prd.json
  • src/i18n/locales/zh-TW/settings.json
  • src/shared/view/ui/Reasoning.tsx
  • src/stores/useBookmarkStore.ts
  • src/types/app.ts
  • vite.config.js

Comment on lines +470 to +489
if (text && !isInternalContent(text) && isHumanOrigin) {
if (isImageContent(text)) {
continue;
}
if (isTaskNotification(text)) {
continue;
}
const cleanText = stripImageAnnotation(text);
const isEcho = isSubagentPromptEcho(cleanText, subagentPrompts);
if (!isEcho) {
messages.push(createNormalizedMessage({
id: `${baseId}_text_${partIndex}`,
sessionId,
timestamp: ts,
provider: PROVIDER,
kind: 'text',
role: 'user',
content: text,
}));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

stripImageAnnotation result not used for message content — annotation leaks to UI.

cleanText is computed via stripImageAnnotation(text) and used for echo detection, but the pushed message uses content: text (the original with annotation). The function's own doc comment states the annotation causes "the echoed user message content [to differ] from the frontend pending message content, causing duplicate user bubbles." The fix is to use cleanText as the content.

🐛 Proposed fix: use cleanText for content
               const cleanText = stripImageAnnotation(text);
               const isEcho = isSubagentPromptEcho(cleanText, subagentPrompts);
               if (!isEcho) {
                 messages.push(createNormalizedMessage({
                   id: `${baseId}_text_${partIndex}`,
                   sessionId,
                   timestamp: ts,
                   provider: PROVIDER,
                   kind: 'text',
                   role: 'user',
-                  content: text,
+                  content: cleanText,
                 }));
               }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (text && !isInternalContent(text) && isHumanOrigin) {
if (isImageContent(text)) {
continue;
}
if (isTaskNotification(text)) {
continue;
}
const cleanText = stripImageAnnotation(text);
const isEcho = isSubagentPromptEcho(cleanText, subagentPrompts);
if (!isEcho) {
messages.push(createNormalizedMessage({
id: `${baseId}_text_${partIndex}`,
sessionId,
timestamp: ts,
provider: PROVIDER,
kind: 'text',
role: 'user',
content: text,
}));
}
if (text && !isInternalContent(text) && isHumanOrigin) {
if (isImageContent(text)) {
continue;
}
if (isTaskNotification(text)) {
continue;
}
const cleanText = stripImageAnnotation(text);
const isEcho = isSubagentPromptEcho(cleanText, subagentPrompts);
if (!isEcho) {
messages.push(createNormalizedMessage({
id: `${baseId}_text_${partIndex}`,
sessionId,
timestamp: ts,
provider: PROVIDER,
kind: 'text',
role: 'user',
content: cleanText,
}));
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/claude/claude-sessions.provider.ts` around
lines 470 - 489, Use the cleaned text consistently in the message created within
the human-origin branch of the session parsing logic. In the block using
stripImageAnnotation and isSubagentPromptEcho, change the normalized message
content from the original text to cleanText so image annotations do not reach
the UI.

Comment thread server/routes/git.js Outdated
await spawnAsync('git', ['rev-parse', '--show-toplevel'], { cwd: projectPath });
} catch {
throw new Error('Not a git repository. This directory does not contain a .git folder. Initialize a git repository with "git init" to use source control features.');
throw new Error('not_git_repo');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Sentinel/consumer mismatch breaks the new i18n error mapping in /status.

validateGitRepository now throws the sentinel 'not_git_repo', but the /status handler still matches on the old human-readable substrings ('not a git repository', 'Project directory is not a git repository'). Since 'not_git_repo' doesn't contain either substring, the condition is always false — error_key will never be 'gitPanel.errors.notGitRepo' for this case, defeating the purpose of the sentinel change.

🐛 Proposed fix
   } catch (error) {
     console.error('Git status error:', error);
     res.json({
-      error_key: error.message.includes('not a git repository') || error.message.includes('Project directory is not a git repository')
-        ? 'gitPanel.errors.notGitRepo'
-        : 'gitPanel.errors.operationFailed',
-      error: error.message.includes('not a git repository') || error.message.includes('Project directory is not a git repository')
-        ? 'not_git_repo'
-        : error.message,
-      details: error.message.includes('not a git repository') || error.message.includes('Project directory is not a git repository')
-        ? 'not_git_repo_details'
-        : error.message
+      error_key: error.message === 'not_git_repo'
+        ? 'gitPanel.errors.notGitRepo'
+        : 'gitPanel.errors.operationFailed',
+      error: error.message === 'not_git_repo'
+        ? 'not_git_repo'
+        : error.message,
+      details: error.message === 'not_git_repo'
+        ? 'not_git_repo_details'
+        : error.message
     });
   }

Also applies to: 396-407

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/routes/git.js` at line 171, Update the `/status` error handling to
recognize the `'not_git_repo'` sentinel thrown by `validateGitRepository`
instead of checking only the old human-readable substrings. Preserve any
necessary legacy checks, and ensure matching this sentinel sets `error_key` to
`'gitPanel.errors.notGitRepo'`.

Comment on lines 30 to +39
export const SETTINGS_MAIN_TABS: SettingsMainTabMeta[] = [
{ id: 'agents', label: 'Agents', keywords: 'agents subagents claude code', icon: Bot },
{ id: 'appearance', label: 'Appearance', keywords: 'appearance theme dark light language', icon: Palette },
{ id: 'git', label: 'Git', keywords: 'git github commits', icon: GitBranch },
{ id: 'api', label: 'API Tokens', keywords: 'api tokens auth keys', icon: KeyRound },
{ id: 'tasks', label: 'Tasks', keywords: 'tasks taskmaster', icon: ListChecks },
{ id: 'browser', label: 'Browser', keywords: 'browser playwright chromium automation', icon: MonitorPlay },
{ id: 'notifications', label: 'Notifications', keywords: 'notifications alerts push', icon: Bell },
{ id: 'plugins', label: 'Plugins', keywords: 'plugins extensions integrations', icon: Plug },
{ id: 'about', label: 'About', keywords: 'about version info', icon: Info },
{ id: 'agents', labelKey: 'mainTabs.agents', keywords: 'agents subagents claude code', icon: Bot },
{ id: 'appearance', labelKey: 'mainTabs.appearance', keywords: 'appearance theme dark light language', icon: Palette },
{ id: 'git', labelKey: 'mainTabs.git', keywords: 'git github commits', icon: GitBranch },
{ id: 'api', labelKey: 'mainTabs.apiTokens', keywords: 'api tokens auth keys', icon: KeyRound },
{ id: 'tasks', labelKey: 'mainTabs.tasks', keywords: 'tasks taskmaster', icon: ListChecks },
{ id: 'browser', labelKey: 'mainTabs.browser', keywords: 'browser playwright chromium automation', icon: MonitorPlay },
{ id: 'notifications', labelKey: 'mainTabs.notifications', keywords: 'notifications alerts push', icon: Bell },
{ id: 'plugins', labelKey: 'mainTabs.plugins', keywords: 'plugins extensions integrations', icon: Plug },
{ id: 'about', labelKey: 'mainTabs.about', keywords: 'about version info', icon: Info },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

SETTINGS_MAIN_TABS is missing the password entry.

The SettingsMainTab type now includes 'password', and both SettingsSidebar.tsx (NAV_ITEMS) and SettingsMainTabs.tsx (TAB_CONFIG) include a password tab entry. However, SETTINGS_MAIN_TABS omits it. Since this array is referenced in CommandPalette.tsx, the password settings tab won't be navigable via the command palette.

🔧 Proposed fix: add password entry to SETTINGS_MAIN_TABS
   { id: 'plugins', labelKey: 'mainTabs.plugins', keywords: 'plugins extensions integrations', icon: Plug },
+  { id: 'password', labelKey: 'mainTabs.password', keywords: 'password security auth lock', icon: Lock },
   { id: 'about', labelKey: 'mainTabs.about', keywords: 'about version info', icon: Info },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const SETTINGS_MAIN_TABS: SettingsMainTabMeta[] = [
{ id: 'agents', label: 'Agents', keywords: 'agents subagents claude code', icon: Bot },
{ id: 'appearance', label: 'Appearance', keywords: 'appearance theme dark light language', icon: Palette },
{ id: 'git', label: 'Git', keywords: 'git github commits', icon: GitBranch },
{ id: 'api', label: 'API Tokens', keywords: 'api tokens auth keys', icon: KeyRound },
{ id: 'tasks', label: 'Tasks', keywords: 'tasks taskmaster', icon: ListChecks },
{ id: 'browser', label: 'Browser', keywords: 'browser playwright chromium automation', icon: MonitorPlay },
{ id: 'notifications', label: 'Notifications', keywords: 'notifications alerts push', icon: Bell },
{ id: 'plugins', label: 'Plugins', keywords: 'plugins extensions integrations', icon: Plug },
{ id: 'about', label: 'About', keywords: 'about version info', icon: Info },
{ id: 'agents', labelKey: 'mainTabs.agents', keywords: 'agents subagents claude code', icon: Bot },
{ id: 'appearance', labelKey: 'mainTabs.appearance', keywords: 'appearance theme dark light language', icon: Palette },
{ id: 'git', labelKey: 'mainTabs.git', keywords: 'git github commits', icon: GitBranch },
{ id: 'api', labelKey: 'mainTabs.apiTokens', keywords: 'api tokens auth keys', icon: KeyRound },
{ id: 'tasks', labelKey: 'mainTabs.tasks', keywords: 'tasks taskmaster', icon: ListChecks },
{ id: 'browser', labelKey: 'mainTabs.browser', keywords: 'browser playwright chromium automation', icon: MonitorPlay },
{ id: 'notifications', labelKey: 'mainTabs.notifications', keywords: 'notifications alerts push', icon: Bell },
{ id: 'plugins', labelKey: 'mainTabs.plugins', keywords: 'plugins extensions integrations', icon: Plug },
{ id: 'about', labelKey: 'mainTabs.about', keywords: 'about version info', icon: Info },
export const SETTINGS_MAIN_TABS: SettingsMainTabMeta[] = [
{ id: 'agents', labelKey: 'mainTabs.agents', keywords: 'agents subagents claude code', icon: Bot },
{ id: 'appearance', labelKey: 'mainTabs.appearance', keywords: 'appearance theme dark light language', icon: Palette },
{ id: 'git', labelKey: 'mainTabs.git', keywords: 'git github commits', icon: GitBranch },
{ id: 'api', labelKey: 'mainTabs.apiTokens', keywords: 'api tokens auth keys', icon: KeyRound },
{ id: 'tasks', labelKey: 'mainTabs.tasks', keywords: 'tasks taskmaster', icon: ListChecks },
{ id: 'browser', labelKey: 'mainTabs.browser', keywords: 'browser playwright chromium automation', icon: MonitorPlay },
{ id: 'notifications', labelKey: 'mainTabs.notifications', keywords: 'notifications alerts push', icon: Bell },
{ id: 'plugins', labelKey: 'mainTabs.plugins', keywords: 'plugins extensions integrations', icon: Plug },
{ id: 'password', labelKey: 'mainTabs.password', keywords: 'password security auth lock', icon: Lock },
{ id: 'about', labelKey: 'mainTabs.about', keywords: 'about version info', icon: Info },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/settings/constants/constants.ts` around lines 30 - 39,
SETTINGS_MAIN_TABS is missing the password tab metadata, preventing
command-palette navigation to password settings. Add a password entry to the
SETTINGS_MAIN_TABS array using the matching password tab identifier, label key,
search keywords, and icon conventions used by SettingsSidebar and
SettingsMainTabs.

Comment on lines 151 to 156
sendSocketMessage(socket, {
type: 'init',
projectPath: currentProject.fullPath || currentProject.path || '',
projectPath: resolveShellProjectPath(selectedSessionRef.current, currentProject),
sessionId: isPlainShellRef.current ? null : selectedSessionRef.current?.id || null,
hasSession: isPlainShellRef.current ? false : Boolean(selectedSessionRef.current),
provider: isPlainShellRef.current ? 'plain-shell' : (selectedSessionRef.current?.__provider || localStorage.getItem('selected-provider') || 'claude'),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file outline =="
ast-grep outline src/components/shell/hooks/useShellConnection.ts --view expanded || true

echo
echo "== relevant lines in useShellConnection.ts =="
nl -ba src/components/shell/hooks/useShellConnection.ts | sed -n '1,260p'

echo
echo "== search for resolveShellProjectPath and plain-shell refs =="
rg -n "resolveShellProjectPath|isPlainShellRef|plain-shell|selectedSessionRef" src/components/shell -S

Repository: siteboon/claudecodeui

Length of output: 552


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== useShellConnection.ts (relevant section) =="
sed -n '1,220p' src/components/shell/hooks/useShellConnection.ts

echo
echo "== references to resolveShellProjectPath and plain-shell/session state =="
rg -n "resolveShellProjectPath|isPlainShellRef|selectedSessionRef|plain-shell|sessionId: null|hasSession: false" src/components/shell -S

Repository: siteboon/claudecodeui

Length of output: 10030


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== useShellRuntime.ts =="
sed -n '1,220p' src/components/shell/hooks/useShellRuntime.ts

echo
echo "== shell types around session/project refs =="
sed -n '1,140p' src/components/shell/types/types.ts

echo
echo "== any code that clears selectedSession when plain-shell is enabled =="
rg -n "setSelectedSession|null.*plain|isPlainShell.*selectedSession|selectedSession.*isPlainShell|plain-shell" src/components/shell -S

Repository: siteboon/claudecodeui

Length of output: 6585


Do not reuse the previous session path for plain-shell init.
src/components/shell/hooks/useShellConnection.ts:151-156

useShellRuntime keeps selectedSessionRef populated when isPlainShell changes, so this init can still pick up the old session directory even though sessionId and hasSession say there is no session. Use the current project path when isPlainShellRef.current is true.

Suggested change
             sendSocketMessage(socket, {
               type: 'init',
-              projectPath: resolveShellProjectPath(selectedSessionRef.current, currentProject),
+              projectPath: isPlainShellRef.current
+                ? (currentProject.fullPath || currentProject.path || '')
+                : resolveShellProjectPath(selectedSessionRef.current, currentProject),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sendSocketMessage(socket, {
type: 'init',
projectPath: currentProject.fullPath || currentProject.path || '',
projectPath: resolveShellProjectPath(selectedSessionRef.current, currentProject),
sessionId: isPlainShellRef.current ? null : selectedSessionRef.current?.id || null,
hasSession: isPlainShellRef.current ? false : Boolean(selectedSessionRef.current),
provider: isPlainShellRef.current ? 'plain-shell' : (selectedSessionRef.current?.__provider || localStorage.getItem('selected-provider') || 'claude'),
sendSocketMessage(socket, {
type: 'init',
projectPath: isPlainShellRef.current
? (currentProject.fullPath || currentProject.path || '')
: resolveShellProjectPath(selectedSessionRef.current, currentProject),
sessionId: isPlainShellRef.current ? null : selectedSessionRef.current?.id || null,
hasSession: isPlainShellRef.current ? false : Boolean(selectedSessionRef.current),
provider: isPlainShellRef.current ? 'plain-shell' : (selectedSessionRef.current?.__provider || localStorage.getItem('selected-provider') || 'claude'),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/shell/hooks/useShellConnection.ts` around lines 151 - 156,
Update the init payload in the socket connection logic to avoid reusing a stale
session path for plain-shell mode. In the sendSocketMessage call, make
resolveShellProjectPath use currentProject directly when isPlainShellRef.current
is true; otherwise retain the existing selected-session path behavior.

Comment thread src/components/sidebar/view/Sidebar.tsx Outdated
Comment on lines +318 to +333
onSelectBookmarkedSession={async (projectId: string, sessionId: string) => {
const project = projects.find(p => p.projectId === projectId);
if (project) {
handleProjectSelect(project);
const sessions = getProjectSessions(project);
const existing = sessions.find(s => s.id === sessionId);
if (existing) {
handleSessionClick(existing, project.projectId);
} else {
handleSessionClick(
{ id: sessionId, __provider: 'claude' },
project.projectId,
);
}
}
}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP -C4 'onSelectBookmarkedSession' src/components/sidebar
rg -nP -C3 'BookmarkedSession' src/stores/useBookmarkStore.ts

Repository: siteboon/claudecodeui

Length of output: 5846


🏁 Script executed:

#!/bin/bash
ast-grep outline src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx --view expanded
ast-grep outline src/components/sidebar/view/subcomponents/SidebarContent.tsx --view expanded
ast-grep outline src/components/sidebar/view/Sidebar.tsx --view expanded
sed -n '1,260p' src/stores/useBookmarkStore.ts | cat -n

Repository: siteboon/claudecodeui

Length of output: 4600


🏁 Script executed:

#!/bin/bash
sed -n '1,220p' src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx | cat -n
printf '\n---\n'
sed -n '115,320p' src/components/sidebar/view/subcomponents/SidebarContent.tsx | cat -n
printf '\n---\n'
sed -n '1,260p' src/components/sidebar/view/Sidebar.tsx | cat -n

Repository: siteboon/claudecodeui

Length of output: 31799


🏁 Script executed:

#!/bin/bash
rg -n -C3 'onSelectSession\(|provider' src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx
sed -n '220,340p' src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx | cat -n
sed -n '260,290p' src/components/sidebar/view/subcomponents/SidebarContent.tsx | cat -n

Repository: siteboon/claudecodeui

Length of output: 9205


🏁 Script executed:

#!/bin/bash
rg -n -C4 'function handleSessionClick|handleSessionClick\s*=|onSessionSelect|__provider|provider:' src/components/sidebar src/components/sidebar/view src/components/sidebar/hooks src

Repository: siteboon/claudecodeui

Length of output: 50378


Thread the bookmark provider through the select callback.

SidebarBookmarks already calls onSelectSession(bm.projectId, bm.sessionId, bm.provider), but SidebarContent drops the third arg and Sidebar.tsx falls back to __provider: 'claude' when the session isn’t loaded. That opens non-Claude bookmarks under the wrong provider.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/sidebar/view/Sidebar.tsx` around lines 318 - 333, Thread the
bookmark provider through the entire selection callback: update SidebarContent
and Sidebar’s onSelectBookmarkedSession handler to accept the provider argument,
then use it for the fallback session’s __provider instead of hardcoding
'claude'. Preserve the provider when invoking handleSessionClick for unloaded
bookmarked sessions.

Comment on lines +276 to +296
{bookmarks.map((bm) => {
const isSelected = selectedSessionId === bm.sessionId;
const isEditing = editingSession === bm.sessionId;
return (
<PinnedSessionRow
key={bm.sessionId}
bookmark={bm}
isSelected={isSelected}
isEditing={isEditing}
editingName={editingSessionName}
onSelect={() => onSelectSession(bm.projectId, bm.sessionId, bm.provider)}
onUnpin={() => onRemoveBookmark(bm)}
onDelete={() => onDeleteSession(bm.projectId, bm.sessionId, bm.sessionSummary, bm.provider)}
onStartEditing={() => onStartEditingSession(bm.sessionId, bm.sessionSummary)}
onCancelEditing={onCancelEditingSession}
onEditingChange={onEditingSessionNameChange}
onSaveEditing={() => onSaveEditingSession(bm.projectId, bm.sessionId, editingSessionName, bm.provider)}
t={t}
/>
);
})}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Potential duplicate React keys when same sessionId is bookmarked under different providers.

The bookmarkKey function in useBookmarkStore.ts uses projectId::sessionId::provider as the composite key, meaning two bookmarks can share the same sessionId if they belong to different projects or providers. However, line 281 uses only bm.sessionId as the React key, which would produce duplicate keys and cause rendering bugs.

🛡️ Proposed fix
-              <PinnedSessionRow
-                key={bm.sessionId}
+              <PinnedSessionRow
+                key={`${bm.projectId}::${bm.sessionId}::${bm.provider}`}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{bookmarks.map((bm) => {
const isSelected = selectedSessionId === bm.sessionId;
const isEditing = editingSession === bm.sessionId;
return (
<PinnedSessionRow
key={bm.sessionId}
bookmark={bm}
isSelected={isSelected}
isEditing={isEditing}
editingName={editingSessionName}
onSelect={() => onSelectSession(bm.projectId, bm.sessionId, bm.provider)}
onUnpin={() => onRemoveBookmark(bm)}
onDelete={() => onDeleteSession(bm.projectId, bm.sessionId, bm.sessionSummary, bm.provider)}
onStartEditing={() => onStartEditingSession(bm.sessionId, bm.sessionSummary)}
onCancelEditing={onCancelEditingSession}
onEditingChange={onEditingSessionNameChange}
onSaveEditing={() => onSaveEditingSession(bm.projectId, bm.sessionId, editingSessionName, bm.provider)}
t={t}
/>
);
})}
{bookmarks.map((bm) => {
const isSelected = selectedSessionId === bm.sessionId;
const isEditing = editingSession === bm.sessionId;
return (
<PinnedSessionRow
key={`${bm.projectId}::${bm.sessionId}::${bm.provider}`}
bookmark={bm}
isSelected={isSelected}
isEditing={isEditing}
editingName={editingSessionName}
onSelect={() => onSelectSession(bm.projectId, bm.sessionId, bm.provider)}
onUnpin={() => onRemoveBookmark(bm)}
onDelete={() => onDeleteSession(bm.projectId, bm.sessionId, bm.sessionSummary, bm.provider)}
onStartEditing={() => onStartEditingSession(bm.sessionId, bm.sessionSummary)}
onCancelEditing={onCancelEditingSession}
onEditingChange={onEditingSessionNameChange}
onSaveEditing={() => onSaveEditingSession(bm.projectId, bm.sessionId, editingSessionName, bm.provider)}
t={t}
/>
);
})}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/sidebar/view/subcomponents/SidebarBookmarks.tsx` around lines
276 - 296, Update the React key in the bookmarks map within SidebarBookmarks to
use a composite identifier matching bookmarkKey, including bm.projectId,
bm.sessionId, and bm.provider, instead of bm.sessionId alone. Ensure the key
remains unique for bookmarks across different projects or providers.

Comment thread src/i18n/locales/en/chat.json
Comment thread src/stores/useBookmarkStore.ts Outdated
Comment on lines +60 to +88
const bookmarkSession = useCallback((session: BookmarkedSession) => {
setBookmarks(prev => {
if (prev.some(b => bookmarkKey(b) === bookmarkKey(session))) return prev;
const next = [session, ...prev];
save(next);
return next;
});
}, []);

const removeBookmark = useCallback((session: { sessionId: string; projectId: string; provider: string }) => {
setBookmarks(prev => {
const next = prev.filter(b => bookmarkKey(b) !== bookmarkKey(session));
save(next);
return next;
});
}, []);

const toggleBookmark = useCallback((session: BookmarkedSession) => {
setBookmarks(prev => {
const idx = prev.findIndex(b => bookmarkKey(b) === bookmarkKey(session));
let next: BookmarkedSession[];
if (idx >= 0) {
next = prev.filter(b => bookmarkKey(b) !== bookmarkKey(session));
} else {
next = [session, ...prev];
}
save(next);
return next;
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Avoid side effects inside React state updater functions.

save() (which writes to localStorage and dispatches a synthetic storage event) is called inside setBookmarks updater callbacks. React expects updater functions to be pure — in StrictMode they may be invoked twice, and in concurrent mode they can be discarded and replayed. Additionally, the dispatched storage event triggers the useEffect handler which calls setBookmarks(load()), creating a redundant second state update while the first is still in progress.

Move the save() call outside the updater:

♻️ Proposed refactor
   const bookmarkSession = useCallback((session: BookmarkedSession) => {
-    setBookmarks(prev => {
-      if (prev.some(b => bookmarkKey(b) === bookmarkKey(session))) return prev;
-      const next = [session, ...prev];
-      save(next);
-      return next;
-    });
+    setBookmarks(prev => {
+      if (prev.some(b => bookmarkKey(b) === bookmarkKey(session))) return prev;
+      return [session, ...prev];
+    });
+    // Persist after state update
+    setBookmarks(current => {
+      if (current.some(b => bookmarkKey(b) === bookmarkKey(session))) return current;
+      save(current);
+      return current;
+    });
   }, []);

A cleaner approach is to compute next from current state, call save(next), then setBookmarks(next):

   const bookmarkSession = useCallback((session: BookmarkedSession) => {
-    setBookmarks(prev => {
-      if (prev.some(b => bookmarkKey(b) === bookmarkKey(session))) return prev;
-      const next = [session, ...prev];
-      save(next);
-      return next;
-    });
+    setBookmarks(prev => {
+      if (prev.some(b => bookmarkKey(b) === bookmarkKey(session))) return prev;
+      const next = [session, ...prev];
+      save(next);
+      return next;
+    });
   }, []);

If you want to keep the current structure, the simplest fix is to remove the window.dispatchEvent from save() and instead call setBookmarks(load()) directly after persistence, or use a useEffect that syncs to localStorage whenever bookmarks changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/stores/useBookmarkStore.ts` around lines 60 - 88, Remove the
side-effecting save() calls from the setBookmarks updater callbacks in
bookmarkSession, removeBookmark, and toggleBookmark. Compute the next bookmark
list from current state, persist it with save(next), then update state with
setBookmarks(next); alternatively, sync persistence from a bookmarks-dependent
effect while keeping updater callbacks pure.

@WenhuaXia WenhuaXia force-pushed the fix/tasks-i18n-small branch from b979be3 to 3a310e8 Compare July 10, 2026 08:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/task-master/view/NextTaskBanner.tsx`:
- Line 105: Replace the hardcoded '隐藏详情' branch in NextTaskBanner with a
notConfigured.hideDetails translation key, and add that key with the appropriate
localized value to every locale's tasks.json file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 99c99878-8336-4cd8-88be-c18b2dccdf30

📥 Commits

Reviewing files that changed from the base of the PR and between b979be3 and 3a310e8.

📒 Files selected for processing (69)
  • server/routes/git.js
  • server/routes/taskmaster.js
  • src/components/browser-use/view/BrowserUsePanel.tsx
  • src/components/git-panel/hooks/useGitPanelController.ts
  • src/components/git-panel/types/types.ts
  • src/components/git-panel/view/GitPanel.tsx
  • src/components/git-panel/view/GitPanelHeader.tsx
  • src/components/git-panel/view/GitRepositoryErrorState.tsx
  • src/components/git-panel/view/GitViewTabs.tsx
  • src/components/git-panel/view/branches/BranchesView.tsx
  • src/components/git-panel/view/changes/ChangesView.tsx
  • src/components/git-panel/view/changes/CommitComposer.tsx
  • src/components/git-panel/view/changes/FileStatusLegend.tsx
  • src/components/git-panel/view/history/HistoryView.tsx
  • src/components/git-panel/view/modals/ConfirmActionModal.tsx
  • src/components/git-panel/view/modals/NewBranchModal.tsx
  • src/components/prd-editor/view/GenerateTasksModal.tsx
  • src/components/prd-editor/view/PrdEditorHeader.tsx
  • src/components/settings/constants/constants.ts
  • src/components/settings/types/types.ts
  • src/components/settings/view/Settings.tsx
  • src/components/settings/view/SettingsMainTabs.tsx
  • src/components/settings/view/SettingsSidebar.tsx
  • src/components/settings/view/tabs/AboutTab.tsx
  • src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx
  • src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx
  • src/components/task-master/view/NextTaskBanner.tsx
  • src/components/task-master/view/modals/CreateTaskModal.tsx
  • src/components/task-master/view/modals/TaskMasterSetupModal.tsx
  • src/i18n/config.js
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/de/prd.json
  • src/i18n/locales/de/settings.json
  • src/i18n/locales/de/sidebar.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/en/common.json
  • src/i18n/locales/en/prd.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/en/sidebar.json
  • src/i18n/locales/fr/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/it/prd.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/it/sidebar.json
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/ja/prd.json
  • src/i18n/locales/ja/settings.json
  • src/i18n/locales/ja/sidebar.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ko/prd.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/ko/sidebar.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/ru/prd.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/ru/sidebar.json
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/tr/prd.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/tr/sidebar.json
  • src/i18n/locales/zh-CN/chat.json
  • src/i18n/locales/zh-CN/common.json
  • src/i18n/locales/zh-CN/prd.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-CN/sidebar.json
  • src/i18n/locales/zh-TW/chat.json
  • src/i18n/locales/zh-TW/prd.json
  • src/i18n/locales/zh-TW/settings.json
  • src/shared/view/ui/Reasoning.tsx
✅ Files skipped from review due to trivial changes (24)
  • src/components/task-master/view/modals/TaskMasterSetupModal.tsx
  • src/i18n/locales/ru/sidebar.json
  • src/i18n/locales/ru/prd.json
  • src/i18n/locales/zh-TW/prd.json
  • src/components/git-panel/view/GitPanel.tsx
  • server/routes/taskmaster.js
  • src/i18n/locales/ja/prd.json
  • src/i18n/locales/de/prd.json
  • src/i18n/locales/de/settings.json
  • src/i18n/locales/tr/prd.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/ko/sidebar.json
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/zh-TW/settings.json
  • src/i18n/locales/tr/sidebar.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/zh-CN/sidebar.json
  • src/i18n/locales/it/sidebar.json
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/en/common.json
  • src/i18n/locales/it/chat.json
🚧 Files skipped from review as they are similar to previous changes (43)
  • src/i18n/locales/it/prd.json
  • src/i18n/locales/ko/prd.json
  • src/components/settings/view/Settings.tsx
  • src/i18n/locales/zh-CN/prd.json
  • src/components/settings/view/tabs/AboutTab.tsx
  • src/components/settings/types/types.ts
  • src/components/git-panel/types/types.ts
  • src/i18n/locales/en/prd.json
  • src/components/settings/constants/constants.ts
  • src/components/git-panel/hooks/useGitPanelController.ts
  • src/components/settings/view/SettingsSidebar.tsx
  • src/i18n/locales/ja/sidebar.json
  • src/i18n/locales/it/settings.json
  • src/components/prd-editor/view/GenerateTasksModal.tsx
  • src/components/git-panel/view/GitRepositoryErrorState.tsx
  • src/components/git-panel/view/changes/FileStatusLegend.tsx
  • src/components/git-panel/view/modals/ConfirmActionModal.tsx
  • src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx
  • src/i18n/locales/zh-TW/chat.json
  • src/i18n/locales/ja/settings.json
  • src/i18n/locales/zh-CN/chat.json
  • src/components/settings/view/SettingsMainTabs.tsx
  • src/components/git-panel/view/GitViewTabs.tsx
  • src/components/git-panel/view/GitPanelHeader.tsx
  • src/i18n/locales/de/sidebar.json
  • src/components/git-panel/view/history/HistoryView.tsx
  • src/components/git-panel/view/modals/NewBranchModal.tsx
  • src/i18n/config.js
  • src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/tr/chat.json
  • src/components/prd-editor/view/PrdEditorHeader.tsx
  • src/components/git-panel/view/changes/CommitComposer.tsx
  • src/i18n/locales/zh-CN/common.json
  • src/i18n/locales/en/sidebar.json
  • server/routes/git.js
  • src/components/task-master/view/modals/CreateTaskModal.tsx
  • src/components/git-panel/view/changes/ChangesView.tsx
  • src/components/git-panel/view/branches/BranchesView.tsx
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/en/chat.json
  • src/shared/view/ui/Reasoning.tsx
  • src/components/browser-use/view/BrowserUsePanel.tsx

>
<Settings className="h-3 w-3" />
{showSetupDetails ? 'Hide details' : 'What is TaskMaster?'}
{showSetupDetails ? '隐藏详情' : t('notConfigured.whatIsTitle')}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Hardcoded Chinese string '隐藏详情' breaks i18n.

The "hide details" label is a raw Chinese string instead of a translation key. The tasks.json locale file (confirmed in src/i18n/locales/en/tasks.json) has no hideDetails key, so this label will display Chinese text for all users regardless of locale.

🌐 Proposed fix

Add a hideDetails key to each locale's tasks.json under notConfigured, then use it:

-            {showSetupDetails ? '隐藏详情' : t('notConfigured.whatIsTitle')}
+            {showSetupDetails ? t('notConfigured.hideDetails') : t('notConfigured.whatIsTitle')}

In src/i18n/locales/en/tasks.json:

 {
   "notConfigured": {
     "title": "TaskMaster AI is not configured",
     "description": "TaskMaster helps break down complex projects into manageable tasks with AI-powered assistance",
     "whatIsTitle": "🎯 What is TaskMaster?",
+    "hideDetails": "Hide details",
     "features": {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/task-master/view/NextTaskBanner.tsx` at line 105, Replace the
hardcoded '隐藏详情' branch in NextTaskBanner with a notConfigured.hideDetails
translation key, and add that key with the appropriate localized value to every
locale's tasks.json file.

@WenhuaXia WenhuaXia force-pushed the fix/tasks-i18n-small branch from 3a310e8 to 2d2c437 Compare July 10, 2026 08:54
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
putComment timed out

@WenhuaXia WenhuaXia force-pushed the fix/tasks-i18n-small branch 2 times, most recently from 803a760 to 76f83f1 Compare July 11, 2026 15:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (2)
src/components/quick-settings-panel/view/QuickSettingsPanelView.tsx (1)

51-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the unused quick-settings drag wiring
handleToggleFromHandle is no longer referenced, and the useQuickSettingsDrag destructured values are unused here too. Drop the callback and, if nothing else in this component needs the hook’s side effects, remove the hook call as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/quick-settings-panel/view/QuickSettingsPanelView.tsx` around
lines 51 - 62, The unused quick-settings drag wiring should be removed from
QuickSettingsPanelView: delete the unreferenced handleToggleFromHandle callback
and its related dependency/imports, then remove the useQuickSettingsDrag call
and destructured values if no other component behavior requires its side
effects.
src/shared/view/ui/Reasoning.tsx (1)

138-142: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Fallback strings are unreachable — use i18next defaultValue instead.

t from useTranslation('chat') (line 153) is always a truthy function, so the t ? t('thinking') : 'Thinking...' ternary always takes the t(...) branch. If a translation key is missing, i18next returns the key name (e.g. "thoughtProcess"), not the English fallback. Use t('key', { defaultValue: '...' }) to get proper fallback behavior.

♻️ Proposed refactor
 const defaultGetThinkingMessage = (isStreaming: boolean, duration?: number, t?: ReturnType<typeof useTranslation>['t']): React.ReactNode => {
   if (isStreaming || duration === 0) {
-    return <Shimmer>{t ? t('thinking') : 'Thinking...'}</Shimmer>;
+    return <Shimmer>{t ? t('thinking', { defaultValue: 'Thinking...' }) : 'Thinking...'}</Shimmer>;
   }
-  return <p>{t ? t('thoughtProcess') : 'Thought for a few seconds'}</p>;
+  return <p>{t ? t('thoughtProcess', { defaultValue: 'Thought for a few seconds' }) : 'Thought for a few seconds'}</p>;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/view/ui/Reasoning.tsx` around lines 138 - 142, Update
defaultGetThinkingMessage to use i18next defaultValue options for both thinking
and thoughtProcess translations, preserving the existing English fallback text
when keys are missing. Remove the unreachable t truthiness checks while
retaining the current streaming and duration branching.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/modules/browser-use/browser-use.service.ts`:
- Line 257: Update the logging statement in the browser command execution flow
to report the resolved spawn working-directory variable `cwd` instead of calling
`process.cwd()`, while preserving the existing command and argument details.
- Around line 248-249: Update the INSTALL_ROOT constant used by runCommand so it
resolves to the repository/workspace root containing the top-level package.json
and node_modules in the compiled server layout. Keep runCommand’s default cwd
behavior, ensuring its npm commands execute from that install directory rather
than dist-server/server.

In `@src/i18n/locales/de/settings.json`:
- Line 500: Update the error.minLength message to use {{min}} instead of
hardcoding 6 in src/i18n/locales/de/settings.json:500-500,
src/i18n/locales/it/settings.json:506-506,
src/i18n/locales/ja/settings.json:500-500, and
src/i18n/locales/tr/settings.json:507-507, preserving each locale’s translation.
Also verify and update the same error.minLength key in
src/i18n/locales/en/settings.json if it hardcodes 6.
- Line 487: Update the German `password.description` translation to use the
locale’s informal “du” register, matching the surrounding settings translations
while preserving its meaning.
- Around line 96-97: Remove the unused password translation entries from the
locale settings definitions, including the nested password block, since
useSettingsController and SettingsMainTabs do not support a password tab.
Preserve all translations for the currently normalized settings sections.

In `@src/i18n/locales/tr/settings.json`:
- Line 494: Update the password.description translation to use the informal
Turkish imperative register, matching the tone used by nearby settings entries
while preserving its meaning.

In `@src/i18n/locales/zh-CN/settings.json`:
- Around line 505-519: Update the voiceSettings.apiKey translation in the
voiceSettings locale object from "***" to the Chinese label "API 密钥", matching
the English API key field name.

---

Nitpick comments:
In `@src/components/quick-settings-panel/view/QuickSettingsPanelView.tsx`:
- Around line 51-62: The unused quick-settings drag wiring should be removed
from QuickSettingsPanelView: delete the unreferenced handleToggleFromHandle
callback and its related dependency/imports, then remove the
useQuickSettingsDrag call and destructured values if no other component behavior
requires its side effects.

In `@src/shared/view/ui/Reasoning.tsx`:
- Around line 138-142: Update defaultGetThinkingMessage to use i18next
defaultValue options for both thinking and thoughtProcess translations,
preserving the existing English fallback text when keys are missing. Remove the
unreachable t truthiness checks while retaining the current streaming and
duration branching.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b85a88ff-b65d-485d-9a47-e921563cacc5

📥 Commits

Reviewing files that changed from the base of the PR and between 2d2c437 and 803a760.

📒 Files selected for processing (62)
  • server/modules/browser-use/browser-use.service.ts
  • src/components/browser-use/view/BrowserUsePanel.tsx
  • src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx
  • src/components/command-palette/CommandPalette.tsx
  • src/components/git-panel/view/GitRepositoryErrorState.tsx
  • src/components/git-panel/view/GitViewTabs.tsx
  • src/components/git-panel/view/changes/CommitComposer.tsx
  • src/components/git-panel/view/changes/FileStatusLegend.tsx
  • src/components/git-panel/view/modals/NewBranchModal.tsx
  • src/components/main-content/view/subcomponents/MainContentTitle.tsx
  • src/components/prd-editor/view/GenerateTasksModal.tsx
  • src/components/prd-editor/view/PrdEditorHeader.tsx
  • src/components/quick-settings-panel/view/QuickSettingsPanelView.tsx
  • src/components/settings/constants/constants.ts
  • src/components/settings/view/tabs/AboutTab.tsx
  • src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx
  • src/components/sidebar/view/subcomponents/SidebarProjectSessions.tsx
  • src/components/task-master/view/NextTaskBanner.tsx
  • src/components/task-master/view/modals/CreateTaskModal.tsx
  • src/components/task-master/view/modals/TaskMasterSetupModal.tsx
  • src/i18n/config.js
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/de/prd.json
  • src/i18n/locales/de/settings.json
  • src/i18n/locales/de/sidebar.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/en/common.json
  • src/i18n/locales/en/prd.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/en/sidebar.json
  • src/i18n/locales/fr/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/it/prd.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/it/sidebar.json
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/ja/prd.json
  • src/i18n/locales/ja/settings.json
  • src/i18n/locales/ja/sidebar.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ko/prd.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/ko/sidebar.json
  • src/i18n/locales/ko/tasks.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/ru/prd.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/ru/sidebar.json
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/tr/prd.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/tr/sidebar.json
  • src/i18n/locales/zh-CN/chat.json
  • src/i18n/locales/zh-CN/common.json
  • src/i18n/locales/zh-CN/prd.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-CN/sidebar.json
  • src/i18n/locales/zh-CN/tasks.json
  • src/i18n/locales/zh-TW/chat.json
  • src/i18n/locales/zh-TW/prd.json
  • src/i18n/locales/zh-TW/settings.json
  • src/shared/view/ui/Reasoning.tsx
✅ Files skipped from review due to trivial changes (23)
  • src/components/task-master/view/modals/TaskMasterSetupModal.tsx
  • src/i18n/locales/ru/prd.json
  • src/i18n/locales/tr/prd.json
  • src/i18n/locales/de/prd.json
  • src/i18n/locales/ko/sidebar.json
  • src/i18n/locales/ko/tasks.json
  • src/i18n/locales/en/sidebar.json
  • src/i18n/locales/it/sidebar.json
  • src/i18n/locales/zh-TW/prd.json
  • src/i18n/locales/en/prd.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/it/prd.json
  • src/i18n/locales/ko/prd.json
  • src/i18n/locales/zh-CN/prd.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/zh-TW/chat.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/fr/chat.json
  • src/components/git-panel/view/modals/NewBranchModal.tsx
  • src/i18n/locales/ru/chat.json
🚧 Files skipped from review as they are similar to previous changes (19)
  • src/i18n/locales/zh-CN/tasks.json
  • src/i18n/locales/zh-CN/common.json
  • src/i18n/locales/ja/prd.json
  • src/components/prd-editor/view/GenerateTasksModal.tsx
  • src/i18n/locales/zh-CN/chat.json
  • src/i18n/locales/it/chat.json
  • src/components/settings/view/tabs/AboutTab.tsx
  • src/components/git-panel/view/changes/FileStatusLegend.tsx
  • src/components/task-master/view/modals/CreateTaskModal.tsx
  • src/components/settings/constants/constants.ts
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/en/common.json
  • src/components/task-master/view/NextTaskBanner.tsx
  • src/components/git-panel/view/GitViewTabs.tsx
  • src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx
  • src/i18n/config.js
  • src/components/prd-editor/view/PrdEditorHeader.tsx
  • src/components/browser-use/view/BrowserUsePanel.tsx
  • src/components/git-panel/view/changes/CommitComposer.tsx

Comment on lines +248 to +249
const INSTALL_ROOT = path.resolve(__dirname, '..', '..', '..');
function runCommand(command: string, args: string[], cwd = INSTALL_ROOT): Promise<void> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify INSTALL_ROOT resolves to the project root containing package.json
ast-grep outline server/modules/browser-use/browser-use.service.ts --match INSTALL_ROOT
# Check the directory structure depth
fd package.json --max-depth 1 --type f

Repository: siteboon/claudecodeui

Length of output: 379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the file's location and the build output layout
git ls-files 'server/modules/browser-use/*' 'tsconfig*.json' 'package.json' | sed -n '1,200p'

echo
echo "== package.json scripts =="
sed -n '1,220p' package.json

echo
echo "== tsconfig files =="
for f in tsconfig.json tsconfig.build.json; do
  if [ -f "$f" ]; then
    echo "-- $f --"
    sed -n '1,220p' "$f"
  fi
done

Repository: siteboon/claudecodeui

Length of output: 8286


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== server/tsconfig.json =="
sed -n '1,240p' server/tsconfig.json

echo
echo "== browser-use service path info =="
python3 - <<'PY'
from pathlib import Path
p = Path('server/modules/browser-use/browser-use.service.ts')
print("source path:", p)
print("source parents:")
for i, parent in enumerate(p.parents[:5]):
    print(i + 1, parent)
PY

Repository: siteboon/claudecodeui

Length of output: 1882


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline server/modules/browser-use/browser-use.service.ts --view expanded
sed -n '220,320p' server/modules/browser-use/browser-use.service.ts
rg -n "INSTALL_ROOT|runCommand\\(" server/modules/browser-use -n

Repository: siteboon/claudecodeui

Length of output: 7762


Point INSTALL_ROOT at the repo root
In the compiled server build, path.resolve(__dirname, '..', '..', '..') lands on dist-server/server, not the top-level package.json/node_modules directory. These npm commands should run from the workspace root or another explicit install directory.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/browser-use/browser-use.service.ts` around lines 248 - 249,
Update the INSTALL_ROOT constant used by runCommand so it resolves to the
repository/workspace root containing the top-level package.json and node_modules
in the compiled server layout. Keep runCommand’s default cwd behavior, ensuring
its npm commands execute from that install directory rather than
dist-server/server.

shell: false,
stdio: ['ignore', 'pipe', 'pipe'],
});
console.info('[Browser] Running:', command, args.join(' '), '| cwd:', process.cwd());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Log cwd instead of process.cwd().

The spawn call uses the cwd parameter (defaulting to INSTALL_ROOT), but the log statement prints process.cwd(). These will differ when the caller's working directory isn't the install root, making the log misleading for debugging.

🐛 Proposed fix
-  console.info('[Browser] Running:', command, args.join(' '), '| cwd:', process.cwd());
+  console.info('[Browser] Running:', command, args.join(' '), '| cwd:', cwd);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.info('[Browser] Running:', command, args.join(' '), '| cwd:', process.cwd());
console.info('[Browser] Running:', command, args.join(' '), '| cwd:', cwd);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/browser-use/browser-use.service.ts` at line 257, Update the
logging statement in the browser command execution flow to report the resolved
spawn working-directory variable `cwd` instead of calling `process.cwd()`, while
preserving the existing command and argument details.

Comment on lines +96 to +97
"about": "Info",
"password": "Passwort"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if KNOWN_MAIN_TABS includes 'password' and TAB_CONFIG has a password entry
rg -n "password" src/components/settings/hooks/useSettingsController.ts src/components/settings/view/SettingsMainTabs.tsx

Repository: siteboon/claudecodeui

Length of output: 159


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate likely settings controller/tab files and inspect relevant symbols.
git ls-files | rg 'settings|SettingsMainTabs|useSettingsController|tab'

Repository: siteboon/claudecodeui

Length of output: 4377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant settings files and search for password/mainTabs usage.
ast-grep outline src/components/settings/hooks/useSettingsController.ts --view expanded || true
ast-grep outline src/components/settings/view/SettingsMainTabs.tsx --view expanded || true
printf '\n--- SEARCH ---\n'
rg -n "mainTabs\.password|password" src/components/settings src/i18n/locales/*/settings.json

Repository: siteboon/claudecodeui

Length of output: 4830


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '50,80p' src/components/settings/hooks/useSettingsController.ts
printf '\n---\n'
sed -n '1,120p' src/components/settings/view/SettingsMainTabs.tsx
printf '\n=== SEARCH SETTINGS PASSWORD USAGES ===\n'
rg -n "settings\.password|t\(['\"]password|changePassword|currentPassword|newPassword|confirmPassword" src

Repository: siteboon/claudecodeui

Length of output: 9922


Wire password into the settings tabs or remove the unused translations. src/components/settings/hooks/useSettingsController.ts only normalizes agents | appearance | git | api | tasks | browser | notifications | plugins | about, and src/components/settings/view/SettingsMainTabs.tsx has no password entry, so mainTabs.password can never render. The nested password block in src/i18n/locales/de/settings.json is unreachable unless a password settings screen is added.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/de/settings.json` around lines 96 - 97, Remove the unused
password translation entries from the locale settings definitions, including the
nested password block, since useSettingsController and SettingsMainTabs do not
support a password tab. Preserve all translations for the currently normalized
settings sections.

},
"password": {
"title": "Passwort",
"description": "Ändern Sie Ihr Kontopasswort",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

German register inconsistency in password.description.

"Ändern Sie Ihr Kontopasswort" uses the formal "Sie" register, while the rest of this locale file consistently uses the informal "du" register (e.g., "Erweitere die Oberfläche mit eigenen Plugins…"). This creates an inconsistent tone for German users.

📝 Suggested fix
-    "description": "Ändern Sie Ihr Kontopasswort",
+    "description": "Ändere dein Kontopasswort",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"description": "Ändern Sie Ihr Kontopasswort",
"description": "Ändere dein Kontopasswort",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/de/settings.json` at line 487, Update the German
`password.description` translation to use the locale’s informal “du” register,
matching the surrounding settings translations while preserving its meaning.

"success": "Passwort erfolgreich geändert",
"error": {
"fillAllFields": "Bitte füllen Sie alle Felder aus",
"minLength": "Passwort muss mindestens 6 Zeichen lang sein",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

error.minLength hardcodes "6" instead of using {{min}} interpolation across all locale files. The minLengthHelp field correctly uses {{min}} interpolation, but the corresponding error.minLength message hardcodes "6" in every locale. If the minimum password length ever changes, the error message will be stale and misleading.

  • src/i18n/locales/de/settings.json#L500-L500: change "Passwort muss mindestens 6 Zeichen lang sein" to use {{min}}
  • src/i18n/locales/it/settings.json#L506-L506: change "La password deve essere di almeno 6 caratteri" to use {{min}}
  • src/i18n/locales/ja/settings.json#L500-L500: change "パスワードは6文字以上である必要があります" to use {{min}}
  • src/i18n/locales/tr/settings.json#L507-L507: change "Şifre en az 6 karakter olmalıdır" to use {{min}}

Also verify the same key in src/i18n/locales/en/settings.json (not provided in this review cohort) for the same issue.

📍 Affects 4 files
  • src/i18n/locales/de/settings.json#L500-L500 (this comment)
  • src/i18n/locales/it/settings.json#L506-L506
  • src/i18n/locales/ja/settings.json#L500-L500
  • src/i18n/locales/tr/settings.json#L507-L507
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/de/settings.json` at line 500, Update the error.minLength
message to use {{min}} instead of hardcoding 6 in
src/i18n/locales/de/settings.json:500-500,
src/i18n/locales/it/settings.json:506-506,
src/i18n/locales/ja/settings.json:500-500, and
src/i18n/locales/tr/settings.json:507-507, preserving each locale’s translation.
Also verify and update the same error.minLength key in
src/i18n/locales/en/settings.json if it hardcodes 6.

},
"password": {
"title": "Şifre",
"description": "Hesap şifrenizi değiştirin",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Turkish register inconsistency in password.description.

"Hesap şifrenizi değiştirin" uses the formal "iniz" register, while the rest of this locale file consistently uses the informal register (e.g., "Arayüzü özel eklentilerle genişlet", "Yalnızca kaynak kodunu incelediğin"). This creates an inconsistent tone for Turkish users.

📝 Suggested fix
-    "description": "Hesap şifrenizi değiştirin",
+    "description": "Hesap şifreni değiştir",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"description": "Hesap şifrenizi değiştirin",
"description": "Hesap şifreni değiştir",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/tr/settings.json` at line 494, Update the
password.description translation to use the informal Turkish imperative
register, matching the tone used by nearby settings entries while preserving its
meaning.

Comment on lines +505 to +519
"voiceSettings": {
"title": "语音",
"description": "语音转文字输入和文字朗读,通过兼容 OpenAI 的音频后端实现。",
"enable": "启用语音",
"enableDescription": "在消息上显示麦克风按钮和朗读按钮。",
"backendTitle": "后端",
"backendDescription": "指向 OpenAI、Groq 或本地服务器(LocalAI、Speaches、Kokoro-FastAPI)。留空以使用服务器默认值。",
"baseUrl": "基础 URL",
"apiKey": "***",
"sttModel": "语音转文字模型",
"ttsModel": "文字转语音模型",
"voice": "音色",
"format": "音频格式",
"note": "自定义基础 URL 由浏览器直接调用,必须允许浏览器 CORS 请求。留空以使用服务器配置的后端。"
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the English voiceSettings.apiKey value to confirm the expected label
rg -n '"apiKey"' src/i18n/locales/en/settings.json -A0 -B2

Repository: siteboon/claudecodeui

Length of output: 366


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "zh-CN apiKey context:"
rg -n '"apiKey"' src/i18n/locales/zh-CN/settings.json -A2 -B2

echo
echo "Other locale apiKey translations:"
for f in src/i18n/locales/*/settings.json; do
  val=$(python3 - <<'PY' "$f"
import json,sys
path=sys.argv[1]
with open(path,encoding='utf-8') as fh:
    data=json.load(fh)
print(data.get("voiceSettings",{}).get("apiKey","<missing>"))
PY
)
  printf '%s: %s\n' "$f" "$val"
done

Repository: siteboon/claudecodeui

Length of output: 881


voiceSettings.apiKey should be translated as a label. *** will render as the field name in src/i18n/locales/zh-CN/settings.json:513; use API 密钥 to match the English API key.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/zh-CN/settings.json` around lines 505 - 519, Update the
voiceSettings.apiKey translation in the voiceSettings locale object from "***"
to the Chinese label "API 密钥", matching the English API key field name.

@WenhuaXia WenhuaXia force-pushed the fix/tasks-i18n-small branch from 76f83f1 to a5d5aea Compare July 11, 2026 18:36
…Browser, Git panels, sidebar, chat

- Add gitPanel namespace translations (9 languages: en/zh-CN/ko/ja/ru/de/tr/it/zh-TW)
- Update all git panel components to use t() instead of hardcoded English strings
  (ChangesView, GitPanel, GitPanelHeader, FileChangeItem, HistoryView)
- Complete sidebar, chat, settings, PRD, Browser, Git panel i18n
- Register gitPanel namespace in i18n config for all languages

完成:Git 面板全面国际化(9种语言),所有硬编码英文字符串已替换为 t() 调用。
补全:侧边栏、聊天、设置、PRD、浏览器、Git 面板的翻译。
@WenhuaXia WenhuaXia force-pushed the fix/tasks-i18n-small branch from a5d5aea to 809a956 Compare July 11, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant