forked from cnighswonger/claude-code-cache-fix-vscode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwrapper.js
More file actions
146 lines (128 loc) · 6.23 KB
/
Copy pathwrapper.js
File metadata and controls
146 lines (128 loc) · 6.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env node
/**
* Claude Code process wrapper for VS Code extension.
*
* This script is set as claudeCode.claudeProcessWrapper by the extension.
* VS Code's Claude extension calls:
* spawn(wrapper, [originalClaudePath, ...args])
*
* We skip argv[2] (the original claude path), set NODE_OPTIONS to load
* the cache-fix interceptor, and spawn node with cli.js directly.
*/
const { execSync, spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
// Resolve Claude Code CLI path
// Priority: env override → Volta packages tree → npm root -g → common fallbacks
function resolveCliPath() {
// 1. Explicit env override (escape hatch for any Node manager)
if (process.env.CLAUDE_CODE_CACHE_FIX_CLI_JS) {
const p = process.env.CLAUDE_CODE_CACHE_FIX_CLI_JS;
if (fs.existsSync(p)) return p;
process.stderr.write(`claude-code-cache-fix: CLAUDE_CODE_CACHE_FIX_CLI_JS path not found: ${p}\n`);
}
// 2. Volta packages tree (Volta keeps current version here, npm root -g hits stale tree)
const localAppData = process.env.LOCALAPPDATA || '';
if (localAppData) {
const voltaPath = path.join(localAppData, 'Volta', 'tools', 'image', 'packages',
'@anthropic-ai', 'claude-code', 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js');
if (fs.existsSync(voltaPath)) return voltaPath;
}
// 3. npm root -g (standard path for npm, nvm, fnm)
try {
const npmRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim();
const npmPath = path.join(npmRoot, '@anthropic-ai', 'claude-code', 'cli.js');
if (fs.existsSync(npmPath)) return npmPath;
} catch {}
// 4. Common fallback locations
const candidates = [
path.join(process.env.APPDATA || '', 'npm', 'node_modules'),
path.join(process.env.HOME || '', '.npm-global', 'lib', 'node_modules'),
'/usr/local/lib/node_modules',
'/usr/lib/node_modules',
];
for (const dir of candidates) {
const p = path.join(dir, '@anthropic-ai', 'claude-code', 'cli.js');
if (fs.existsSync(p)) return p;
}
return null;
}
// Resolve preload path (same priority minus Volta — cache-fix is always via npm)
function resolvePreloadPath() {
try {
const npmRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim();
const p = path.join(npmRoot, 'claude-code-cache-fix', 'preload.mjs');
if (fs.existsSync(p)) return p;
} catch {}
const candidates = [
path.join(process.env.APPDATA || '', 'npm', 'node_modules'),
path.join(process.env.HOME || '', '.npm-global', 'lib', 'node_modules'),
'/usr/local/lib/node_modules',
'/usr/lib/node_modules',
];
for (const dir of candidates) {
const p = path.join(dir, 'claude-code-cache-fix', 'preload.mjs');
if (fs.existsSync(p)) return p;
}
return null;
}
const cliPath = resolveCliPath();
const preloadPath = resolvePreloadPath();
if (!preloadPath) {
process.stderr.write('claude-code-cache-fix: preload.mjs not found.\nInstall with: npm install -g claude-code-cache-fix\n');
process.exit(1);
}
if (!cliPath) {
process.stderr.write('claude-code-cache-fix: Claude Code cli.js not found.\nInstall with: npm install -g @anthropic-ai/claude-code\nVolta users: volta install @anthropic-ai/claude-code\nOr set CLAUDE_CODE_CACHE_FIX_CLI_JS to the path.\n');
process.exit(1);
}
// Build file:// URL with forward slashes and space encoding
let preloadUrl = preloadPath.replace(/\\/g, '/');
preloadUrl = preloadUrl.replace(/ /g, '%20');
if (!preloadUrl.startsWith('/')) preloadUrl = '/' + preloadUrl;
// Read VS Code settings from a config file the extension writes on enable
// This bridges VS Code settings into env vars for the interceptor
const configPath = path.join(process.env.HOME || process.env.USERPROFILE || '', '.claude', 'cache-fix-vscode-config.json');
try {
if (fs.existsSync(configPath)) {
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
// Core settings
if (config.debug) process.env.CACHE_FIX_DEBUG = '1';
if (config.stripGitStatus) process.env.CACHE_FIX_STRIP_GIT_STATUS = '1';
if (config.outputEfficiencyReplacement) process.env.CACHE_FIX_OUTPUT_EFFICIENCY_REPLACEMENT = config.outputEfficiencyReplacement;
if (config.imageKeepLast > 0) process.env.CACHE_FIX_IMAGE_KEEP_LAST = String(config.imageKeepLast);
// Opt-in features
if (config.normalizeIdentity) process.env.CACHE_FIX_NORMALIZE_IDENTITY = '1';
if (config.normalizeCwd) process.env.CACHE_FIX_NORMALIZE_CWD = '1';
if (config.normalizeSmoosh) process.env.CACHE_FIX_NORMALIZE_SMOOSH = '1';
if (config.prefixDiff) process.env.CACHE_FIX_PREFIXDIFF = '1';
// Per-extension skip toggles
if (config.skipRelocate) process.env.CACHE_FIX_SKIP_RELOCATE = '1';
if (config.skipFingerprint) process.env.CACHE_FIX_SKIP_FINGERPRINT = '1';
if (config.skipToolSort) process.env.CACHE_FIX_SKIP_TOOL_SORT = '1';
if (config.skipTtl) process.env.CACHE_FIX_SKIP_TTL = '1';
if (config.skipSmooshSplit) process.env.CACHE_FIX_SKIP_SMOOSH_SPLIT = '1';
if (config.skipSessionStartNormalize) process.env.CACHE_FIX_SKIP_SESSION_START_NORMALIZE = '1';
if (config.skipContinueTrailerStrip) process.env.CACHE_FIX_SKIP_CONTINUE_TRAILER_STRIP = '1';
if (config.skipDeferredToolsRestore) process.env.CACHE_FIX_SKIP_DEFERRED_TOOLS_RESTORE = '1';
if (config.skipReminderStrip) process.env.CACHE_FIX_SKIP_REMINDER_STRIP = '1';
if (config.skipCacheControlNormalize) process.env.CACHE_FIX_SKIP_CACHE_CONTROL_NORMALIZE = '1';
if (config.skipToolUseInputNormalize) process.env.CACHE_FIX_SKIP_TOOL_USE_INPUT_NORMALIZE = '1';
if (config.skipCacheControlSticky) process.env.CACHE_FIX_SKIP_CACHE_CONTROL_STICKY = '1';
}
} catch {}
// Set NODE_OPTIONS
const existingOpts = process.env.NODE_OPTIONS || '';
process.env.NODE_OPTIONS = `--import file://${preloadUrl} ${existingOpts}`.trim();
// Skip argv[2] (original claude path passed by the extension)
// argv[0] = node, argv[1] = this script, argv[2] = original claude, argv[3+] = actual args
const args = [cliPath, ...process.argv.slice(3)];
const child = spawn(process.execPath, args, {
stdio: 'inherit',
env: process.env,
});
child.on('exit', (code) => process.exit(code ?? 0));
child.on('error', (err) => {
process.stderr.write(`claude-code-cache-fix wrapper error: ${err.message}\n`);
process.exit(1);
});