🤖 refactor: auto-cleanup#3213
Conversation
708166d to
1312f5a
Compare
|
Failed job: Failures (both in
What I checked:
No fix pushed. A re-run of |
07976fe to
5f8c84b
Compare
|
Failed job: Failing test: Why this looks flaky, not regression-caused:
No fix pushed — recommend re-running the failed job ( |
4a68a36 to
062f028
Compare
Replace the inline `theme === "light" || theme === "flexoki-light"` check in `getColorScheme` with the shared `isLightThemeMode` helper from `shiki-shared.ts`, so the `-light` suffix convention has a single source of truth and stays consistent with the syntax-highlighting call sites that already use it.
…stions The skill and model alias build callbacks in getSlashCommandSuggestions hardcode the trailing space, so the appendSpace: true property on those SuggestionDefinition literals is dead. Remove it and add a brief comment explaining why we don't propagate appendSpace through these paths so a future reader doesn't assume the field is consulted there.
The OpenAI service-tier literal union ('auto' | 'default' | 'flex' |
'priority') was duplicated in three places: the CLI options interface
(src/cli/run.ts), the providerModelFactory cast at the providers.jsonc
boundary, and a local OpenAIServiceTier alias in ProvidersSection.tsx.
ServiceTierSchema (src/common/config/schemas/providersConfig.ts)
already defines this enum as the runtime source of truth, so derive a
TypeScript ServiceTier alias via z.infer once and import it at each
site. Pure type-only refactor; the emitted JS and the schema remain
unchanged.
The shape `{ model: string; thinkingLevel?: ThinkingLevel }` (used
internally to read per-agent AI settings off partial workspace metadata)
was duplicated 7 times across the parameter and return types of
`resolveWorkspaceAISettings`, `resolveTaskAISettings`, and
`resolveParentAutoResumeOptions`. The new sub-agent defaults split
(#3215) made this duplication especially visible because it added a
third method copying the same inline shape.
Introduce a private `ResolvedWorkspaceAiSettings` interface at module
scope and use it everywhere. Pure type-level cleanup — emitted JS,
runtime behavior, and the schema-derived `WorkspaceAISettings` type
(where `thinkingLevel` is required) are all unchanged.
🤖 _Generated with `mux` • Model: `anthropic:claude-opus-4-7` • Thinking: `xhigh`_
In `src/node/services/tools/file_edit_insert.ts`, `GuardAnchors` was defined as `Pick<InsertContentOptions, "insert_before" | "insert_after">`, but `InsertContentOptions` itself is already `Pick<FileEditInsertToolArgs, "insert_before" | "insert_after">` after the `.nullish()` strict-mode refactor in #2250 stripped the `InsertContentOptions` interface down to those same two fields. The two aliases are now structurally identical, so `GuardAnchors` is dead. Drop the alias and use `InsertContentOptions` for the two callers (`insertWithGuards`, `resolveGuardAnchor`). Both names were file-local; no exports change. The function names (`insertWithGuards`, `resolveGuardAnchor`) already convey "guard" context, so the parameter type doesn't need to repeat it. Pure type-level cleanup — emitted JS, runtime behavior, and the public tool surface are all unchanged.
…ator Both stream-error rows in `buildDisplayedMessagesForMessage` (the existing `message.metadata?.error` branch and the new `finishReason === "length"` branch added in #3223) push structurally identical objects, differing only in `id` suffix, `error` string, and `errorType`. The shared parent-message-derived fields (`historyId`, `historySequence`, `model`, `routedThroughGateway`, `timestamp`) were duplicated across both pushes. Extract a local `pushStreamErrorRow` closure that captures the shared fields once. Each branch now reduces to a single call passing the three differing values. Pure refactor — emitted DisplayedMessage objects are identical.
…uilder The `isPlanHandoffAgent` boolean in `buildPlanInstructions` was extracted when the gate was `effectiveAgentId === "exec" || effectiveAgentId === "orchestrator"`. After #3224 ripped out the Orchestrator agent, the boolean collapsed to a single equality check (`effectiveAgentId === "exec"`), and the trailing `else if (isPlanHandoffAgent && chatHasStartHerePlanSummary)` redundantly re-evaluated the same gate just to log a debug line. Replace the flat `if/else if` with a nested `if (effectiveAgentId === "exec") { … }` that tests the Start Here summary inside, removing the duplicate gate re-check and the now-meaningless boolean. A short comment captures the rationale so a future reader doesn't reintroduce the alias. Pure refactor — emitted control flow, the debug log, and `planContentForTransition` assignments are identical, and the existing 8-test `streamContextBuilder.test.ts` suite passes unchanged (257 tests across the related taskService / modelMessageTransform / aiService suites also pass).
The second argument was named `_workspaceName` (underscore-prefixed = unused) since it was introduced in the original SSH runtime PR and has never been referenced by the function body. The /new simplification (#3230) made the noise especially visible: the new `createNewWorkspace` call site had to pass `options.workspaceName ?? "(auto-generated)"` purely to satisfy the signature, and added a comment claiming `parseRuntimeString only uses the name for error reporting context` — but the function never reads it. Drop the parameter from the signature, the placeholder + misleading comment at the only non-test caller, and the boilerplate `workspaceName` constant + 23 second-arguments in `chatCommands.test.ts`. Pure dead-parameter cleanup — emitted JS, error messages, and runtime behavior are all identical. Mobile already had the cleaner shape (`parseRuntimeStringForMobile(runtime?: string)`) so the desktop signature now matches it.
The early `dotParts.length < 2` return at the top of `parseBedrockModelName` already guarantees `dotParts.length >= 2` by the time we compute `secondPart`, so the `dotParts.length > 1 ? dotParts[1].toLowerCase() : ""` ternary's empty-string branch is unreachable. The Deepseek V4 commit (#3237) extended the surrounding logic but didn't introduce this asymmetry — `firstPart` on the line above already accesses `dotParts[0].toLowerCase()` without a guard, so the redundant ternary on `secondPart` was the odd one out. Inline to a direct `dotParts[1].toLowerCase()` access (matching `firstPart`'s shape) and capture the rationale in a one-line comment so a future reader doesn't reintroduce the guard. Pure dead-code cleanup — emitted JS, runtime behavior, and the existing 18-test `modelDisplay` suite (including the new DeepSeek + Bedrock cases) are all unchanged.
Dedupe the three call sites in task_await.ts that gated on the active agent-task subset (queued | running | awaiting_report). The duplication became especially visible in #3234, which extended both the timeout=0 and "timed out" branches symmetrically with `getAgentTaskElapsedField`, making the two structurally identical `{ status, taskId, ...elapsed }` returns sit a few lines apart from a third copy in the ForegroundWaitBackgroundedError branch that picked between the same three values. Add a local `isAgentTaskActiveStatus` type predicate (with the `AgentTaskActiveStatus` subset alias) at the top of the file alongside the existing `coerceTimeoutMs` / `parseTimestampMs` helpers and replace all three inline checks with a single call. The predicate narrows the nullable `AgentTaskStatus | null` return of `getAgentTaskStatus` to the active subset so the existing returns keep their narrowed `status` field without `as const` gymnastics. Pure refactor — emitted return shapes (including `elapsed_ms`), narrowed `status` literals, and the existing 17-test `task_await` suite all pass unchanged.
moveLanguageModelCleanup and runLanguageModelCleanup both implemented the same single-shot "read attached cleanup, delete the slot, return it" sequence inline (the same as LanguageModelWithCleanup cast + symbol read + delete). The new file from #3241 introduced both call sites with the duplication baked in. Extract a private detachLanguageModelCleanup() helper so the two surviving public functions read as their intent (move = re-attach to target, run = invoke + swallow) instead of repeating the slot-management plumbing. The behaviour is identical: detach is the only path that mutates the slot, callers take the same return-on-undefined branch they did before, and runLanguageModelCleanup keeps its existing try/catch around the invocation. Pure refactor — emitted JS, the symbol's single-shot semantics, and the existing 6-test languageModelCleanup suite are all unchanged.
The bash tool's z.preprocess shim normalizes quirky model emissions to canonical field names. After the DeepSeek v4 fix in #3247 added a second 'description' → 'display_name' rename block (mirroring the existing 'command' → 'script' rename), the two blocks were structurally identical: skip when canonical is already a string, drop the alias via destructure, re-spread with the canonical name. Each alias still required its own 'as Record<string, unknown> & { <alias>: string }' cast plus the same three-line destructure/spread. Extract a private renameAliasField(obj, alias, canonical) helper that captures the rename pattern in one place, with the rationale for why aliases exist (and why they stay undocumented) noted on the helper. The call site collapses to two named lines that read as the intent ('rename command to script', 'rename description to display_name') instead of fifteen lines of mostly-identical destructure/spread. Pure refactor — emitted JS, the canonical-field-wins precedence, the 'no-op when neither alias nor canonical is a string' branches, and the existing 36-test toolDefinitions suite (including the four new command/description alias precedence cases) are all unchanged.
Both arms of the immersive vs non-immersive selection-validity check in ReviewPanel did the same shape: `selectedHunkId && X.some(...)`, then `setSelectedHunkId(filteredHunks[0].id)` if false. Only `X` differed (`hunks` for immersive, `filteredHunks` otherwise). Pick the validity list up front and run a single check so both modes stay in lockstep, preserving the immersive-aware behavior added in #3249. Pure refactor — emitted JS, the early-return on `filteredHunks.length === 0`, the effect's dependency list, and the existing 5-test ImmersiveReviewView suite (including the two #3249 regression tests) are all unchanged.
Summary
Long-lived auto-cleanup PR that accumulates low-risk, behavior-preserving refactors picked from recent
maincommits.Changes
Collapse
ReviewPanelselection-validity branchesReviewPanel.tsx's post-filter selection-validity effect (touched by the immersive sidebar fix in #3249) split into two structurally identical arms: anisImmersivebranch that validatedselectedHunkIdagainsthunks(the unfiltered diff) and a non-immersive branch that validated againstfilteredHunks. Both arms then ran the samesetSelectedHunkId(filteredHunks[0].id)reset on miss, with the immersive arm needing its own earlyreturnto avoid double-running the reset. The duplication invited drift between the two modes — e.g. a future hide-read-style filter that adjusts the immersive reset would have to keep both arms in lockstep by hand.Pick the validity list up front (
const validityList = isImmersive ? hunks : filteredHunks;) and run a singleselectedHunkId && validityList.some(...)check, with a short comment capturing the rationale so a future reader doesn't reintroduce the split. The early-return onfilteredHunks.length === 0, the dependency list ([filteredHunks, hunks, isImmersive, selectedHunkId, setSelectedHunkId]), and the immersive-aware "only reset when the hunk has truly disappeared from the diff" semantics added in #3249 are all preserved.Pure refactor — emitted JS, the selection-reset trigger conditions, and the existing 5-test
ImmersiveReviewViewsuite (including the two immersive regression tests added in #3249) are all unchanged.Previous cleanups
Extract
renameAliasFieldhelper for bash tool preprocessThe bash tool's
z.preprocessshim (insrc/common/utils/tools/toolDefinitions.ts) normalizes quirky model emissions to canonical field names. After the DeepSeek v4 fix in #3247 added a seconddescription→display_namerename block (mirroring the existingcommand→scriptrename), the two blocks were structurally identical: skip when canonical is already a string, drop the alias via destructure, re-spread with the canonical name. Each alias still required its ownas Record<string, unknown> & { <alias>: string }cast plus the same three-line destructure/spread.Extract a private
renameAliasField(obj, alias, canonical)helper that captures the rename pattern in one place, with the rationale for why aliases exist (and why they stay undocumented) noted on the helper. The call site collapses to two named lines that read as the intent (rename command to script,rename description to display_name) instead of fifteen lines of mostly-identical destructure/spread. A future alias (e.g. another quirky-model field) becomes a one-line addition.Pure refactor — emitted JS, the canonical-field-wins precedence, the "no-op when neither alias nor canonical is a string" branches, and the existing 36-test
toolDefinitionssuite (including the fourcommand/descriptionalias precedence cases added in #3247) are all unchanged.Derive
TokenRecordfromBrowserBridgeTokenPayloadBrowserBridgeTokenManager(insrc/node/services/browser/BrowserBridgeTokenManager.ts, touched by the new other-workspace session picker in #3243) declared two structurally identical interfaces side by side: a privateTokenRecord(the stored token state) and an exportedBrowserBridgeTokenPayload(thevalidate()return shape), withTokenRecorddiffering only by the extraexpiresAtMs: numberdeadline.validate()then rebuilt the payload by listing each of the four shared fields a third time. The #3243 commit made this drift surface especially visible — addingallowOtherWorkspaceSessionrequired parallel edits inTokenRecord,BrowserBridgeTokenPayload, themint()insert, and thevalidate()rebuild.Collapse
TokenRecordtoextends BrowserBridgeTokenPayload(with the rationale captured in a short comment so a future reader doesn't reintroduce the duplicated field list) and rewrite thevalidate()rebuild as a rest-spread destructure (const { expiresAtMs, ...payload } = record; return payload;). The eslint config already enablesignoreRestSiblings: true, so the unusedexpiresAtMsbinding doesn't triggerno-unused-vars. A future payload field (e.g. another scoping flag) now lives in exactly one place — the exportedBrowserBridgeTokenPayloadinterface — and automatically flows through both the stored record shape and the validate-time rebuild.Pure refactor — emitted JS, the TTL semantics, the
null-on-expired path, and the existing 5-testBrowserBridgeTokenManagersuite (including the new "preserves explicit other-workspace session scope" case) are all unchanged.Extract
detachLanguageModelCleanuphelper inlanguageModelCleanupmoveLanguageModelCleanupandrunLanguageModelCleanup(in the newsrc/node/services/languageModelCleanup.tsfrom the OpenAI WebSocket transport opt-in PR #3241) both implemented the same "look up the attached cleanup, delete the symbol slot, return it" sequence inline. The duplication is structurally identical — sameLanguageModelWithCleanupcast, same symbol read, samedelete— so both call sites were one stray edit away from drifting on whether the slot gets cleared before or after the cleanup runs (which matters becauseattachLanguageModelCleanupasserts the slot is empty).Extract a private
detachLanguageModelCleanuphelper that does the single-shot pop in one place and returns the cleanup (orundefined). Both surviving public functions reduce to their intent:movere-attaches the popped cleanup to the target, andruninvokes it inside the existingtry/catchthat swallows + logs failures. A short comment captures the rationale on the helper itself so the next caller (e.g. a future "cancel without invoking" path) can't accidentally leak a slot.Pure refactor — emitted JS, the symbol's single-shot semantics, and the existing 6-test
languageModelCleanupsuite are all unchanged.Extract
isAgentTaskActiveStatuspredicate intask_awaitThree call sites in
src/node/services/tools/task_await.tsgated on the active agent-task subset ("queued" | "running" | "awaiting_report") by inlining the three-arm equality check. The new task_await elapsed-timing commit (#3234) extended both thetimeoutMs === 0branch and thetimed outcatch-branch symmetrically with...getAgentTaskElapsedField(taskId), making the two structurally identical{ status, taskId, ...elapsed }returns sit a handful of lines from a third copy in theForegroundWaitBackgroundedErrorbranch that picks between the same three values to coalesce against a"running"fallback.Add a local
AgentTaskActiveStatussubset alias plus anisAgentTaskActiveStatustype predicate near the existingcoerceTimeoutMs/parseTimestampMshelpers, and collapse all three inline checks to a single call. The predicate narrows the nullableAgentTaskStatus | nullreturn ofgetAgentTaskStatusto the active subset, so the surviving{ status, taskId, ... }returns keep their narrowedstatusfield with noas constgymnastics. The new comment captures the rationale so a future field added to one of the active-status branches won't silently drift away from the others.Pure refactor — emitted return shapes (including
elapsed_ms), narrowedstatusliterals, and the existing 17-testtask_awaitsuite are all unchanged.Drop dead length guard in
parseBedrockModelNamesecondPartThe early
dotParts.length < 2return at the top ofparseBedrockModelName(insrc/common/utils/ai/modelDisplay.ts) already guaranteesdotParts.length >= 2by the timesecondPartis computed, which makes thedotParts.length > 1 ? dotParts[1].toLowerCase() : ""ternary's empty-string branch unreachable. The DeepSeek V4 commit (#3237) extended the surrounding formatter without touching this site, but the new DeepSeek branch made the asymmetry more obvious — the line directly above (firstPart) already accessesdotParts[0].toLowerCase()without a guard, so the ternary onsecondPartwas the odd one out.Inline to a direct
dotParts[1].toLowerCase()access (matchingfirstPart's shape) and capture the rationale in a one-line comment so a future reader doesn't reintroduce the guard. Pure dead-code cleanup — emitted JS, runtime behavior, and the existing 18-testmodelDisplaysuite (including the new DeepSeek + existing Bedrock cases) are all unchanged.Drop unused
workspaceNameparam fromparseRuntimeStringThe second argument to
parseRuntimeString(insrc/browser/utils/chatCommands.ts) was named_workspaceName(underscore-prefixed = unused) when it was introduced in the original SSH runtime PR, and has never been referenced by the function body — error messages are all generic and don't include any workspace-specific context.The
/new-mirrors-/forksimplification (#3230) made the noise especially visible: the newcreateNewWorkspacecall site had to passoptions.workspaceName ?? "(auto-generated)"purely to satisfy the signature, and added a comment claimingparseRuntimeString only uses the name for error reporting context— but the function never reads it. Mobile already had the cleaner shape (parseRuntimeStringForMobile(runtime?: string)).Drop the parameter from the signature, drop the placeholder + misleading comment at the only non-test caller (
createNewWorkspace), and drop theworkspaceName = "test-workspace"constant + 23 second-arguments inchatCommands.test.ts. Pure dead-parameter cleanup — emitted JS, error messages, and runtime behavior are all identical, and the desktop signature now matches mobile's.Drop redundant
isPlanHandoffAgentboolean instreamContextBuilderThe
isPlanHandoffAgentboolean inbuildPlanInstructionswas extracted when the gate waseffectiveAgentId === "exec" || effectiveAgentId === "orchestrator". After #3224 ripped out the Orchestrator agent, the boolean collapsed to a single equality check (effectiveAgentId === "exec"), and the trailingelse if (isPlanHandoffAgent && chatHasStartHerePlanSummary)redundantly re-evaluated the same gate just to log a debug line.Replace the flat
if/else ifwith a nestedif (effectiveAgentId === "exec") { … }that tests the Start Here summary inside, removing the duplicate gate re-check and the now-meaningless boolean. A short comment captures the rationale so a future reader doesn't reintroduce the alias.Pure refactor — emitted control flow, the debug log, and
planContentForTransitionassignments are identical.Extract
seedScrollDirectionBaselinehelper inuseAutoScrolluseAutoScroll(touched by #3226) seedslastScrollTopReffrom two call sites —jumpToBottomanddisableAutoScroll— to keephandleScroll's released-branch direction check (currentScrollTop > previousScrollTop) honest after a programmatic ownership transfer that may not produce a follow-up scroll event. Both sites repeated the same write (lastScrollTopRef.current = contentRef.current?.scrollTop ?? 0) and a multi-line block comment re-explaining the same shared rationale.Extract a
seedScrollDirectionBaselineuseCallbackwith the shared rationale captured once on the helper itself. Each call site reduces to a single call plus a one-line comment naming the site-specific reason it doesn't get a free scroll-event refresh (stickToBottomskips the write at max;disableAutoScrollnever fires a scroll event itself). The dependency arrays forjumpToBottomanddisableAutoScrolladd the new helper, which has empty deps (useCallback(..., [])) so its identity is stable across renders — no extra re-creations of the surrounding callbacks.This shrinks the surface area for future drift: a third path that needs to flip
autoScrollRef/programmaticDisableRefwithout a guaranteed scroll-event tail (e.g. the deferred workspace-switch hydration race called out in #3226's "Pains") can call the helper instead of duplicating the rationale a third time. Pure refactor — emitted writes, write order, and ref values are identical, and the existing 25-testuseAutoScrollsuite (including the 6 new regression tests added in #3226) passes unchanged.Extract
pushStreamErrorRowhelper inStreamingMessageAggregatorbuildDisplayedMessagesForMessagenow has two branches that synthesize astream-errorDisplayedMessage: the existingmessage.metadata?.errorpath and thefinishReason === "length"path added in #3223. Both pushes were structurally identical, differing only inidsuffix,errorstring, anderrorType— the parent-message-derived fields (historyId,historySequence,model,routedThroughGateway,timestamp) were duplicated across both call sites.Extract a local
pushStreamErrorRowclosure that captures the shared fields once. Each branch reduces to a single call passing the three differing values. Themodelaccess switches frommessage.metadata.model(which relied on the outerif (message.metadata?.error)narrowing) tomessage.metadata?.model, which is functionally identical whenmetadatais defined and falls through toundefinedotherwise — same emitted value either way.This shrinks the surface area for future drift: the next branch added (e.g. a different finish-reason synthesis) can't accidentally pass a stale
modelor forgetroutedThroughGateway. Pure refactor — emittedDisplayedMessageobjects are identical, and the existing 77-test SMA suite (including the 6 new max-tokens tests) passes unchanged.Drop redundant
GuardAnchorstype alias infile_edit_insertIn
src/node/services/tools/file_edit_insert.ts,GuardAnchorswas defined asPick<InsertContentOptions, "insert_before" | "insert_after">, butInsertContentOptionsitself is alreadyPick<FileEditInsertToolArgs, "insert_before" | "insert_after">after the.nullish()strict-mode refactor in #2250 stripped theInsertContentOptionsinterface down to those same two fields. The two aliases became structurally identical, soGuardAnchorsis dead.Drop the alias and use
InsertContentOptionsfor the two callers (insertWithGuards,resolveGuardAnchor). Both names were file-local; no exports change. The function names already convey "guard" context, so the parameter type doesn't need to repeat it. This noise was especially visible to the new guardless-empty-file path added in #3220 since it sits next toinsertContentwhich usesInsertContentOptions.Pure type-level cleanup — emitted JS, runtime behavior, and the public tool surface are all unchanged.
Extract
ResolvedWorkspaceAiSettingstype alias intaskServiceThe shape
{ model: string; thinkingLevel?: ThinkingLevel }(used internally to read per-agent AI settings off partial workspace metadata) was duplicated 7 times across the parameter and return types ofresolveWorkspaceAISettings,resolveTaskAISettings, andresolveParentAutoResumeOptionsinsrc/node/services/taskService.ts. The new sub-agent defaults split (#3215) made this duplication especially visible because it added a third method copying the same inline shape.A private
ResolvedWorkspaceAiSettingsinterface at module scope replaces all 7 inline occurrences. Pure type-level cleanup — emitted JS, runtime behavior, and the schema-derivedWorkspaceAISettingstype (wherethinkingLevelis required) are all unchanged. The new interface is intentionally local to this file (not exported) since it captures the looser internal-reader shape, distinct from the canonical schema-derived type.Extract shared
ServiceTiertype fromServiceTierSchemaThe OpenAI service-tier literal union (
"auto" | "default" | "flex" | "priority") was duplicated in three places: the CLI options interface (src/cli/run.ts), theproviderModelFactorycast at theproviders.jsoncboundary (src/node/services/providerModelFactory.ts), and a localOpenAIServiceTieralias inProvidersSection.tsx.ServiceTierSchema(src/common/config/schemas/providersConfig.ts) already defines the same enum as the runtime source of truth, so this change derives a TypeScriptServiceTieralias viaz.inferonce and imports it at each site.The Settings UI keeps its
OpenAIServiceTierlocal alias (used byOpenAIServiceTierSelectValueand theisOpenAIServiceTiertype guard) but it is nowtype OpenAIServiceTier = ServiceTier, so the disambiguating name and call sites stay intact.Drop unused
appendSpaceliterals on skill/model alias suggestionsIn
src/browser/utils/slashCommands/suggestions.ts, theSuggestionDefinitionliterals built for agent skills and model alias one-shots setappendSpace: true, but the build callbacks for those two paths hardcode the trailing space and never readdefinition.appendSpace. Only the top-level command and subcommand build callbacks consult the field. Remove the no-opappendSpace: truefrom the skill and model alias mappings and leave a short comment near each so a future reader doesn't assume the field is consulted on these paths.Behavior is preserved — the field is unread on these paths, and the existing
suggestions.test.ts/inlineSkillSuggestions.test.ts/suggestionMatching.test.tssuites all still pass.Route
ThemeContextcolor-scheme throughisLightThemeModeReplace the inline
theme === "light" || theme === "flexoki-light"check ingetColorScheme(insrc/browser/contexts/ThemeContext.tsx) with the sharedisLightThemeModehelper fromsrc/browser/utils/highlighting/shiki-shared.ts.The helper was just introduced as the single source of truth for the
-lightsuffix → light-theme mapping, and the highlighting call sites (MarkdownComponents,HighlightedCode,highlightDiffChunk) already use it. This change extends that convention toThemeContextso a future palette likesolarized-lightwould automatically map tocolorScheme: "light"without revisiting this site.Behavior is preserved: for the four valid
ThemeModevalues ("light","dark","flexoki-light","flexoki-dark"),isLightThemeModereturns the same result as the previous explicit comparison.Validation
bun test src/browser/features/RightSidebar/CodeReview/ImmersiveReviewView.test.tsx— 5/5 pass (includes both immersive regression tests added in 🤖 fix: keep immersive sidebar review click on its hunk #3249, which together exercise the immersive validity-list branch and the non-immersive validity-list branch end-to-end through the parent harness).make static-check— eslint, tsgo (×2), prettier all pass; onlyshfmtfails because the binary is unavailable in this environment, and no shell files are touched.Risks
Minimal — purely a local effect-body simplification in
ReviewPanel.tsx. TheisImmersive ? hunks : filteredHunksselection produces the identical validity list each branch was already using, the survivingselectedHunkId && validityList.some(...)check is a literal hoist of the previous duplicated expression, andsetSelectedHunkId(filteredHunks[0].id)runs in exactly the same conditions (selection missing or stale against the chosen list, after the existingfilteredHunks.length === 0early-return). The dependency list is byte-identical to the post-#3249 version, so React's effect-rerun cadence is unchanged. There's no IPC, persisted-state, or rendered-output coupling.Auto-cleanup checkpoint: 555621d
Generated with
mux• Model:anthropic:claude-opus-4-7• Thinking:xhigh