Files
update: install.sh and magpie update take --proxy and --mirror, and magpie update mirror keeps one for the app's updates too (akic404 on Discord: 安装和update如果没有梯子也是麻烦事,能否在install.sh和magpie update后加子选项?--proxy等可自定义或默认ghproxy) — install.sh had no options and fetched with curl alone, and magpie update took none; without a way out to GitHub both failed. Now both take --proxy <url> (http, https, socks5, socks5h; install.sh also MAGPIE_PROXY=) for the feed and the download, and --mirror <prefix> (or MAGPIE_MIRROR=), a GitHub download mirror the release file is fetched from as <prefix>https://github.com/…; only github.com / githubusercontent.com URLs are put through it. No mirror is used unless one is given: magpie names none and has none by default. The feed with each file's SHA-256 is always fetched from usemagpie.ai, never through the mirror, so a file the mirror changed is refused and deleted ("… from the mirror X does not match its checksum from https://usemagpie.ai; not installed"); macOS still checks the app's signing team. magpie update mirror <prefix>|off saves Settings' updateMirror (http(s) only), which the app's own background update follows too; magpie update --mirror off skips it once; the Settings page's save keeps it. The app's update already followed Settings → Proxy (#294); magpie update --proxy overrides it for one run. The environment's ALL_PROXY / all_proxy is now honoured when HTTPS_PROXY / HTTP_PROXY are unset (Go's ProxyFromEnvironment ignores it), with NO_PROXY as curl reads it. magpie update takes --flag value or --flag=value, and an unknown word is an error instead of an update. The help, README and the docs' FAQ (en/zh/ja) say how. install.test.mjs's proxy, mirror and tampered-mirror tests, TestAllProxyFromTheEnvironment, TestUpdateThroughAMirror, TestUpdateThroughAProxyGiven and TestUpdateFlags fail on the old code and pass; TestSettingsSaveKeepsWhatItDoesNotSend covers updateMirror. A dry run of install.sh as Linux amd64 into a temp HOME installed the real 0.1.773 with its SHA-256 checked, refused a local mirror serving a wrong file, and with --proxy to a closed port failed reaching the site through it. go vet, builds (darwin, GOOS=linux, GOOS=windows), sh -n, node --test site/install.test.mjs and go test -tags nogui -count=1 ./... under a temp HOME pass but TestClaudeIdentityServedWhileAsked, a timing test that passes alone. Not tried through a real proxy server or a real public mirror; no install.ps1 exists for Windows, and the app has no field for the mirror.
netproxy: a host on the user's own network goes around the proxy (#982, jiz4oh: a Remote magpie's model list failed with "no model list: http://server…:3425/v1/models: 502 Bad Gateway", and Test with "no model to try", while curl with the key got the list) — the 502 had no body, which magpie's own errors always carry, and the other magpie logged nothing for the refresh: the request went to the proxy magpie takes from its settings, the environment or the system (Clash and the like), which couldn't reach the LAN name and answered 502. netproxy.Func now sends a request directly when the global proxy would take it and the host is on the user's network: a private, link-local, loopback or 100.64/10 (Tailscale) address, a .local name, or a name whose every address is one of those (looked up for at most 400ms, kept a minute; a name that doesn't resolve still goes through the proxy). A provider's own proxy is still taken as it is. Models, chat, count_tokens and the shared quota cards to a Remote magpie all go through Func (http.DefaultClient and the gateway's transport), so all are covered; so is any other provider on the LAN (an Ollama on a NAS). TestLANModelListNotThroughProxy (a proxy that answers 502 to everything, set in magpie, and a fake remote magpie on this computer's LAN address) fails without the change with the reporter's bare "502 Bad Gateway" and passes; TestLANGoesAroundTheProxy (IPs, LAN/Tailscale names, a vendor, a provider's own proxy) fails without it. Not tried on the reporter's network; they're asked to confirm. go test ./internal/netproxy/ ./internal/catalog/ ./internal/provider/ ./internal/gateway/ ./internal/update/ ./internal/usage/ pass; -race -count=5 on the new tests; go vet, darwin/linux(nogui)/windows builds pass.
netproxy: a host on the user's own network goes around the proxy (#982, jiz4oh: a Remote magpie's model list failed with "no model list: http://server…:3425/v1/models: 502 Bad Gateway", and Test with "no model to try", while curl with the key got the list) — the 502 had no body, which magpie's own errors always carry, and the other magpie logged nothing for the refresh: the request went to the proxy magpie takes from its settings, the environment or the system (Clash and the like), which couldn't reach the LAN name and answered 502. netproxy.Func now sends a request directly when the global proxy would take it and the host is on the user's network: a private, link-local, loopback or 100.64/10 (Tailscale) address, a .local name, or a name whose every address is one of those (looked up for at most 400ms, kept a minute; a name that doesn't resolve still goes through the proxy). A provider's own proxy is still taken as it is. Models, chat, count_tokens and the shared quota cards to a Remote magpie all go through Func (http.DefaultClient and the gateway's transport), so all are covered; so is any other provider on the LAN (an Ollama on a NAS). TestLANModelListNotThroughProxy (a proxy that answers 502 to everything, set in magpie, and a fake remote magpie on this computer's LAN address) fails without the change with the reporter's bare "502 Bad Gateway" and passes; TestLANGoesAroundTheProxy (IPs, LAN/Tailscale names, a vendor, a provider's own proxy) fails without it. Not tried on the reporter's network; they're asked to confirm. go test ./internal/netproxy/ ./internal/catalog/ ./internal/provider/ ./internal/gateway/ ./internal/update/ ./internal/usage/ pass; -race -count=5 on the new tests; go vet, darwin/linux(nogui)/windows builds pass.
update: install.sh and magpie update take --proxy and --mirror, and magpie update mirror keeps one for the app's updates too (akic404 on Discord: 安装和update如果没有梯子也是麻烦事,能否在install.sh和magpie update后加子选项?--proxy等可自定义或默认ghproxy) — install.sh had no options and fetched with curl alone, and magpie update took none; without a way out to GitHub both failed. Now both take --proxy <url> (http, https, socks5, socks5h; install.sh also MAGPIE_PROXY=) for the feed and the download, and --mirror <prefix> (or MAGPIE_MIRROR=), a GitHub download mirror the release file is fetched from as <prefix>https://github.com/…; only github.com / githubusercontent.com URLs are put through it. No mirror is used unless one is given: magpie names none and has none by default. The feed with each file's SHA-256 is always fetched from usemagpie.ai, never through the mirror, so a file the mirror changed is refused and deleted ("… from the mirror X does not match its checksum from https://usemagpie.ai; not installed"); macOS still checks the app's signing team. magpie update mirror <prefix>|off saves Settings' updateMirror (http(s) only), which the app's own background update follows too; magpie update --mirror off skips it once; the Settings page's save keeps it. The app's update already followed Settings → Proxy (#294); magpie update --proxy overrides it for one run. The environment's ALL_PROXY / all_proxy is now honoured when HTTPS_PROXY / HTTP_PROXY are unset (Go's ProxyFromEnvironment ignores it), with NO_PROXY as curl reads it. magpie update takes --flag value or --flag=value, and an unknown word is an error instead of an update. The help, README and the docs' FAQ (en/zh/ja) say how. install.test.mjs's proxy, mirror and tampered-mirror tests, TestAllProxyFromTheEnvironment, TestUpdateThroughAMirror, TestUpdateThroughAProxyGiven and TestUpdateFlags fail on the old code and pass; TestSettingsSaveKeepsWhatItDoesNotSend covers updateMirror. A dry run of install.sh as Linux amd64 into a temp HOME installed the real 0.1.773 with its SHA-256 checked, refused a local mirror serving a wrong file, and with --proxy to a closed port failed reaching the site through it. go vet, builds (darwin, GOOS=linux, GOOS=windows), sh -n, node --test site/install.test.mjs and go test -tags nogui -count=1 ./... under a temp HOME pass but TestClaudeIdentityServedWhileAsked, a timing test that passes alone. Not tried through a real proxy server or a real public mirror; no install.ps1 exists for Windows, and the app has no field for the mirror.
netproxy: a host on the user's own network goes around the proxy (#982, jiz4oh: a Remote magpie's model list failed with "no model list: http://server…:3425/v1/models: 502 Bad Gateway", and Test with "no model to try", while curl with the key got the list) — the 502 had no body, which magpie's own errors always carry, and the other magpie logged nothing for the refresh: the request went to the proxy magpie takes from its settings, the environment or the system (Clash and the like), which couldn't reach the LAN name and answered 502. netproxy.Func now sends a request directly when the global proxy would take it and the host is on the user's network: a private, link-local, loopback or 100.64/10 (Tailscale) address, a .local name, or a name whose every address is one of those (looked up for at most 400ms, kept a minute; a name that doesn't resolve still goes through the proxy). A provider's own proxy is still taken as it is. Models, chat, count_tokens and the shared quota cards to a Remote magpie all go through Func (http.DefaultClient and the gateway's transport), so all are covered; so is any other provider on the LAN (an Ollama on a NAS). TestLANModelListNotThroughProxy (a proxy that answers 502 to everything, set in magpie, and a fake remote magpie on this computer's LAN address) fails without the change with the reporter's bare "502 Bad Gateway" and passes; TestLANGoesAroundTheProxy (IPs, LAN/Tailscale names, a vendor, a provider's own proxy) fails without it. Not tried on the reporter's network; they're asked to confirm. go test ./internal/netproxy/ ./internal/catalog/ ./internal/provider/ ./internal/gateway/ ./internal/update/ ./internal/usage/ pass; -race -count=5 on the new tests; go vet, darwin/linux(nogui)/windows builds pass.
windows: the desktop app no longer opens a console window for every command it runs (#54) — it is linked as a GUI program and has no console, so each console CLI it started (devin auth status and models list, devin acp for every Devin turn, claude, codex, cursor-agent and grok probes and runs, grok login) was given a new console by Windows, and a Windows Terminal window with it, some every few seconds while the app sat idle. Every command magpie runs is now made through internal/proc, which starts it with CREATE_NO_WINDOW when magpie has no console of its own: the child gets a console without a window, and its output, which magpie always pipes back, arrives as before. A magpie run in a terminal (magpie serve, the TUI, the desktop app started from one with a command) has one, and its children share it as they did, so Ctrl+C there still reaches them. The relaunch after an update keeps its DETACHED_PROCESS, added to rather than replacing the flags it was made with, and a test fails on any command made with os/exec directly, so a new one can't bring the windows back
netproxy: a host whose IPv6 takes the connection and drops it is reached over IPv4 (tony on Discord: models.dev sync and the update check failed with a bare EOF, direct or auto, while curl got through) — behind a TUN (xray) without IPv6 out, a connection to a site's IPv6 address is accepted, so the dialer's own fallback to IPv4 never starts, and closed once TLS begins. A connection to an IPv6 address that ends before a byte comes back now marks its host:port to be dialed over IPv4 for 30 minutes, and the request that met it is sent once more over IPv4 when nothing of it can have reached the site (HTTPS, or an idempotent method) and its body can be had again; proxied requests and IPv4 connections are left as they are, and TLS, ALPN/HTTP/2, headers and bodies are unchanged. Every transport made with Dispatch (http.DefaultClient, the gateway's) and the update client get it. TestIPv4Fallback fails without the change (Get "https://example.com/": EOF). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFXInState flaked on TempDir cleanup under load, passes alone).
netproxy: a host whose IPv6 takes the connection and drops it is reached over IPv4 (tony on Discord: models.dev sync and the update check failed with a bare EOF, direct or auto, while curl got through) — behind a TUN (xray) without IPv6 out, a connection to a site's IPv6 address is accepted, so the dialer's own fallback to IPv4 never starts, and closed once TLS begins. A connection to an IPv6 address that ends before a byte comes back now marks its host:port to be dialed over IPv4 for 30 minutes, and the request that met it is sent once more over IPv4 when nothing of it can have reached the site (HTTPS, or an idempotent method) and its body can be had again; proxied requests and IPv4 connections are left as they are, and TLS, ALPN/HTTP/2, headers and bodies are unchanged. Every transport made with Dispatch (http.DefaultClient, the gateway's) and the update client get it. TestIPv4Fallback fails without the change (Get "https://example.com/": EOF). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFXInState flaked on TempDir cleanup under load, passes alone).