@bman654/clodex 2.13.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/{chunk-ZM2KYLPH.js → chunk-3NCDMS7N.js} +468 -2
- package/dist/chunk-3NCDMS7N.js.map +1 -0
- package/dist/claude-wrapper.js +276 -7
- package/dist/claude-wrapper.js.map +1 -1
- package/dist/cli.js +555 -488
- package/dist/cli.js.map +1 -1
- package/docs/background-agents.md +35 -0
- package/docs/windows-setup.md +203 -168
- package/launcher/clodex-claude-launcher.cs +311 -0
- package/package.json +2 -1
- package/dist/chunk-ZM2KYLPH.js.map +0 -1
|
@@ -11,6 +11,7 @@ This page explains how to bridge **every** Claude Code process on your machine
|
|
|
11
11
|
- endpoint-mode server: `ANTHROPIC_BASE_URL` pointing at the gateway;
|
|
12
12
|
- **no live server: env untouched** — `claude` always launches normally, a stopped server never breaks anything.
|
|
13
13
|
- Setting **`CLAUDE_CODE_PROCESS_WRAPPER`** to `clodex-claude` makes Claude Code invoke it as `clodex-claude <claude-binary-path> <args...>` for every process it spawns — agents view sessions and background agents are bridged automatically.
|
|
14
|
+
- That ordinary process-wrapper route keeps the handed-in binary. A separate VS Code-only path (`CLAUDE_CODE_ENTRYPOINT=claude-vscode`, explicit bundled executable, live proxy server; on Windows reached through the launcher from `clodex install-vscode-launcher`) may run the clodex-patched install instead, but only when the patch manifest proves by full SHA-256 that it is the patched output of those exact pristine bytes. Missing or mismatched proof keeps the bundled binary. When the manifest identifies the other install, a refused chat spawn emits one stderr line; refused helper commands stay silent, and the inspected extension source sends chat stderr to VS Code's **Claude VSCode** output channel. Tool, hook, and agent children carry child-session markers, while background pty wrappers lose the `claude-vscode` entrypoint; neither shape substitutes. Endpoint, no-server, and direct launches do not substitute either.
|
|
14
15
|
- For your own terminal sessions, run **`clodex-claude`** instead of `claude` — same auto-discovery, no port or CA path to hardcode anywhere.
|
|
15
16
|
- Set **`CLODEX_REQUIRE_SERVER=1`** in an isolated routed profile when bypassing Clodex must be impossible. `clodex-claude` then exits with an error if no advertised server passes its process and TCP checks. The default remains fail-open for ordinary installations.
|
|
16
17
|
- A live standalone server has already snapshotted its credentials and account selection. If a wrapper launch sets `CLODEX_OAUTH_ACCOUNT` or a nonblank `CLODEX_KEY_*`, `clodex-claude` warns that the variable is ignored and still launches through that server. Restart the server with the selector, or save the provider credential and refresh its models, before launching without the process-only variable. With no live server these variables pass through unchanged.
|
|
@@ -20,6 +21,39 @@ This page explains how to bridge **every** Claude Code process on your machine
|
|
|
20
21
|
`clodex-claude` invocation does not reconfigure the running server.
|
|
21
22
|
- Proxy-mode wrapper launches remove Anthropic entries from the union of `NO_PROXY` and `no_proxy`, while preserving unrelated bypasses. The manual server output prints the same adjusted values for users who export the proxy settings themselves.
|
|
22
23
|
|
|
24
|
+
## VS Code model picker
|
|
25
|
+
|
|
26
|
+
After installing clodex, patch a compatible local Claude Code install and keep
|
|
27
|
+
`clodex server --proxy` running. On macOS and Linux, find the absolute, extensionless wrapper path:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
command -v clodex-claude
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Put that exact path in VS Code's user `settings.json` (do not use the underlying `.js` file), then
|
|
34
|
+
reload the window. If a Node version manager owns that path, use the stable launcher described in
|
|
35
|
+
step 3 below instead of an ephemeral or version-specific path:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
"claudeCode.claudeProcessWrapper": "/absolute/path/to/clodex-claude"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
On Windows the extension cannot spawn npm's script shims; run `clodex install-vscode-launcher` and
|
|
42
|
+
paste the `.exe` path it prints instead — the same substitution then applies. Full walkthrough in
|
|
43
|
+
[windows-setup.md](windows-setup.md).
|
|
44
|
+
|
|
45
|
+
The extension and local Claude install update independently. If their pristine bytes no longer
|
|
46
|
+
match, the wrapper keeps the extension's bundled executable; align compatible builds and run
|
|
47
|
+
`clodex patch` again. A fallback notice appears in VS Code's **Claude VSCode** output channel, not
|
|
48
|
+
as a toast; main-chat lines use the `From claude: ...` prefix.
|
|
49
|
+
|
|
50
|
+
At least two extension behaviors relevant to this setup change when `claudeProcessWrapper` is set;
|
|
51
|
+
these were verified from source rather than in a running editor: it skips a post-update activation health/telemetry probe (not the VS Code
|
|
52
|
+
marketplace updater), and the SDK supplies `--permission-mode default` when no explicit permission
|
|
53
|
+
mode is configured. An explicit mode still wins. Process-level tests cover the wrapper selection;
|
|
54
|
+
the picker was not exercised in a running editor, and the Linux host path was not run for this
|
|
55
|
+
change.
|
|
56
|
+
|
|
23
57
|
## Setup steps
|
|
24
58
|
|
|
25
59
|
1. **Install clodex globally** (puts both `clodex` and `clodex-claude` on your PATH):
|
|
@@ -113,6 +147,7 @@ The check does not launch Claude.
|
|
|
113
147
|
## Troubleshooting
|
|
114
148
|
|
|
115
149
|
- **Is my session bridged?** In a session started via `clodex-claude` (or spawned by Claude Code with the wrapper set), `/model` accepts your `clodex:` model names and aliases (run `clodex models --list` to see them). If those models are rejected and you haven't run `clodex patch`, that's expected for unpatched binaries — but a bridged session still routes them; an unbridged one errors at the API instead.
|
|
150
|
+
- **VS Code routes models but omits picker entries:** open the **Claude VSCode** channel in the Output panel and look for a one-line `From claude: clodex-claude: running ...` fallback notice. Missing or unreadable state that cannot identify another install is deliberately silent, so the absence of a notice is not proof of selection. The extension and installed CLI update separately, and equal version labels do not prove equal artifacts. Align their builds and run `clodex patch` again. On Windows the wrapper setting must be the `.exe` from `clodex install-vscode-launcher` (npm's `.cmd` shim cannot be configured directly — see [windows-setup.md](windows-setup.md)); the notice appears in the same output channel.
|
|
116
151
|
- **Server not running:** `clodex-claude` launches plain `claude` by default. With `CLODEX_REQUIRE_SERVER=1`, it exits instead. Check `cat ~/.clodex/server-runtime.json` — a missing file (or records whose `pid` is no longer alive) means no server is advertised; start `clodex server --proxy`. If a server is running but absent from the file, make sure it was not started with `--no-discovery` / `CLODEX_NO_DISCOVERY=1`.
|
|
117
152
|
- **Wrapper variable empty or stale:** run `echo "$CLAUDE_CODE_PROCESS_WRAPPER"` in a **new login shell**. If it is empty, a `$(command -v ...)` in your profile ran before your Node version manager initialized (see the warning in step 3) — switch to a literal path. If it points at a path that no longer exists (a Node upgrade moved the global bin, an fnm/nvm shim directory expired, or it still names an old hand-written script), spawned processes fail to start or silently skip bridging. Verify with `[ -x "$CLAUDE_CODE_PROCESS_WRAPPER" ] && echo OK`.
|
|
118
153
|
- **Agents fail to spawn / `env: node: No such file or directory`:** the wrapper's `#!/usr/bin/env node` shebang could not find Node, typically because Claude Code was launched from a GUI (Spotlight, Raycast, an IDE) with a minimal PATH. Use the launcher script from step 3, which resolves Node by absolute path, and test it with `env -i HOME="$HOME" PATH=/usr/bin:/bin "$CLAUDE_CODE_PROCESS_WRAPPER" --version`.
|
package/docs/windows-setup.md
CHANGED
|
@@ -9,10 +9,15 @@ There are two levels of setup, and they solve different problems:
|
|
|
9
9
|
| Setup | What you get |
|
|
10
10
|
| --- | --- |
|
|
11
11
|
| [Proxy env vars](#1-route-the-extension-through-clodex) | clodex models **work** in the extension |
|
|
12
|
-
| [
|
|
12
|
+
| [Launcher](#2-launch-the-extensions-claude-code-through-clodex) | the extension launches Claude Code **through `clodex-claude`**, which follows your running server on its own — no proxy values to copy into VS Code settings — and runs your **clodex-patched install** in place of the bundled binary, so clodex models appear in the extension's **model picker** |
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
Only the launcher level changes the picker. `clodex-claude` replaces the extension's bundled,
|
|
15
|
+
unpatched Claude Code with your verified clodex-patched install exactly as it does on macOS and
|
|
16
|
+
Linux (see the [VS Code setup in
|
|
17
|
+
background-agents.md](background-agents.md#vs-code-model-picker)): the bundled file's full SHA-256
|
|
18
|
+
must match the pristine hash `clodex patch` recorded, and the patched install must still match its
|
|
19
|
+
recorded output. With the step 1 settings alone the extension launches its own bundled binary and
|
|
20
|
+
the picker stays as it was.
|
|
16
21
|
|
|
17
22
|
## 1. Route the extension through clodex
|
|
18
23
|
|
|
@@ -53,14 +58,15 @@ running; stop it and the port goes dead, so every request fails until you start
|
|
|
53
58
|
|
|
54
59
|
> [!NOTE]
|
|
55
60
|
> Do not set `claudeCode.claudeProcessWrapper` to `clodex-claude` here. On Windows npm installs that
|
|
56
|
-
> bin as
|
|
57
|
-
> extension spawns the wrapper without a shell, so pointing
|
|
58
|
-
>
|
|
61
|
+
> bin as three script shims — `clodex-claude` (a POSIX shell script), `clodex-claude.cmd` and
|
|
62
|
+
> `clodex-claude.ps1` — and no `.exe`. The extension spawns the wrapper without a shell, so pointing
|
|
63
|
+
> it at any of them fails with `spawn EINVAL`.
|
|
64
|
+
> [Step 2](#2-launch-the-extensions-claude-code-through-clodex) builds the `.exe` that setting needs.
|
|
59
65
|
|
|
60
66
|
### Selecting a clodex model
|
|
61
67
|
|
|
62
68
|
At this level the extension's model picker will **not** list clodex models (see
|
|
63
|
-
[why](#why-the-picker-is-empty-without-a-
|
|
69
|
+
[why](#why-the-picker-is-empty-without-a-launcher)). Set one as your default from a terminal instead:
|
|
64
70
|
|
|
65
71
|
```powershell
|
|
66
72
|
clodex claude
|
|
@@ -72,9 +78,9 @@ launch — Claude Code reports it as `Using <model> (from .claude\settings.json)
|
|
|
72
78
|
|
|
73
79
|
Existing chat tabs keep whatever model they launched with; open a new chat to pick up the change.
|
|
74
80
|
|
|
75
|
-
## 2.
|
|
81
|
+
## 2. Launch the extension's Claude Code through clodex
|
|
76
82
|
|
|
77
|
-
### Why the picker is empty without a
|
|
83
|
+
### Why the picker is empty without a launcher
|
|
78
84
|
|
|
79
85
|
`clodex patch` patches the Claude Code binary that npm installed. The VS Code extension does not
|
|
80
86
|
launch that binary — it ships and launches its own copy:
|
|
@@ -83,218 +89,247 @@ launch that binary — it ships and launches its own copy:
|
|
|
83
89
|
%USERPROFILE%\.vscode\extensions\anthropic.claude-code-<version>-win32-x64\resources\native-binary\claude.exe
|
|
84
90
|
```
|
|
85
91
|
|
|
86
|
-
On the machine this was written from, that bundled copy was byte-identical (SHA-256) to the
|
|
87
|
-
backup clodex took before patching, confirming it was unpatched. The model picker's entries
|
|
88
|
-
inside the binary, so the dropdown shows whatever the *launched* binary offers — which is why
|
|
89
|
-
routed correctly while remaining invisible in the picker.
|
|
92
|
+
On the machine this was first written from, that bundled copy was byte-identical (SHA-256) to the
|
|
93
|
+
pristine backup clodex took before patching, confirming it was unpatched. The model picker's entries
|
|
94
|
+
live inside the binary, so the dropdown shows whatever the *launched* binary offers — which is why
|
|
95
|
+
models routed correctly while remaining invisible in the picker.
|
|
90
96
|
|
|
91
97
|
Routing does not depend on the patch. Claude Code sends the model name it was given, and the proxy
|
|
92
98
|
maps it. The patch is what makes the binary itself aware of clodex models — listing them in the
|
|
93
99
|
picker, accepting them as known aliases, and reporting their context windows.
|
|
94
100
|
|
|
95
|
-
|
|
101
|
+
`clodex-claude` solves this itself: when the extension hands it the bundled binary, it substitutes
|
|
102
|
+
the install recorded in `patch-state.json` — only when the extension's full binary hash matches
|
|
103
|
+
that manifest's pristine hash and the install's full hash still matches the recorded patched
|
|
104
|
+
output (equal version labels or sizes are not enough); a mismatch runs the extension's own binary
|
|
105
|
+
and writes one line to its output channel. On Windows the only missing piece was an executable the
|
|
106
|
+
extension could spawn; the launcher below is that piece.
|
|
96
107
|
|
|
97
|
-
|
|
108
|
+
### What the launcher is
|
|
109
|
+
|
|
110
|
+
`claudeCode.claudeProcessWrapper` takes a single executable path. Claude Code invokes it as:
|
|
98
111
|
|
|
99
112
|
```
|
|
100
113
|
<wrapper> <path-to-claude-binary> <args...>
|
|
101
114
|
```
|
|
102
115
|
|
|
103
|
-
passing the binary it *would* have run as the first argument.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
exe
|
|
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
|
-
return ""
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// patchedBinary reads the binary clodex last patched, or "" if unavailable.
|
|
147
|
-
func patchedBinary() string {
|
|
148
|
-
home := clodexHome()
|
|
149
|
-
if home == "" {
|
|
150
|
-
return ""
|
|
151
|
-
}
|
|
152
|
-
data, err := os.ReadFile(filepath.Join(home, "patch-state.json"))
|
|
153
|
-
if err != nil {
|
|
154
|
-
return ""
|
|
155
|
-
}
|
|
156
|
-
var manifest struct {
|
|
157
|
-
BinaryPath string `json:"binaryPath"`
|
|
158
|
-
}
|
|
159
|
-
if err := json.Unmarshal(data, &manifest); err != nil {
|
|
160
|
-
return ""
|
|
161
|
-
}
|
|
162
|
-
return manifest.BinaryPath
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
func isFile(path string) bool {
|
|
166
|
-
if path == "" {
|
|
167
|
-
return false
|
|
168
|
-
}
|
|
169
|
-
info, err := os.Stat(path)
|
|
170
|
-
return err == nil && !info.IsDir()
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
func main() {
|
|
174
|
-
args := os.Args[1:]
|
|
175
|
-
|
|
176
|
-
// The caller passes the binary it would have run; hold it as the fallback.
|
|
177
|
-
handedIn := ""
|
|
178
|
-
if len(args) > 0 {
|
|
179
|
-
if base := strings.ToLower(filepath.Base(args[0])); base == "claude.exe" || base == "claude" {
|
|
180
|
-
handedIn = args[0]
|
|
181
|
-
args = args[1:]
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
target := ""
|
|
186
|
-
for _, candidate := range []string{
|
|
187
|
-
strings.TrimSpace(os.Getenv("CLODEX_WRAPPER_TARGET")),
|
|
188
|
-
patchedBinary(),
|
|
189
|
-
handedIn,
|
|
190
|
-
} {
|
|
191
|
-
if isFile(candidate) {
|
|
192
|
-
target = candidate
|
|
193
|
-
break
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
if target == "" {
|
|
197
|
-
os.Stderr.WriteString("claude-wrapper: no Claude Code binary found\n")
|
|
198
|
-
os.Exit(1)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
cmd := exec.Command(target, args...)
|
|
202
|
-
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
|
203
|
-
cmd.Env = os.Environ()
|
|
204
|
-
|
|
205
|
-
if err := cmd.Run(); err != nil {
|
|
206
|
-
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
207
|
-
os.Exit(exitErr.ExitCode())
|
|
208
|
-
}
|
|
209
|
-
os.Stderr.WriteString("claude-wrapper: " + err.Error() + "\n")
|
|
210
|
-
os.Exit(1)
|
|
211
|
-
}
|
|
212
|
-
}
|
|
116
|
+
passing the binary it *would* have run as the first argument. clodex already ships a wrapper for
|
|
117
|
+
exactly this contract — `clodex-claude`, the one [background agents](background-agents.md) use —
|
|
118
|
+
but on Windows npm installs it as three script shims (extensionless, `.cmd`, `.ps1`) and no
|
|
119
|
+
executable, and the extension refuses those with `spawn EINVAL`.
|
|
120
|
+
|
|
121
|
+
`clodex install-vscode-launcher` builds the missing `.exe` on your machine. It compiles a small C#
|
|
122
|
+
program (`launcher\clodex-claude-launcher.cs` in the clodex package — a short, commented file you
|
|
123
|
+
can read) with the C# compiler that ships inside the .NET Framework on every Windows 10/11 install,
|
|
124
|
+
so there is nothing to download and no prebuilt binary to trust. The resulting
|
|
125
|
+
`clodex-claude.exe`:
|
|
126
|
+
|
|
127
|
+
- runs `node.exe` with clodex's `claude-wrapper.js`, passing the extension's arguments through
|
|
128
|
+
with their **values preserved, Unicode included** (it forwards the raw command line rather than
|
|
129
|
+
re-quoting each argument, and the wrapper spawns a native `claude.exe` directly rather than
|
|
130
|
+
through `cmd.exe`, so JSON arguments, empty strings, `%NAMES%` and paths with spaces reach Claude
|
|
131
|
+
Code as sent);
|
|
132
|
+
- ties Node and the Claude Code it launches to its own lifetime with a Windows job object, so that
|
|
133
|
+
when the extension cancels a chat or the window reloads, no `node.exe` or `claude.exe` is left
|
|
134
|
+
behind. If Windows refuses the job object the launcher prints one warning line and runs anyway;
|
|
135
|
+
- lets Ctrl+C reach Claude Code rather than swallowing it, waits, and exits with Claude Code's own
|
|
136
|
+
exit code.
|
|
137
|
+
|
|
138
|
+
`clodex-claude` then does what it does for any Claude process: finds your running
|
|
139
|
+
`clodex server --proxy` and bridges the session to it. **The launcher does not choose the Claude
|
|
140
|
+
Code binary.** It hands `clodex-claude` the bundled `claude.exe` the extension named, exactly as the
|
|
141
|
+
extension would, and `clodex-claude` applies its usual rule: when that file's full SHA-256 equals
|
|
142
|
+
the pristine hash in `patch-state.json` and your patched `claude.exe` still hashes to the recorded
|
|
143
|
+
patched output, it runs the patched install; otherwise it runs the bundled `claude.exe` and, for
|
|
144
|
+
the chat itself, writes one line to the **Claude VSCode** output channel (helper commands the
|
|
145
|
+
extension runs fall back silently). On Windows both files must be `.exe` programs (a
|
|
146
|
+
`.cmd` launcher is never substituted for or into), and the bundled file (about 200 MB) is hashed on
|
|
147
|
+
every launch — `tests/wrapper-substitution.windows.test.ts` prints the measured time on the CI
|
|
148
|
+
runner; see that job's log for the current number.
|
|
149
|
+
|
|
150
|
+
### Build it
|
|
151
|
+
|
|
152
|
+
Run once, from any terminal, with the Node you normally use:
|
|
153
|
+
|
|
154
|
+
```powershell
|
|
155
|
+
clodex install-vscode-launcher
|
|
213
156
|
```
|
|
214
157
|
|
|
215
|
-
|
|
158
|
+
It prints where the launcher went and the setting to paste:
|
|
216
159
|
|
|
217
|
-
```powershell
|
|
218
|
-
go build -ldflags="-s -w" -o claude-wrapper.exe .
|
|
219
160
|
```
|
|
161
|
+
Built C:\Users\<you>\.clodex\bin\clodex-claude.exe
|
|
162
|
+
compiler: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe
|
|
163
|
+
runs: C:\nvm4w\nodejs\node.exe C:\nvm4w\nodejs\node_modules\@bman654\clodex\dist\claude-wrapper.js
|
|
164
|
+
|
|
165
|
+
Add this to your VS Code settings (Ctrl+Shift+P → Preferences: Open User Settings (JSON)):
|
|
166
|
+
|
|
167
|
+
"claudeCode.claudeProcessWrapper": "C:\\Users\\<you>\\.clodex\\bin\\clodex-claude.exe"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The two paths on the `runs:` line are compiled into the executable. **Re-run the command after
|
|
171
|
+
switching Node versions or moving the clodex install** — it is idempotent and replaces the launcher.
|
|
172
|
+
If the wrapper script it was built against disappears, the launcher exits with code 127 and a
|
|
173
|
+
one-line message naming the command to re-run, which shows up in the extension's **Claude VSCode**
|
|
174
|
+
output channel.
|
|
175
|
+
|
|
176
|
+
If the command reports that it cannot find `csc.exe`, your Windows install is missing the .NET
|
|
177
|
+
Framework 4.x runtime it normally ships with; install .NET Framework 4.8 from Microsoft and re-run.
|
|
220
178
|
|
|
221
|
-
|
|
222
|
-
|
|
179
|
+
### Add the setting
|
|
180
|
+
|
|
181
|
+
Paste the printed line into your user settings and **remove** the `HTTPS_PROXY`, `HTTP_PROXY` and
|
|
182
|
+
`NODE_EXTRA_CA_CERTS` entries from step 1: `clodex-claude` injects the equivalent values itself
|
|
183
|
+
from the server it discovers, and static entries pointing at a fixed port would keep failing while
|
|
184
|
+
the server is down, whereas the wrapper leaves the environment alone and lets Claude Code start
|
|
185
|
+
unbridged.
|
|
223
186
|
|
|
224
187
|
```json
|
|
225
|
-
"claudeCode.claudeProcessWrapper": "C:\\
|
|
188
|
+
"claudeCode.claudeProcessWrapper": "C:\\Users\\<you>\\.clodex\\bin\\clodex-claude.exe"
|
|
226
189
|
```
|
|
227
190
|
|
|
228
|
-
Reload the window.
|
|
191
|
+
Reload the window. `clodex server --proxy` still has to be running — the launcher does not start it.
|
|
192
|
+
Open a new chat: the model picker now lists your clodex favorites and aliases, provided the CLI you
|
|
193
|
+
patched and the extension ship the same Claude Code build. When they drift apart (the extension and
|
|
194
|
+
the CLI update separately), the picker falls back to the bundled list and the **Claude VSCode**
|
|
195
|
+
output channel shows a `From claude: clodex-claude: running ...` line; update the CLI to the
|
|
196
|
+
extension's version and re-run `clodex patch`.
|
|
229
197
|
|
|
230
198
|
If Claude fails to start, remove the `claudeCode.claudeProcessWrapper` line, save, and reload — that
|
|
231
|
-
returns you to the step 1 setup.
|
|
199
|
+
returns you to the step 1 setup. The **Claude VSCode** output channel (View → Output) shows the
|
|
200
|
+
launcher's and wrapper's messages, prefixed `From claude:`.
|
|
232
201
|
|
|
233
202
|
> [!TIP]
|
|
234
|
-
>
|
|
235
|
-
>
|
|
236
|
-
> across both Node upgrades and Claude Code updates.
|
|
203
|
+
> `clodex-claude` looks for the server in `%USERPROFILE%\.clodex`. If you set `CLODEX_HOME` in your
|
|
204
|
+
> shell only, VS Code will not see it; add it under `claudeCode.environmentVariables` as well.
|
|
237
205
|
|
|
238
206
|
### Consequences of setting a process wrapper
|
|
239
207
|
|
|
240
|
-
|
|
241
|
-
extension's own code rather than observed
|
|
208
|
+
At least two extension behaviors relevant to this setup change when `claudeProcessWrapper` is set.
|
|
209
|
+
These were read from the extension's own code rather than observed in a running editor:
|
|
242
210
|
|
|
243
|
-
- **
|
|
211
|
+
- **A post-update activation health/telemetry probe is skipped.** This is not the VS Code
|
|
212
|
+
marketplace updater and does not show that extension auto-updates stop. The extension can still
|
|
213
|
+
update separately from the CLI, so keep the CLI you patch aligned with the extension you run:
|
|
244
214
|
|
|
245
215
|
```powershell
|
|
246
216
|
npm install -g @anthropic-ai/claude-code@latest
|
|
247
217
|
clodex patch
|
|
248
218
|
```
|
|
249
219
|
|
|
250
|
-
- **
|
|
251
|
-
|
|
220
|
+
- **The SDK supplies a permission mode.** With no explicit mode, wrapper launches add
|
|
221
|
+
`--permission-mode default` instead of leaving default-mode resolution to the CLI. An explicitly
|
|
222
|
+
configured mode still wins. If permission prompts behave unexpectedly under a wrapper, remove the
|
|
223
|
+
wrapper setting while narrowing it down.
|
|
252
224
|
|
|
253
|
-
Re-running `clodex patch` after each Claude Code update is required regardless of the wrapper —
|
|
254
|
-
patch applies to
|
|
225
|
+
Re-running `clodex patch` after each Claude Code CLI update is required regardless of the wrapper —
|
|
226
|
+
the patch applies to specific bytes.
|
|
255
227
|
|
|
256
|
-
|
|
257
|
-
longer the one it ships with, while the extension itself can still update from the marketplace — so
|
|
258
|
-
the two can drift apart. Compare them if something starts behaving unexpectedly:
|
|
228
|
+
### Previous manual workaround
|
|
259
229
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
230
|
+
Earlier versions of this page carried a hand-built Go program to compile yourself. It ran the
|
|
231
|
+
patched npm `claude.exe` directly, bypassing `clodex-claude` entirely: it needed the step 1
|
|
232
|
+
environment variables, got no server discovery, and had none of `clodex-claude`'s full-hash
|
|
233
|
+
verification, so its target had to be kept aligned and re-patched by hand. It still works if you
|
|
234
|
+
built one, but `clodex install-vscode-launcher` is the supported path and the only one that verifies
|
|
235
|
+
what it runs.
|
|
265
236
|
|
|
266
237
|
## Troubleshooting
|
|
267
238
|
|
|
268
|
-
**`spawn EINVAL`** — `claudeProcessWrapper` points at a `.cmd`, `.ps1`, or `.bat`. It must be
|
|
269
|
-
`.exe`.
|
|
239
|
+
**`spawn EINVAL`** — `claudeProcessWrapper` points at a `.cmd`, `.ps1`, or `.bat`. It must be the
|
|
240
|
+
`.exe` from `clodex install-vscode-launcher`.
|
|
270
241
|
|
|
271
|
-
|
|
272
|
-
|
|
242
|
+
**`clodex-claude.exe: clodex's claude-wrapper.js is no longer at ...`** (output channel, exit 127)
|
|
243
|
+
— clodex moved or was reinstalled under a different Node. Re-run `clodex install-vscode-launcher`.
|
|
273
244
|
|
|
274
|
-
|
|
275
|
-
|
|
245
|
+
**`could not find the .NET Framework C# compiler`** — install .NET Framework 4.8 from Microsoft; the
|
|
246
|
+
command looks under `%WINDIR%\Microsoft.NET\Framework64\v4.*` and `Framework\v4.*`.
|
|
276
247
|
|
|
277
|
-
**
|
|
278
|
-
|
|
248
|
+
**Windows Defender or SmartScreen flags the launcher** — it is a freshly compiled unsigned
|
|
249
|
+
executable, so reputation-based checks have never seen it. The source is in the clodex package
|
|
250
|
+
(`launcher\clodex-claude-launcher.cs`); allow the file, or build it again after clearing the
|
|
251
|
+
warning.
|
|
252
|
+
|
|
253
|
+
**Every request fails** — check `clodex server --proxy` is still running. With the step 1 env vars
|
|
254
|
+
the extension's `HTTPS_PROXY` points at a fixed port and nothing falls back when the server is gone;
|
|
255
|
+
with the launcher, sessions started while the server is down run unbridged.
|
|
256
|
+
|
|
257
|
+
**Certificate errors** (step 1 setup) — `NODE_EXTRA_CA_CERTS` must match the path the server
|
|
258
|
+
printed, with backslashes escaped in JSON.
|
|
259
|
+
|
|
260
|
+
**Models route but the picker is empty** — with the step 1 settings alone that is expected: the
|
|
261
|
+
extension launches its own bundled binary. With the launcher, open View → Output → **Claude VSCode**
|
|
262
|
+
and look for a `From claude: clodex-claude: running ...` line: it names the reason (usually the
|
|
263
|
+
extension and the installed CLI are different Claude Code builds). Align them —
|
|
264
|
+
`npm install -g @anthropic-ai/claude-code@<extension version>` — and re-run `clodex patch`. No
|
|
265
|
+
line at all is not proof either way: a missing or unreadable patch manifest is deliberately silent.
|
|
266
|
+
Run `clodex patch`, and check that `CLODEX_HOME`, if you set it, is also set under
|
|
267
|
+
`claudeCode.environmentVariables` so the wrapper reads the same manifest.
|
|
268
|
+
|
|
269
|
+
**`CLODEX_CLAUDE_PATH` points at `clodex-claude` or `claude` without an extension, or at a `.ps1`** —
|
|
270
|
+
Node cannot spawn those on Windows at all. Point it at the `.cmd` or at the program's `.exe`.
|
|
279
271
|
|
|
280
272
|
**`clodex patch` reports it cannot detect the installation** — upgrade clodex; resolving npm
|
|
281
273
|
launchers to the underlying binary on Windows was fixed in 2.11.5.
|
|
282
274
|
|
|
283
275
|
## What was verified, and where
|
|
284
276
|
|
|
285
|
-
|
|
286
|
-
Code VS Code extension 2.1.267, against
|
|
277
|
+
Step 1, and the *previous* Go workaround, were verified on Windows 11, NVM for Windows
|
|
278
|
+
(node v22.19.0), clodex 2.11.6, Claude Code 2.1.267, Claude Code VS Code extension 2.1.267, against
|
|
279
|
+
the ChatGPT/Codex-plan OAuth provider:
|
|
287
280
|
|
|
288
281
|
- Step 1 routes extension traffic through clodex, and a model set as default from `clodex claude` is
|
|
289
282
|
used by the extension.
|
|
290
|
-
-
|
|
283
|
+
- A process wrapper that launches a patched binary makes clodex models appear in the extension's
|
|
284
|
+
model picker and selectable from it.
|
|
291
285
|
- The extension's bundled binary was unpatched, matching clodex's pristine backup by SHA-256.
|
|
292
|
-
- The wrapper's target resolution, exercised in all four states: `patch-state.json` present (runs the
|
|
293
|
-
recorded binary), manifest absent (falls back to the handed-in binary), manifest absent with an
|
|
294
|
-
unreadable handed-in path (exits 1 with a message rather than hanging), and the normal case on this
|
|
295
|
-
machine. The listing above was extracted from this page and compiled to confirm it builds as
|
|
296
|
-
printed.
|
|
297
286
|
|
|
298
|
-
Not verified: any Node version manager other than NVM for Windows, any provider other than
|
|
287
|
+
Not verified there: any Node version manager other than NVM for Windows, any provider other than
|
|
299
288
|
ChatGPT/Codex-plan OAuth, and the two wrapper consequences above, which were read from the
|
|
300
289
|
extension's code rather than reproduced.
|
|
290
|
+
|
|
291
|
+
`clodex install-vscode-launcher` is verified on every pull request by a Windows CI job
|
|
292
|
+
(`windows-latest`, `tests/vscode-launcher.windows.test.ts`): the command builds the launcher with the
|
|
293
|
+
runner's own .NET Framework `csc.exe`; the resulting `.exe` is spawned the way the extension spawns
|
|
294
|
+
it (no shell, arguments as a list) with `node.exe` plus a probe script standing in for the bundled
|
|
295
|
+
Claude Code; argument values with spaces, quotes, JSON, empty strings, `%PATH%`, `&|<>^` and
|
|
296
|
+
non-ASCII text arrive at the probe unchanged through Node and `clodex-claude`; stdin, stdout and the
|
|
297
|
+
exit code pass through; killing the launcher takes Node, the probe and the probe's own child process
|
|
298
|
+
down; re-running the install over a running launcher ends in a one-line message; and a launcher
|
|
299
|
+
whose baked wrapper script was removed exits 127 with the re-run hint. Off Windows the command's
|
|
300
|
+
compiler discovery, source rendering, scratch compile and install are exercised against a fake
|
|
301
|
+
`csc.exe`.
|
|
302
|
+
|
|
303
|
+
The patched-install substitution behind the launcher is verified on the same job by
|
|
304
|
+
`tests/wrapper-substitution.windows.test.ts`: a fake `claude.exe` compiled with the runner's
|
|
305
|
+
`csc.exe` is patched by the real `clodex patch` command, the launcher is handed a pristine copy of
|
|
306
|
+
it and runs the patched one (its output names which copy ran, and the proxy settings and arguments
|
|
307
|
+
reach it intact); a same-size copy with different bytes runs as handed in with exactly one line on
|
|
308
|
+
stderr, written before anything the binary prints; helper spawns (`auth status`,
|
|
309
|
+
`--no-session-persistence` queries) fall back silently; and a dead server disables substitution.
|
|
310
|
+
The same file records what Node reports about files on the runner's NTFS volume (file ids, volume
|
|
311
|
+
serial, change time on an in-place rewrite, the read-only attribute) and prints the time to hash a
|
|
312
|
+
200 MB file.
|
|
313
|
+
|
|
314
|
+
**Not covered by CI, please report on #245 if you can try it:** the real VS Code extension spawning
|
|
315
|
+
the launcher and showing clodex models in its picker (it is spawned by a test harness in CI, which
|
|
316
|
+
cannot open an editor), Windows Defender/SmartScreen behaviour on the freshly compiled `.exe`, and
|
|
317
|
+
Windows on ARM.
|
|
318
|
+
|
|
319
|
+
```powershell
|
|
320
|
+
# 1. Build, and note the three paths it prints.
|
|
321
|
+
clodex install-vscode-launcher
|
|
322
|
+
|
|
323
|
+
# 2. Paste the printed "claudeCode.claudeProcessWrapper" line into user settings, remove the
|
|
324
|
+
# HTTPS_PROXY/HTTP_PROXY/NODE_EXTRA_CA_CERTS entries, keep `clodex server --proxy` running,
|
|
325
|
+
# Developer: Reload Window. Then, with a chat open and a reply streaming:
|
|
326
|
+
Get-Process node, claude -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, StartTime
|
|
327
|
+
# Press the stop button in the chat, wait five seconds, run the same line again: the node/claude
|
|
328
|
+
# processes started when the chat began (their StartTime) must be gone. Paste both listings.
|
|
329
|
+
|
|
330
|
+
# 3. Output channel: View > Output > "Claude VSCode". Paste any line starting with
|
|
331
|
+
# "From claude: clodex-claude.exe:" (job-object warnings) — there should be none.
|
|
332
|
+
|
|
333
|
+
# 4. Defender/SmartScreen: paste any prompt or quarantine notice about
|
|
334
|
+
# $env:USERPROFILE\.clodex\bin\clodex-claude.exe, or say there was none.
|
|
335
|
+
```
|