Something went wrong. Try again.
A simple patch that toggles claude-code thinking traces to be fully expanded by default without having to press ctrl + o
Something went wrong. Try again.
claude-code-patches patch-thinking.js
10 kB · 267 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268#!/usr/bin/env node
const fs = require('fs');const path = require('path');const os = require('os');const { execSync } = require('child_process');
// Parse command line argumentsconst args = process.argv.slice(2);const isDryRun = args.includes('--dry-run');const isRestore = args.includes('--restore');const showHelp = args.includes('--help') || args.includes('-h');
// Display helpif (showHelp) { console.log('Claude Code Thinking Visibility Patcher v2.0.62'); console.log('==============================================\n'); console.log('Usage: node patch-thinking.js [options]\n'); console.log('Options:'); console.log(' --dry-run Preview changes without applying them'); console.log(' --restore Restore from backup file'); console.log(' --help, -h Show this help message\n'); console.log('Examples:'); console.log(' node patch-thinking.js # Apply patches'); console.log(' node patch-thinking.js --dry-run # Preview changes'); console.log(' node patch-thinking.js --restore # Restore original'); process.exit(0);}
console.log('Claude Code Thinking Visibility Patcher v2.0.62');console.log('==============================================\n');
// Helper function to safely execute shell commandsfunction safeExec(command) { try { return execSync(command, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim(); } catch (error) { return null; }}
// Auto-detect Claude Code installation pathfunction getClaudeCodePath() { const homeDir = os.homedir(); const attemptedPaths = [];
// Helper to check and return path if it exists function checkPath(testPath, method) { if (!testPath) return null;
attemptedPaths.push({ path: testPath, method });
try { if (fs.existsSync(testPath)) { // Resolve symlinks for global npm installs try { const realPath = fs.realpathSync(testPath); return realPath; } catch (e) { return testPath; } } } catch (error) { // Path check failed, continue } return null; }
// PRIORITY 1: Local installations (existing behavior - user overrides) const localPaths = [ path.join(homeDir, '.claude', 'local', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'), path.join(homeDir, '.config', 'claude', 'local', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'), ];
for (const localPath of localPaths) { const found = checkPath(localPath, 'local installation'); if (found) return found; }
// PRIORITY 2: Global npm installation via 'npm root -g' const npmGlobalRoot = safeExec('npm root -g'); if (npmGlobalRoot) { const npmGlobalPath = path.join(npmGlobalRoot, '@anthropic-ai', 'claude-code', 'cli.js'); const found = checkPath(npmGlobalPath, 'npm root -g'); if (found) return found; }
// PRIORITY 3: Derive from process.execPath // Global modules are typically in ../lib/node_modules relative to node binary const nodeDir = path.dirname(process.execPath); const derivedGlobalPath = path.join(nodeDir, '..', 'lib', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'); const found = checkPath(derivedGlobalPath, 'derived from process.execPath'); if (found) return found;
// PRIORITY 4: Unix systems - try 'which claude' to find binary if (process.platform !== 'win32') { const claudeBinary = safeExec('which claude'); if (claudeBinary) { try { // Resolve symlinks const realBinary = fs.realpathSync(claudeBinary); // Navigate from bin/claude to lib/node_modules/@anthropic-ai/claude-code/cli.js const binDir = path.dirname(realBinary); const nodeModulesPath = path.join(binDir, '..', 'lib', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js'); const foundFromBinary = checkPath(nodeModulesPath, 'which claude'); if (foundFromBinary) return foundFromBinary; } catch (e) { // Failed to resolve, continue } } }
// No installation found, return null and include attempted paths for error reporting getClaudeCodePath.attemptedPaths = attemptedPaths; return null;}
const targetPath = getClaudeCodePath();
if (!targetPath) { console.error('❌ Error: Could not find Claude Code installation\n'); console.error('Searched using the following methods:\n');
const attemptedPaths = getClaudeCodePath.attemptedPaths || [];
if (attemptedPaths.length > 0) { // Group by method for cleaner output const byMethod = {}; attemptedPaths.forEach(({ path, method }) => { if (!byMethod[method]) byMethod[method] = []; byMethod[method].push(path); });
Object.entries(byMethod).forEach(([method, paths]) => { console.error(` [${method}]`); paths.forEach(p => console.error(` - ${p}`)); }); } else { console.error(' - ~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js'); console.error(' - ~/.config/claude/local/node_modules/@anthropic-ai/claude-code/cli.js'); console.error(' - Global npm installation (npm root -g)'); }
console.error('\n💡 Troubleshooting:'); console.error(' 1. Verify Claude Code is installed: claude --version'); console.error(' 2. For local install: Check ~/.claude/local or ~/.config/claude/local'); console.error(' 3. For global install: Ensure "npm install -g @anthropic-ai/claude-code" succeeded'); console.error(' 4. Check that npm is in your PATH if using global install'); process.exit(1);}
console.log(`Found Claude Code at: ${targetPath}\n`);
const backupPath = targetPath + '.backup';
// Restore from backupif (isRestore) { if (!fs.existsSync(backupPath)) { console.error('❌ Error: Backup file not found at:', backupPath); process.exit(1); }
console.log('Restoring from backup...'); fs.copyFileSync(backupPath, targetPath); console.log('✅ Restored successfully!'); console.log('\nPlease restart Claude Code for changes to take effect.'); process.exit(0);}
// Read fileconsole.log('Reading cli.js...');if (!fs.existsSync(targetPath)) { console.error('❌ Error: cli.js not found at:', targetPath); process.exit(1);}
let content = fs.readFileSync(targetPath, 'utf8');
// Patch 1: ZT2 Banner Removal (v2.0.62)// Note: Changed from RR2 (v2.0.61) to ZT2 (v2.0.62), rTA/GP namespaces, P containerconst bannerSearchPattern = 'function ZT2({streamMode:A}){let[Q,B]=rTA.useState(null),[G,Z]=rTA.useState(null);if(rTA.useEffect(()=>{if(A==="thinking"&&Q===null)B(Date.now());else if(A!=="thinking"&&Q!==null)Z(Date.now()-Q),B(null)},[A,Q]),A==="thinking")return GP.createElement(P,{marginTop:1},GP.createElement($,{dimColor:!0},"∴ Thinking…"));if(G!==null)return GP.createElement(P,{marginTop:1},GP.createElement($,{dimColor:!0},"∴ Thought for ",Math.max(1,Math.round(G/1000)),"s (",GP.createElement($,{dimColor:!0,bold:!0},"ctrl+o")," ","to show thinking)"));return null}';const bannerReplacement = 'function ZT2({streamMode:A}){return null}';
// Patch 2: Thinking Visibility (v2.0.62)// Note: Changed from T69 (v2.0.61) to X59 (v2.0.62), A3 to J3const thinkingSearchPattern = 'case"thinking":if(!F&&!G)return null;return J3.createElement(X59,{addMargin:Q,param:A,isTranscriptMode:F,verbose:G});';const thinkingReplacement = 'case"thinking":return J3.createElement(X59,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:G});';
let patch1Applied = false;let patch2Applied = false;
// Check if patches can be appliedconsole.log('Checking patches...\n');
console.log('Patch 1: ZT2 banner removal');if (content.includes(bannerSearchPattern)) { patch1Applied = true; console.log(' ✅ Pattern found - ready to apply');} else if (content.includes(bannerReplacement)) { console.log(' ⚠️ Already applied');} else { console.log(' ❌ Pattern not found - may need update for newer version');}
console.log('\nPatch 2: Thinking visibility');if (content.includes(thinkingSearchPattern)) { patch2Applied = true; console.log(' ✅ Pattern found - ready to apply');} else if (content.includes(thinkingReplacement)) { console.log(' ⚠️ Already applied');} else { console.log(' ❌ Pattern not found - may need update for newer version');}
// Dry run mode - just previewif (isDryRun) { console.log('\n📋 DRY RUN - No changes will be made\n'); console.log('Summary:'); console.log(`- Patch 1 (banner): ${patch1Applied ? 'WOULD APPLY' : 'SKIP'}`); console.log(`- Patch 2 (visibility): ${patch2Applied ? 'WOULD APPLY' : 'SKIP'}`);
if (patch1Applied || patch2Applied) { console.log('\nRun without --dry-run to apply patches.'); } process.exit(0);}
// Apply patchesif (!patch1Applied && !patch2Applied) { console.error('\n❌ No patches to apply'); console.error('Patches may already be applied or version may have changed.'); console.error('Run with --dry-run to see details.'); process.exit(1);}
// Create backup if it doesn't existif (!fs.existsSync(backupPath)) { console.log('\nCreating backup...'); fs.copyFileSync(targetPath, backupPath); console.log(`✅ Backup created: ${backupPath}`);}
console.log('\nApplying patches...');
// Apply Patch 1if (patch1Applied) { content = content.replace(bannerSearchPattern, bannerReplacement); console.log('✅ Patch 1 applied: ZT2 function now returns null');}
// Apply Patch 2if (patch2Applied) { content = content.replace(thinkingSearchPattern, thinkingReplacement); console.log('✅ Patch 2 applied: thinking content forced visible');}
// Write fileconsole.log('\nWriting patched file...');fs.writeFileSync(targetPath, content, 'utf8');console.log('✅ File written successfully\n');
console.log('Summary:');console.log(`- Patch 1 (banner): ${patch1Applied ? 'APPLIED' : 'SKIPPED'}`);console.log(`- Patch 2 (visibility): ${patch2Applied ? 'APPLIED' : 'SKIPPED'}`);console.log('\n🎉 Patches applied! Please restart Claude Code for changes to take effect.');console.log('\nTo restore original behavior, run: node patch-thinking.js --restore');process.exit(0);