Repository navigation
Conversation
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
Co-authored-by: Aiden Cline <[email protected]> Co-authored-by: r266-tech <[email protected]> Co-authored-by: pj.reid <[email protected]>
3ee86c9 to
f3be23e
Compare
There was a problem hiding this comment.
The proxy fix works. I ran the PR's own end-to-end tests on base and on this branch. On base, the CLI's /api/info request and the client's discovery/API/SSE requests to a loopback server all went through a stub HTTP_PROXY (502). With this PR they connect directly. The new and nearby tests in cli, client, core and desktop pass. I did not test the desktop app or Windows.
Public API: in @opencode/client, OpenCode.make now uses a fetch that sets proxy: false for loopback URLs when the caller doesn't pass its own fetch. The CLI and Desktop now add 127.0.0.1,localhost,::1 to both NO_PROXY and no_proxy at startup (or set both to * if either contains *), and the service applies the same merge to NO_PROXY/no_proxy saved in its environment. This is backwards compatible: only loopback traffic stops going through env proxies.
Concerns:
- The description doesn't match the diff. It describes
AllocConsoleWithOptionsandhidden-console.*changes for Windows console flashing, and none of those files are in this PR. ItsFixes #52266/Closes #59598would auto-close two Windows console-window issues that this change doesn't touch. Please replace the description with one for the proxy change and drop those two references. The issue this actually fixes is #52054. - Core's type check breaks (
RequestInfoinloopback.ts, see inline). - The
NO_PROXYmerge logic is duplicated between cli and desktop (see inline).
| // Bun routes loopback fetch() calls through HTTP(S)_PROXY/ALL_PROXY unless proxy: false is set on the request; | ||
| // browsers and Node's fetch ignore the extra field. | ||
| export const loopbackAwareFetch = Object.assign( | ||
| (input: RequestInfo | URL, init?: RequestInit) => { |
There was a problem hiding this comment.
RequestInfo is a DOM global that core's tsconfig (types: ["bun"], no DOM lib) doesn't have. Core type-checks this file through its references, so bun run typecheck:tsc in packages/core now fails with TS2552: Cannot find name 'RequestInfo' (it passes on base). Parameters<typeof globalThis.fetch>[0] (or string | URL | Request) avoids that.
| @@ -0,0 +1,34 @@ | |||
| // Bun and Node's EnvHttpProxyAgent read lowercase `no_proxy` alone whenever set, so both spellings | |||
| // receive one merged list. Preserves `*` intact because EnvHttpProxyAgent checks `noProxy === "*"`. | |||
| export function ensureLoopbackNoProxy() { | |||
There was a problem hiding this comment.
This is the same merge as Env.ensureLoopbackNoProxy in packages/cli/src/env.ts. Both packages already depend on @opencode/client, which now has the matching loopback.ts. Keeping one copy there (taking an env record, like the CLI version) would stop the two lists drifting apart, for example when the next wildcard or IPv6 edge case gets fixed in only one of them.
There was a problem hiding this comment.
The earlier type-check issue is fixed: core's typecheck:tsc and the client's tsc are clean again, and the loopback-proxy tests still pass. The updated description now correctly targets #52054. The duplicated NO_PROXY merge between cli and desktop is still open in its thread. Nothing new to raise.
Public API is unchanged from my last review: @opencode/client OpenCode.make still bypasses env proxies for loopback URLs when no custom fetch is passed, and the CLI and Desktop still merge loopback hosts into NO_PROXY/no_proxy. This is backwards compatible.
Issue for this PR
Fixes #52054
Related: #51247
Supersedes #60441, #57030, #57744
Type of change
What does this PR do?
Exempts loopback traffic from
HTTP(S)_PROXY/ALL_PROXYat both the transport boundary (@opencode/client,@opencode/core) and process startup (@opencode/cli,@opencode/desktop), stopping/api/eventSSE stalls, false unresponsive-service kills, and Basic-auth password leaks to forward proxies.@opencode/client,@opencode/core):service-probeandOpenCode.makewrap defaultfetchwith Bun's{ proxy: false }forlocalhost,*.localhost,127.0.0.0/8(e.g.127.0.0.2), and[::1], protecting standalone SDK callers and early probes before any CLI entrypoint runs;WebSocketConstructor.proxynow matches bracketed IPv6[::1],127.0.0.0/8, and*.localhost.NO_PROXY/no_proxymerge (@opencode/cli,@opencode/desktop): Bun and Node'sEnvHttpProxyAgentread lowercaseno_proxyalone whenever set whileWebSocketConstructorreads uppercaseNO_PROXYfirst, so both spellings receive one case-insensitively deduplicated list (corp.internal,127.0.0.1,localhost,::1).*preservation: KeepsNO_PROXY=*intact as"*"instead of"*,127.0.0.1,...", which otherwise breaks Node/Electron'sEnvHttpProxyAgentexactnoProxy === "*"check underhttp.setGlobalProxyFromEnv().ServiceConfig.processEnvand afterObject.assign(process.env, ...)inserver-process.tssoopencode service set env no_proxy ...cannot recapture loopback; runsensureLoopbackNoProxy()before Desktop'sstartSidecarProbe()andBackgroundService.connect, dropping the duplicateloadProxyEnvironmentcall.Env.session()restores the caller's pre-startupNO_PROXY/no_proxysnapshot sobashtool subprocesses do not inherit synthetic loopback exemptions.How did you verify your code works?
Unit and integration coverage across
@opencode/client,@opencode/cli,@opencode/core, and@opencode/desktopagainst a recording502proxy withHTTP(S)_PROXY/ALL_PROXYset andNO_PROXYempty or split.Visual
Checklist
Added by the opencode bot (AI-generated).
Fixes #52054
Related: #49796, #47041, #54523, #51247
Public API: @opencode/client OpenCode.make bypasses env proxies for loopback URLs by default; CLI/Desktop add loopback hosts to NO_PROXY/no_proxy (backwards compatible)