mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-07-03 12:27:41 +08:00
### What this PR does fix #13833 Before this PR: Spawned Claude Code child processes did not reliably use the app's configured proxy settings. HTTP proxy mode could work, but SOCKS proxy mode could hang before the SDK returned any initial stream events. After this PR: Spawned Claude Code child processes inherit a dedicated Node-only proxy bootstrap that applies the app's configured proxy settings for fetch/undici, http/https, and axios. SOCKS proxy mode now avoids exporting incompatible HTTP proxy env vars and emits clearer diagnostics when proxy injection is active. Fixes # None ### Why we need it and why it was done in this way Claude Code runs as a standalone spawned `cli.js` process, so main-process proxy patching and Electron session proxy configuration do not automatically apply to it. This change builds a separate proxy bootstrap, injects it only when proxy settings are configured, and keeps the child-process proxy behavior aligned with the app's proxy settings without changing the Claude SDK package itself. The following tradeoffs were made: - Added a separate build artifact for the Claude Code child-process proxy bootstrap. - Added child-process-specific proxy diagnostics to improve debugging when proxy routing fails. - Split SOCKS proxy environment handling from HTTP proxy handling to avoid incompatible env combinations. The following alternatives were considered: - Relying only on inherited shell proxy environment variables. - Relying on Electron session proxy configuration from the main process. - Patching the Claude SDK package directly instead of injecting a local bootstrap. Links to places where the discussion took place: None ### Breaking changes None. If this PR introduces breaking changes, please describe the changes and the impact on users. No breaking changes. ### Special notes for your reviewer - `out/proxy/index.js` is built as a standalone child-process bootstrap and unpacked for packaged app usage. - SOCKS proxy mode now exports `ALL_PROXY` / `SOCKS_PROXY` for the Claude child process instead of forcing `HTTP_PROXY` / `HTTPS_PROXY` to a SOCKS URL. - Added tests covering HTTP vs SOCKS child-process proxy environment generation. ### Checklist This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR. Approvers are expected to review this list. - [x] PR: The PR description is expressive enough and will help future contributors - [x] Code: [Write code that humans can understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans) and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle) - [x] Refactor: You have [left the code cleaner than you found it (Boy Scout Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html) - [x] Upgrade: Impact of this change on upgrade flows was considered and addressed if required - [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com) was considered and is present (link) or not required. Check this only when the PR introduces or changes a user-facing feature or behavior. - [x] Self-review: I have reviewed my own code (e.g., via [`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`, or GitHub UI) before requesting review from others ### Release note <!-- Write your release note: 1. Enter your extended release note in the below block. If the PR requires additional action from users switching to the new release, include the string "action required". 2. If no release note is required, just write "NONE". 3. Only include user-facing changes (new features, bug fixes visible to users, UI changes, behavior changes). For CI, maintenance, internal refactoring, build tooling, or other non-user-facing work, write "NONE". --> ```release-note Fixed Claude Code agent sessions so spawned child processes respect configured HTTP and SOCKS proxy settings. ``` --------- Signed-off-by: beyondkmp <beyondkmp@gmail.com> Signed-off-by: Payne Fu <payne@Paynes-MacBook-Air.local> Co-authored-by: Payne Fu <payne@Paynes-MacBook-Air.local> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: suyao <sy20010504@gmail.com> Co-authored-by: 亢奋猫 <kangfenmao@qq.com> Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
53 lines
1.3 KiB
TypeScript
53 lines
1.3 KiB
TypeScript
import { builtinModules } from 'node:module'
|
|
|
|
import { resolve } from 'path'
|
|
import { build as viteBuild, type Plugin } from 'vite'
|
|
|
|
interface BuildProxyBootstrapPluginOptions {
|
|
dependencies: string[]
|
|
isProd: boolean
|
|
rootDir: string
|
|
}
|
|
|
|
export const buildProxyBootstrapPlugin = ({
|
|
dependencies,
|
|
isProd,
|
|
rootDir
|
|
}: BuildProxyBootstrapPluginOptions): Plugin => {
|
|
return {
|
|
name: 'cherry-build-proxy-bootstrap',
|
|
apply: 'build',
|
|
async closeBundle() {
|
|
await viteBuild({
|
|
configFile: false,
|
|
publicDir: false,
|
|
resolve: {
|
|
mainFields: ['module', 'jsnext:main', 'jsnext'],
|
|
conditions: ['node']
|
|
},
|
|
build: {
|
|
outDir: resolve(rootDir, 'out/proxy'),
|
|
target: 'node22',
|
|
minify: false,
|
|
reportCompressedSize: false,
|
|
copyPublicDir: false,
|
|
lib: {
|
|
entry: resolve(rootDir, 'src/main/services/proxy/bootstrap.ts'),
|
|
formats: ['cjs'],
|
|
fileName: () => 'index.js'
|
|
},
|
|
rollupOptions: {
|
|
external: [
|
|
'electron',
|
|
/^electron\/.+/,
|
|
...builtinModules.flatMap((moduleName) => [moduleName, `node:${moduleName}`]),
|
|
...dependencies
|
|
]
|
|
}
|
|
},
|
|
esbuild: isProd ? { legalComments: 'none' } : {}
|
|
})
|
|
}
|
|
}
|
|
}
|