Skip to content

Instantly share code, notes, and snippets.

@sekedus
Last active September 16, 2026 06:24
Show Gist options
  • Select an option

  • Save sekedus/fd4e2810db5231aa9b788b33b82eb74f to your computer and use it in GitHub Desktop.

Select an option

Save sekedus/fd4e2810db5231aa9b788b33b82eb74f to your computer and use it in GitHub Desktop.
Stop Claude Code Extension from Auto-Attaching Your Open Files (VS Code, VSCodium, Cursor).

Claude Code Extension: Fix Auto-Attach

Every time you open a new chat in Claude Code extension, it automatically attaches your currently-open file as context.

This wastes tokens, can leak sensitive files (like .env), and adds noise to every prompt.

This guide shows you how to turn off that feature.


Based on community fix from:


Important

On extension version 2.1.273 and newer, the upstream removed the include/exclude toggle button.
After this patch there is no chip and no toggle — nothing is auto-attached, so there is nothing to Remove per chat.
To include file context you must add it manually each time: type @ to mention a file, or use + > Upload from computer.


🔧 Option 1: Run the Script (Recommended)

Important

Disable auto-update for the "Claude Code for VS Code" extension, otherwise auto-updates will silently overwrite your patched file.

Go to the Extensions tab (Ctrl+Shift+X / Cmd+Shift+X), find "Claude Code for VS Code", and uncheck Auto Update.

When you want to update:

  1. Disable "Claude Code for VS Code" extension
  2. Update to the latest version
  3. Re-enable the extension
  4. Restart Extension
  5. Re-run the script

Windows (PowerShell)

  1. Download or save the fix-auto-attach.ps1 file to your computer.

  2. Open PowerShell in the folder where you saved the script and run:

    # The -Force parameter skips the user confirmation prompt to speed things up
    Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
    .\fix-auto-attach.ps1

    Or apply directly with a one-liner (no script download needed, 2.1.273 only):

    $f = (Get-ChildItem "$env:USERPROFILE\.vscode\extensions\anthropic.claude-code-*\webview\index.js" -Recurse | Select-Object -Last 1).FullName; $c = Get-Content $f -Raw; $c = $c -replace 'let (\w+)=!([A-Za-z_\$][\w\$]*);(\w+)\(\$\.selection\.value,\1,', 'let $1=!1;$3($$.selection.value,$1,'; $c = $c -replace 'applySelectionUpdate\(\$\)\{let J=this\.dismissedSelection;', 'applySelectionUpdate($){if($!==void 0)return;let J=this.dismissedSelection;'; Set-Content $f $c -NoNewline

    ❗ Important: For Cursor replace \.vscode with \.cursor, and for VSCodium with \.vscode-oss.

    Custom path & dry run:

    # Preview the patch against a specific bundle without writing anything
    .\fix-auto-attach.ps1 -Path "C:\path\to\index.js" -DryRun
    
    # Apply to a specific bundle (a file, or a directory containing webview\index.js)
    .\fix-auto-attach.ps1 -Path "C:\path\to\index.js"
  3. Reload VS Code / VSCodium / Cursor:

    • Press Ctrl+Shift+P
    • Type and run: Developer: Reload Window

macOS / Linux (bash)

Run the fix in one command (2.1.273 only):

WV=$(find ~/.vscode{,-server}/extensions -path '*anthropic.claude-code-*/webview/index.js' 2>/dev/null | tail -1)
cp "$WV" "$WV.bak"
perl -i -pe 's{let (\w+)=!([A-Za-z_\$][\w\$]*);(\w+)\(\$\.selection\.value,\1,}{let $1=!1;$3(\$.selection.value,$1,}g; s/applySelectionUpdate\(\$\)\{let J=this\.dismissedSelection;/applySelectionUpdate(\$){if(\$!==void 0)return;let J=this.dismissedSelection;/g' "$WV"

❗ Important: For Cursor replace ~/.vscode with ~/.cursor, and for VSCodium replace with ~/.vscode-oss.

Then press Cmd+Shift+P → Developer: Reload Window.


🛠️ Option 2: Hardcore Mode

Caution

🚨 USE AT YOUR OWN RISK! 🚨

If you want to be absolutely certain that files can't be auto-injected – even if you accidentally click the toggle – use Hardcore mode. It removes the injection code entirely. Any remaining chip/toggle UI stays visible but does nothing (2.1.273+ has no toggle — the selection chip is display-only).

PowerShell:

.\fix-auto-attach.ps1 -Hardcore

Bash:

WV=$(find ~/.vscode{,-server}/extensions -path '*anthropic.claude-code-*/webview/index.js' 2>/dev/null | tail -1)
cp "$WV" "$WV.bak"
perl -0 -i -pe 's{if\(([A-Za-z_\$][\w\$]*)\)if\(\1\.selectedText\)([A-Za-z_\$][\w\$]*)\.push\(\{type:"text",text:`<ide_selection>[\s\S]*?</ide_selection>`\}\);else \2\.push\(\{type:"text",text:`<ide_opened_file>[\s\S]*?</ide_opened_file>`\}\);}{}g' "$WV"

❗ Important: For Cursor replace ~/.vscode with ~/.cursor, and for VSCodium replace with ~/.vscode-oss.


Then Developer: Reload Window (Ctrl+Shift+P / Cmd+Shift+P).


↩️ How to Revert

Want to undo the patch? Restore the backup and reload:

PowerShell:

Get-ChildItem "$env:USERPROFILE\.vscode\extensions\anthropic.claude-code-*\webview\index.js.bak" | ForEach-Object {
    Copy-Item -Path $_.FullName -Destination (Join-Path $_.DirectoryName "index.js") -Force
}

❗ Important: For Cursor replace \.vscode with \.cursor, and for VSCodium with \.vscode-oss.


Bash:

WV=$(find ~/.vscode{,-server}/extensions -path '*anthropic.claude-code-*/webview/index.js' 2>/dev/null | tail -1) && cp -f "$WV.bak" "$WV"

❗ Important: For Cursor replace ~/.vscode with ~/.cursor, and for VSCodium replace with ~/.vscode-oss.


Then Developer: Reload Window (Ctrl+Shift+P / Cmd+Shift+P).


Note

If the extension auto-updated since you applied the patch, the .bak file may be a version behind and causing errors when the extension runs.

In that case, reinstall the extension to get a fresh index.js, or download the same version manually from Open VSX (under Resources) and copy webview/index.js into the extension's webview/ folder.


❓ FAQ

What does the patch actually do?

In 2.1.273 the upstream removed the includeSelection toggle: every non-slash message auto-attaches the current selection (let w1=!r = !isSlashCommand), and the chip renders from session.selection, which reactive effects keep seeded from the IDE. The patch does two things: forces that send flag to false (let w1=!1) so no selection content is sent, and guards applySelectionUpdate to drop non-undefined seeds so the chip never appears. There is no toggle to turn back ON per chat — use @-mentions or the attach-file button for manual context. (On older versions ≤2.1.267 the patch instead flipped the includeSelection useState(true) default to false, keeping the toggle functional.)

Will this break Claude Code?

No. The patch only changes a default value. All features remain functional. The only difference: your open file won't be auto-attached to new conversations.

What if the extension auto-updates?

Auto-updates revert the patch because the extension files get replaced. After an update, just run the script again. The script tells you if the pattern wasn't found.

I get "Patch pattern not found" – what now?

The script tries four patterns — legacy (≤2.1.177, namespace hooks like Ke.useRef), modern (≥2.1.211, direct aliases like Se=useRef), void-0-ref (≥2.1.267, ref alias called with void 0 like =G1(void 0),[L,b]=n(!0),...), and send-flag without toggle (≥2.1.273, let w1=!r;JJ0($.selection.value,w1,...)). If all fail, the extension was updated and the variable names changed.

To debug, unpack the bundle with webcrack:

npx webcrack <path-to-webview>/index.js -o ./unpacked

Then search for ide_opened_file in ./unpacked/deobfuscated.js — the function containing it is your injection producer. On ≤2.1.267, look for the React component that calls it; the chip's toggle state is the useState(!0) / ne(!0) / n(!0) (e.g. includeSelection) in that same component. On ≥2.1.273 there is no toggle — find the .send(...) caller that passes the selection flag (e.g. await $.send(z1,W,w1,{kind:"human"})) and trace where that flag is assigned.

Check the original GitHub comment for updates, or file an issue linking back to it.

Does this affect @-mention attachments, images, or drag-drop?

No. Only the automatic <ide_opened_file> and <ide_selection> injection. Manual attachments still work as expected.

I use Cursor or VSCodium – will the script find it?

Yes. The PowerShell script automatically searches .vscode, .vscode-server, .vscode-oss, .cursor, and .cursor-server extension directories and picks the most recent bundle.


📋 Quick Reference

Action Command
Apply fix (Windows) .\fix-auto-attach.ps1
Apply fix (Mac/Linux) Run the perl one-liner above
Apply fix to a custom bundle .\fix-auto-attach.ps1 -Path "C:\path\to\index.js"
Preview without writing (dry run) .\fix-auto-attach.ps1 -DryRun
Hardcore mode (Windows) .\fix-auto-attach.ps1 -Hardcore
Unpack bundle for inspection npx webcrack <path>/index.js -o ./unpacked
Revert Restore .bak file, reload window
Reload window Ctrl+Shift+P → Developer: Reload Window

How It Works (for the curious)

The auto-attach logic lives in a minified React component inside the extension's webview/index.js. There are four bundle formats the script handles (one-liners in this guide target 2.1.273 / Format D only):

Format A — Legacy namespace hooks (≤2.1.177)

Hooks called via a React namespace variable (e.g. Ke.useRef, Ke.useState):

_=Ke.useRef(!0),[v,x]=Ke.useState(!0)  // true = ON by default

The patch flips the useState default:

_=Ke.useRef(!0),[v,x]=Ke.useState(!1)  // false = OFF by default

The =Ke.useRef(!0) anchor (with leading =) uniquely identifies this useState among the many useState(!0) calls in the bundle.

Format B — Direct hook imports (≥2.1.211)

Hooks destructured as local aliases (e.g. Se=useRef, ne=useState):

_=Se(!0),[C,y]=ne(!0)  // true = ON by default

Patched:

_=Se(!0),[C,y]=ne(!1)  // false = OFF by default

Again the leading = anchors to the useRef-alias assignment, making the match unique.

Format C — Direct hook imports with void-0 ref (≥2.1.267)

Same direct-alias hooks, but the useRef alias is now called with (void 0) instead of (!0), so Format B no longer matches. The toggle state (includeSelection) is anchored by the trailing state sequence:

_=G1(void 0),[L,b]=n(!0),[f,h]=n(!1),[S,a]=n(null)  // true = ON by default

Patched:

_=G1(void 0),[L,b]=n(!1),[f,h]=n(!1),[S,a]=n(null)  // false = OFF by default

The script auto-detects which format your bundle uses and applies the correct pattern. On ≤2.1.267 the toggle button remains fully functional — only the default changes.

Format D — Send-flag without toggle (≥2.1.273)

The includeSelection toggle was removed upstream. The send handler now computes the flag as !isSlashCommand, so every non-slash message auto-attaches the selection:

let w1=!r;JJ0($.selection.value,w1,...),await $.send(z1,W,w1,{kind:"human"})

Forcing the flag alone is not enough: the chip renders from session.selection, which reactive effects keep seeded from the IDE via applySelectionUpdate — so the chip would still appear and demand a manual Remove click. The patch therefore does two things:

let w1=!1;JJ0($.selection.value,w1,...),await $.send(z1,W,w1,{kind:"human"})
applySelectionUpdate($){if($!==void 0)return;let J=this.dismissedSelection;...}

The guard only drops non-undefined seeds; explicit applySelectionUpdate(undefined) calls (clear-on-close, dismiss) and dismissSelection() still run, and manual @-mentions / file upload (separate attachedFiles state) keep working. There is no toggle to flip back ON — standard mode on 2.1.273+ means never auto-attach, no chip shown.

<#
.SYNOPSIS
Disables the auto-attach of open files / selections in Claude Code's IDE extension.
.DESCRIPTION
Patches the Claude Code webview bundle to default the file-attachment chip to OFF
(ide_opened_file / ide_selection no longer injected automatically). The toggle
button remains fully functional — click it ON when you want to attach the current file.
NOTE: in 2.1.273+ the toggle was removed upstream, so standard mode there means
always-off with no chip shown (send flag forced false + selection seeding
neutralized). Manual @-mentions / file upload keep working.
Supports VS Code, VSCodium, and Cursor extensions.
Uses webcrack to unpack the bundle for inspection, then patches the minified bundle.
Use -Hardcore to also excise the injection logic entirely (chip toggle does nothing).
.PARAMETER Hardcore
If set, removes the ide_opened_file/ide_selection injection block entirely
so the chip toggle has no effect — zero chance of accidental injection.
.PARAMETER Path
Custom path to the webview bundle to patch. Accepts either the index.js file
directly, or a directory containing webview\index.js. When omitted, the script
auto-detects the bundle across the standard extension directories.
.PARAMETER DryRun
If set, performs all detection, patching, and validation in memory but writes
NOTHING to disk (no backup, no file change). Prints the exact before/after so
you can review the change before applying it.
.LINK
https://github.com/anthropics/claude-code/issues/24726
https://github.com/anthropics/claude-code/issues/24726#issuecomment-4343376892
https://github.com/anthropics/claude-code/issues/24726#issuecomment-4577281297
.EXAMPLE
.\fix-auto-attach.ps1
Default behaviour: chip starts OFF but can be toggled ON.
.EXAMPLE
.\fix-auto-attach.ps1 -Hardcore
Aggressive: chip toggle does nothing, zero injection possible.
.EXAMPLE
.\fix-auto-attach.ps1 -Path "C:\path\to\index.js" -DryRun
Preview the patch against a custom bundle without writing anything.
#>
param(
[switch]$Hardcore,
[string]$Path,
[switch]$DryRun
)
$ErrorActionPreference = "Stop"
function Truncate-Text {
param(
[string]$Text,
[int]$Length = 300
)
if ($Text.Length -le $Length) { return $Text }
return $Text.Substring(0, $Length) + " ... [truncated]"
}
# --- 1. Locate the webview bundle ---
$bundlePath = $null
if ($Path) {
# Custom path supplied by the user
if (-not (Test-Path $Path)) {
Write-Host "ERROR: Custom path not found: $Path" -ForegroundColor Red
Write-Host ""
exit 1
}
$item = Get-Item $Path
if ($item.PSIsContainer) {
# Directory: prefer webview\index.js (extension root), fall back to
# index.js directly inside (e.g. the webview folder itself)
$candidate = Join-Path $item.FullName "webview\index.js"
if (-not (Test-Path $candidate)) {
$candidate = Join-Path $item.FullName "index.js"
}
if (Test-Path $candidate) {
$bundlePath = (Get-Item $candidate).FullName
} else {
Write-Host "ERROR: No webview\index.js or index.js found in directory: $Path" -ForegroundColor Red
Write-Host ""
exit 1
}
} else {
$bundlePath = $item.FullName
}
} else {
# Auto-detect across the standard extension directories
$searchPaths = @(
"$env:USERPROFILE\.vscode\extensions",
"$env:USERPROFILE\.vscode-server\extensions",
"$env:USERPROFILE\.vscode-oss\extensions",
"$env:USERPROFILE\.cursor\extensions",
"$env:USERPROFILE\.cursor-server\extensions"
)
$bundles = @()
foreach ($base in $searchPaths) {
$found = Get-ChildItem "$base\anthropic.claude-code-*\webview\index.js" -ErrorAction SilentlyContinue
$bundles += $found
}
Write-Host ""
if ($bundles.Count -eq 0) {
Write-Host "ERROR: No Claude Code extension webview found." -ForegroundColor Red
Write-Host ""
Write-Host "Checked paths:" -ForegroundColor Red
foreach ($p in $searchPaths) {
Write-Host " - ${p}\anthropic.claude-code-*\webview\index.js"
}
Write-Host ""
Write-Host "Tip: pass -Path to point at a specific bundle." -ForegroundColor Yellow
Write-Host ""
exit 1
}
if ($bundles.Count -gt 1) {
Write-Host "WARNING: Multiple Claude Code extensions found!" -ForegroundColor Yellow
foreach ($b in $bundles) {
Write-Host " $($b.FullName)"
}
Write-Host ""
Write-Host "Using the most recent: $($bundles[-1].FullName)" -ForegroundColor Cyan
Write-Host ""
}
$bundlePath = $bundles[-1].FullName
}
Write-Host ""
Write-Host "Found: $bundlePath" -ForegroundColor Green
# Extract version from extension path for display
if ($bundlePath -match 'anthropic\.claude-code-([^\\]+)') {
Write-Host "Extension version: $($matches[1])" -ForegroundColor Cyan
}
Write-Host ""
# --- 2. Create a backup ---
$backupPath = "${bundlePath}.bak"
if ($DryRun) {
Write-Host "DRY RUN: skipping backup creation." -ForegroundColor Yellow
} elseif (-not (Test-Path $backupPath)) {
Copy-Item $bundlePath $backupPath
Write-Host "Backup created: $backupPath" -ForegroundColor Cyan
} else {
Write-Host "Backup already exists: $backupPath (skipping)" -ForegroundColor Yellow
}
Write-Host ""
# --- 3. Read the bundle ---
$content = Get-Content $bundlePath -Raw
$oldContent = $content
# --- 4. Apply patch ---
$modeLabel = if ($Hardcore) { "HARDCORE" } else { "STANDARD" }
$patchType = $null
$beforeSnippets = @()
$afterSnippets = @()
if ($Hardcore) {
# ----------------------------------------------------------------
# Hardcore mode: remove the if(J){...ide_opened_file...} block
# from the injection function entirely.
# The chip stays visible but no selection content is ever injected.
#
# Works for all bundle formats (2.1.177, 2.1.211, 2.1.267, 2.1.273).
# ----------------------------------------------------------------
$pattern = 'if\(([A-Za-z_\$][\w\$]*)\)if\(\1\.selectedText\)([A-Za-z_\$][\w\$]*)\.push\(\{type:"text",text:`<ide_selection>[\s\S]*?</ide_selection>`\}\);else \2\.push\(\{type:"text",text:`<ide_opened_file>[\s\S]*?</ide_opened_file>`\}\);'
$matchH = [regex]::Match($content, $pattern)
$beforeSnippet = $matchH.Value
$afterSnippet = ""
$content = $content -replace $pattern, ''
} else {
# ----------------------------------------------------------------
# Standard mode: flip useState(!0) -> useState(!1) so the chip
# defaults to OFF but the user can still toggle it ON per chat.
#
# Three bundle formats are supported:
#
# Format A (<=2.1.177): =Ke.useRef(!0),[v,x]=Ke.useState(!0)
# React hooks called via namespace (Ke.useRef / Ke.useState).
# Anchored on the leading = + distinctive useRef(!0) before useState(!0).
#
# Format B (>=2.1.211): =Se(!0),[C,y]=ne(!0)
# React hooks imported as direct aliases (Se=useRef, ne=useState).
# The leading = anchors to the useRef-alias assignment, making the
# generic `FUNC(!0),[X,Y]=FUNC(!0)` match unique and robust.
#
# Format C (>=2.1.267): =G1(void 0),[L,b]=n(!0),[f,h]=n(!1),[S,a]=n(null)
# Same direct-alias hooks, but the useRef alias is now called with
# (void 0) instead of (!0), so Format B no longer matches. The toggle
# state [L,b] (= includeSelection) is anchored by the trailing
# `,[f,h]=n(!1),[S,a]=n(null)` state sequence, making the match unique.
#
# Format D (>=2.1.273): let w1=!r;JJ0($.selection.value,w1,...),await $.send(z1,W,w1,{kind:"human"})
# The includeSelection toggle was removed upstream: the send flag is now
# just !isSlashCommand, so every non-slash message auto-attaches the
# selection. Two changes are applied:
# (D) force the flag to !1 (false) so no selection CONTENT is sent;
# (E) guard applySelectionUpdate to drop non-undefined seeds so the
# CHIP never appears (it renders from session.selection, which is
# seeded by reactive effects — D alone would leave the chip
# visible, requiring a manual Remove click each time).
# D is anchored on `($.selection.value,FLAG,` so the match is unique.
# The `!VAR` (letter) requirement keeps this from matching older
# formats or the already-patched `let w1=!1;...` form. E is anchored
# on the dismissedSelection body unique to 2.1.273 (older formats have
# a plain `applySelectionUpdate($){this.selection.value=$}` or none).
# NOTE: with no toggle in the UI, standard mode on 2.1.273+ means
# always-off. Manual @-mentions / file upload use a different path
# (attachedFiles state) and keep working.
# ----------------------------------------------------------------
# Pattern A — legacy namespace hooks (2.1.177 and similar)
# Matches: =Ke.useRef(!0),[v,x]=Ke.useState(!0)
# Anchored on leading = to avoid false positives.
$patternA = '=(\w+)\.useRef\(!0\),\[(\w+),(\w+)\]=(\w+)\.useState\(!0\)'
$matchA = [regex]::Match($content, $patternA)
if ($matchA.Success) {
Write-Host "Detected bundle format: legacy namespace hooks (2.1.177 style)." -ForegroundColor Cyan
$content = $content -replace $patternA, '=$1.useRef(!0),[$2,$3]=$4.useState(!1)'
$patchType = "legacy"
$beforeSnippet = $matchA.Value
$afterSnippet = $matchA.Value -replace $patternA, '=$1.useRef(!0),[$2,$3]=$4.useState(!1)'
} else {
# Pattern B — direct hook imports (2.1.211+)
# Matches: =Se(!0),[C,y]=ne(!0)
# The leading = anchors this to the assignment of the useRef alias.
$patternB = '=(\w+)\(!0\),\[(\w+),(\w+)\]=(\w+)\(!0\)'
$matchB = [regex]::Match($content, $patternB)
if ($matchB.Success) {
Write-Host "Detected bundle format: direct hook imports (2.1.211+ style)." -ForegroundColor Cyan
$content = $content -replace $patternB, '=$1(!0),[$2,$3]=$4(!1)'
$patchType = "modern"
$beforeSnippet = $matchB.Value
$afterSnippet = $matchB.Value -replace $patternB, '=$1(!0),[$2,$3]=$4(!1)'
} else {
# Pattern C — direct hook imports with (void 0) ref (2.1.267+)
# Matches: =G1(void 0),[L,b]=n(!0),[f,h]=n(!1),[S,a]=n(null)
# [L,b] is the includeSelection toggle; flip n(!0) -> n(!1).
$patternC = '=(\w+)\(void 0\),\[(\w+),(\w+)\]=(\w+)\(!0\),\[(\w+),(\w+)\]=(\w+)\(!1\),\[(\w+),(\w+)\]=(\w+)\(null\)'
$matchC = [regex]::Match($content, $patternC)
if ($matchC.Success) {
Write-Host "Detected bundle format: direct hook imports with void-0 ref (2.1.267+ style)." -ForegroundColor Cyan
$content = $content -replace $patternC, '=$1(void 0),[$2,$3]=$4(!1),[$5,$6]=$7(!1),[$8,$9]=${10}(null)'
$patchType = "v267"
$beforeSnippet = $matchC.Value
$afterSnippet = $matchC.Value -replace $patternC, '=$1(void 0),[$2,$3]=$4(!1),[$5,$6]=$7(!1),[$8,$9]=${10}(null)'
} else {
# Pattern D — send-flag without toggle (2.1.273+)
# Matches: let w1=!r;JJ0($.selection.value,w1,
# Forces the flag to !1 so the selection is never auto-attached.
$patternD = 'let (\w+)=!([A-Za-z_\$][\w\$]*);(\w+)\(\$\.selection\.value,\1,'
$matchD = [regex]::Match($content, $patternD)
if ($matchD.Success) {
Write-Host "Detected bundle format: send-flag without toggle (2.1.273+ style)." -ForegroundColor Cyan
$content = $content -replace $patternD, 'let $1=!1;$3($$.selection.value,$1,'
$patchType = "v273"
$beforeSnippets += $matchD.Value
$afterSnippets += ($matchD.Value -replace $patternD, 'let $1=!1;$3($$.selection.value,$1,')
# Pattern E — neutralize selection seeding (2.1.273+ only).
# Pattern D alone stops the CONTENT from being sent, but the
# CHIP is driven separately: reactive effects copy the IDE
# selection into session.selection via applySelectionUpdate,
# and the chip renders from that. So the chip would still
# appear (requiring a manual Remove click each time).
# Matches: applySelectionUpdate($){let J=this.dismissedSelection;
# Guarded so only non-undefined seeds are dropped: explicit
# applySelectionUpdate(undefined) calls (clear-on-close,
# dismiss) still run, and dismissSelection() is untouched.
# Manual @-mentions / file upload use a different path
# (attachedFiles state) and keep working.
$patternE = 'applySelectionUpdate\(\$\)\{let J=this\.dismissedSelection;'
$matchE = [regex]::Match($content, $patternE)
if ($matchE.Success) {
$content = $content -replace $patternE, 'applySelectionUpdate($){if($!==void 0)return;let J=this.dismissedSelection;'
$beforeSnippets += $matchE.Value
$afterSnippets += ($matchE.Value -replace $patternE, 'applySelectionUpdate($){if($!==void 0)return;let J=this.dismissedSelection;')
} else {
Write-Host "WARNING: Seeding-neutralize anchor not found (2.1.273) - chip may still appear." -ForegroundColor Yellow
}
} else {
Write-Host "ERROR: No recognized chip-toggle pattern found in the bundle ($modeLabel mode)." -ForegroundColor Red
Write-Host ""
Write-Host "The extension version may have changed. Check the original issues for updated anchors:" -ForegroundColor Yellow
Write-Host " https://github.com/anthropics/claude-code/issues/24726#issuecomment-4343376892" -ForegroundColor Yellow
Write-Host " https://github.com/anthropics/claude-code/issues/24726#issuecomment-4577281297" -ForegroundColor Yellow
Write-Host ""
exit 1
}
}
}
}
}
if ($content -ceq $oldContent) {
Write-Host "ERROR: Patch pattern matched but replacement produced no change ($modeLabel mode)." -ForegroundColor Red
Write-Host ""
exit 1
}
if ($DryRun) {
Write-Host "DRY RUN: no changes written to disk." -ForegroundColor Yellow
Write-Host ""
if ($beforeSnippets.Count -gt 0) {
for ($i = 0; $i -lt $beforeSnippets.Count; $i++) {
if ($beforeSnippets.Count -gt 1) { Write-Host " [change $($i + 1)/$($beforeSnippets.Count)]" -ForegroundColor Cyan }
Write-Host " BEFORE: $(Truncate-Text $beforeSnippets[$i])" -ForegroundColor Red
Write-Host " AFTER: $(Truncate-Text $afterSnippets[$i])" -ForegroundColor Green
Write-Host ""
}
} else {
Write-Host " BEFORE: $(Truncate-Text $beforeSnippet)" -ForegroundColor Red
Write-Host " AFTER: $(Truncate-Text $afterSnippet)" -ForegroundColor Green
Write-Host ""
}
Write-Host "Re-run WITHOUT -DryRun to apply this patch." -ForegroundColor Yellow
Write-Host ""
} else {
Set-Content $bundlePath -Value $content -NoNewline
Write-Host "Patch applied successfully! ($modeLabel mode)" -ForegroundColor Green
Write-Host ""
}
# --- 5. Validate ---
if ($Hardcore) {
# Check if any <ide_selection> injection blocks remain (the producer, not the parser)
$stillPresent = $content -match 'if\(\w+\)if\(\w+\.selectedText\)\w+\.push\(\{type:"text",text:`<ide_selection>'
if ($stillPresent) {
Write-Host "WARNING: ide_selection injection block still present in bundle -- patch may be incomplete." -ForegroundColor Yellow
} else {
Write-Host "Validation: ide_selection injection block removed from bundle." -ForegroundColor Green
}
} else {
if ($patchType -eq "legacy") {
# Check the flipped pattern — the =useRef(!0), prefix makes it unique
$matchCount = [regex]::Matches($content, '=\w+\.useRef\(!0\),\[\w+,\w+\]=\w+\.useState\(!1\)').Count
if ($matchCount -eq 1) {
Write-Host "Validation: 1 patched anchor found (legacy format, expected)." -ForegroundColor Green
} else {
Write-Host "WARNING: Expected 1 patched anchor (legacy), found $matchCount." -ForegroundColor Yellow
}
} elseif ($patchType -eq "modern") {
# Check the ORIGINAL pattern is gone — the flipped pattern has false
# positives against other `(!1)` states in the same component.
$origCount = [regex]::Matches($content, '=\w+\(!0\),\[\w+,\w+\]=\w+\(!0\)').Count
if ($origCount -eq 0) {
Write-Host "Validation: original pattern removed (modern format, expected)." -ForegroundColor Green
} else {
Write-Host "WARNING: Original pattern still has $origCount matches (modern)." -ForegroundColor Yellow
}
} elseif ($patchType -eq "v267") {
# v267: check the ORIGINAL pattern is gone — same false-positive concern.
$origCount = [regex]::Matches($content, '=\w+\(void 0\),\[\w+,\w+\]=\w+\(!0\),\[\w+,\w+\]=\w+\(!1\),\[\w+,\w+\]=\w+\(null\)').Count
if ($origCount -eq 0) {
Write-Host "Validation: original pattern removed (2.1.267 format, expected)." -ForegroundColor Green
} else {
Write-Host "WARNING: Original pattern still has $origCount matches (2.1.267)." -ForegroundColor Yellow
}
} else {
# v273: the ORIGINAL send-flag must be gone and exactly one patched
# flag must exist. The `!VAR` (letter) anchor keeps the original check
# from matching the patched `let w1=!1;...` form. The seeding guard
# must also be present exactly once.
$origCount = [regex]::Matches($content, 'let \w+=![A-Za-z_\$][\w\$]*;\w+\(\$\.selection\.value,\w+,').Count
$newCount = [regex]::Matches($content, 'let \w+=!1;\w+\(\$\.selection\.value,\w+,').Count
$seedCount = [regex]::Matches($content, 'applySelectionUpdate\(\$\)\{if\(\$\!==void 0\)return;let J=this\.dismissedSelection;').Count
if (($origCount -eq 0) -and ($newCount -eq 1) -and ($seedCount -eq 1)) {
Write-Host "Validation: send-flag forced to false + seeding neutralized (2.1.273 format, expected)." -ForegroundColor Green
} else {
Write-Host "WARNING: Expected 0 original / 1 patched send-flag / 1 seeding guard (2.1.273), found $origCount / $newCount / $seedCount." -ForegroundColor Yellow
}
}
}
# --- 6. Instructions ---
$reloadKey = if ($env:OS -match 'Windows_NT') { "Ctrl+Shift+P" } else { "Cmd+Shift+P" }
Write-Host ""
if ($DryRun) {
Write-Host "============================================" -ForegroundColor Cyan
Write-Host " DRY RUN - Nothing was written to disk." -ForegroundColor Cyan
Write-Host "============================================" -ForegroundColor Cyan
Write-Host " Re-run WITHOUT -DryRun to apply the patch." -ForegroundColor White
Write-Host ""
} else {
Write-Host "============================================" -ForegroundColor Cyan
Write-Host " ${modeLabel} MODE - Fix applied!" -ForegroundColor Cyan
Write-Host "============================================" -ForegroundColor Cyan
Write-Host " 1. Press $reloadKey in VS Code / VSCodium / Cursor" -ForegroundColor White
Write-Host " 2. Run: `"Developer: Reload Window`"" -ForegroundColor White
Write-Host " 3. The auto-attach chip will now start OFF in new chats." -ForegroundColor White
Write-Host ""
Write-Host "To revert, restore the backup:" -ForegroundColor Yellow
Write-Host " Copy-Item -Path '${backupPath}' -Destination '${bundlePath}' -Force" -ForegroundColor Yellow
Write-Host ""
Write-Host "Then reload the window." -ForegroundColor Yellow
Write-Host ""
}
@sekedus

sekedus commented Jun 14, 2026 •

Copy link
Copy Markdown
Author

Tested on: Claude Code for VS Code 2.1.273

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