Skip to content

Fix patching for 2.1.81#624

Open
basekevin wants to merge 2 commits intomainfrom
fix-patching-for-2.1.81
Open

Fix patching for 2.1.81#624
basekevin wants to merge 2 commits intomainfrom
fix-patching-for-2.1.81

Conversation

@basekevin
Copy link
Copy Markdown
Member

@basekevin basekevin commented Mar 22, 2026

Closes #611.
Closes #626.
Closes #628.
Closes #629.
Closes #645.

Summary by CodeRabbit

Release Notes

Bug Fixes & Improvements

  • Enhanced compatibility across multiple Claude Code versions with improved pattern detection and fallback strategies
  • Extended support for additional UI component rendering variations to accommodate minified code differences
  • More robust feature patching with better error tolerance and silent fallbacks when patterns cannot be located
  • Refined version-specific handling for improved reliability across diverse Claude Code builds

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 22, 2026

📝 Walkthrough

Walkthrough

This PR updates 24 patch modules to improve compatibility across Claude Code versions 2.1.76–2.1.87 by introducing async/sync fallback strategies, broadening regex patterns, adding multi-path detection heuristics, and relaxing failure modes to become no-ops. The changes address widespread pattern-matching failures reported in recent Claude Code releases by making patch detection more flexible and robust.

Changes

Cohort / File(s) Summary
Async/Sync Reader Fallback
src/patches/agentsMd.ts
Added writeAgentsMdAsync(...) for CC ≥2.1.83 async reader patching with didReroute parameter and alternative-filename retry logic; refactored sync path into writeAgentsMdSync(...) with expanded fs-expression discovery via caller-region lookup; main function now dispatches to async first, then sync fallback.
Pattern Matching Flexibility
src/patches/helpers.ts, src/patches/themes.ts, src/patches/tokenCountRounding.ts, src/patches/statuslineUpdateThrottle.ts
Broadened regex distance tolerances and matching alternatives: findTextComponent expanded gap tolerance; findBoxComponent added Method 4 memoized-function detection; getThemesLocation added two-tier parsing (new/old format); tokenCountRounding added three-pattern matching sequence; statuslineUpdateThrottle extended pattern for newer throttling shapes.
Multi-Path Detection & Fallback
src/patches/autoAcceptPlanMode.ts, src/patches/hideStartupBanner.ts, src/patches/suppressLineNumbers.ts, src/patches/hideStartupClawd.ts
Added multiple regex variants and detection strategies: autoAcceptPlanMode supports multiple onChange AST forms with idempotency guard; hideStartupBanner adds fallback startup-function scan for CC ≥2.1.83; suppressLineNumbers uses signature-based boundary replacement with arrow-match fallback; hideStartupClawd refactored wrapper discovery to single index with inner-function name extraction.
Failure Mode Relaxation
src/patches/mcpStartup.ts, src/patches/allowCustomAgentModels.ts, src/patches/voiceMode.ts, src/patches/inputBorderBox.ts
Changed hard-failure behavior to no-op returns: mcpStartup returns original file when MCP env-var check not found; allowCustomAgentModels returns input unchanged when patterns absent; voiceMode silently returns file for missing tengu_amber_quartz_disabled; inputBorderBox returns file immediately when removeBorder=false.
Robust Detection & Injection
src/patches/patchesAppliedIndication.ts, src/patches/userMessageDisplay.ts, src/patches/increaseFileReadLimit.ts, src/patches/scrollEscapeSequenceFilter.ts
Refactored location finding and injection: patchesAppliedIndication added multi-location helper and VyK-compact-first matcher; userMessageDisplay added nested-subcomponent pattern with conditional capture indexing; increaseFileReadLimit switched to anchor-based approach with dynamic regex construction; scrollEscapeSequenceFilter narrowed filtered escape sequences to scroll-specific types only.
Feature Expansion & Sub-Patch Integration
src/patches/showMoreItemsInSelectMenus.ts, src/patches/toolsets.ts, src/patches/inputPatternHighlighters.ts
Added new regex-based patches and sub-patch orchestration: showMoreItemsInSelectMenus added three math-formula patches (help menu halving, visible-count division, suggestions cap); toolsets added new exports writeComputeToolsFilter and writeToolsetAwareErrors with Step 2b/2c integration; inputPatternHighlighters refactored shimmer/renderer patching with multi-step workflow and flexible useMemo detection.
Unit Test Updates
src/patches/allowCustomAgentModels.test.ts
Updated "no patterns found" test case to assert input-unchanged return instead of null, with CC ≥2.1.83 version indicator in test name.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • bl-ue
  • georpar

Poem

🐰 A patchwork of fallbacks, so clever and keen,
Async then sync, the best we have seen!
From 2.1.76 up to 2.1.87,
With regex broadened—our patterns reach heaven!
No match? No fuss, just return as before,
Robustness now knocks on each new version's door. 🚪

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix patching for 2.1.81' is specific and directly relates to the main objective of fixing multiple patch failures across Claude Code versions (2.1.76, 2.1.81, 2.1.87).
Linked Issues check ✅ Passed The PR addresses all five linked issues (#611, #626, #628, #629, #645) by implementing fallback strategies, expanded regex patterns, and alternative detection paths for failing patches across multiple CC versions.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the identified patch failures: pattern matching improvements, fallback detection strategies, and robustness enhancements align directly with the PR objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-patching-for-2.1.81

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

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
src/patches/mcpStartup.ts (1)

28-29: Remove newly added inline comments in this patch file.

These added comments violate the repository TS/JS rule that comments should not
be added unless explicitly requested.

✂️ Suggested cleanup
-    // CC ≥2.1.79 removed this env var — non-blocking is now the default.
     return null;
@@
-    // CC ≥2.1.79 removed MCP_CONNECTION_NONBLOCKING — non-blocking is now default.
-    // Return file unchanged (no-op) instead of failing.
     return oldFile;

As per coding guidelines "Do not add comments unless explicitly requested".

Also applies to: 77-78

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/mcpStartup.ts` around lines 28 - 29, Remove the newly added
inline comment lines (e.g., the "CC ≥2.1.79 removed this env var — non-blocking
is now the default." and the other comment at the later occurrence) from the
mcpStartup patch so the file no longer contains those unsolicited comments; keep
the code behavior (the return null statements and surrounding logic in the same
function/block) unchanged and only delete the comment text in the same scope
where return null is present to satisfy the repository rule forbidding added
comments.
src/patches/userMessageDisplay.ts (1)

150-153: Consider replacing \b with a literal character anchor for consistency with guidelines.

The new pattern uses \b (word boundary), which the coding guidelines discourage due to V8 performance issues. However, since the existing pattern on line 147-148 also uses \b, this is consistent with the current codebase style.

If you choose to address this, you could replace .{0,50}?\b with a more explicit delimiter, but given the existing pattern uses the same approach, this is optional.

As per coding guidelines: "Avoid \b in regex patterns due to V8 performance issues; use literal character alternatives."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/userMessageDisplay.ts` around lines 150 - 153, The regex in the
newPattern constant uses \b which the guidelines disallow; update newPattern to
remove the word-boundary token and instead match an explicit delimiter (for
example a whitespace, punctuation or end-of-string) after the short .{0,50}?
span so it behaves the same without using \b; modify the newPattern declaration
accordingly and mirror the same change in the other existing pattern variable if
you want consistency with the nearby pattern.
src/patches/agentsMd.ts (2)

106-106: Consider increasing the body slice limit.

The 500-character limit may be insufficient if the catch block appears later in larger functions. The same limit is used at line 159 for the async version.

💡 Suggested fix
-    const callerBody = newFile.slice(callerStart, callerStart + 500);
+    const callerBody = newFile.slice(callerStart, callerStart + 1000);

And similarly at line 159:

-      const asyncBody = newFile.slice(asyncStart, asyncStart + 500);
+      const asyncBody = newFile.slice(asyncStart, asyncStart + 1000);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/agentsMd.ts` at line 106, The slice length for extracting the
caller body is too small: increase the 500-character limit used when creating
callerBody (const callerBody = newFile.slice(callerStart, callerStart + 500)) so
the search for a later catch block in large functions succeeds; update that
value to a larger safe window (and apply the same change to the corresponding
async-version slice at the other occurrence around line 159) so both callerBody
and the async callerBody capture enough characters to include a trailing catch
block.

164-167: Inconsistent regex pattern compared to sync version.

Line 117 uses /\([$\w]+,([$\w]+)/ which matches functions with 2+ parameters, but line 164 uses /\([$\w]+,([$\w]+)\)/ with a closing paren, requiring exactly 2 parameters. If the async function has more parameters, this pattern won't match and the fallback will use callerSecondParam from the sync caller—which may not match the async function's param name.

♻️ Suggested fix to align patterns
-      const asyncSecondMatch = asyncUpToParams.match(
-        /\([$\w]+,([$\w]+)\)/
-      );
+      const asyncSecondMatch = asyncUpToParams.match(
+        /\([$\w]+,([$\w]+)/
+      );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/agentsMd.ts` around lines 164 - 167, The regex used to extract
the second parameter from the async signature (asyncUpToParams →
asyncSecondMatch → asyncSecondParam) is too strict and requires exactly two
params; update the pattern to match the sync version so it captures the second
param even when there are 2+ params (i.e., remove the trailing closing-paren
requirement used in the async match and use the same `/\([$\w]+,([$\w]+)/` style
pattern), so asyncSecondParam falls back correctly only when no match exists
rather than when the async function has more parameters than two; ensure you
modify the regex passed to asyncUpToParams.match accordingly.
src/patches/patchesAppliedIndication.ts (2)

198-199: Add boundary prefix to fragmentPattern for consistency.

The pattern lacks a boundary character at the start, which could theoretically match within a larger identifier. Other patterns in this file use [^$\w] prefix for stricter matching.

Suggested fix
-  const fragmentPattern = /createElement\([$\w]+\.Fragment,null,/;
+  const fragmentPattern = /[^$\w]createElement\([$\w]+\.Fragment,null,/;

Note: If you apply this, adjust fragmentMatch.index by +1 when calculating fragStart on line 205.

Based on learnings: "Regex patterns in patches should be strict and match the minified format."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/patchesAppliedIndication.ts` around lines 198 - 199, The regex
fragmentPattern is missing the leading boundary used elsewhere; update
fragmentPattern to include the same prefix ([^$\w]) so it only matches fragment
calls as a standalone token, then account for the added prefix by adding +1 to
the index when using fragmentMatch.index to compute fragStart (adjust the
computation that references fragStart). References: fragmentPattern,
fragmentMatch, fragStart.

499-512: Minor inconsistency in line joining.

Line 512 uses lines.join('\n') while the similar code in applyIndicatorPatchesListPatch (line 265) uses lines.join(''). Both work correctly since JavaScript ignores whitespace, but consider aligning them for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/patchesAppliedIndication.ts` around lines 499 - 512, The code
builds a string array `lines` and then creates `patchesListCode` using
`lines.join('\n')`, which is inconsistent with the similar implementation in
`applyIndicatorPatchesListPatch` that uses `lines.join('')`; update the join
call so both use the same delimiter (prefer matching
`applyIndicatorPatchesListPatch`) to keep consistency—modify the
`patchesListCode` assignment where `lines.join('\n')` is used to use
`lines.join('')` (or vice versa if you prefer the other style).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/patches/helpers.ts`:
- Line 299: In findTextComponent update the regex on the pattern that currently
begins with \b to avoid V8 \b performance issues: remove the leading \b and
instead anchor with a literal-alternative group that matches the allowed patch
delimiters (for example replace the start with a non-capturing group like
(?:^|[,{;}]) so the pattern still finds components preceded by start or the
literal characters `,` `;` `{` `}`), keeping the rest of the pattern intact (the
fragment matching function name and color/backgroundColor/dimColor/bold tokens)
so the regex behavior is unchanged but avoids \b.

---

Nitpick comments:
In `@src/patches/agentsMd.ts`:
- Line 106: The slice length for extracting the caller body is too small:
increase the 500-character limit used when creating callerBody (const callerBody
= newFile.slice(callerStart, callerStart + 500)) so the search for a later catch
block in large functions succeeds; update that value to a larger safe window
(and apply the same change to the corresponding async-version slice at the other
occurrence around line 159) so both callerBody and the async callerBody capture
enough characters to include a trailing catch block.
- Around line 164-167: The regex used to extract the second parameter from the
async signature (asyncUpToParams → asyncSecondMatch → asyncSecondParam) is too
strict and requires exactly two params; update the pattern to match the sync
version so it captures the second param even when there are 2+ params (i.e.,
remove the trailing closing-paren requirement used in the async match and use
the same `/\([$\w]+,([$\w]+)/` style pattern), so asyncSecondParam falls back
correctly only when no match exists rather than when the async function has more
parameters than two; ensure you modify the regex passed to asyncUpToParams.match
accordingly.

In `@src/patches/mcpStartup.ts`:
- Around line 28-29: Remove the newly added inline comment lines (e.g., the "CC
≥2.1.79 removed this env var — non-blocking is now the default." and the other
comment at the later occurrence) from the mcpStartup patch so the file no longer
contains those unsolicited comments; keep the code behavior (the return null
statements and surrounding logic in the same function/block) unchanged and only
delete the comment text in the same scope where return null is present to
satisfy the repository rule forbidding added comments.

In `@src/patches/patchesAppliedIndication.ts`:
- Around line 198-199: The regex fragmentPattern is missing the leading boundary
used elsewhere; update fragmentPattern to include the same prefix ([^$\w]) so it
only matches fragment calls as a standalone token, then account for the added
prefix by adding +1 to the index when using fragmentMatch.index to compute
fragStart (adjust the computation that references fragStart). References:
fragmentPattern, fragmentMatch, fragStart.
- Around line 499-512: The code builds a string array `lines` and then creates
`patchesListCode` using `lines.join('\n')`, which is inconsistent with the
similar implementation in `applyIndicatorPatchesListPatch` that uses
`lines.join('')`; update the join call so both use the same delimiter (prefer
matching `applyIndicatorPatchesListPatch`) to keep consistency—modify the
`patchesListCode` assignment where `lines.join('\n')` is used to use
`lines.join('')` (or vice versa if you prefer the other style).

In `@src/patches/userMessageDisplay.ts`:
- Around line 150-153: The regex in the newPattern constant uses \b which the
guidelines disallow; update newPattern to remove the word-boundary token and
instead match an explicit delimiter (for example a whitespace, punctuation or
end-of-string) after the short .{0,50}? span so it behaves the same without
using \b; modify the newPattern declaration accordingly and mirror the same
change in the other existing pattern variable if you want consistency with the
nearby pattern.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 555c8f40-46a5-44cc-a659-2ddbc21c1366

📥 Commits

Reviewing files that changed from the base of the PR and between f876bc8 and 62ce3fa.

📒 Files selected for processing (5)
  • src/patches/agentsMd.ts
  • src/patches/helpers.ts
  • src/patches/mcpStartup.ts
  • src/patches/patchesAppliedIndication.ts
  • src/patches/userMessageDisplay.ts

// function X({color:A,backgroundColor:B,dimColor:C=!1,bold:D=!1,...})
const textComponentPattern =
/\bfunction ([$\w]+).{0,20}color:[$\w]+,backgroundColor:[$\w]+,dimColor:[$\w]+(?:=![01])?,bold:[$\w]+(?:=![01])?/;
/\bfunction ([$\w]+).{0,30}color:[$\w]+,backgroundColor:[$\w]+,dimColor:[$\w]+(?:=![01])?,bold:[$\w]+(?:=![01])?/;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Replace \b at regex start in findTextComponent.

Line 299 uses \b at the pattern start, which violates patch regex performance guidance for this repo.

Suggested fix
-  const textComponentPattern =
-    /\bfunction ([$\w]+).{0,30}color:[$\w]+,backgroundColor:[$\w]+,dimColor:[$\w]+(?:=![01])?,bold:[$\w]+(?:=![01])?/;
+  const textComponentPattern =
+    /(?:^|[,;{}])function ([$\w]+).{0,30}color:[$\w]+,backgroundColor:[$\w]+,dimColor:[$\w]+(?:=![01])?,bold:[$\w]+(?:=![01])?/;

As per coding guidelines: "Avoid \\b in regex patterns due to V8 performance issues; use literal character alternatives" and "Use , ; } { literal characters at regex start instead of \\b for performance in patch patterns".

📝 Committable suggestion

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

Suggested change
/\bfunction ([$\w]+).{0,30}color:[$\w]+,backgroundColor:[$\w]+,dimColor:[$\w]+(?:=![01])?,bold:[$\w]+(?:=![01])?/;
/(?:^|[,;{}])function ([$\w]+).{0,30}color:[$\w]+,backgroundColor:[$\w]+,dimColor:[$\w]+(?:=![01])?,bold:[$\w]+(?:=![01])?/;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/helpers.ts` at line 299, In findTextComponent update the regex on
the pattern that currently begins with \b to avoid V8 \b performance issues:
remove the leading \b and instead anchor with a literal-alternative group that
matches the allowed patch delimiters (for example replace the start with a
non-capturing group like (?:^|[,{;}]) so the pattern still finds components
preceded by start or the literal characters `,` `;` `{` `}`), keeping the rest
of the pattern intact (the fragment matching function name and
color/backgroundColor/dimColor/bold tokens) so the regex behavior is unchanged
but avoids \b.

@WestDragon
Copy link
Copy Markdown

WestDragon commented Mar 29, 2026

Снимок экрана 2026-03-29 в 17 29 55

I applied this fix on my native MacOS 2.1.81 installation, Unfortunately, the commands aren't working.

@WestDragon
Copy link
Copy Markdown

After a full clean install of Claude Code and TweakCC, the patch applied well and CC is back to working.

sla-te added a commit to sla-te/tweakcc that referenced this pull request Mar 30, 2026
Claude Code 2.1.85+ uses the React Compiler, which moves props
destructuring from function parameters into the function body with
useMemoCache. This broke several regex patterns that assumed inline
destructuring.

Fixes:
- helpers.ts: Widen findTextComponent regex gap from .{0,20} to .{0,80}
  (React Compiler gap is 21 chars, just 1 over the old limit)
- helpers.ts: Widen findBoxComponent Method 1 gap from .{0,200} to
  .{0,500} (cache slot assignments expand the gap to ~336 chars)
- helpers.ts: Update findBoxComponent Method 2 to handle body-level
  destructuring (.{0,200}children: instead of \(\{children:)
- agentsMd.ts: Support async split-function pattern where the single
  sync CLAUDE.md reader was split into content processor (ol4), async
  reader (Fb8), and error handler (al4). The patch now targets the
  async reader when fs operations aren't found in the content processor.
- patchesAppliedIndication.ts: Handle memoized "Claude Code" createElement
  (React Compiler caches it in a variable). PATCH 5 (indicator view
  patches list) gracefully degrades when paren-counting fails on
  flattened component trees.
- userMessageDisplay.ts: Widen regex gaps (.{0,150}->.{0,250},
  .{0,100}->.{0,200}) and use flexible prop matching ([^}]* instead
  of hardcoded thinkingMetadata).
- index.ts: Version-gate mcp-non-blocking patch to CC < 2.1.85 since
  MCP_CONNECTION_NONBLOCKING was removed (non-blocking is now default).

Tested on CC 2.1.87 native installation (Linux). All default patches
apply successfully.

Closes Piebald-AI#643, closes Piebald-AI#645, closes Piebald-AI#628, closes Piebald-AI#624

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@basekevin basekevin force-pushed the fix-patching-for-2.1.81 branch from a3afe2d to 44ec80f Compare April 2, 2026 18:13
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 13

Caution

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

⚠️ Outside diff range comments (1)
src/patches/agentsMd.ts (1)

184-184: ⚠️ Potential issue | 🟡 Minor

Incorrect showDiff arguments for replacement display.

The call passes earlyReturnStart twice, suggesting a zero-length range, and uses indices computed from newFile while passing file (original) as the first argument. The actual patch logic (lines 179-182) is correct; this only affects debug output.

🐛 Proposed fix
-  showDiff(file, newFile, newStr, earlyReturnStart, earlyReturnStart);
+  showDiff(newFile, newFile, newStr, earlyReturnStart, earlyReturnStart + oldStr.length);

Note: The first argument should probably be the pre-modification state or you may need to track indices differently if showDiff expects original file positions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/agentsMd.ts` at line 184, The debug call to showDiff is passing
mismatched arguments: it uses file as the first parameter while the start/end
indices (earlyReturnStart) were computed from newFile, and it accidentally
repeats earlyReturnStart twice. Update the call to pass the modified buffer
(newFile) as the first argument and use the correct end index (earlyReturnEnd)
instead of repeating earlyReturnStart so the displayed range matches the indices
computed earlier; keep showDiff, file, newFile, newStr, earlyReturnStart, and
earlyReturnEnd in mind when making the change.
♻️ Duplicate comments (1)
src/patches/helpers.ts (1)

299-299: ⚠️ Potential issue | 🟠 Major

Replace leading \b in findTextComponent pattern.

This still uses a leading \b, which violates the patch-regex performance rule for this repo.

Suggested fix
-  const textComponentPattern =
-    /\bfunction ([$\w]+).{0,30}color:[$\w]+,backgroundColor:[$\w]+,dimColor:[$\w]+(?:=![01])?,bold:[$\w]+(?:=![01])?/;
+  const textComponentPattern =
+    /(?:^|[,;{}])function ([$\w]+).{0,30}color:[$\w]+,backgroundColor:[$\w]+,dimColor:[$\w]+(?:=![01])?,bold:[$\w]+(?:=![01])?/;
#!/bin/bash
# Verify no patch regex in this file starts with \b
rg -nP --type=ts '=\s*/\\b' src/patches/helpers.ts

As per coding guidelines: "Avoid \\b in regex patterns due to V8 performance issues; use literal character alternatives" and "Use , ; } { literal characters at regex start instead of \\b for performance in patch patterns".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/helpers.ts` at line 299, The regex in findTextComponent uses a
leading '\b' which violates the repo's patch-regex performance rule; replace the
leading '\b' with a literal start alternative such as a non-capturing group like
(?:^|[,\;{}\s]) (or a fixed-width lookbehind for those literals) so the pattern
starts with explicit characters instead of a word-boundary; update the regex
used in findTextComponent (the pattern matching "function ...
color:...,backgroundColor:...,dimColor:...,bold:...") accordingly and run the
provided grep to verify no '\b' remains.
🧹 Nitpick comments (7)
src/patches/increaseFileReadLimit.ts (1)

20-20: Consider using a non-capturing group for minor performance improvement.

The capture group ([\s\S]{0,200}) is never used (only match.index is accessed, not match[1]). Using a non-capturing group would be slightly more efficient.

♻️ Proposed refactor
-    const pattern = new RegExp(`=25000,([\\s\\S]{0,200})${escaped}`);
+    const pattern = new RegExp(`=25000,(?:[\\s\\S]{0,200})${escaped}`);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/increaseFileReadLimit.ts` at line 20, The RegExp assigned to the
variable pattern uses an unnecessary capturing group `([\s\S]{0,200})` which is
never read; replace it with a non-capturing group `(?:[\s\S]{0,200})` in the
RegExp construction to avoid the unused capture overhead in the pattern created
in increaseFileReadLimit.ts (the const pattern = new RegExp(...)). Ensure you
keep the surrounding anchors/text (`=25000,` and `${escaped}`) intact so only
the inner group changes.
src/patches/inputPatternHighlighters.ts (2)

177-177: Dead code: useMemoCode is always empty.

useMemoCode is initialized to an empty string and never reassigned, yet it's concatenated into replacement and passed to showDiff. This appears to be leftover from a previous implementation.

🧹 Proposed cleanup
-  const useMemoCode = '';
-
   let genCode = '';
   // ... rest of the loop ...
 
-  let newFile = beforeMatch + useMemoCode + replacement + afterMatch;
+  let newFile = beforeMatch + replacement + afterMatch;
 
   // ... dependency array logic ...
 
   showDiff(
     oldFile,
     newFile,
-    useMemoCode + replacement,
+    replacement,
     match.index,
     match.index + match[0].length
   );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/inputPatternHighlighters.ts` at line 177, The variable
useMemoCode is dead (initialized as const useMemoCode = '' and never changed)
but still concatenated into replacement and passed to showDiff; remove the
unused const useMemoCode and eliminate its concatenation/usage in the creation
of replacement and the argument list for showDiff in inputPatternHighlighters.ts
(look for symbols useMemoCode, replacement, and showDiff) so the replacement
string and showDiff call no longer reference this unused placeholder.

221-254: Dependency array injection logic is sound but fragile.

The parenthesis-depth tracking approach to locate the useMemo closure end works, but relies on several assumptions:

  • The closing ] directly precedes the closing )
  • No string literals containing unbalanced parens exist in the region
  • The dependency check !depsCheck.includes(,${inputVar}]) only catches inputVar at array end

This is acceptable for minified code (which typically doesn't have misleading string content), but consider adding a brief inline comment explaining these assumptions for future maintainers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/inputPatternHighlighters.ts` around lines 221 - 254, The
dependency-array injection logic around forLoopIdx / useMemo uses
parenthesis-depth tracking (memoOffset/region/depth) and a heuristic that the
closing ']' directly precedes the closing ')' and that string literals won't
contain unbalanced parens, and the depsCheck.includes(`,${inputVar}]`) only
detects the var at the array end; add a short inline comment above this block
(near the forLoopIdx check and before the depth loop) documenting these
assumptions and the fragility so future maintainers understand why the heuristic
is acceptable for minified code and what edge cases could break it (unbalanced
parens in strings, different dependency ordering, or the var not being last).
src/patches/themes.ts (1)

29-40: Minor: Redundant indexOf calls could be consolidated.

The validation at lines 29-35 checks specific strings, then lines 37-40 recalculate anchor from scratch with slightly different strings ('case"dark":return{' vs 'case"dark":return{"autoAccept"'). Consider reusing the already-found indices:

♻️ Optional consolidation
   } else {
     // Try old format (inline objects) — use brace counting
-    const oldAnchor = oldFile.indexOf('case"dark":return{"autoAccept"');
-    if (oldAnchor === -1) {
-      const oldAnchor2 = oldFile.indexOf('case"light":return{');
-      if (oldAnchor2 === -1) {
-        console.error('patch: themes: failed to find switchMatch');
-        return null;
-      }
-    }
-    const anchor =
-      oldFile.indexOf('case"dark":return{') !== -1
-        ? oldFile.indexOf('case"dark":return{')
-        : oldFile.indexOf('case"light":return{');
+    const darkAnchor = oldFile.indexOf('case"dark":return{');
+    const lightAnchor = oldFile.indexOf('case"light":return{');
+    if (darkAnchor === -1 && lightAnchor === -1) {
+      console.error('patch: themes: failed to find switchMatch');
+      return null;
+    }
+    const anchor = darkAnchor !== -1 ? darkAnchor : lightAnchor;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/themes.ts` around lines 29 - 40, The code redundantly calls
oldFile.indexOf multiple times to find the switch anchor; reuse the previously
computed oldAnchor and oldAnchor2 instead of re-scanning the string. Update the
logic around oldAnchor, oldAnchor2 and anchor so that after checking for
'case"dark":return{"autoAccept"' and 'case"light":return{' you set anchor =
oldAnchor !== -1 ? oldAnchor : oldAnchor2 (or similar) and remove the extra
indexOf calls that search for 'case"dark":return{' again; this keeps the same
branching behavior but avoids duplicate string searches in the functions using
oldAnchor, oldAnchor2, and anchor.
src/patches/autoAcceptPlanMode.ts (1)

99-106: The lastIndexOf fallback may match unintended return statements.

When the specific regex at line 94 fails, this fallback finds the last return in a 500-character window. If there are multiple return statements in that window (e.g., ternary returns, early returns), this could inject at the wrong location.

Consider tightening the fallback by at least verifying the matched return is followed by a React.createElement call:

💡 Suggested approach
     const simpleReturnIdx = beforeReady.lastIndexOf('return ');
     if (simpleReturnIdx === -1) {
       console.error(
         'patch: autoAcceptPlanMode: failed to find return before "Ready to code?"'
       );
       return null;
     }
+    // Verify this return is followed by createElement (basic sanity check)
+    const afterReturn = beforeReady.slice(simpleReturnIdx);
+    if (!/^return [$\w]+\.(?:default\.)?createElement/.test(afterReturn)) {
+      console.error(
+        'patch: autoAcceptPlanMode: found return but not createElement pattern'
+      );
+      return null;
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/autoAcceptPlanMode.ts` around lines 99 - 106, The fallback using
simpleReturnIdx can match the wrong "return " in beforeReady; change it to
iterate backwards over all occurrences of "return " within beforeReady and
validate each candidate by checking the following characters after that index
(from beforeReady.slice(simpleReturnIdx)) match a pattern indicating a React
component return—e.g., optional whitespace then either '<',
'React.createElement', or '(' leading into JSX—until you find a valid one;
update the logic around the simpleReturnIdx lookup (using
beforeReady.lastIndexOf in a loop) so it only accepts a return that is followed
by JSX/React.createElement and otherwise continues searching earlier returns,
returning null only if none validate.
src/patches/patchesAppliedIndication.ts (1)

103-103: Consider removing disabled PATCH 4/5 helpers from this file.

The helpers are explicitly unused and disabled; keeping them in active patch code increases maintenance and misleads future edits.

Also applies to: 214-214, 610-613

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/patchesAppliedIndication.ts` at line 103, Remove the inactive
"PATCH 4" and "PATCH 5" helper functions and their accompanying ESLint disable
comments from patchesAppliedIndication.ts: delete the helper function
declarations (the explicit PATCH 4 and PATCH 5 helpers), any related exports and
unused imports, and remove the "// eslint-disable-next-line
`@typescript-eslint/no-unused-vars`" lines that were silencing them; run a
build/TS check to ensure no remaining references and tidy up any now-unused
types or imports.
src/patches/agentsMd.ts (1)

140-144: Unreachable fallback in ternary expression.

The 'require("fs")' fallback on line 144 is unreachable. When !fsMatch, we enter the if block on line 128; if callerFsMatch is also null, we return on line 136. So after line 138, either fsMatch or callerFsMatch is truthy.

♻️ Suggested simplification
-const fsExpr = fsMatch
-  ? fsMatch[1]
-  : callerFsMatch
-    ? callerFsMatch[1]
-    : 'require("fs")';
+const fsExpr = fsMatch ? fsMatch[1] : callerFsMatch![1];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/agentsMd.ts` around lines 140 - 144, The nested ternary assigning
fsExpr is using an unreachable fallback ('require("fs")') because earlier logic
guarantees either fsMatch or callerFsMatch is present; replace the three-way
ternary with a simpler expression that selects fsMatch[1] when fsMatch exists
otherwise callerFsMatch[1] (e.g., use fsMatch ? fsMatch[1] : callerFsMatch[1] or
(fsMatch ?? callerFsMatch)[1]) so fsExpr only depends on fsMatch and
callerFsMatch and the unreachable string literal is removed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/patches/hideStartupBanner.ts`:
- Around line 35-52: The regex lookahead is fragile; change funcPattern to
simply /(function ([$\w]+)\(\)\{)/g and, after matching (using funcMatch and
computing bodyStart/bodyPreview), check bodyPreview.includes('Welcome to Claude
Code') && bodyPreview.includes('Apple_Terminal') before performing the
insertion; keep insertion = 'return null;' and the showDiff/newFile return flow
intact so nested braces in minified functions no longer break detection.

In `@src/patches/inputPatternHighlighters.ts`:
- Line 166: The regex assigned to inputPattern uses the \b word-boundary (const
inputPattern = /\binput:([$\w]+),/g) which we avoid; replace the \b with a
literal-character alternative that matches either start-of-string or a
non-word/non-$/non-_ character (for example an explicit group like
(?:^|[^A-Za-z0-9_$]) before "input:") so the pattern still only matches
standalone "input:" tokens; keep the rest of the pattern (capturing group for
the name and trailing comma) and the global flag.
- Around line 96-98: The regex construction in shimmerPattern uses
segVar.replace('$', '\\$') which only escapes the first dollar; update the
escape to handle all occurrences (e.g., use segVar.replace(/\$/g, '\\$') or an
escapeRegExp utility) so every '$' in segVar is escaped before interpolating
into the RegExp; ensure the change is applied to both segVar.replace(...)
occurrences inside the RegExp template used when creating shimmerPattern.
- Around line 122-125: The renderer capture isn't being applied: when rebuilding
newFile you insert newMatches2[0] unchanged, so only the shimmer guard is
effective; instead reconstruct the renderer string using the captured groups
(reactVar, textComp, keyVar, segVar) from newMatches2 and insert that
reconstructed renderer in place of newMatches2[0] (mirroring how the shimmer
branch builds its replacement); update the newFile expression to splice in the
synthesized renderer (not the original match) so the "shimmer guard + renderer"
transformation is actually applied.

In `@src/patches/patchesAppliedIndication.ts`:
- Around line 515-517: The injected variable uses a fixed name '_tw' (varName
and varDecl) which can collide in minified scopes; change the injection to
generate a collision-safe unique identifier (e.g., prefix like "__tweakcc" plus
a short random/hex suffix or an incrementing counter) and use that generated
name everywhere you currently reference varName (including the varDecl string
using locs.reactVar, locs.textComponent, chalkVar, and tweakccVersion). Ensure
the generator runs once per patch application so the same unique identifier is
used consistently and replace all occurrences of the hardcoded '_tw' in the
patch logic to avoid redeclaration collisions at runtime.
- Around line 508-512: The current PATCH 2 hard-fails when
findTweakccVersionLocations(content) returns null (variable locs), aborting the
whole patchesAppliedIndication flow even if Path A/B (banner/compact text)
succeeded; change the logic in patchesAppliedIndication so that if locs is null
you do not return null but instead log a warning and skip only the Path
C/TweakCC version patch step, continuing to apply/return results for the other
patches; ensure any subsequent code that assumes locs exists checks for its
presence before using it (references: findTweakccVersionLocations, locs, the
PATCH 2 handling block).

In `@src/patches/suppressLineNumbers.ts`:
- Around line 74-76: Replace the generic console.error in suppressLineNumbers.ts
with the repo logger's debug() and make the failure mode specific: when the
signature is found but the boundary/end scan fails, log a distinct debug message
like "suppressLineNumbers: signature found but end not found" before returning
null; also wrap the scanning logic in a try-catch in the containing function
(e.g., the function that searches for the line number formatter signature) and
log caught exceptions with debug() and return the graceful null fallback.
- Around line 28-29: The current funcSig regex used to locate the minified
formatter (the const funcSig pattern matching the {content:...,startLine:...}
helper) is too permissive because of the split([^)]+) fragment; tighten this
anchor to be byte-accurate for minified Claude Code by replacing the ([^)]+)
wildcard with the exact token sequence used in the original minified build (or
extend the pattern with more adjacent minified tokens) so the regex only matches
the precise ".split(...)" invocation in the intended helper; update the funcSig
definition to use those exact characters/escapes (referencing the const funcSig
identifier and the {content:...,startLine:...} / .split(...) sequence) so the
patch cannot accidentally match a similarly-structured helper.

In `@src/patches/toolsets.ts`:
- Around line 1057-1062: The patch currently treats writeComputeToolsFilter
failure as a hard abort (console.error + return null), which makes the toolsets
patch brittle across upstream/minified variants; change this to a safe fallback:
if writeComputeToolsFilter returns falsy, log a warning (not an error), skip the
compute-tools filter step and continue processing the rest of the pipeline so
the patch can still apply other transformations; optionally attempt a secondary,
more permissive match before skipping (i.e., try an alternate pattern) but do
not return null from the toolsets flow — leave result unchanged and proceed.
- Around line 142-143: The regex literal in the patch that currently uses the
word-boundary anchors `\bfunction\b` should be changed to avoid \b; locate the
pattern containing "`function
([$\\w]+)\\([$\\w]+\\)\\{(?:(?!\\bfunction\\b).){0,300}${escapedStore}\\(\\)...useSyncExternalStore\\(`"
and replace the `\bfunction\b` portion with a character-based boundary such as
`function\s` (i.e., use `function\s` or `function(?=\s|[$A-Za-z_])` in the same
regex string) so it matches the same tokens without using \b.

In `@src/patches/userMessageDisplay.ts`:
- Around line 165-176: The current block assumes capture groups exist when
setting createElementFn and messageVar (using oldMatch, match[4], match[5],
match[6], match[7]) and can emit invalid replacement text if captures are
undefined; add a validation guard after computing createElementFn/messageVar
that checks they are non-empty (e.g., if (!createElementFn || !messageVar)), and
if the guard fails log a clear error and fail fast (throw or return the original
input) instead of proceeding to generate replacement code so you never produce
`${undefined}` or a missing callee; reference the variables createElementFn,
messageVar, oldMatch and match to locate where to add the check.
- Around line 152-153: The regex assigned to newPattern uses \b which violates
patch regex guidelines; update the pattern in the newPattern constant by
removing the \b or replacing it with a literal character that actually appears
in the minified output (for example a comma, parenthesis, or space) so the match
remains anchored—adjust the segment between "No content found in user prompt
message" and the following createElement sequence (the portion around
(([$\w]+(?:\.default)?)\.createElement...) ) to use that literal delimiter
instead of \b while keeping the rest of the pattern intact.

---

Outside diff comments:
In `@src/patches/agentsMd.ts`:
- Line 184: The debug call to showDiff is passing mismatched arguments: it uses
file as the first parameter while the start/end indices (earlyReturnStart) were
computed from newFile, and it accidentally repeats earlyReturnStart twice.
Update the call to pass the modified buffer (newFile) as the first argument and
use the correct end index (earlyReturnEnd) instead of repeating earlyReturnStart
so the displayed range matches the indices computed earlier; keep showDiff,
file, newFile, newStr, earlyReturnStart, and earlyReturnEnd in mind when making
the change.

---

Duplicate comments:
In `@src/patches/helpers.ts`:
- Line 299: The regex in findTextComponent uses a leading '\b' which violates
the repo's patch-regex performance rule; replace the leading '\b' with a literal
start alternative such as a non-capturing group like (?:^|[,\;{}\s]) (or a
fixed-width lookbehind for those literals) so the pattern starts with explicit
characters instead of a word-boundary; update the regex used in
findTextComponent (the pattern matching "function ...
color:...,backgroundColor:...,dimColor:...,bold:...") accordingly and run the
provided grep to verify no '\b' remains.

---

Nitpick comments:
In `@src/patches/agentsMd.ts`:
- Around line 140-144: The nested ternary assigning fsExpr is using an
unreachable fallback ('require("fs")') because earlier logic guarantees either
fsMatch or callerFsMatch is present; replace the three-way ternary with a
simpler expression that selects fsMatch[1] when fsMatch exists otherwise
callerFsMatch[1] (e.g., use fsMatch ? fsMatch[1] : callerFsMatch[1] or (fsMatch
?? callerFsMatch)[1]) so fsExpr only depends on fsMatch and callerFsMatch and
the unreachable string literal is removed.

In `@src/patches/autoAcceptPlanMode.ts`:
- Around line 99-106: The fallback using simpleReturnIdx can match the wrong
"return " in beforeReady; change it to iterate backwards over all occurrences of
"return " within beforeReady and validate each candidate by checking the
following characters after that index (from beforeReady.slice(simpleReturnIdx))
match a pattern indicating a React component return—e.g., optional whitespace
then either '<', 'React.createElement', or '(' leading into JSX—until you find a
valid one; update the logic around the simpleReturnIdx lookup (using
beforeReady.lastIndexOf in a loop) so it only accepts a return that is followed
by JSX/React.createElement and otherwise continues searching earlier returns,
returning null only if none validate.

In `@src/patches/increaseFileReadLimit.ts`:
- Line 20: The RegExp assigned to the variable pattern uses an unnecessary
capturing group `([\s\S]{0,200})` which is never read; replace it with a
non-capturing group `(?:[\s\S]{0,200})` in the RegExp construction to avoid the
unused capture overhead in the pattern created in increaseFileReadLimit.ts (the
const pattern = new RegExp(...)). Ensure you keep the surrounding anchors/text
(`=25000,` and `${escaped}`) intact so only the inner group changes.

In `@src/patches/inputPatternHighlighters.ts`:
- Line 177: The variable useMemoCode is dead (initialized as const useMemoCode =
'' and never changed) but still concatenated into replacement and passed to
showDiff; remove the unused const useMemoCode and eliminate its
concatenation/usage in the creation of replacement and the argument list for
showDiff in inputPatternHighlighters.ts (look for symbols useMemoCode,
replacement, and showDiff) so the replacement string and showDiff call no longer
reference this unused placeholder.
- Around line 221-254: The dependency-array injection logic around forLoopIdx /
useMemo uses parenthesis-depth tracking (memoOffset/region/depth) and a
heuristic that the closing ']' directly precedes the closing ')' and that string
literals won't contain unbalanced parens, and the
depsCheck.includes(`,${inputVar}]`) only detects the var at the array end; add a
short inline comment above this block (near the forLoopIdx check and before the
depth loop) documenting these assumptions and the fragility so future
maintainers understand why the heuristic is acceptable for minified code and
what edge cases could break it (unbalanced parens in strings, different
dependency ordering, or the var not being last).

In `@src/patches/patchesAppliedIndication.ts`:
- Line 103: Remove the inactive "PATCH 4" and "PATCH 5" helper functions and
their accompanying ESLint disable comments from patchesAppliedIndication.ts:
delete the helper function declarations (the explicit PATCH 4 and PATCH 5
helpers), any related exports and unused imports, and remove the "//
eslint-disable-next-line `@typescript-eslint/no-unused-vars`" lines that were
silencing them; run a build/TS check to ensure no remaining references and tidy
up any now-unused types or imports.

In `@src/patches/themes.ts`:
- Around line 29-40: The code redundantly calls oldFile.indexOf multiple times
to find the switch anchor; reuse the previously computed oldAnchor and
oldAnchor2 instead of re-scanning the string. Update the logic around oldAnchor,
oldAnchor2 and anchor so that after checking for
'case"dark":return{"autoAccept"' and 'case"light":return{' you set anchor =
oldAnchor !== -1 ? oldAnchor : oldAnchor2 (or similar) and remove the extra
indexOf calls that search for 'case"dark":return{' again; this keeps the same
branching behavior but avoids duplicate string searches in the functions using
oldAnchor, oldAnchor2, and anchor.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 16ea2546-0290-442b-ad42-9cdb68c417b2

📥 Commits

Reviewing files that changed from the base of the PR and between 62ce3fa and 44ec80f.

📒 Files selected for processing (22)
  • src/patches/agentsMd.ts
  • src/patches/allowCustomAgentModels.test.ts
  • src/patches/allowCustomAgentModels.ts
  • src/patches/autoAcceptPlanMode.ts
  • src/patches/helpers.ts
  • src/patches/hideStartupBanner.ts
  • src/patches/hideStartupClawd.ts
  • src/patches/increaseFileReadLimit.ts
  • src/patches/index.ts
  • src/patches/inputBorderBox.ts
  • src/patches/inputPatternHighlighters.ts
  • src/patches/mcpStartup.ts
  • src/patches/patchesAppliedIndication.ts
  • src/patches/scrollEscapeSequenceFilter.ts
  • src/patches/showMoreItemsInSelectMenus.ts
  • src/patches/statuslineUpdateThrottle.ts
  • src/patches/suppressLineNumbers.ts
  • src/patches/themes.ts
  • src/patches/tokenCountRounding.ts
  • src/patches/toolsets.ts
  • src/patches/userMessageDisplay.ts
  • src/patches/voiceMode.ts
✅ Files skipped from review due to trivial changes (1)
  • src/patches/statuslineUpdateThrottle.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/patches/mcpStartup.ts
  • src/patches/scrollEscapeSequenceFilter.ts
  • src/patches/allowCustomAgentModels.ts
  • src/patches/hideStartupClawd.ts
  • src/patches/index.ts
  • src/patches/showMoreItemsInSelectMenus.ts
  • src/patches/tokenCountRounding.ts

Comment on lines +96 to +98
const shimmerPattern = new RegExp(
`if\\(${segVar.replace('$', '\\$')}\\.highlight\\.color\\)return ([$\\w]+)\\.createElement\\([$\\w]+,\\{key:[$\\w]+\\},${segVar.replace('$', '\\$')}\\.text\\.split\\(""\\)\\.map\\([^)]+\\)\\)`
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Incomplete escaping: only the first $ is escaped.

String.replace('$', '\\$') only replaces the first occurrence. If segVar contains multiple $ characters (e.g., $a$b), subsequent ones won't be escaped, causing the regex to malfunction.

🔧 Proposed fix
  const shimmerPattern = new RegExp(
-   `if\\(${segVar.replace('$', '\\$')}\\.highlight\\.color\\)return ([$\\w]+)\\.createElement\\([$\\w]+,\\{key:[$\\w]+\\},${segVar.replace('$', '\\$')}\\.text\\.split\\(""\\)\\.map\\([^)]+\\)\\)`
+   `if\\(${segVar.replace(/\$/g, '\\$')}\\.highlight\\.color\\)return ([$\\w]+)\\.createElement\\([$\\w]+,\\{key:[$\\w]+\\},${segVar.replace(/\$/g, '\\$')}\\.text\\.split\\(""\\)\\.map\\([^)]+\\)\\)`
  );
📝 Committable suggestion

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

Suggested change
const shimmerPattern = new RegExp(
`if\\(${segVar.replace('$', '\\$')}\\.highlight\\.color\\)return ([$\\w]+)\\.createElement\\([$\\w]+,\\{key:[$\\w]+\\},${segVar.replace('$', '\\$')}\\.text\\.split\\(""\\)\\.map\\([^)]+\\)\\)`
);
const shimmerPattern = new RegExp(
`if\\(${segVar.replace(/\$/g, '\\$')}\\.highlight\\.color\\)return ([$\\w]+)\\.createElement\\([$\\w]+,\\{key:[$\\w]+\\},${segVar.replace(/\$/g, '\\$')}\\.text\\.split\\(""\\)\\.map\\([^)]+\\)\\)`
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/inputPatternHighlighters.ts` around lines 96 - 98, The regex
construction in shimmerPattern uses segVar.replace('$', '\\$') which only
escapes the first dollar; update the escape to handle all occurrences (e.g., use
segVar.replace(/\$/g, '\\$') or an escapeRegExp utility) so every '$' in segVar
is escaped before interpolating into the RegExp; ensure the change is applied to
both segVar.replace(...) occurrences inside the RegExp template used when
creating shimmerPattern.

const searchWindow = oldFile.slice(searchStart, match.index);
const inputPattern = /\binput:([$\w]+),/;
const inputMatch = searchWindow.match(inputPattern);
const inputPattern = /\binput:([$\w]+),/g;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Avoid \b in regex patterns per coding guidelines.

The pattern uses \b which should be avoided due to V8 performance issues. Use a literal character alternative instead.

♻️ Proposed fix
-  const inputPattern = /\binput:([$\w]+),/g;
+  const inputPattern = /[,{]input:([$\w]+),/g;

As per coding guidelines: "Avoid \b in regex patterns due to V8 performance issues; use literal character alternatives"

📝 Committable suggestion

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

Suggested change
const inputPattern = /\binput:([$\w]+),/g;
const inputPattern = /[,{]input:([$\w]+),/g;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/inputPatternHighlighters.ts` at line 166, The regex assigned to
inputPattern uses the \b word-boundary (const inputPattern =
/\binput:([$\w]+),/g) which we avoid; replace the \b with a literal-character
alternative that matches either start-of-string or a non-word/non-$/non-_
character (for example an explicit group like (?:^|[^A-Za-z0-9_$]) before
"input:") so the pattern still only matches standalone "input:" tokens; keep the
rest of the pattern (capturing group for the name and trailing comma) and the
global flag.

Comment on lines +508 to 512
const locs = findTweakccVersionLocations(content);
if (!locs) {
console.error('patch: patchesAppliedIndication: patch 2 failed');
return null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t hard-fail PATCH 2 when only Path A/B is present.

findTweakccVersionLocations(content) is currently mandatory; if Path C is absent, patching aborts even when banner/compact text patches already succeeded.

Suggested fix
-    const locs = findTweakccVersionLocations(content);
-    if (!locs) {
-      console.error('patch: patchesAppliedIndication: patch 2 failed');
-      return null;
-    }
+    let patch2Applied = false;
+    if (bannerMatch && bannerMatch.index !== undefined) {
+      patch2Applied = true;
+    }
+
+    const beforeCompactPatch = content;
+    content = content.replace(
+      /([$\w]+\("claude",[$\w]+\)\(" Claude Code) ("\))/,
+      `$1 + tweakcc v${tweakccVersion} $2`
+    );
+    if (content !== beforeCompactPatch) {
+      patch2Applied = true;
+    }
+
+    const locs = findTweakccVersionLocations(content);
+    if (!locs) {
+      if (!patch2Applied) {
+        console.error('patch: patchesAppliedIndication: patch 2 failed');
+        return null;
+      }
+    } else {
+      patch2Applied = true;
+      // existing Path C insertion logic...
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/patchesAppliedIndication.ts` around lines 508 - 512, The current
PATCH 2 hard-fails when findTweakccVersionLocations(content) returns null
(variable locs), aborting the whole patchesAppliedIndication flow even if Path
A/B (banner/compact text) succeeded; change the logic in
patchesAppliedIndication so that if locs is null you do not return null but
instead log a warning and skip only the Path C/TweakCC version patch step,
continuing to apply/return results for the other patches; ensure any subsequent
code that assumes locs exists checks for its presence before using it
(references: findTweakccVersionLocations, locs, the PATCH 2 handling block).

Comment on lines +74 to +76
console.error(
'patch: suppressLineNumbers: failed to find line number formatter pattern'
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Keep the failure mode specific, and use the repo logger.

If the signature is found but the boundary scan fails, this emits the same generic console.error as a total miss. That makes new bundle regressions much harder to diagnose; please log a distinct "signature found, end not found" path through debug() before returning null.

As per coding guidelines, "Implement error handling with try-catch blocks, log errors with debug(), and return graceful fallbacks".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/suppressLineNumbers.ts` around lines 74 - 76, Replace the generic
console.error in suppressLineNumbers.ts with the repo logger's debug() and make
the failure mode specific: when the signature is found but the boundary/end scan
fails, log a distinct debug message like "suppressLineNumbers: signature found
but end not found" before returning null; also wrap the scanning logic in a
try-catch in the containing function (e.g., the function that searches for the
line number formatter signature) and log caught exceptions with debug() and
return the graceful null fallback.

Comment on lines +142 to 143
`function ([$\\w]+)\\([$\\w]+\\)\\{(?:(?!\\bfunction\\b).){0,300}${escapedStore}\\(\\)(?:(?!\\bfunction\\b).){0,300}useSyncExternalStore\\(`
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify no \b boundary anchors remain in regexes for this patch file.
fd -i 'toolsets.ts' src/patches --exec rg -n '\\\\b' {}

Repository: Piebald-AI/tweakcc

Length of output: 212


🏁 Script executed:

sed -n '135,155p' src/patches/toolsets.ts

Repository: Piebald-AI/tweakcc

Length of output: 977


🏁 Script executed:

rg -n '\\\\b' src/patches/toolsets.ts

Repository: Piebald-AI/tweakcc

Length of output: 212


🏁 Script executed:

rg -n 'function' src/patches/toolsets.ts | head -20

Repository: Piebald-AI/tweakcc

Length of output: 2081


Remove \b word-boundary anchors from line 142 regex to follow repo perf guidance.

This pattern uses \bfunction\b, which violates the coding guideline: "Avoid \b in regex patterns due to V8 performance issues; use literal character alternatives." Replace with a character-based pattern:

♻️ Suggested update
 const selectorPat = new RegExp(
-  `function ([$\\w]+)\\([$\\w]+\\)\\{(?:(?!\\bfunction\\b).){0,300}${escapedStore}\\(\\)(?:(?!\\bfunction\\b).){0,300}useSyncExternalStore\\(`
+  `function ([$\\w]+)\\([$\\w]+\\)\\{(?:(?!function\\s).){0,300}${escapedStore}\\(\\)(?:(?!function\\s).){0,300}useSyncExternalStore\\(`
 );

In minified Claude Code, function is always followed by whitespace or an identifier, so function\s provides sufficient boundary detection without V8 performance overhead.

📝 Committable suggestion

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

Suggested change
`function ([$\\w]+)\\([$\\w]+\\)\\{(?:(?!\\bfunction\\b).){0,300}${escapedStore}\\(\\)(?:(?!\\bfunction\\b).){0,300}useSyncExternalStore\\(`
);
const selectorPat = new RegExp(
`function ([$\\w]+)\\([$\\w]+\\)\\{(?:(?!function\\s).){0,300}${escapedStore}\\(\\)(?:(?!function\\s).){0,300}useSyncExternalStore\\(`
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/toolsets.ts` around lines 142 - 143, The regex literal in the
patch that currently uses the word-boundary anchors `\bfunction\b` should be
changed to avoid \b; locate the pattern containing "`function
([$\\w]+)\\([$\\w]+\\)\\{(?:(?!\\bfunction\\b).){0,300}${escapedStore}\\(\\)...useSyncExternalStore\\(`"
and replace the `\bfunction\b` portion with a character-based boundary such as
`function\s` (i.e., use `function\s` or `function(?=\s|[$A-Za-z_])` in the same
regex string) so it matches the same tokens without using \b.

Comment on lines +1057 to +1062
// Step 2b: Patch computeTools() to filter API-bound tools
result = writeComputeToolsFilter(result, toolsets, defaultToolset);
if (!result) {
console.error('patch: toolsets: step 2b failed (writeComputeToolsFilter)');
return null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Step 2b hard-failure makes the toolsets patch brittle across upstream releases.

If writeComputeToolsFilter misses on a new minified variant, the entire toolsets pipeline aborts. This reintroduces the same cross-version fragility this PR is trying to reduce.

🛠️ Safer fallback
-  result = writeComputeToolsFilter(result, toolsets, defaultToolset);
-  if (!result) {
-    console.error('patch: toolsets: step 2b failed (writeComputeToolsFilter)');
-    return null;
-  }
+  const result2b = writeComputeToolsFilter(result, toolsets, defaultToolset);
+  if (!result2b) {
+    console.error(
+      'patch: toolsets: step 2b failed (writeComputeToolsFilter) — continuing with UI-only filtering'
+    );
+  } else {
+    result = result2b;
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/toolsets.ts` around lines 1057 - 1062, The patch currently treats
writeComputeToolsFilter failure as a hard abort (console.error + return null),
which makes the toolsets patch brittle across upstream/minified variants; change
this to a safe fallback: if writeComputeToolsFilter returns falsy, log a warning
(not an error), skip the compute-tools filter step and continue processing the
rest of the pipeline so the patch can still apply other transformations;
optionally attempt a secondary, more permissive match before skipping (i.e., try
an alternate pattern) but do not return null from the toolsets flow — leave
result unchanged and proceed.

Comment on lines +152 to +153
const newPattern =
/(No content found in user prompt message.{0,50}?\b)(([$\w]+(?:\.default)?)\.createElement\([$\w]+,\{flexDirection:"column"[^}]*\},([$\w]+(?:\.default)?\.createElement)\([$\w]+,\{text:([$\w]+)[^}]*\}\)\))/;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n src/patches/userMessageDisplay.ts | head -160 | tail -20

Repository: Piebald-AI/tweakcc

Length of output: 1502


🏁 Script executed:

# Search for context around the "No content found in user prompt message" string
rg "No content found in user prompt message" --context 3

Repository: Piebald-AI/tweakcc

Length of output: 3619


🏁 Script executed:

# Check if there are any test files or related documentation for this patch
fd -i "usermessagedisplay"

Repository: Piebald-AI/tweakcc

Length of output: 140


🏁 Script executed:

# Look at the full patch file to understand the pattern better
wc -l src/patches/userMessageDisplay.ts

Repository: Piebald-AI/tweakcc

Length of output: 99


Replace \b in patch regex with a literal delimiter or remove if subsequent pattern is sufficiently specific.

Line 153 uses \b in a patch regex, which conflicts with repo guidelines that require literal character delimiters instead due to V8 performance issues. The proposed removal works because the subsequent pattern (([$\w]+(?:\.default)?\.createElement\( is specific enough to anchor the match, but consider whether a literal character (,, ), etc.) that actually appears in the minified code would be more precise.

♻️ Proposed change
-  const newPattern =
-    /(No content found in user prompt message.{0,50}?\b)(([$\w]+(?:\.default)?)\.createElement\([$\w]+,\{flexDirection:"column"[^}]*\},([$\w]+(?:\.default)?\.createElement)\([$\w]+,\{text:([$\w]+)[^}]*\}\)\))/;
+  const newPattern =
+    /(No content found in user prompt message.{0,50}?)(([$\w]+(?:\.default)?)\.createElement\([$\w]+,\{flexDirection:"column"[^}]*\},([$\w]+(?:\.default)?\.createElement)\([$\w]+,\{text:([$\w]+)[^}]*\}\)\))/;

Per coding guidelines for **/patches/**/*.{ts,tsx}: Avoid \b in regex patterns due to V8 performance issues; use literal character alternatives.

📝 Committable suggestion

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

Suggested change
const newPattern =
/(No content found in user prompt message.{0,50}?\b)(([$\w]+(?:\.default)?)\.createElement\([$\w]+,\{flexDirection:"column"[^}]*\},([$\w]+(?:\.default)?\.createElement)\([$\w]+,\{text:([$\w]+)[^}]*\}\)\))/;
const newPattern =
/(No content found in user prompt message.{0,50}?)(([$\w]+(?:\.default)?)\.createElement\([$\w]+,\{flexDirection:"column"[^}]*\},([$\w]+(?:\.default)?\.createElement)\([$\w]+,\{text:([$\w]+)[^}]*\}\)\))/;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/userMessageDisplay.ts` around lines 152 - 153, The regex assigned
to newPattern uses \b which violates patch regex guidelines; update the pattern
in the newPattern constant by removing the \b or replacing it with a literal
character that actually appears in the minified output (for example a comma,
parenthesis, or space) so the match remains anchored—adjust the segment between
"No content found in user prompt message" and the following createElement
sequence (the portion around (([$\w]+(?:\.default)?)\.createElement...) ) to use
that literal delimiter instead of \b while keeping the rest of the pattern
intact.

Comment on lines +165 to +176
let createElementFn: string;
let messageVar: string;

if (oldMatch) {
// Old pattern matches
createElementFn = match[4];
messageVar = match[6] ?? match[7];
} else {
// New pattern (CC ≥2.1.79)
createElementFn = match[4];
messageVar = match[5];
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add a capture validation guard before generating replacement code.

Lines 170-175 assume captures are always present. If a boundary case match misses groups, the replacement can emit invalid code (${undefined} / missing callee). Fail fast with a clear log.

🛡️ Proposed change
   if (oldMatch) {
     // Old pattern matches
     createElementFn = match[4];
     messageVar = match[6] ?? match[7];
   } else {
     // New pattern (CC ≥2.1.79)
     createElementFn = match[4];
     messageVar = match[5];
   }
+
+  if (!createElementFn || !messageVar) {
+    console.error(
+      'patch: userMessageDisplay: matched pattern but required captures are missing'
+    );
+    return null;
+  }
📝 Committable suggestion

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

Suggested change
let createElementFn: string;
let messageVar: string;
if (oldMatch) {
// Old pattern matches
createElementFn = match[4];
messageVar = match[6] ?? match[7];
} else {
// New pattern (CC ≥2.1.79)
createElementFn = match[4];
messageVar = match[5];
}
let createElementFn: string;
let messageVar: string;
if (oldMatch) {
// Old pattern matches
createElementFn = match[4];
messageVar = match[6] ?? match[7];
} else {
// New pattern (CC ≥2.1.79)
createElementFn = match[4];
messageVar = match[5];
}
if (!createElementFn || !messageVar) {
console.error(
'patch: userMessageDisplay: matched pattern but required captures are missing'
);
return null;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/userMessageDisplay.ts` around lines 165 - 176, The current block
assumes capture groups exist when setting createElementFn and messageVar (using
oldMatch, match[4], match[5], match[6], match[7]) and can emit invalid
replacement text if captures are undefined; add a validation guard after
computing createElementFn/messageVar that checks they are non-empty (e.g., if
(!createElementFn || !messageVar)), and if the guard fails log a clear error and
fail fast (throw or return the original input) instead of proceeding to generate
replacement code so you never produce `${undefined}` or a missing callee;
reference the variables createElementFn, messageVar, oldMatch and match to
locate where to add the check.

@basekevin basekevin force-pushed the fix-patching-for-2.1.81 branch from 44ec80f to abcf76d Compare April 2, 2026 19:18
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (6)
src/patches/hideStartupBanner.ts (1)

35-52: ⚠️ Potential issue | 🟠 Major

Fragile lookahead: [^}]{0,500} breaks on nested braces.

The lookahead (?=[^}]{0,500}Apple_Terminal) stops matching at the first } character. In minified code, object literals and nested structures frequently introduce } early in function bodies (e.g., function Banner(){var o={x:1};...Apple_Terminal...}), causing the regex to miss valid targets.

Since you already do a manual string search for "Welcome to Claude Code" in the body preview (line 42), applying the same approach for "Apple_Terminal" would be more robust:

Suggested fix
-  const funcPattern = /(function ([$\w]+)\(\)\{)(?=[^}]{0,500}Apple_Terminal)/g;
+  // Match zero-arg named function declarations
+  const funcPattern = /(function [$\w]+\(\)\{)/g;

   let funcMatch: RegExpExecArray | null;
   while ((funcMatch = funcPattern.exec(oldFile)) !== null) {
-    // Verify this function also contains "Welcome to Claude Code"
     const bodyStart = funcMatch.index + funcMatch[0].length;
     const bodyPreview = oldFile.slice(bodyStart, bodyStart + 5000);
-    if (bodyPreview.includes('Welcome to Claude Code')) {
+    // Verify this function contains both banner markers
+    if (
+      bodyPreview.includes('Apple_Terminal') &&
+      bodyPreview.includes('Welcome to Claude Code')
+    ) {
       const insertIndex = bodyStart;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/hideStartupBanner.ts` around lines 35 - 52, The current fragile
regex funcPattern uses a lookahead (?=[^}]{0,500}Apple_Terminal) which breaks on
nested braces; instead simplify funcPattern to only match the function header
(keep /(function ([$\w]+)\(\)\{)/g or the existing left-hand part) and then,
inside the while loop where bodyPreview is computed, check
bodyPreview.includes('Welcome to Claude Code') &&
bodyPreview.includes('Apple_Terminal') (optionally increase the slice length
from 5000 if needed) before performing the insertion of 'return null;' and
returning newFile; update references to funcPattern, funcMatch, bodyPreview,
insertion, showDiff and newFile accordingly.
src/patches/suppressLineNumbers.ts (1)

27-29: ⚠️ Potential issue | 🟠 Major

Tighten the formatter signature and stop the legacy fallback after a signature hit.

split([^)]+) is still much looser than the documented minified helper, and if endPattern misses a new terminator this falls through to arrowPattern, which can patch only the inner arrow branch of the same formatter. Keep the signature byte-accurate and gate the fallback behind !sigMatch.

Based on learnings, patches in src/patches/ are designed to work with original, minified Claude Code installations, not formatted/prettified code; regex patterns should be strict and match the minified format exactly.

Also applies to: 32-49

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/suppressLineNumbers.ts` around lines 27 - 29, The current funcSig
regex is too permissive (uses split([^)]+)) and allows fall-through to
legacy/arrow fallbacks; tighten funcSig to match the exact minified formatter
signature byte-for-byte (no loose [^)]+) and ensure the legacy fallback logic is
only executed when there is no signature match (guard calls to
endPattern/arrowPattern behind a !sigMatch check). Update the corresponding
signature regexes in the same file (the other patterns referenced around lines
32-49) to the strict minified form and modify the branching so that once
sigMatch (funcSig) is true, the legacy fallback paths are not attempted.
src/patches/toolsets.ts (2)

384-390: ⚠️ Potential issue | 🟠 Major

Don't let compute-tools filtering take down the whole toolsets patch.

writeComputeToolsFilter() now returns null before even trying its own closure match when getAppStateSelectorAndUseState() misses, even though this sub-patch only needs the STORE.getState() closure it matches locally. That null then hard-aborts writeToolsets(), so one selector-detection miss disables the UI/toolset pieces too. Drop the selector precondition and only run step 2c when step 2b actually patched.

Also applies to: 1057-1072

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/toolsets.ts` around lines 384 - 390, The current patch logic in
writeComputeToolsFilter bail outs early when
getAppStateSelectorAndUseState(oldFile) returns null, causing writeToolsets() to
abort and disabling UI/toolsets; instead, remove the precondition that returns
null and only perform the closure-specific follow-up (the step 2c matching that
needs the selector) when the prior step 2b actually applied a patch — i.e., keep
writeComputeToolsFilter running and use STORE.getState() closure matching
locally only if the selector-aware change was made; update
writeComputeToolsFilter to not return null on a missing selector
(getAppStateSelectorAndUseState) and gate the step-2c closure-match logic on the
boolean or result that indicates step-2b patched successfully so other toolsets
logic can proceed and writeToolsets() doesn't abort.

140-143: ⚠️ Potential issue | 🟡 Minor

Remove \b from selectorPat.

This selector search still uses \bfunction\b, which the repo explicitly avoids in patch regexes. A literal boundary such as function\s is enough here.

As per coding guidelines, "Avoid \\b in regex patterns due to V8 performance issues; use literal character alternatives".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/toolsets.ts` around lines 140 - 143, The regex assigned to
selectorPat uses the forbidden word-boundary pattern '\bfunction\b'; update it
to avoid '\b' by replacing both instances with a literal whitespace-based
alternative (e.g., 'function\\s' or 'function\\s*') so the pattern still
excludes nested functions but follows the repo guideline; modify the RegExp
construction that references escapedStore and storeFn so the two
'(?!\\bfunction\\b)' fragments become '(?!function\\s)' (or '(?!function\\s*)')
accordingly.
src/patches/inputPatternHighlighters.ts (2)

164-167: ⚠️ Potential issue | 🟡 Minor

Avoid \b in inputPattern.

A literal boundary is enough here; \b is explicitly discouraged for patch regexes that scan the minified bundle.

As per coding guidelines, "Avoid \\b in regex patterns due to V8 performance issues; use literal character alternatives".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/inputPatternHighlighters.ts` around lines 164 - 167, Replace the
word-boundary in the inputPattern with a literal-character alternative: change
the regex assigned to inputPattern (currently /\binput:([$\w]+),/g) to use a
non-word-char or start-of-string boundary such as /(?:^|[^$\w])input:([$\w]+),/g
so it still matches "input:" preceded by start or a non-identifier char without
using \b; keep the same capture group and global flag and update usages like
inputMatches = [...searchWindow.matchAll(inputPattern)] accordingly.

96-98: ⚠️ Potential issue | 🟠 Major

The >=2.1.83 renderer path still isn't fully patched.

segVar.replace('$', '\\$') only escapes the first dollar when re-finding the shimmer branch, and the final splice inserts newMatches2[0] back unchanged. So on $-heavy minified identifiers—or on renderer shapes without the shimmer branch—you still fall through to the original color: seg.highlight?.color path instead of the function-aware render.

Based on learnings, "Use [\$\\w]+ instead of \\w+ for identifier matching in regex patterns to include $ for React refs".

Also applies to: 113-125

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/inputPatternHighlighters.ts` around lines 96 - 98, The shimmer
branch regex and related identifier patterns in
src/patches/inputPatternHighlighters.ts are too permissive and only escape the
first $ in segVar and use \w+ (missing $ in identifiers) which causes falls back
to the color path; fix by escaping all $ occurrences when building regex (use a
global replace on segVar to replace '$' with '\$'), replace all identifier
subpatterns from '\\w+' to '[\\$\\\\w]+' so identifiers can include $ (apply
this to shimmerPattern and the other patterns in the 113-125 region), and ensure
the value you splice back in (the current newMatches2[0] insertion) uses the
escaped/modified string (not the unmodified original) so the function-aware
render branch is reinserted correctly.
🧹 Nitpick comments (2)
src/patches/showMoreItemsInSelectMenus.ts (1)

40-41: Minor: Use [$\w]+ for identifier patterns per coding guidelines.

Lines 41, 70, and 105 use [\w$]+ which is functionally equivalent but the coding guidelines prefer [$\w]+ for consistency across patch files.

Suggested fix for line 41
-    /\{rows:([\w$]+),columns:[\w$]+\}=[\w$]+\(\),([\w$]+)=Math\.floor\(\1\/2\)/;
+    /\{rows:([$\w]+),columns:[$\w]+\}=[$\w]+\(\),([$\w]+)=Math\.floor\(\1\/2\)/;

As per coding guidelines: "Use [\\$\\w]+ instead of \\w+ for identifier matching in regex patterns to include $ for React refs".

Also applies to: 70-70, 105-105

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/showMoreItemsInSelectMenus.ts` around lines 40 - 41, Replace the
identifier character class in the regexes to follow coding guidelines: update
the const pattern (named pattern in showMoreItemsInSelectMenus.ts) and the two
other regex literals in the same file (the other regex variables around the
second and third occurrences) by changing all occurrences of [\w$]+ to [$\w]+ so
identifiers allow $ consistently; ensure you update each regex literal exactly
(no other regex structure changes) and run tests/lint to confirm conformity.
src/patches/autoAcceptPlanMode.ts (1)

98-118: Fallback lastIndexOf('return ') may be fragile.

The simple fallback on lines 100-117 finds the last return keyword within a 500-char window before "Ready to code?". This could match an unrelated return statement if the code structure varies. Consider adding a sanity check that the matched return is followed by a createElement call.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/autoAcceptPlanMode.ts` around lines 98 - 118, The fallback using
lastIndexOf('return ') can match unrelated returns; update the logic around
returnMatch/simpleReturnIdx (using beforeReady and readyIdx) to verify the
located return actually begins a component render by checking that the text
after absoluteReturnIdx (e.g., within the next ~200-400 chars) contains a
createElement/React.createElement/jsx/JSX-like pattern; if the sanity check
fails, continue searching backwards for the previous 'return ' occurrence (loop)
until a match passes the sanity check or give up and return null. Use the same
variables (simpleReturnIdx, absoluteReturnIdx, beforeReady, readyIdx) and only
proceed to build insertion/newFile and call showDiff when the post-return sanity
check confirms a createElement/React.createElement/jsx pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/patches/agentsMd.ts`:
- Around line 127-137: The current lookup uses callerSearch.match(fsPattern)
which returns the first fs-like accessor in the 5000-char window and can pick an
earlier helper; change the logic in agentsMd to search backwards from funcStart
for the nearest fs accessor instead: instead of callerSearch.match(fsPattern),
scan the substring (file.slice(Math.max(0, funcStart - N), funcStart)) from end
to start and use fsPattern.exec in a loop or repeated matches to pick the last
match (nearest to funcStart), updating callerFsMatch accordingly; reference the
variables callerFsMatch, fsPattern, callerSearch, funcStart and replace the
single .match call with a reverse/last-match strategy (or reduce N) so the
injected reroute targets the correct fs object.

In `@src/patches/inputBorderBox.ts`:
- Around line 39-50: Escape any '$' characters in the interpolated identifiers
before building topBorderPattern: sanitize textComp, bottomMatch[2], and
bottomMatch[3] (e.g., replace '$' with an escaped dollar) and then construct
topBorderPattern using those escaped values; perform the content.replace only
when topMatch is truthy and set patched = true only when a replacement actually
occurred (move or gate the patched assignment inside the topMatch conditional or
derive it from the replace result) so failed top-border matching doesn't get
masked.

In `@src/patches/themes.ts`:
- Around line 83-86: The objPat regex is wrong: it allows assignment prefixes
like the pattern in objPat (?:return|[$\w]+=) but the rewrite always emits a
return, and its value-side requires "Auto " (trailing space) while objArrPat
expects "Auto" without space; fix by removing the assignment alternative so
objPat only matches return-prefixed objects (or update the rewrite to
reconstruct an assignment when prefix is an assignment), and make the value
pattern in objPat consistent with objArrPat by changing the Auto part to the
same group (?:Auto|Dark|Light|Monochrome) so the trailing space is not required.
Ensure you update the objPat definition used in themes.ts and keep objArrPat and
the replacement logic consistent with the chosen prefix handling.

---

Duplicate comments:
In `@src/patches/hideStartupBanner.ts`:
- Around line 35-52: The current fragile regex funcPattern uses a lookahead
(?=[^}]{0,500}Apple_Terminal) which breaks on nested braces; instead simplify
funcPattern to only match the function header (keep /(function ([$\w]+)\(\)\{)/g
or the existing left-hand part) and then, inside the while loop where
bodyPreview is computed, check bodyPreview.includes('Welcome to Claude Code') &&
bodyPreview.includes('Apple_Terminal') (optionally increase the slice length
from 5000 if needed) before performing the insertion of 'return null;' and
returning newFile; update references to funcPattern, funcMatch, bodyPreview,
insertion, showDiff and newFile accordingly.

In `@src/patches/inputPatternHighlighters.ts`:
- Around line 164-167: Replace the word-boundary in the inputPattern with a
literal-character alternative: change the regex assigned to inputPattern
(currently /\binput:([$\w]+),/g) to use a non-word-char or start-of-string
boundary such as /(?:^|[^$\w])input:([$\w]+),/g so it still matches "input:"
preceded by start or a non-identifier char without using \b; keep the same
capture group and global flag and update usages like inputMatches =
[...searchWindow.matchAll(inputPattern)] accordingly.
- Around line 96-98: The shimmer branch regex and related identifier patterns in
src/patches/inputPatternHighlighters.ts are too permissive and only escape the
first $ in segVar and use \w+ (missing $ in identifiers) which causes falls back
to the color path; fix by escaping all $ occurrences when building regex (use a
global replace on segVar to replace '$' with '\$'), replace all identifier
subpatterns from '\\w+' to '[\\$\\\\w]+' so identifiers can include $ (apply
this to shimmerPattern and the other patterns in the 113-125 region), and ensure
the value you splice back in (the current newMatches2[0] insertion) uses the
escaped/modified string (not the unmodified original) so the function-aware
render branch is reinserted correctly.

In `@src/patches/suppressLineNumbers.ts`:
- Around line 27-29: The current funcSig regex is too permissive (uses
split([^)]+)) and allows fall-through to legacy/arrow fallbacks; tighten funcSig
to match the exact minified formatter signature byte-for-byte (no loose [^)]+)
and ensure the legacy fallback logic is only executed when there is no signature
match (guard calls to endPattern/arrowPattern behind a !sigMatch check). Update
the corresponding signature regexes in the same file (the other patterns
referenced around lines 32-49) to the strict minified form and modify the
branching so that once sigMatch (funcSig) is true, the legacy fallback paths are
not attempted.

In `@src/patches/toolsets.ts`:
- Around line 384-390: The current patch logic in writeComputeToolsFilter bail
outs early when getAppStateSelectorAndUseState(oldFile) returns null, causing
writeToolsets() to abort and disabling UI/toolsets; instead, remove the
precondition that returns null and only perform the closure-specific follow-up
(the step 2c matching that needs the selector) when the prior step 2b actually
applied a patch — i.e., keep writeComputeToolsFilter running and use
STORE.getState() closure matching locally only if the selector-aware change was
made; update writeComputeToolsFilter to not return null on a missing selector
(getAppStateSelectorAndUseState) and gate the step-2c closure-match logic on the
boolean or result that indicates step-2b patched successfully so other toolsets
logic can proceed and writeToolsets() doesn't abort.
- Around line 140-143: The regex assigned to selectorPat uses the forbidden
word-boundary pattern '\bfunction\b'; update it to avoid '\b' by replacing both
instances with a literal whitespace-based alternative (e.g., 'function\\s' or
'function\\s*') so the pattern still excludes nested functions but follows the
repo guideline; modify the RegExp construction that references escapedStore and
storeFn so the two '(?!\\bfunction\\b)' fragments become '(?!function\\s)' (or
'(?!function\\s*)') accordingly.

---

Nitpick comments:
In `@src/patches/autoAcceptPlanMode.ts`:
- Around line 98-118: The fallback using lastIndexOf('return ') can match
unrelated returns; update the logic around returnMatch/simpleReturnIdx (using
beforeReady and readyIdx) to verify the located return actually begins a
component render by checking that the text after absoluteReturnIdx (e.g., within
the next ~200-400 chars) contains a
createElement/React.createElement/jsx/JSX-like pattern; if the sanity check
fails, continue searching backwards for the previous 'return ' occurrence (loop)
until a match passes the sanity check or give up and return null. Use the same
variables (simpleReturnIdx, absoluteReturnIdx, beforeReady, readyIdx) and only
proceed to build insertion/newFile and call showDiff when the post-return sanity
check confirms a createElement/React.createElement/jsx pattern.

In `@src/patches/showMoreItemsInSelectMenus.ts`:
- Around line 40-41: Replace the identifier character class in the regexes to
follow coding guidelines: update the const pattern (named pattern in
showMoreItemsInSelectMenus.ts) and the two other regex literals in the same file
(the other regex variables around the second and third occurrences) by changing
all occurrences of [\w$]+ to [$\w]+ so identifiers allow $ consistently; ensure
you update each regex literal exactly (no other regex structure changes) and run
tests/lint to confirm conformity.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d4dd1cce-52a0-44f4-ac95-cae5d50327f7

📥 Commits

Reviewing files that changed from the base of the PR and between 44ec80f and abcf76d.

📒 Files selected for processing (19)
  • src/patches/agentsMd.ts
  • src/patches/allowCustomAgentModels.test.ts
  • src/patches/allowCustomAgentModels.ts
  • src/patches/autoAcceptPlanMode.ts
  • src/patches/helpers.ts
  • src/patches/hideStartupBanner.ts
  • src/patches/hideStartupClawd.ts
  • src/patches/increaseFileReadLimit.ts
  • src/patches/inputBorderBox.ts
  • src/patches/inputPatternHighlighters.ts
  • src/patches/patchesAppliedIndication.ts
  • src/patches/scrollEscapeSequenceFilter.ts
  • src/patches/showMoreItemsInSelectMenus.ts
  • src/patches/statuslineUpdateThrottle.ts
  • src/patches/suppressLineNumbers.ts
  • src/patches/themes.ts
  • src/patches/tokenCountRounding.ts
  • src/patches/toolsets.ts
  • src/patches/voiceMode.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/patches/allowCustomAgentModels.test.ts
  • src/patches/scrollEscapeSequenceFilter.ts
  • src/patches/statuslineUpdateThrottle.ts
  • src/patches/hideStartupClawd.ts
  • src/patches/voiceMode.ts

Comment on lines +127 to +137
let callerFsMatch: RegExpMatchArray | null = null;
if (!fsMatch) {
console.error('patch: agentsMd: failed to find fs expression in function');
return null;
// Try the caller function for fs expression
const callerSearch = file.slice(Math.max(0, funcStart - 5000), funcStart);
callerFsMatch = callerSearch.match(fsPattern);
if (!callerFsMatch) {
console.error(
'patch: agentsMd: failed to find fs expression in function or caller'
);
return null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the file structure and locate the file
find . -name "agentsMd.ts" -type f

Repository: Piebald-AI/tweakcc

Length of output: 87


🏁 Script executed:

# Read the relevant section and surrounding context
head -n 160 src/patches/agentsMd.ts | tail -n 60

Repository: Piebald-AI/tweakcc

Length of output: 2029


🏁 Script executed:

# Search for fsPattern definition in the file
rg "fsPattern" src/patches/agentsMd.ts -B 3 -A 3

Repository: Piebald-AI/tweakcc

Length of output: 637


🏁 Script executed:

# Get the full context of the function containing lines 127-137
sed -n '100,160p' src/patches/agentsMd.ts

Repository: Piebald-AI/tweakcc

Length of output: 2079


Replace first-match lookup with nearest-match strategy for caller fs accessor.

The 5000-character lookback window uses callerSearch.match(fsPattern), which captures the first fs-like accessor in the entire prefix, not the one nearest to the target function. If that window contains any earlier helper or wrapper with readFileSync, existsSync, or statSync, the injected reroute will reference the wrong object and generate incorrect fallback behavior.

Consider walking backward from funcStart to find the nearest match, or use a smaller, more contextually relevant lookback window.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/agentsMd.ts` around lines 127 - 137, The current lookup uses
callerSearch.match(fsPattern) which returns the first fs-like accessor in the
5000-char window and can pick an earlier helper; change the logic in agentsMd to
search backwards from funcStart for the nearest fs accessor instead: instead of
callerSearch.match(fsPattern), scan the substring (file.slice(Math.max(0,
funcStart - N), funcStart)) from end to start and use fsPattern.exec in a loop
or repeated matches to pick the last match (nearest to funcStart), updating
callerFsMatch accordingly; reference the variables callerFsMatch, fsPattern,
callerSearch, funcStart and replace the single .match call with a
reverse/last-match strategy (or reduce N) so the injected reroute targets the
correct fs object.

Comment on lines +39 to +50
// Top border: createElement(Text,{color:VAR.bgColor},VAR.text?...Fragment..."─".repeat(...)..."──"):"─".repeat(VAR))
const topBorderPattern = new RegExp(
`createElement\\(${textComp},\\{color:${bottomMatch[2]}\\.bgColor\\},${bottomMatch[2]}\\.text\\?.+?"─"\\.repeat\\(${bottomMatch[3]}\\)\\)`
);
const topMatch = content.match(topBorderPattern);
if (topMatch) {
content = content.replace(
topMatch[0],
`createElement(${textComp},null,"")`
);
}
patched = true;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n src/patches/inputBorderBox.ts | head -60

Repository: Piebald-AI/tweakcc

Length of output: 2932


🏁 Script executed:

# Search for examples in patch files to see if this pattern is common
rg '\[\$\\w\]\+' src/patches/ -A 2 -B 2

Repository: Piebald-AI/tweakcc

Length of output: 48982


Escape $ in captured identifiers before interpolating into topBorderPattern.

The textComp, bottomMatch[2], and bottomMatch[3] values are captured via ([$\w]+), which allows $ as a valid identifier character (e.g., $a, $X5). When interpolated raw into the RegExp constructor at line 40, $ triggers regex syntax (backreferences), breaking pattern matching. Additionally, patched is set unconditionally at line 50 after the bottom border succeeds, masking any failure in top border matching.

Escape each interpolated identifier: bottomMatch[2].replace(/\$/g, '$$') and similarly for bottomMatch[3].

🧰 Tools
🪛 ast-grep (0.42.0)

[warning] 39-41: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(
createElement\\(${textComp},\\{color:${bottomMatch[2]}\\.bgColor\\},${bottomMatch[2]}\\.text\\?.+?"─"\\.repeat\\(${bottomMatch[3]}\\)\\)
)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/inputBorderBox.ts` around lines 39 - 50, Escape any '$'
characters in the interpolated identifiers before building topBorderPattern:
sanitize textComp, bottomMatch[2], and bottomMatch[3] (e.g., replace '$' with an
escaped dollar) and then construct topBorderPattern using those escaped values;
perform the content.replace only when topMatch is truthy and set patched = true
only when a replacement actually occurred (move or gate the patched assignment
inside the topMatch conditional or derive it from the replace result) so failed
top-border matching doesn't get masked.

Comment on lines +83 to +86
// === Theme Name Mapping Object ===
// {dark:"Dark mode",...} or {"dark":"Dark mode",...}
const objPat =
/(?:return|[$\w]+=)\{(?:"?(?:[$\w-]+)"?:"(?:Auto |Dark|Light|Monochrome)[^"]*",?)+\}/;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

head -n 110 src/patches/themes.ts | tail -n +75

Repository: Piebald-AI/tweakcc

Length of output: 1098


🏁 Script executed:

# Get broader context around lines 83-86 and the rewrite logic
head -n 150 src/patches/themes.ts | tail -n +75

Repository: Piebald-AI/tweakcc

Length of output: 1966


🏁 Script executed:

# Find the rewrite logic that uses objPat
rg -A 20 "objPat" src/patches/themes.ts | head -n 80

Repository: Piebald-AI/tweakcc

Length of output: 700


🏁 Script executed:

# Search for test cases or examples that show what the minified code looks like
rg -B 5 -A 5 "Dark mode|Light mode" src/patches/themes.ts | head -n 100

Repository: Piebald-AI/tweakcc

Length of output: 443


🏁 Script executed:

# Look for any test files related to themes patch
find . -type f -name "*.test.*" -o -name "*.spec.*" | xargs rg -l "themes" 2>/dev/null

Repository: Piebald-AI/tweakcc

Length of output: 130


🏁 Script executed:

# Check the complete writeThemes function to understand the replacement context better
sed -n '100,180p' src/patches/themes.ts

Repository: Piebald-AI/tweakcc

Length of output: 1954


🏁 Script executed:

# Look at git history to see when [$\w]+= was added to objPat
git log -p --follow -S '[$\w]+=' -- src/patches/themes.ts | head -n 150

Repository: Piebald-AI/tweakcc

Length of output: 44


🏁 Script executed:

# Check if there are any comments or documentation about the themes patch
rg -B 10 -A 10 "Theme Name Mapping" src/patches/themes.ts

Repository: Piebald-AI/tweakcc

Length of output: 835


🏁 Script executed:

# Look at objArrPat to see the full pattern and understand the inconsistency
sed -n '70,90p' src/patches/themes.ts

Repository: Piebald-AI/tweakcc

Length of output: 851


🏁 Script executed:

# Check if there's a PR or issue discussing this change
git log --oneline --all | head -n 50 | grep -i theme

Repository: Piebald-AI/tweakcc

Length of output: 164


🏁 Script executed:

# Search for any minified code examples or patterns in the codebase
rg "return\{|let.*=\{" --max-count=10 -B 2 -A 2 | head -n 60

Repository: Piebald-AI/tweakcc

Length of output: 50375


🏁 Script executed:

# Check git diff to see what changed in this file recently
git log -p --max-count=5 -- src/patches/themes.ts | head -n 200

Repository: Piebald-AI/tweakcc

Length of output: 44


🏁 Script executed:

# Check the full file to understand the context better
wc -l src/patches/themes.ts

Repository: Piebald-AI/tweakcc

Length of output: 87


🏁 Script executed:

# Look at the entire getThemesLocation function
sed -n '50,130p' src/patches/themes.ts

Repository: Piebald-AI/tweakcc

Length of output: 2063


🏁 Script executed:

# Test the regex patterns to understand their exact behavior
python3 << 'EOF'
import re

# The two patterns from the code
objArrPat = r'\[(?:\.\.\.\[\],)?(?:\{"?label"?:"(?:Dark|Light|Auto|Monochrome)[^"]*","?value"?:"[^"]+"\},?)+\]'
objPat = r'(?:return|[$\w]+=)\{(?:"?(?:[$\w-]+)"?:"(?:Auto |Dark|Light|Monochrome)[^"]*",?)+\}'

# Test cases
test_cases = [
    'return{dark:"Dark mode",light:"Light mode",auto:"Auto mode"}',  # return with "auto" (no space)
    'return{dark:"Dark mode",light:"Light mode","Auto ":"Auto mode"}',  # return with "Auto " (space)
    'let x={dark:"Dark mode",light:"Light mode"}',  # assignment form
    'const themes={auto:"Auto",dark:"Dark mode"}',  # assignment with const
]

print("Testing objPat:")
for test in test_cases:
    match = re.search(objPat, test)
    print(f"  '{test[:50]}...' -> {'MATCH' if match else 'NO MATCH'}")

print("\nTesting objArrPat:")
test_arr_cases = [
    '[{label:"Auto",value:"auto"},{label:"Dark",value:"dark"}]',
    '[{label:"Auto ",value:"auto"}]',  # with space
]
for test in test_arr_cases:
    match = re.search(objArrPat, test)
    print(f"  '{test[:50]}...' -> {'MATCH' if match else 'NO MATCH'}")

# Check the specific "Auto" issue
print("\nChecking Auto with/without space in objPat:")
auto_with_space = 'return{auto:"Auto mode"}'  # Should NOT match (Auto without space)
auto_no_space = 'return{"Auto ":"Auto mode"}'  # Should match
print(f"  auto without space: {auto_with_space} -> {'MATCH' if re.search(objPat, auto_with_space) else 'NO MATCH'}")
print(f"  'Auto ' with space: {auto_no_space} -> {'MATCH' if re.search(objPat, auto_no_space) else 'NO MATCH'}")
EOF

Repository: Piebald-AI/tweakcc

Length of output: 634


The objPat regex has two incompatible issues that break the patch.

First, the pattern (?:return|[$\w]+=) allows bare assignment prefixes like x={...}, but the rewrite always produces return{...}. This creates invalid syntax—a simple assignment gets overwritten with a return statement in the middle of an expression.

Second, objPat requires "Auto " (with trailing space) in the value pattern, while objArrPat uses (?:Dark|Light|Auto|Monochrome) (no space required). If the minified code contains a plain "Auto" value without trailing text, objPat silently fails to match when objArrPat succeeds, causing the patch to abort.

Remove the assignment alternative from the prefix pattern or ensure the rewrite handles both cases. Align the value patterns: either both require the trailing space, or both make it optional with (?:Auto|Dark|Light|Monochrome).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/patches/themes.ts` around lines 83 - 86, The objPat regex is wrong: it
allows assignment prefixes like the pattern in objPat (?:return|[$\w]+=) but the
rewrite always emits a return, and its value-side requires "Auto " (trailing
space) while objArrPat expects "Auto" without space; fix by removing the
assignment alternative so objPat only matches return-prefixed objects (or update
the rewrite to reconstruct an assignment when prefix is an assignment), and make
the value pattern in objPat consistent with objArrPat by changing the Auto part
to the same group (?:Auto|Dark|Light|Monochrome) so the trailing space is not
required. Ensure you update the objPat definition used in themes.ts and keep
objArrPat and the replacement logic consistent with the chosen prefix handling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants