feat(i18n): add prd namespace translations + register missing tasks for zh-CN/ko#983
feat(i18n): add prd namespace translations + register missing tasks for zh-CN/ko#983WenhuaXia wants to merge 1 commit into
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis 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. ChangesBrowser Use localization
Git panel localization
PRD localization
Chat and reasoning localization
Settings, TaskMaster, and sidebar updates
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
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 liftConfirmation 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 inConfirmActionModal, and manual pluralization won't work for locales with different plural rules (e.g., Russian, Japanese).Consider passing an
error_keyor message key from the caller and translating inConfirmActionModal, 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 winAdd
gitPanel.newBranchModaltranslations to the missing locale files
Onlyenandzh-CNdefine this block;de,it,ja,ko,ru,tr, andzh-TWfall back to English, andfris not wired intosrc/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 winLocalize 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.messageis still passed in as a prebuilt English string from callers, which leaves these dialogs partly untranslated; pass a translation key plus params intoConfirmationRequestand translate it inConfirmActionModal.🤖 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 winRestore the missing
onStageFiles/onUnstageFilespropsGitPanel.tsxstill passes both callbacks into<ChangesView>, butChangesViewPropsno 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 winHandle
initProcessspawn failures here.task-masteris invoked directly without an installation guard, but there’s noinitProcess.on('error', ...). If the binary is missing, the child emitsENOENTand 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 winRestore
tooltips.attentionRequiredIndicatorinsrc/i18n/locales/zh-CN/sidebar.json.
SidebarSessionItem.tsxstill 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 winHardcoded
titleattributes on branch action buttons.
title={Switch to ${name}}(line 94) andtitle={Delete ${name}}(line 101) are still hardcoded English. These should be localized:t('gitPanel.branches.switchTo', { name })andt('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 winRemaining hardcoded English strings in tooltips and aria-labels.
Several user-facing strings are still hardcoded: button
titleattributes (lines 195, 207, 218, 230) andaria-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 winGuard against
undefinedraw.eventforstream_eventtype.If the SDK emits a
stream_eventwith a missingeventproperty,innerEventisundefinedandinnerEvent.typeon the next line throws aTypeError. 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 winAdd missing
thoughtProcesstranslation key.The English
chat.jsonincludes"thoughtProcess": "Thought process"(line 251), but the zh-TW file ends atscrollNavwithout this key. Users in zh-TW will see the English fallback or raw key. Add the translation after thescrollNavobject.💚 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 winFix "加載" to "載入" for Traditional Chinese consistency.
The
loadMorevalue uses "加載" (simplified Chinese), while the rest of the file consistently uses "載入" (traditional Chinese) — e.g., lines 184, 189, 191–194. ThescrollNav.loadAllat 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 winAlign
bookmarks.pinwith the source label.
src/i18n/locales/tr/sidebar.json:147uses “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 winTranslate the expanded-state label.
Line 105 displays hardcoded Chinese whenever details are open, regardless of the selected locale. Add a
notConfigured.hideDetailskey to everytaskslocale.🤖 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 winTranslate the status prefix too.
Line 147 localizes the value but leaves
Status:in English. Use an interpolated translation such asbrowserSettings.statusLabelso 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 winFix 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 winReplace
voiceSettings.apiKeywith a real label
src/i18n/locales/zh-CN/settings.jsonuses***here, but the English source isAPI key; this should be translated asAPI 密钥.🤖 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 winHardcoded minimum length in
error.minLengthdiverges fromminLengthHelpinterpolation.Same pattern as the German locale:
minLengthHelpuses{{min}}(line 501) buterror.minLengthhardcodes "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 winHardcoded minimum length in
error.minLengthdiverges fromminLengthHelpinterpolation.
minLengthHelp(line 599) uses{{min}}buterror.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 winHardcoded minimum length in
error.minLengthdiverges fromminLengthHelpinterpolation.
minLengthHelpuses{{min}}interpolation (line 494) buterror.minLengthhardcodes "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 winAdd the missing
browserSettingsblock tosrc/i18n/locales/de/settings.json. The German locale currently haspasswordbut nobrowserSettings, 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 winAdd
browserSettingstosrc/i18n/locales/tr/settings.json
This locale is missing the newbrowserSettingsblock, 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 winValidate parsed bookmark data shape.
load()returnsJSON.parse(raw)without verifying the result is an array of validBookmarkedSessionobjects. 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 winLog the effective
cwd, notprocess.cwd().This change exists to move the command's working directory off
process.cwd()(toINSTALL_ROOTor a caller-suppliedcwd), yet the diagnostic still printsprocess.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 winSend API keys with
x-api-key, notBearer
resolveAnthropicConfig()collapsesANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKENand OAuth access tokens into onekey, but/v1/messagesexpectsx-api-keyfor direct API-key auth andAuthorization: Beareronly for OAuth/WIF tokens. As written, the API-key path will 401 and always fall back totruncateToTitle; 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 winUse
{{min}}interpolation inerror.minLengthinstead of hardcoding "6".
minLengthHelpuses{{min}}interpolation buterror.minLengthhardcodes "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
isCursorSessionneeds to be part of the session view model
SessionViewModeldoesn’t declareisCursorSession, andcreateSessionViewModelnever 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 winReplace the
not_git_repo_detailssentinel with a typed detail key
src/components/git-panel/view/GitRepositoryErrorState.tsx:13-16
These keys are only present inen/common.jsonandzh-CN/common.json, so the rest of the locales fall back to English. Thedetails === 'not_git_repo_details'check still hard-codes a backend string; adetails_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 valueAdd branch filtering to the branch dropdown
The menu renders every entry inbranchesand only limits height withmax-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 winStandardize pluralization key naming convention.
The file uses two different pluralization patterns:
commitFile/commitFiles(line 107) vsfilesSelected/filesSelected_plural(line 158). The_pluralsuffix is the i18next convention; the distinct-key approach is non-standard and may confuse translators managing locale files.♻️ Align to i18next
_pluralconvention- {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 valueDrop the stale
tab.labelfallback.MainTabConfigstill allowslabel, but everyTAB_CONFIGentry now useslabelKey, 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 valueUnused
expandedProjectsprop.
expandedProjectsis 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 winRedundant subagent check — already handled two lines above.
Lines 88-90 already call
this.isSubagentTranscript(filePath)(which normalizes and checks for asubagentssegment) and returnnull. 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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (104)
.gitignorepnpm-workspace.yamlserver/claude-sdk.jsserver/modules/browser-use/browser-use.service.tsserver/modules/database/repositories/sessions.db.tsserver/modules/projects/services/projects-with-sessions-fetch.service.tsserver/modules/providers/list/claude/claude-session-synchronizer.provider.tsserver/modules/providers/list/claude/claude-sessions.provider.tsserver/modules/providers/provider.routes.tsserver/modules/providers/services/sessions-watcher.service.tsserver/modules/providers/services/sessions.service.tsserver/routes/git.jsserver/routes/taskmaster.jsserver/shared/interfaces.tssrc/components/browser-use/view/BrowserUsePanel.tsxsrc/components/chat/hooks/useChatMessages.tssrc/components/chat/hooks/useChatSessionState.tssrc/components/chat/utils/exportSession.tssrc/components/chat/view/ChatInterface.tsxsrc/components/chat/view/subcomponents/ChatMessagesPane.tsxsrc/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsxsrc/components/chat/view/subcomponents/ScrollNavigation.tsxsrc/components/command-palette/CommandPalette.tsxsrc/components/git-panel/hooks/useGitPanelController.tssrc/components/git-panel/types/types.tssrc/components/git-panel/view/GitPanel.tsxsrc/components/git-panel/view/GitPanelHeader.tsxsrc/components/git-panel/view/GitRepositoryErrorState.tsxsrc/components/git-panel/view/GitViewTabs.tsxsrc/components/git-panel/view/branches/BranchesView.tsxsrc/components/git-panel/view/changes/ChangesView.tsxsrc/components/git-panel/view/changes/CommitComposer.tsxsrc/components/git-panel/view/changes/FileStatusLegend.tsxsrc/components/git-panel/view/history/HistoryView.tsxsrc/components/git-panel/view/modals/ConfirmActionModal.tsxsrc/components/git-panel/view/modals/NewBranchModal.tsxsrc/components/main-content/view/subcomponents/MainContentTitle.tsxsrc/components/prd-editor/view/GenerateTasksModal.tsxsrc/components/prd-editor/view/PrdEditorHeader.tsxsrc/components/settings/constants/constants.tssrc/components/settings/types/types.tssrc/components/settings/view/Settings.tsxsrc/components/settings/view/SettingsMainTabs.tsxsrc/components/settings/view/SettingsSidebar.tsxsrc/components/settings/view/tabs/AboutTab.tsxsrc/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsxsrc/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsxsrc/components/shell/hooks/useShellConnection.tssrc/components/sidebar/view/Sidebar.tsxsrc/components/sidebar/view/subcomponents/SidebarBookmarks.tsxsrc/components/sidebar/view/subcomponents/SidebarContent.tsxsrc/components/sidebar/view/subcomponents/SidebarProjectItem.tsxsrc/components/sidebar/view/subcomponents/SidebarProjectList.tsxsrc/components/sidebar/view/subcomponents/SidebarProjectSessions.tsxsrc/components/sidebar/view/subcomponents/SidebarSessionItem.tsxsrc/components/task-master/view/NextTaskBanner.tsxsrc/components/task-master/view/modals/CreateTaskModal.tsxsrc/components/task-master/view/modals/TaskMasterSetupModal.tsxsrc/hooks/useProjectsState.tssrc/i18n/config.jssrc/i18n/locales/de/chat.jsonsrc/i18n/locales/de/prd.jsonsrc/i18n/locales/de/settings.jsonsrc/i18n/locales/de/sidebar.jsonsrc/i18n/locales/en/chat.jsonsrc/i18n/locales/en/common.jsonsrc/i18n/locales/en/prd.jsonsrc/i18n/locales/en/settings.jsonsrc/i18n/locales/en/sidebar.jsonsrc/i18n/locales/fr/chat.jsonsrc/i18n/locales/it/chat.jsonsrc/i18n/locales/it/prd.jsonsrc/i18n/locales/it/settings.jsonsrc/i18n/locales/it/sidebar.jsonsrc/i18n/locales/ja/chat.jsonsrc/i18n/locales/ja/prd.jsonsrc/i18n/locales/ja/settings.jsonsrc/i18n/locales/ja/sidebar.jsonsrc/i18n/locales/ko/chat.jsonsrc/i18n/locales/ko/prd.jsonsrc/i18n/locales/ko/settings.jsonsrc/i18n/locales/ko/sidebar.jsonsrc/i18n/locales/ko/tasks.jsonsrc/i18n/locales/ru/chat.jsonsrc/i18n/locales/ru/prd.jsonsrc/i18n/locales/ru/settings.jsonsrc/i18n/locales/ru/sidebar.jsonsrc/i18n/locales/tr/chat.jsonsrc/i18n/locales/tr/prd.jsonsrc/i18n/locales/tr/settings.jsonsrc/i18n/locales/tr/sidebar.jsonsrc/i18n/locales/zh-CN/chat.jsonsrc/i18n/locales/zh-CN/common.jsonsrc/i18n/locales/zh-CN/prd.jsonsrc/i18n/locales/zh-CN/settings.jsonsrc/i18n/locales/zh-CN/sidebar.jsonsrc/i18n/locales/zh-CN/tasks.jsonsrc/i18n/locales/zh-TW/chat.jsonsrc/i18n/locales/zh-TW/prd.jsonsrc/i18n/locales/zh-TW/settings.jsonsrc/shared/view/ui/Reasoning.tsxsrc/stores/useBookmarkStore.tssrc/types/app.tsvite.config.js
| 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, | ||
| })); | ||
| } |
There was a problem hiding this comment.
🎯 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.
| 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.
| 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'); |
There was a problem hiding this comment.
🎯 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'`.
| 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 }, |
There was a problem hiding this comment.
🗄️ 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.
| 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.
| 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'), |
There was a problem hiding this comment.
🎯 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 -SRepository: 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 -SRepository: 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 -SRepository: 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.
| 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.
| 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, | ||
| ); | ||
| } | ||
| } | ||
| }} |
There was a problem hiding this comment.
🎯 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.tsRepository: 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 -nRepository: 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 -nRepository: 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 -nRepository: 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 srcRepository: 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.
| {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} | ||
| /> | ||
| ); | ||
| })} |
There was a problem hiding this comment.
🎯 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.
| {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.
| 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; | ||
| }); |
There was a problem hiding this comment.
🩺 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.
b979be3 to
3a310e8
Compare
There was a problem hiding this comment.
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
📒 Files selected for processing (69)
server/routes/git.jsserver/routes/taskmaster.jssrc/components/browser-use/view/BrowserUsePanel.tsxsrc/components/git-panel/hooks/useGitPanelController.tssrc/components/git-panel/types/types.tssrc/components/git-panel/view/GitPanel.tsxsrc/components/git-panel/view/GitPanelHeader.tsxsrc/components/git-panel/view/GitRepositoryErrorState.tsxsrc/components/git-panel/view/GitViewTabs.tsxsrc/components/git-panel/view/branches/BranchesView.tsxsrc/components/git-panel/view/changes/ChangesView.tsxsrc/components/git-panel/view/changes/CommitComposer.tsxsrc/components/git-panel/view/changes/FileStatusLegend.tsxsrc/components/git-panel/view/history/HistoryView.tsxsrc/components/git-panel/view/modals/ConfirmActionModal.tsxsrc/components/git-panel/view/modals/NewBranchModal.tsxsrc/components/prd-editor/view/GenerateTasksModal.tsxsrc/components/prd-editor/view/PrdEditorHeader.tsxsrc/components/settings/constants/constants.tssrc/components/settings/types/types.tssrc/components/settings/view/Settings.tsxsrc/components/settings/view/SettingsMainTabs.tsxsrc/components/settings/view/SettingsSidebar.tsxsrc/components/settings/view/tabs/AboutTab.tsxsrc/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsxsrc/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsxsrc/components/task-master/view/NextTaskBanner.tsxsrc/components/task-master/view/modals/CreateTaskModal.tsxsrc/components/task-master/view/modals/TaskMasterSetupModal.tsxsrc/i18n/config.jssrc/i18n/locales/de/chat.jsonsrc/i18n/locales/de/prd.jsonsrc/i18n/locales/de/settings.jsonsrc/i18n/locales/de/sidebar.jsonsrc/i18n/locales/en/chat.jsonsrc/i18n/locales/en/common.jsonsrc/i18n/locales/en/prd.jsonsrc/i18n/locales/en/settings.jsonsrc/i18n/locales/en/sidebar.jsonsrc/i18n/locales/fr/chat.jsonsrc/i18n/locales/it/chat.jsonsrc/i18n/locales/it/prd.jsonsrc/i18n/locales/it/settings.jsonsrc/i18n/locales/it/sidebar.jsonsrc/i18n/locales/ja/chat.jsonsrc/i18n/locales/ja/prd.jsonsrc/i18n/locales/ja/settings.jsonsrc/i18n/locales/ja/sidebar.jsonsrc/i18n/locales/ko/chat.jsonsrc/i18n/locales/ko/prd.jsonsrc/i18n/locales/ko/settings.jsonsrc/i18n/locales/ko/sidebar.jsonsrc/i18n/locales/ru/chat.jsonsrc/i18n/locales/ru/prd.jsonsrc/i18n/locales/ru/settings.jsonsrc/i18n/locales/ru/sidebar.jsonsrc/i18n/locales/tr/chat.jsonsrc/i18n/locales/tr/prd.jsonsrc/i18n/locales/tr/settings.jsonsrc/i18n/locales/tr/sidebar.jsonsrc/i18n/locales/zh-CN/chat.jsonsrc/i18n/locales/zh-CN/common.jsonsrc/i18n/locales/zh-CN/prd.jsonsrc/i18n/locales/zh-CN/settings.jsonsrc/i18n/locales/zh-CN/sidebar.jsonsrc/i18n/locales/zh-TW/chat.jsonsrc/i18n/locales/zh-TW/prd.jsonsrc/i18n/locales/zh-TW/settings.jsonsrc/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')} |
There was a problem hiding this comment.
🎯 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.
3a310e8 to
2d2c437
Compare
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
803a760 to
76f83f1
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (2)
src/components/quick-settings-panel/view/QuickSettingsPanelView.tsx (1)
51-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove the unused quick-settings drag wiring
handleToggleFromHandleis no longer referenced, and theuseQuickSettingsDragdestructured 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 winFallback strings are unreachable — use i18next
defaultValueinstead.
tfromuseTranslation('chat')(line 153) is always a truthy function, so thet ? t('thinking') : 'Thinking...'ternary always takes thet(...)branch. If a translation key is missing, i18next returns the key name (e.g."thoughtProcess"), not the English fallback. Uset('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
📒 Files selected for processing (62)
server/modules/browser-use/browser-use.service.tssrc/components/browser-use/view/BrowserUsePanel.tsxsrc/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsxsrc/components/command-palette/CommandPalette.tsxsrc/components/git-panel/view/GitRepositoryErrorState.tsxsrc/components/git-panel/view/GitViewTabs.tsxsrc/components/git-panel/view/changes/CommitComposer.tsxsrc/components/git-panel/view/changes/FileStatusLegend.tsxsrc/components/git-panel/view/modals/NewBranchModal.tsxsrc/components/main-content/view/subcomponents/MainContentTitle.tsxsrc/components/prd-editor/view/GenerateTasksModal.tsxsrc/components/prd-editor/view/PrdEditorHeader.tsxsrc/components/quick-settings-panel/view/QuickSettingsPanelView.tsxsrc/components/settings/constants/constants.tssrc/components/settings/view/tabs/AboutTab.tsxsrc/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsxsrc/components/sidebar/view/subcomponents/SidebarProjectSessions.tsxsrc/components/task-master/view/NextTaskBanner.tsxsrc/components/task-master/view/modals/CreateTaskModal.tsxsrc/components/task-master/view/modals/TaskMasterSetupModal.tsxsrc/i18n/config.jssrc/i18n/locales/de/chat.jsonsrc/i18n/locales/de/prd.jsonsrc/i18n/locales/de/settings.jsonsrc/i18n/locales/de/sidebar.jsonsrc/i18n/locales/en/chat.jsonsrc/i18n/locales/en/common.jsonsrc/i18n/locales/en/prd.jsonsrc/i18n/locales/en/settings.jsonsrc/i18n/locales/en/sidebar.jsonsrc/i18n/locales/fr/chat.jsonsrc/i18n/locales/it/chat.jsonsrc/i18n/locales/it/prd.jsonsrc/i18n/locales/it/settings.jsonsrc/i18n/locales/it/sidebar.jsonsrc/i18n/locales/ja/chat.jsonsrc/i18n/locales/ja/prd.jsonsrc/i18n/locales/ja/settings.jsonsrc/i18n/locales/ja/sidebar.jsonsrc/i18n/locales/ko/chat.jsonsrc/i18n/locales/ko/prd.jsonsrc/i18n/locales/ko/settings.jsonsrc/i18n/locales/ko/sidebar.jsonsrc/i18n/locales/ko/tasks.jsonsrc/i18n/locales/ru/chat.jsonsrc/i18n/locales/ru/prd.jsonsrc/i18n/locales/ru/settings.jsonsrc/i18n/locales/ru/sidebar.jsonsrc/i18n/locales/tr/chat.jsonsrc/i18n/locales/tr/prd.jsonsrc/i18n/locales/tr/settings.jsonsrc/i18n/locales/tr/sidebar.jsonsrc/i18n/locales/zh-CN/chat.jsonsrc/i18n/locales/zh-CN/common.jsonsrc/i18n/locales/zh-CN/prd.jsonsrc/i18n/locales/zh-CN/settings.jsonsrc/i18n/locales/zh-CN/sidebar.jsonsrc/i18n/locales/zh-CN/tasks.jsonsrc/i18n/locales/zh-TW/chat.jsonsrc/i18n/locales/zh-TW/prd.jsonsrc/i18n/locales/zh-TW/settings.jsonsrc/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
| const INSTALL_ROOT = path.resolve(__dirname, '..', '..', '..'); | ||
| function runCommand(command: string, args: string[], cwd = INSTALL_ROOT): Promise<void> { |
There was a problem hiding this comment.
🩺 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 fRepository: 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
doneRepository: 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)
PYRepository: 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 -nRepository: 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()); |
There was a problem hiding this comment.
🎯 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.
| 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.
| "about": "Info", | ||
| "password": "Passwort" |
There was a problem hiding this comment.
🎯 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.tsxRepository: 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.jsonRepository: 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" srcRepository: 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", |
There was a problem hiding this comment.
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.
| "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", |
There was a problem hiding this comment.
🎯 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-L506src/i18n/locales/ja/settings.json#L500-L500src/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", |
There was a problem hiding this comment.
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.
| "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.
| "voiceSettings": { | ||
| "title": "语音", | ||
| "description": "语音转文字输入和文字朗读,通过兼容 OpenAI 的音频后端实现。", | ||
| "enable": "启用语音", | ||
| "enableDescription": "在消息上显示麦克风按钮和朗读按钮。", | ||
| "backendTitle": "后端", | ||
| "backendDescription": "指向 OpenAI、Groq 或本地服务器(LocalAI、Speaches、Kokoro-FastAPI)。留空以使用服务器默认值。", | ||
| "baseUrl": "基础 URL", | ||
| "apiKey": "***", | ||
| "sttModel": "语音转文字模型", | ||
| "ttsModel": "文字转语音模型", | ||
| "voice": "音色", | ||
| "format": "音频格式", | ||
| "note": "自定义基础 URL 由浏览器直接调用,必须允许浏览器 CORS 请求。留空以使用服务器配置的后端。" | ||
| }, |
There was a problem hiding this comment.
🎯 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 -B2Repository: 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"
doneRepository: 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.
76f83f1 to
a5d5aea
Compare
…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 面板的翻译。
a5d5aea to
809a956
Compare
feat(i18n): add prd namespace translations + register missing tasks for zh-CN/ko
Summary by CodeRabbit
New Features
Improvements