Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Stop native `--apply` from bloating the patched binary with a large zero-padding gap on Linux/ELF installs: the rebuilt `.bun` section was placed at LIEF's `nextVirtualAddress()` (which rounds up to a coarse boundary) and extending the writable segment to reach it materialized the virtual-address gap as real zero bytes in the file (Claude Code 2.1.218 grew from 273MB to 721MB, ~59% zeros); it is now placed immediately after the writable segment when that segment is topmost, cutting the same patched binary to ~460MB (#915) - @StreamDemon
- Stop `--apply` corrupting non-ASCII characters in double- and single-quoted system prompts on native installs: the `\uXXXX` encoding for Bun's Latin-1 module ran before the backslash-doubling from #664, so the doubling escaped the backslash the encoder had just emitted and an em dash reached Claude Code as the literal text `\u2014`; the encoding now runs after the string-literal escaping (#920) - @StreamDemon
- Decode `\"` and `\'` when generating a system prompt's markdown, so the file shows the prompt text instead of JavaScript string-literal syntax and `--apply` stops embedding a real backslash where the bundle only had a quote; this is applied to prompts that are plain text end to end, since inside a `${...}` interpolation those escapes belong to nested JavaScript and decoding them would make the prompt look unterminated and be skipped (#921) - @StreamDemon
- Add an opt-in patch that prevents Claude Code from loading enterprise settings delivered by Anthropic or a gateway (#725) - @mike1858

## [v4.3.2](https://github.com/Piebald-AI/tweakcc/releases/tag/v4.3.2) - 2026-07-20

Expand Down
1 change: 1 addition & 0 deletions src/defaultSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ export const DEFAULT_SETTINGS: Settings = {
suppressLineNumbers: false,
suppressRateLimitOptions: false,
suppressRateLimitWarning: false,
disableServerManagedSettings: false,
mcpConnectionNonBlocking: true,
mcpServerBatchSize: null,
statuslineThrottleMs: null,
Expand Down
96 changes: 96 additions & 0 deletions src/patches/disableServerManagedSettings.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { describe, expect, it } from 'vitest';
import { writeDisableServerManagedSettings } from './disableServerManagedSettings';

const makeEligibilityGate = (
delimiter = '}',
names = {
fn: 'cEe',
cache: 'lEe',
overridePath: 'JOe',
recordDecision: 'XOe',
provider: 'Hn',
gatewayConfig: 'Cy',
isGatewayEnabled: 'B5e',
}
) =>
`${delimiter}function ${names.fn}(){if(${names.cache}!==void 0)return ${names.cache};if(${names.overridePath}())return ${names.cache}=${names.recordDecision}(!0);if(${names.provider}()==="gateway")return ${names.cache}=${names.recordDecision}(${names.isGatewayEnabled}(${names.gatewayConfig}()));if(${names.provider}()!=="firstParty")return ${names.cache}=${names.recordDecision}(!1);return ${names.cache}=${names.recordDecision}(!1)}`;

describe('writeDisableServerManagedSettings', () => {
it('disables the Claude Code 2.1.220 remote settings eligibility gate', () => {
const input =
makeEligibilityGate() +
'function JUs(){if(cEe())Pmt=new Promise(e=>{})}' +
'function Vu_(){return `${Rs().BASE_API_URL}/api/claude_code/settings`}';

const result = writeDisableServerManagedSettings(input);

expect(result).not.toBeNull();
expect(result).toContain('function cEe(){return !1;if(lEe!==void 0)');
expect(result).toContain('function JUs(){if(cEe())');
expect(result).toContain('/api/claude_code/settings');
});

it('supports the formatted Claude Code 2.1.220 syntax', () => {
const input = `}
function cEe() {
if (lEe !== void 0) return lEe;
if (JOe()) return (lEe = XOe(!0));
if (Hn() === "gateway") return (lEe = XOe(B5e(Cy())));
if (Hn() !== "firstParty") return (lEe = XOe(!1));
return (lEe = XOe(!1));
}
`;

const result = writeDisableServerManagedSettings(input);

expect(result).not.toBeNull();
expect(result).toMatch(/function cEe\(\) \{\s*return !1;/);
});

it('matches independently of minified identifier names', () => {
const input = makeEligibilityGate(';', {
fn: '$a',
cache: 'B$2',
overridePath: 'Q0',
recordDecision: 'r$9',
provider: 'zZ',
gatewayConfig: 'C$y',
isGatewayEnabled: 'm4',
});

const result = writeDisableServerManagedSettings(input);

expect(result).not.toBeNull();
expect(result).toContain('function $a(){return !1;if(B$2!==void 0)');
});

it('returns the file unchanged when already patched', () => {
const patched = writeDisableServerManagedSettings(makeEligibilityGate())!;

expect(writeDisableServerManagedSettings(patched)).toBe(patched);
});

it('supports all efficient boundary delimiters', () => {
for (const delimiter of [',', ';', '}', '{']) {
const result = writeDisableServerManagedSettings(
makeEligibilityGate(delimiter)
);
expect(result).not.toBeNull();
expect(result).toContain('(){return !1;if(');
}
});

it('does not patch a generic memoized boolean helper', () => {
const input =
'}function other(){if(cache!==void 0)return cache;if(hasOverride())return cache=record(!0);return cache=record(!1)}';

expect(writeDisableServerManagedSettings(input)).toBeNull();
});

it('returns null for a partial remote settings gate', () => {
const input =
'}function cEe(){if(lEe!==void 0)return lEe;if(JOe())return lEe=XOe(!0);if(Hn()==="gateway")return true}';

expect(writeDisableServerManagedSettings(input)).toBeNull();
});
});
54 changes: 54 additions & 0 deletions src/patches/disableServerManagedSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { debug } from '../utils';
import { showDiff } from './index';

/**
* Disable Claude Code's server-managed settings eligibility gate.
*
* This gate controls the initial load, cache use, refresh, and polling paths for
* settings delivered by Anthropic's API or a configured gateway. Local managed
* settings files use separate loaders and intentionally remain unaffected.
*
* CC 2.1.220:
* ```diff
* function cEe(){
* + return !1;
* if(lEe!==void 0)return lEe;
* if(JOe())return lEe=XOe(!0);
* if(Hn()==="gateway")return lEe=XOe(B5e(Cy()));
* ```
*/
export const writeDisableServerManagedSettings = (
oldFile: string
): string | null => {
const alreadyPatched =
/[,;{}]\s*function\s+([$\w]+)\s*\(\s*\)\s*\{\s*return\s+!1;\s*if\s*\(\s*([$\w]+)\s*!==\s*void\s+0\s*\)\s*return\s+\2;\s*if\s*\(\s*([$\w]+)\s*\(\s*\)\s*\)\s*return\s+\(?\s*\2\s*=\s*[$\w]+\s*\(\s*!0\s*\)\s*\)?;\s*if\s*\(\s*([$\w]+)\s*\(\s*\)\s*===\s*"gateway"\s*\)\s*return\s+\(?\s*\2\s*=\s*[$\w]+\s*\(/;
if (alreadyPatched.test(oldFile)) return oldFile;

// The override-file and gateway branches uniquely identify the remote-settings
// eligibility helper without depending on minified names from a specific build.
const pattern =
/[,;{}]\s*function\s+([$\w]+)\s*\(\s*\)\s*\{\s*if\s*\(\s*([$\w]+)\s*!==\s*void\s+0\s*\)\s*return\s+\2;\s*if\s*\(\s*([$\w]+)\s*\(\s*\)\s*\)\s*return\s+\(?\s*\2\s*=\s*[$\w]+\s*\(\s*!0\s*\)\s*\)?;\s*if\s*\(\s*([$\w]+)\s*\(\s*\)\s*===\s*"gateway"\s*\)\s*return\s+\(?\s*\2\s*=\s*[$\w]+\s*\(/;
const match = oldFile.match(pattern);

if (!match || match.index === undefined) {
debug(
'patch: disableServerManagedSettings: failed to find remote settings eligibility gate'
);
return null;
}

const functionBodyOffset = match[0].indexOf('{', 1) + 1;
if (functionBodyOffset === 0) {
debug(
'patch: disableServerManagedSettings: matched eligibility gate without a function body'
);
return null;
}
const insertIndex = match.index + functionBodyOffset;
const insertion = 'return !1;';
const newFile =
oldFile.slice(0, insertIndex) + insertion + oldFile.slice(insertIndex);

showDiff(oldFile, newFile, insertion, insertIndex, insertIndex);
return newFile;
};
12 changes: 12 additions & 0 deletions src/patches/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import { writeIncreaseFileReadLimit } from './increaseFileReadLimit';
import { writeSuppressLineNumbers } from './suppressLineNumbers';
import { writeSuppressRateLimitOptions } from './suppressRateLimitOptions';
import { writeSuppressRateLimitWarning } from './suppressRateLimitWarning';
import { writeDisableServerManagedSettings } from './disableServerManagedSettings';
import { writeSessionMemory } from './sessionMemory';
import { writeRememberSkill } from './rememberSkill';
import { writeThinkingBlockStyling } from './thinkingBlockStyling';
Expand Down Expand Up @@ -355,6 +356,13 @@ const PATCH_DEFINITIONS = [
description:
'Rate limit warning banners will be suppressed (errors still shown)',
},
{
id: 'disable-server-managed-settings',
name: 'Disable server-managed settings',
group: PatchGroup.MISC_CONFIGURABLE,
description:
'Prevent Claude Code from loading enterprise settings delivered by a server',
},
{
id: 'token-count-rounding',
name: 'Token count rounding',
Expand Down Expand Up @@ -859,6 +867,10 @@ export const applyCustomization = async (
fn: c => writeSuppressRateLimitWarning(c),
condition: !!config.settings.misc?.suppressRateLimitWarning,
},
'disable-server-managed-settings': {
fn: c => writeDisableServerManagedSettings(c),
condition: !!config.settings.misc?.disableServerManagedSettings,
},
'token-count-rounding': {
fn: c =>
writeTokenCountRounding(c, config.settings.misc!.tokenCountRounding!),
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export interface MiscConfig {
suppressLineNumbers: boolean;
suppressRateLimitOptions: boolean;
suppressRateLimitWarning: boolean;
disableServerManagedSettings: boolean;
mcpConnectionNonBlocking: boolean;
mcpServerBatchSize: number | null;
statuslineThrottleMs: number | null;
Expand Down
15 changes: 15 additions & 0 deletions src/ui/components/MiscView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export function MiscView({ onSubmit }: MiscViewProps) {
suppressLineNumbers: false,
suppressRateLimitOptions: false,
suppressRateLimitWarning: false,
disableServerManagedSettings: false,
mcpConnectionNonBlocking: true,
mcpServerBatchSize: null as number | null,
statuslineThrottleMs: null as number | null,
Expand Down Expand Up @@ -340,6 +341,20 @@ export function MiscView({ onSubmit }: MiscViewProps) {
});
},
},
{
id: 'disableServerManagedSettings',
title: 'Disable server-managed settings',
description:
'Prevents Claude Code from downloading enterprise settings from Anthropic or a gateway. Local managed settings still apply.',
getValue: () => settings.misc?.disableServerManagedSettings ?? false,
toggle: () => {
updateSettings(settings => {
ensureMisc();
settings.misc!.disableServerManagedSettings =
!settings.misc!.disableServerManagedSettings;
});
},
},
{
id: 'mcpNonBlocking',
title: 'Non-blocking MCP startup',
Expand Down