🤖 refactor: auto-cleanup#3291
Conversation
2ca21da to
31a3fa8
Compare
|
Failure: Why this is a flake, not caused by the cleanup commit:
Action: No fix pushed. Recommend retrying the Windows job; if it persists, the Windows ready-wait may need to be bumped above 900ms or the assertion further hardened (separate from this cleanup PR). |
f4a79eb to
0a996c2
Compare
|
Symptom (run Root cause: Why this isn't the cleanup PR's fault:
Existing fixes on other branches (not yet on
Recommendation: cherry-pick |
Both image_generate and image_edit duplicated the same "Adjust Settings > Experiments > Image Tools or request fewer images." setup hint literal when the requested image count exceeded the configured maxImagesPerCall. Hoist it next to the existing IMAGE_TOOL_PROVIDER_SETUP_HINT in imageArtifacts.ts so the guidance has a single source of truth, matching the pattern established by the prior auto-cleanup PR.
Move `urlAttributes`/`blockedSchemes` out of `sanitizeMermaidSvg` and into module-level constants (`SANITIZER_URL_ATTRIBUTES`, `SANITIZER_BLOCKED_URL_SCHEMES`). They are pure lookup data with no per-call dependency, so allocating them on every render of every Mermaid diagram was wasted work — these now allocate once per module load. Pure cleanup: identical contents, identical lookup semantics, no behavior change. The full Mermaid.test.tsx suite (including the recent sanitizer regression tests) still passes. --- _Generated with `mux` • Model: `anthropic:claude-opus-4-7` • Thinking: `xhigh` • Cost: `$`_ <!-- mux-attribution: model=anthropic:claude-opus-4-7 thinking=xhigh costs= -->
`summarizeToolPart` carried the AI SDK v5 `state` → lifecycle phase mapping inline as a nested ternary plus a multi-line comment listing the states. The ternary obscured the actual mapping (output-available and output-redacted both fold to "done") and made adding new states a multi-line edit. Hoist the mapping to a `TOOL_PART_PHASE_BY_STATE` record at module scope, keyed on the SDK state strings and typed as the literal phase union. The summarizer now does a single table lookup. States not in the table (e.g. `input-streaming`) still yield `null` and the bare `[tool <name>]` form, matching prior behavior exactly. Behavior-preserving: same input strings, same output bytes for every `state` value the prior code handled, and the same `null` fallthrough for everything else.
Three slash-command discovery surfaces (suggestions in ChatInput, ghost
hints in ChatInput, and CommandPalette) duplicated the same inline
lambda:
(experimentId) =>
resolveSlashCommandExperimentValue(experimentId, {
goals: goalsExperimentEnabled,
workspaceHeartbeats: workspaceHeartbeatsExperimentEnabled,
})
Add createSlashCommandExperimentResolver(snapshot) next to its sibling
resolver so each callsite only describes the experiment snapshot it
observes. The new helper returns the exact same closure each callsite
previously built inline, so behavior is byte-identical.
The SSH-provisioning commit (#3302) added a second `import type { Runtime } from "../node/runtime/Runtime"` line right below an existing `import type { InitLogger, WorkspaceInitResult }` from the same module. Fold the new symbol into the existing import — byte-identical semantics, one fewer line of boilerplate, no behavior change.
Extract a shared `BUILT_IN_SKILL_NAMES` constant for the two test assertions in `agentSkillsService.test.ts` that previously enumerated the same five built-in skill names inline. The two existing call sites differ only in their project-skill prefix; spreading the shared constant at the end of each list preserves the exact sort order and assertion semantics. Byte-equivalent to the previous inline arrays; the only effect is that the next new built-in skill needs to land in one place instead of two.
The Tooltip + Switch + Reset Button block for the per-agent advisor toggle was duplicated between renderAgentDefaults and renderUnknownAgentDefaults. The two call sites differ only in the agent id variable and which setter/resetter to invoke, so wrap the shared markup in a small AdvisorSwitch component. Same aria-label, same tooltip text via getAdvisorSwitchState, same conditional Reset semantics — pure cleanup with no behavior change.
Hoist the ["text", "delta", "textDelta"] field priority used to extract AI SDK v5 text-delta payloads into a shared TEXT_OUTPUT_DELTA_FIELDS constant in src/common/utils/ai/streamChunks.ts and reuse it from streamManager.ts (fullStream text-delta handling) and tools/advisor.ts (advisor streamText onChunk handling). Byte-equivalent semantics; only the wiring detail (that the same fallback list applies to both callsites) moves into the shared module.
BudgetTile and TurnsTile each render the same dt-label + Edit-button
header row. Lift the duplicated markup into a small file-scoped
`StatTileHeader` helper so the styling lives in one place and the
tile bodies focus on their own numeric content. Behavior, aria
labels, and class names are unchanged — `GoalTab.test.tsx` (23
tests, including the inline budget/turn-cap editors that locate
the openers via `getByLabelText("Edit goal …")`) still passes.
Three callsites (ChatInput/types.ts, messageQueue.ts, agentSession.ts) each privately redeclared the same NonNullable<SendMessageOptions["goalInterventionPolicy"]> alias after #3319 added the field. Centralizing the type next to SendMessageOptions itself removes the duplication and ensures future sub-typing changes only need to land in one place. Pure relocation — identical type semantics at every callsite.
The silent-continuation summary helper added in #3326 was declared as a private method on `AgentSession` but only depends on its input `parts` argument — it never touches `this`. Convert it to a module-level free function alongside the existing free helpers (`stripGoalInterventionPolicy`, `coerceGoalSyntheticMessageKind`, `extractAgentSkillRefs`, etc.) so the no-`this` contract is obvious to readers and the file's helper style stays consistent. The companion `maybeAutoCompleteGoalFromSilentContinuation` method stays on the class because it accesses `this.workspaceGoalService`, `this.workspaceId`, and `log` indirectly through instance context. Byte-for-byte identical logic at the only callsite. Pure cleanup, no behavior change.
The seed loop in applyReviewPaneUpdate built a key→index map for the existing base list by calling base.indexOf(h) on every iteration — O(n²) when the loop already had the index in hand. Switch to `base.entries()` so the position the map stores is unambiguously the slot we just visited. Behavior-identical for unique references (the only realistic case), and now correct-by-construction even if a future refactor ever introduced duplicate references in `base`.
This test-only export was added speculatively in #3262 (Instructions tab) but no test ever imports it; ripgrep across src/ and tests/ finds zero callers. Removing the unused export lets pendingFocusGeneration become `const` since the reset helper was the only reason it was `let`. The Map is still mutated in place via .set(), and getter/setter exports are unchanged, so observable runtime behavior is byte-identical.
Five toolPolicy entries differed only by tool name and all shared
`action: "disable" as const`. Hoist the names into a local
`CLI_DISABLED_TOOL_NAMES` tuple and produce the policy array via
`.map(name => ({ regex_match: name, action: "disable" as const }))`.
Picked from the `ask_user_question` disable that landed in #3336 —
that commit added a fifth identical-shape entry, so the table form is
now strictly tidier than five copy-pasted object literals. Adding the
next disabled CLI tool drops to one string instead of duplicating the
shape. Byte-equivalent toolPolicy contents (same five entries, same
order, same action), so no behavior change.
Generated with `mux`
…lCall The two pill renderers in the ask_user_question executing UI (one per question plus the Summary pill) inlined the same nine-class Tailwind string and the same three-way selected/complete/neutral branch logic. Extract a module-level `getSectionPillClassName(isSelected, isComplete)` helper so both callsites share one declaration; the next visual tweak to those pills now lives in one place instead of two. Identical class strings at both callsites, so the rendered output is byte-equivalent and the AskUserQuestionToolCall.test.tsx suite (4/4 pass) continues to find the question pills by their unchanged role and labels.
The SSH_AUTH_SOCK / SSH_AGENT_PID save+restore pattern was inlined four times (twice in withoutSshAgent's finally block, twice in afterAll) using the same 'if (saved === undefined) delete; else assign' shape. The new module-local restoreEnvVar(key, savedValue) helper mirrors that exact semantics in one place. Each callsite collapses from four lines to one and the per-key delete-vs-assign decision lives in a single function. Picked from #3340 - that PR brought signingService.test.ts back under review when it bumped the Ed25519 capabilities test timeout to 15s. Tests still pass (14/14).
The single-result `buildReviewDiffPathFilter` wrapper was exported from ReviewPanel.tsx solely so two assertions in ReviewPanel.assistedStats.test.ts could grab the first spec's pathFilter. Production callers (ReviewPanel's diff-load effect and ReviewAssistedStatsReporter) already use the multi-spec `buildReviewDiffPathFilterSpecs` form directly so they can handle assisted multi-project pins. Move the wrapper into the test file as a private helper. Pure relocation — identical implementation, same two describe-block assertions, same buildReviewDiffPathFilterSpecs delegation — so the ReviewPanel module's exported surface drops one helper that no production code ever called. Picked from the `fix: surface assisted review hunks reliably` change in #3344, which introduced the test-only wrapper alongside the production multi-spec form.
The two new `parseGoalBudgetFlag` and `parseGoalTurnsFlag` helpers in src/cli/run.ts (added in #3348) built their error strings with `'...' + value + '...'` concatenation, which is the only `throw new Error('...')` pair in the file — every other error (including the adjacent `parseMode` helper) uses backtick template literals. Convert these two messages to template literals for consistency. Pure stylistic alignment; the thrown Error has the same message text.
Hoist the duplicated Tailwind class string used by the Pause / Mark complete / Reopen buttons in GoalTab.tsx into a single module-level GOAL_LIFECYCLE_NEUTRAL_BUTTON_CLASS constant. Each call site previously inlined the same 'border-border-light bg-surface-secondary text-foreground hover:bg-surface-tertiary inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm' string; the accent-colored Archive and success-tinted Resume buttons keep their own class strings because they are the only primary / positive variants in the row. Pure DRY relocation: same class string at every callsite, so the existing GoalTab.test.tsx 'active goals expose a de-prominent Clear; completed goals promote Archive as primary' assertion (which checks that Reopen's className does NOT contain 'bg-accent' and that Archive's DOES) still holds, and every Pause / Mark complete / Reopen aria-label lookup in the suite continues to resolve. No behavior change.
…RYABLE_ERRORS #3356 introduced two adjacent constants in SSHRuntime.ts that listed the same four receive-pack thin-pack failure patterns inline: PROJECT_SYNC_RETRYABLE_ERRORS (used by the broad retry classifier) and UNRESOLVED_DELTA_PUSH_PATTERNS (used by isUnresolvedDeltaPushFailure to decide whether the next retry attempt should add --no-thin). Define the four-string sub-class once on UNRESOLVED_DELTA_PUSH_PATTERNS and spread it into PROJECT_SYNC_RETRYABLE_ERRORS so the lists can never drift. .some(pattern => errorMsg.includes(pattern)) sees the same patterns in the same order, so the retry classification is byte-equivalent — pure DRY, no behavior change.
The intent-only summary mode added in #3360 introduced a second normalizeForComparison(value) !== normalizeForComparison(command) call, so the same whitespace- and case-insensitive command-equality check now appears in three spots: filtering a redundant intent, filtering a redundant display-name fallback, and the trailing-using-clause stripper. Pull that predicate into a single matchesCommand helper next to normalizeForComparison so all three callsites read as 'intent (or display name, or candidate) is the same as the command' and any future tweak to the comparison normalization happens in one place. Pure rename/extract: the helper composes the existing normalizer, returns the identical boolean, and no callsite changes its branch direction.
Summary
Rolling, low-risk cleanup batch. Each run adds one extremely small,
behavior-preserving refactor picked from changes that have landed on
mainsince the last checkpoint.
Auto-cleanup checkpoint: 789053a
Current diff against
main:src/browser/utils/additionalSystemContextStore.ts— drop theunused
__resetAdditionalSystemContextFocusForTestsexport andpromote
pendingFocusGenerationfromlettoconst. The resethelper was added speculatively alongside the Instructions tab in
🤖 feat: Instructions tab in right sidebar #3262, but ripgrep across
src/andtests/finds zero importers —no test ever calls it. Removing it lets the only other reason the
module needed a mutable binding (the
pendingFocusGeneration = new Map()reassignment inside the helper) go away, so the binding canbe a
constMap that's still mutated in place via.set(). TherequestAdditionalSystemContextFocus/getAdditionalSystemContextFocusGenerationcallers continue to seethe exact same Map identity and counter semantics — pure dead-code
removal with no runtime behavior change.
src/browser/features/Messages/Mermaid.tsx— hoist the URL-attributeset and blocked-scheme list out of
sanitizeMermaidSvgintomodule-level constants (
SANITIZER_URL_ATTRIBUTES,SANITIZER_BLOCKED_URL_SCHEMES). They are pure lookup data with noper-call dependency, so allocating them on every Mermaid render was
wasted work; they now allocate once per module load. Identical
contents and identical lookup semantics — pure cleanup with no
behavior change.
src/node/services/agentStatusService.ts— hoist the AI SDK v5tool-part
state→ lifecycle phase mapping out ofsummarizeToolPartinto a module-level
TOOL_PART_PHASE_BY_STATErecord. The previousnested ternary obscured the actual mapping (
output-availableandoutput-redactedboth fold to"done") and made adding new states amulti-line edit. The summarizer now does a single table lookup; the
union-typed values document the two valid phases inline. States not
in the table (e.g.
input-streaming) still yieldnulland the bare[tool <name>]form, byte-for-byte identical to before.src/browser/utils/slashCommands/experimentVisibility.ts(+ twoconsumers) — add
createSlashCommandExperimentResolver(snapshot)alongside
resolveSlashCommandExperimentValue. Three slash-commanddiscovery surfaces (suggestions in
ChatInput, the ghost-hint call inChatInput, and theCommandPalettepalette query) had each inlinedthe same
(experimentId) => resolveSlashCommandExperimentValue(experimentId, snapshot)lambda. The new helper returns the exact same closure eachcallsite previously built inline, so the
isExperimentEnabledpredicate handed to
getSlashCommandSuggestions/getCommandGhostHintis behaviorally identical; only the wiring detail (that resolution
is parameterized by experiment id) moves into the visibility module.
Rebased through the
goalsGA removal — the snapshot now carriesonly
workspaceHeartbeatsbut the resolver helper itself isunchanged.
src/cli/run.ts— fold theRuntimetype import into the existingimport type { InitLogger, WorkspaceInitResult } from "../node/runtime/Runtime"line. The SSH-provisioning commit (🤖 perf: cut SSH workspace startup ~9× on the warm path via fused single-RTT materialization #3302) added a second
import type { Runtime } from "../node/runtime/Runtime"directly below it; mergingthem is byte-identical semantics with one fewer line of boilerplate.
No behavior change.
src/node/services/agentSkills/agentSkillsService.test.ts— extract ashared
BUILT_IN_SKILL_NAMESconstant for the twotoEqual([...])assertions that previously enumerated the same five built-in skill
names (
imagegen,init,mux-diagram,mux-docs,orchestrate)inline. The two call sites differ only in their project-skill prefix;
spreading the shared constant at the end of each list preserves the
exact sort order and assertion semantics. The next built-in skill
added (e.g. when
/orchestrategraduates to advertised, or a newhidden skill lands) only needs to update one list instead of two.
Byte-equivalent assertion output; no runtime behavior change.
src/browser/features/Settings/Sections/TasksSection.tsx— extract anAdvisorSwitchcomponent for the per-agent advisor toggle. TheTooltip+Switch+ optionalResetbutton block was duplicatedbetween
renderAgentDefaultsandrenderUnknownAgentDefaults(addedin 🤖 fix: enable advisor for default subagents #3309 when the Advisor experiment gained default-on behavior for
Exec and Plan). The two call sites differ only in the agent-id
variable they close over and which setter/resetter to invoke, so the
shared markup now lives in one place. Same
aria-label, sametooltip text via
getAdvisorSwitchState, same conditional Resetsemantics — the TasksSection UI test (
defaults advisor on for Exec and Plan when the experiment is enabled) still finds both switchesby their unchanged role + name.
src/common/utils/ai/streamChunks.ts(+ two consumers) — hoist the["text", "delta", "textDelta"]field priority used to extract AI SDKv5 text-delta payloads into a shared
TEXT_OUTPUT_DELTA_FIELDSconstant. Both
streamManager.ts(thefullStreamtext-deltaparthandler) and
tools/advisor.ts(the advisorstreamTextonChunktext-delta handler, added in 🤖 feat: stream advisor output live #3310) had inlined the same array
literal; centralizing it prevents drift if the AI SDK normalizes
another alias and documents the intent in one place. The other two
extractChunkDeltaTextcallsites inaiService.tsuse deliberatelydifferent field orderings (
["textDelta", "delta", "text"]forparent-step text-delta capture,
["text", "textDelta", "delta"]forreasoning-delta capture) and are intentionally left untouched.
Byte-equivalent lookup semantics at every callsite — pure DRY.
src/browser/features/RightSidebar/GoalTab.tsx— extract a smallfile-scoped
StatTileHeadercomponent for the duplicated<dt>+inline-
Edit-button header row used byBudgetTileandTurnsTile(added in 🤖 feat(goals-tab): consolidate Cost/Budget/Remaining + always show Turn cap #3314 when the active-goal stat surface was consolidated).
The two tiles previously inlined the same
flexwrapper, the sametext-muted text-xs<dt>, and the sametext-xs underlineEditbutton — only the label string and
aria-labeldiffered. The sharedhelper preserves those two parameters as props and keeps every class
name,
type="button", and aria label byte-for-byte identical, so theinline budget/turn-cap editors in
GoalTab.test.tsx(which locatetheir openers via
getByLabelText("Edit goal budget")/getByLabelText("Edit goal turn cap")) still match. Pure DRY; nobehavior change.
src/common/orpc/types.ts(+ three consumers) — hoist theGoalInterventionPolicy = NonNullable<SendMessageOptions["goalInterventionPolicy"]>alias next to
SendMessageOptionsitself. After 🤖 feat: add goal intervention policy #3319 added thepolicy field, three independent files re-derived the same alias:
the browser
ChatInput/types.tsbarrel,node/services/messageQueue.ts,and
node/services/agentSession.ts. The canonical alias now livesbeside its source schema;
ChatInput/types.tsre-exports it so thefeature-local import surface stays unchanged, and the two node-side
files import directly. Identical type semantics at every callsite —
pure relocation with no runtime behavior change.
src/node/services/agentSession.ts— convertsynthesizeSilentContinuationSummaryfrom a private method onAgentSessionto a module-level free function. The helper, added in🤖 fix(goals): treat text-only continuation turns as goal completion #3326 as part of the silent-continuation auto-complete hook, only
depends on its input
partsargument — it never touchesthis.Moving it alongside the existing free helpers
(
stripGoalInterventionPolicy,coerceGoalSyntheticMessageKind,extractAgentSkillRefs, etc.) makes the no-thiscontract obviousto readers and keeps the file's helper style consistent. The
companion
maybeAutoCompleteGoalFromSilentContinuationmethod stayson the class because it accesses
this.workspaceGoalService,this.workspaceId, and the instance-scopedlog. Byte-for-byteidentical logic at the only callsite; the
agentSession.goalAutoPause.test.tssuite (18/18 pass) continues tocover the silent-continuation, dynamic-tool-present, manual-user, and
paused-goal branches.
src/node/services/tools/review_pane.ts— switch the dedup seed loopin
applyReviewPaneUpdatefromfor (const h of base) { seen.set(..., base.indexOf(h)) }tofor (const [i, h] of base.entries()) { seen.set(..., i) }. The previous form ran an O(n²) reference scan on every seediteration even though the loop already had the index in hand; the
result is byte-equivalent for the realistic case where every entry in
baseis a unique reference (which is always true today —baseiseither
[]or[...current]after the previous deduped call) and nowcorrect-by-construction even if a future refactor ever introduced
duplicate references. Same dedup map contents, same final hunk
ordering — the 15 existing
review_pane.test.tstests (including the"dedupes by formatted path:range key when adding, preferring the
latest comment" case) all pass unchanged. Picked from the
review_pane_updatetool feature landed in 🤖 feat: add review_pane_update tool + Assisted review toggle #3331.src/cli/run.ts— extract aCLI_DISABLED_TOOL_NAMEStuple and buildthe
mux runtoolPolicyarray via.map(name => ({ regex_match: name, action: "disable" as const })). The five entries previously inlinedin
buildSendOptions(ask_user_question,status_set,todo_write,todo_read,notify) differed only by tool name and all shared theexact same
action: "disable"shape. Picked from theask_user_questiondisable that landed in 🤖 fix: disable ask_user_question in mux run #3336 — that commit addeda fifth identical-shape entry, so the table form is now strictly
tidier than five copy-pasted object literals, and the next disabled
CLI tool drops to one string instead of duplicating the object
shape. Byte-equivalent
toolPolicycontents (same five entries,same order, same regex_match and action values), so no behavior
change.
src/browser/features/Tools/AskUserQuestionToolCall.tsx— extract amodule-level
getSectionPillClassName(isSelected, isComplete)helperfor the executing-UI section pills. The two pill renderers (one per
question, plus the
Summarypill, both added in 🤖 refactor: polish ask_user_question UI #3339 when theask_user_questionUI was polished) inlined the exact same nine-classTailwind string and the same three-way selected (accent) / complete
(success-tinted) / pending (neutral) branch logic — they differed
only in which boolean drove the "selected" leg (
isActiveforquestion pills,
isOnSummaryfor the Summary pill) and which booleandrove the "complete" leg (
answeredvsisComplete). The helpercentralizes the class string so the next visual tweak to those pills
lives in one place. Byte-equivalent class output at both callsites
(verified by diffing the rendered class strings), so the existing
AskUserQuestionToolCall.test.tsxsuite (4/4 pass) continues tolocate the buttons by their unchanged role + accessible name.
src/node/services/signingService.test.ts— extract a module-localrestoreEnvVar(key, savedValue)helper to fold the four inlinedcopies of the SSH env-var restore block (twice in the
withoutSshAgentfinally, twice inafterAll) into single-linecalls. Each copy used the identical
if (saved === undefined) delete process.env[X]; else process.env[X] = savedshape — only the env-varname differed (
SSH_AUTH_SOCKvsSSH_AGENT_PID). The helperpreserves that exact delete-vs-assign decision per key, so the
process.env state after
withoutSshAgentreturns and after the suitetears down is byte-equivalent to before. Picked from 🤖 tests: stabilize flaky signing and best-of task tests #3340, which
brought this file back under review when it bumped the Ed25519
"should load key and return capabilities" test to a 15s timeout. The
full suite (14/14 SigningService tests, including all
withoutSshAgentpaths and the agent-vs-disk priority tests that depend on the
restore semantics) passes unchanged. Pure DRY; no behavior change.
src/browser/features/RightSidebar/CodeReview/ReviewPanel.tsx(+ test consumer) — relocate the test-only
buildReviewDiffPathFiltersingle-result wrapper out of
ReviewPanel.tsxand intoReviewPanel.assistedStats.test.tsas a private file-scoped helper.The wrapper was introduced in 🤖 fix: surface assisted review hunks reliably #3344 alongside the multi-spec
buildReviewDiffPathFilterSpecsform so the existingbuildReviewDiffPathFilterdescribe block (two assertions: assistedmode fetches agent-pinned files, non-assisted mode preserves the
selected file pathspec) could keep using a
pathFilter: stringreturn shape. The two production callers in the same file
(
ReviewAssistedStatsReporter's diff-load effect andReviewPanel's diff-load effect) already use the multi-specbuildReviewDiffPathFilterSpecsdirectly so they can fan out acrossper-repo-root pathspecs — nothing in production ever called the
single-result wrapper. The relocated helper has byte-identical
implementation (same
...params, projectPath: repoRootProjectPath ?? ""forwarding, same[0]?.pathFilter ?? ""first-specextraction), so the 10/10
ReviewPanel.assistedStats.test.tsassertions pass unchanged;
ReviewPanel.tsxjust stops exporting ahelper that no production code consumes.
src/cli/run.ts— convert the twothrow new Error('Invalid --goal-* "' + value + '" ...')messages in the newparseGoalBudgetFlagandparseGoalTurnsFlaghelpers (added in 🤖 bench: add Terminal-Bench strict goal mode #3348) to backtick templateliterals (
`Invalid --goal-budget "${value}". ...`). These werethe only two
throw new Error('...')single-quoted-concatenationpairs left in
src/cli/run.ts; every otherthrow new Error(in thefile — including the adjacent
parseModehelper at the top of thesame block — already uses a backtick template literal. The thrown
Errormessage text is byte-for-byte identical (sameInvalid --goal-budget "<value>". Expected dollars like 5, $5.00, or cents like 500candInvalid --goal-turns "<value>". Expected a positive integerstrings, same single quotes around the user value), so thisis a pure stylistic alignment with no behavior change.
src/browser/features/RightSidebar/GoalTab.tsx— hoist the duplicatedneutral-button Tailwind class string used by the Pause / Mark complete
/ Reopen lifecycle action buttons into a single module-level
GOAL_LIFECYCLE_NEUTRAL_BUTTON_CLASSconstant. After 🤖 refactor: style goal row actions as real buttons #3342 reshapedthe completed-goal action row, three buttons in the same
flex flex-wrap gap-2group inlined the same nine-class string(
border-border-light bg-surface-secondary text-foreground hover:bg-surface-tertiary inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm); the accent-colored Archive andsuccess-tinted Resume buttons keep their own inline strings because
they are the only primary / positive variants in the row. The
existing
active goals expose a de-prominent Clear; completed goals promote Archive as primaryassertion (reopenButton.classNamedoesNOT contain
bg-accent;archiveButton.classNameDOES) and everyPause / Mark complete / Reopen aria-label lookup in
GoalTab.test.tsx(23/23 pass) continue to hold. Byte-equivalentclass string at every callsite; no behavior change.
src/node/runtime/SSHRuntime.ts— dedupe the four receive-packthin-pack failure patterns (
unresolved deltas,unpacker error,unpack-objects abnormal exit,remote unpack failed) that 🤖 fix(ssh): harden bare base repo against receive-pack thin-pack failures #3356introduced inline in both
PROJECT_SYNC_RETRYABLE_ERRORS(used bythe broad retry classifier at the
isProjectSyncRetryableErrorcallsite) and
UNRESOLVED_DELTA_PUSH_PATTERNS(used byisUnresolvedDeltaPushFailureto decide whether the next retryattempt should add
--no-thin). The sub-class is now declared onceon
UNRESOLVED_DELTA_PUSH_PATTERNS(with the long rationaleconsolidated onto its JSDoc) and spread into
PROJECT_SYNC_RETRYABLE_ERRORSvia...UNRESOLVED_DELTA_PUSH_PATTERNS.Both
.some((pattern) => errorMsg.includes(pattern))iterations seethe same four patterns in the same order, so retry classification and
the
forceNoThinNextAttemptdecision are byte-equivalent — pure DRY,no behavior change. The existing
SSHRuntime.retry.test.tsandSSHRuntime.syncContract.test.tssuites both pass unchanged.src/browser/features/Tools/bashCollapsedSummary.ts— extract amatchesCommand(value, command)helper next tonormalizeForComparisonand route the three existing
normalizeForComparison(X) !== normalizeForComparison(command)callsites through it. The intent-onlysummary mode added in 🤖 feat: add intent-only bash summaries #3360 introduced a second
normalizeForComparison(displayName) !== normalizeForComparison(command)inside the new
getIntentOnlyFallback, doubling the predicate that wasalready used to filter a redundant intent and inside
stripTrailingUsingCommandto detect a redundant trailingusing <command>clause. The helper composes the existing normalizer, returnsthe identical boolean, and no callsite changes its branch direction —
so intent-vs-command redundancy filtering, display-name fallback
selection, and the using-clause stripper are all byte-for-byte
identical. The existing
bashCollapsedSummary.test.tssuite (10/10)exercises every branch — intent equal to command, intent missing,
intent-only mode falling back to display name, display name equal to
command, and the nested using-clause sanitize pass — and all pass
unchanged.
Validation
make static-check— eslint, tsgo (×2 configs), and prettier all greenlocally; the only red step is
fmt-shell-checkfailing becauseshfmtisn't installed in this environment (pre-existing env limitation, no
shell files touched by these changes).
bun test src/browser/features/RightSidebar/GoalTab.test.tsx— 23/23 pass.bun test src/browser/features/RightSidebar/CodeReview/ReviewPanel.assistedStats.test.ts— 10/10 pass.
bun test src/browser/features/Tools/AskUserQuestionToolCall.test.tsx— 4/4 pass.
bun test src/node/services/signingService.test.ts— 14/14 pass.bun test src/browser/features/Tools/bashCollapsedSummary.test.ts— 10/10 pass.Generated with
mux• Model:anthropic:claude-opus-4-7• Thinking:xhigh