yetone
ee8a371cf4
gui, update: saving the Settings page keeps the models hidden from each agent, and update checks go through magpie's proxy and say so (#294: 设置代理之后只有模型代理生效了,代理没有用于检查 magpie 是否有更新) — POST /api/settings carried over the models' names, levels and images but not HiddenModels, which the page never sends, so changing the theme, the language or anything else there showed every model hidden one by one on the Agents page again; it is carried over with the others. The update feed and the release came through http.DefaultTransport, proxied only because main installs netproxy first; the update client now takes netproxy.Func on a transport of its own (Settings' Proxy, else *_PROXY, else the system's). A check that failed at start-up, before a proxy was set, stayed failed for six hours: saving a new proxy now checks again through it. And the Settings row read "requests to vendors go through {proxy}", which says update checks don't: it now names both. TestSettingsSaveKeepsWhatItDoesNotSend (every field prefsKeep doesn't send survives a save of the theme alone; fails on main with HiddenModels emptied), TestUpdateGoesThroughTheProxy (feed and asset at hosts only a local proxy answers; fails without the transport), TestSettingsProxyRechecksAFailedUpdate (fails without the re-check). account-proxy, provider-proxy and click-scroll GUI tests pass; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin, known flakes under load, pass alone).
2026-09-30 16:03:52 +08:00
..
gui, update: saving the Settings page keeps the models hidden from each agent, and update checks go through magpie's proxy and say so (#294: 设置代理之后只有模型代理生效了,代理没有用于检查 magpie 是否有更新) — POST /api/settings carried over the models' names, levels and images but not HiddenModels, which the page never sends, so changing the theme, the language or anything else there showed every model hidden one by one on the Agents page again; it is carried over with the others. The update feed and the release came through http.DefaultTransport, proxied only because main installs netproxy first; the update client now takes netproxy.Func on a transport of its own (Settings' Proxy, else *_PROXY, else the system's). A check that failed at start-up, before a proxy was set, stayed failed for six hours: saving a new proxy now checks again through it. And the Settings row read "requests to vendors go through {proxy}", which says update checks don't: it now names both. TestSettingsSaveKeepsWhatItDoesNotSend (every field prefsKeep doesn't send survives a save of the theme alone; fails on main with HiddenModels emptied), TestUpdateGoesThroughTheProxy (feed and asset at hosts only a local proxy answers; fails without the transport), TestSettingsProxyRechecksAFailedUpdate (fails without the re-check). account-proxy, provider-proxy and click-scroll GUI tests pass; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin, known flakes under load, pass alone).
2026-09-30 16:03:52 +08:00
providers: DimAgent's subscription is taken out of magpie (a DimAgent team member on X: dim doesn't allow its subscription used through a proxy, and users doing so get banned or lose their discount) — #226 signed in to DimAgent as its desktop client does and served its models through the gateway. The sign-in, the account provider and its dimagent/<model> models, the quota card, magpie accounts … dimagent and the icon are gone, with internal/dimagent. An account signed in before is left out when logins.json is read and dropped from the file at its next write, so its tokens aren't kept. The pasted-callback field and route stay, generic, with no sign-in using them. Tested with TestDimAgentLoginDropped (fails without the filter); in a sandbox HOME with a DimAgent login left in logins.json, magpie accounts --json lists nothing and magpie accounts add dimagent is refused. signin-callback (fixture renamed), old-webkit and click-scroll pass; go vet, go build (GUI, -tags nogui, GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass (TestUserPath and the Claude/Devin sign-in tests flaked under the full run and pass alone).
2026-09-30 15:33:40 +08:00
tray: clicked, the bird flaps as the header logo does on hover (一定要用应用里的那个 Magpie icon 被 hover 的动画效果) — the frames were a bend of the outline of my own; now build/icon/gen.go draws app.css's .logo.wag itself: the bird cut into body, tail and wing by index.html's clip paths, each turned about the same origin through the same keyframes, cubic-bezier(.3, 0, .3, 1) between each two, the whole bobbing about its feet, over the same .9s — 29 frames played 30ms apart. Checked against Chrome's own rendering of the logo paused at the same 29 moments: at most 0.7% of pixels differ, all of them at anti-aliased edges
2026-09-28 18:43:55 +08:00
agents: each agent's own model list — under an agent's name on the Agents page, "Showing 5 / 32 models" (or "All 41 models") opens a list to take models out of that agent's picker one by one and put them back (@ChongkaiX on X: 在 magpie 里选哪些模型出现在 Codex 的模型列表里) — until now an agent's list could only be narrowed by whole providers or families (Visible). settings.HiddenModels holds, by agent, the catalog entries taken out, after Visible: a deny list, so a new model is shown. provider.CatalogFor drops them, so the gateway's /models, the agents' files and pickers and Codex's catalog all follow in one place, and catalog.Touched rewrites the agents' files; Codex's own ChatGPT models are dropped from the backend's list too (CodexNativeHidden), and the list's ETag and models_cache tag carry them (CodexListTag) so Codex asks again. The model an agent is set to is marked 在用 and never taken out, on the server as well. The list groups routing groups first, then providers with their logos and on/total, a long group folded; search, 全部/已显示, a group's 全部显示/全部隐藏 on hover, 恢复全部显示; a click on a row applies at once, Esc or a click elsewhere closes it, and nothing scrolls. A renamed provider's hidden models follow it. Tested with agent-models.test.cjs in Chromium and WebKit, English and Chinese; TestHiddenModels (provider), TestCodexModelListHidesOnAgentsPage (gateway) and TestAgentModelsAPI (gui) in sandbox HOMEs. click-scroll, panel-fold, old-webkit, model-pick, menu-scroll, add-button pass; GOOS=linux go vet, linux and windows builds, go test -tags nogui ./... pass. Not tried in the real Wails window or against a real Codex.
2026-09-30 12:44:59 +08:00
agents: an agent's model list shows each model's maker's logo (这里能否显示模型的图标?) — the list had a logo only on a provider's heading, so a relay's or a routing group's rows were names alone. Now each row has its maker's: known by the model's family (gpt → OpenAI, claude, gemini, grok, qwen, glm, mimo/xiaomi, step, …; "vendor/model" ids too), a routing group by the name it was given or its id, a model of a vendor's own provider by the provider's logo; a routing group whose maker isn't known shows the routing mark, anything else keeps the slot empty so the names line up; a model turned off has its logo dimmed. Checked in a sandbox HOME with a copy of the real providers (keys blanked): 路由组 shows OpenAI for GPT-6 Sol/Luna/Astra, Claude, MiMo, Grok, Qwen and the routing mark for semantic/test; AiHubMix's rows each their maker's; light and dark
2026-09-30 14:23:48 +08:00
gui, update: saving the Settings page keeps the models hidden from each agent, and update checks go through magpie's proxy and say so (#294: 设置代理之后只有模型代理生效了,代理没有用于检查 magpie 是否有更新) — POST /api/settings carried over the models' names, levels and images but not HiddenModels, which the page never sends, so changing the theme, the language or anything else there showed every model hidden one by one on the Agents page again; it is carried over with the others. The update feed and the release came through http.DefaultTransport, proxied only because main installs netproxy first; the update client now takes netproxy.Func on a transport of its own (Settings' Proxy, else *_PROXY, else the system's). A check that failed at start-up, before a proxy was set, stayed failed for six hours: saving a new proxy now checks again through it. And the Settings row read "requests to vendors go through {proxy}", which says update checks don't: it now names both. TestSettingsSaveKeepsWhatItDoesNotSend (every field prefsKeep doesn't send survives a save of the theme alone; fails on main with HiddenModels emptied), TestUpdateGoesThroughTheProxy (feed and asset at hosts only a local proxy answers; fails without the transport), TestSettingsProxyRechecksAFailedUpdate (fails without the re-check). account-proxy, provider-proxy and click-scroll GUI tests pass; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin, known flakes under load, pass alone).
2026-09-30 16:03:52 +08:00
gui: the tray panel's link to one request opens the Routing page on it again — ShowMain escaped the whole view it was given (831df85, v0.1.458, for magpie gui <tab>), so "routing&req=42" reached the window as one view named that, which is none: the window came up on no tab, the request not picked. Found reviewing #239, whose "Open Usage" link hit the same. The view mainView builds keeps its req as its own parameter (mainURL); only a tab named on the command line — magpie gui settings, a restart to update — is escaped (argView). Tested with a new TestMainURL (routing&req=42 comes through as view=routing, req=42; a command-line tab is escaped); it fails with the old escaping. panel-routing.test.cjs passes; go vet, go build (GUI, -tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass.
2026-09-30 13:09:27 +08:00
2026-09-27 03:44:55 +08:00
catalog: fetched again each day magpie stays open, and sooner when a call's model has no price, so a model models.dev lists after magpie started is priced (#224 Koohoko: gpt-6.1-sol shows no cost) — the models.dev catalog, where list prices come from, was fetched only at the app's start (when older than a week), so a magpie left open, or magpie serve, never learned a new model's price. KeepFresh (internal/catalog/fresh.go), run by the app's backend and by magpie serve, looks every hour and fetches when the cache is older than a day; a call whose model has no price asks for a fetch (catalog.Missing, from usage's pricer) when the cache is older than six hours and none was tried in that time, only in a process keeping it fresh, so CLI commands and tests never fetch on their own. Loading and Reset now share a mutex instead of a sync.Once reassigned under a running Do, which a background Sync could hit while a call was being priced. Tested with fresh_test.go against a fake models.dev in a temp XDG_CACHE_HOME: stale after 25h and not before, Missing fetching nothing when not keeping, fetching once when keeping and gpt-6.1-sol then priced, and not again; passes under -race (failed under -race with the Once). go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass.
2026-09-30 04:28:01 +08:00
agent: OmO (oh-my-openagent, omo-ai), a fork of Pi that keeps its own ~/.omo/agent, gets its own row: a magpie model sets settings.json's defaultProvider/defaultModel and magpie's provider in models.json there as Pi's does, $OMO_CODING_AGENT_DIR / $SENPI_CODING_AGENT_DIR are honoured, the Library writes its AGENTS.md, mcp.json and skills, and omo update updates it (#264 rhyme227). Pi's own ~/.pi is left alone. piIn becomes piLike(at, id, name, dir) so both share one wiring. Tested with omo_test.go in agent and library (fail without the change); go vet, go build -tags nogui (darwin, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass.
2026-09-30 11:38:07 +08:00
2026-09-28 14:54:04 +08:00
2026-09-28 14:54:04 +08:00
2026-09-24 12:17:45 +08:00
2026-09-24 12:17:45 +08:00
2026-09-29 11:59:57 +08:00
2026-09-28 18:56:50 +08:00
2026-09-28 18:56:50 +08:00
web: magpie web serves the app's window to a browser, with the gateway beside it — for a computer that can't show the app: no desktop, WSL, a server over SSH, or the CLI-only build, which now carries the page too (what of the app needs Wails is left out of nogui builds). Every request needs this run's key, which the printed link carries and trades for a cookie other sites' pages can't send with a POST; --lan serves it on the network too, with a warning, --addr elsewhere, --no-open leaves the browser shut. In the browser the page opens links and sign-ins itself, names a folder instead of opening it, and leaves out the tray, the Dock and open at login. Tested from a nogui build in a sandbox: no key, a wrong key and a cookieless POST are refused; with the link Agents, Providers and Settings load and a setting saves. Issue #102
2026-09-27 16:21:26 +08:00
2026-09-28 17:51:03 +08:00
2026-09-30 11:22:21 +08:00
web: magpie web serves the app's window to a browser, with the gateway beside it — for a computer that can't show the app: no desktop, WSL, a server over SSH, or the CLI-only build, which now carries the page too (what of the app needs Wails is left out of nogui builds). Every request needs this run's key, which the printed link carries and trades for a cookie other sites' pages can't send with a POST; --lan serves it on the network too, with a warning, --addr elsewhere, --no-open leaves the browser shut. In the browser the page opens links and sign-ins itself, names a folder instead of opening it, and leaves out the tray, the Dock and open at login. Tested from a nogui build in a sandbox: no key, a wrong key and a cookieless POST are refused; with the link Agents, Providers and Settings load and a setting saves. Issue #102
2026-09-27 16:21:26 +08:00
web: magpie web serves the app's window to a browser, with the gateway beside it — for a computer that can't show the app: no desktop, WSL, a server over SSH, or the CLI-only build, which now carries the page too (what of the app needs Wails is left out of nogui builds). Every request needs this run's key, which the printed link carries and trades for a cookie other sites' pages can't send with a POST; --lan serves it on the network too, with a warning, --addr elsewhere, --no-open leaves the browser shut. In the browser the page opens links and sign-ins itself, names a folder instead of opening it, and leaves out the tray, the Dock and open at login. Tested from a nogui build in a sandbox: no key, a wrong key and a cookieless POST are refused; with the link Agents, Providers and Settings load and a setting saves. Issue #102
2026-09-27 16:21:26 +08:00
2026-09-30 12:14:41 +08:00
web: magpie web serves the app's window to a browser, with the gateway beside it — for a computer that can't show the app: no desktop, WSL, a server over SSH, or the CLI-only build, which now carries the page too (what of the app needs Wails is left out of nogui builds). Every request needs this run's key, which the printed link carries and trades for a cookie other sites' pages can't send with a POST; --lan serves it on the network too, with a warning, --addr elsewhere, --no-open leaves the browser shut. In the browser the page opens links and sign-ins itself, names a folder instead of opening it, and leaves out the tray, the Dock and open at login. Tested from a nogui build in a sandbox: no key, a wrong key and a cookieless POST are refused; with the link Agents, Providers and Settings load and a setting saves. Issue #102
2026-09-27 16:21:26 +08:00
2026-09-29 19:41:29 +08:00
settings: a Text size preference (文字大小) that makes everything in magpie's windows larger, 100/110/125/150%, with Ctrl/Cmd + = − 0 in the window and the tray panel, and Windows' text drawn in its own UI faces (Discord, Clarence Dan: the font size is hard on the eyes on Windows) — Settings → Preferences gains a Text size row under Language whose pick posts to a new POST /api/settings/text-size (saved as settings.TextSize, validated against 100/110/125/150, 0 read as 100, and kept by the Settings page's general save, which never sends it). The size is each webview's own zoom, as a browser zooms, not CSS zoom: CSS zoom leaves getBoundingClientRect and clientX in zoomed pixels while offsets, scrollTop and 100vh are not, and app.js, routing.js and library.js place menus, popovers and the panel's height by those measures; under the webview's zoom the page is laid out again in fewer, larger CSS pixels and every measure agrees. Windows and Linux use Wails' SetZoom (WebView2's zoom factor, WebKitGTK's zoom level; the Zoom window option at creation, so the pages open at the saved size), the Mac WKWebView.pageZoom through cgo (macOS 11+), since Wails' Mac zoom is magnification, which lays nothing out again. None is under 100% because Wails clamps SetZoom below 1 on Windows and Linux. The windows grow around the pages: the panel's width and the height its page asks for (still in CSS pixels) are multiplied by the zoom, capped at the screen's work area (textsize.go panelFrame), and resized at once when the size changes; the main window's minimum is 560×420 CSS pixels at the size, capped by the screen, so a window smaller than that grows. Runtime changes wait for the app to be ready (whenReady), and at startup the Mac applies the zoom once its webviews exist. The Mac header, drawn under the native traffic lights which do not grow, divides its height, left padding and the modal's top by --zoom (set from boot.js before the first paint and from the settings), so it stays 50 points tall and level with them. The shortcuts are Cmd on the Mac and Ctrl elsewhere (the other modifier does nothing), step through the sizes and 0 goes back to 100%, with a "Text size 125%" toast; in magpie web the row is hidden and the keys are left to the browser's own zoom. On Windows the page names its faces (html.win): Segoe UI Variable Text, Segoe UI, then Microsoft YaHei UI for Chinese rather than whatever WebView2 falls back to; the Mac and Linux stack is unchanged, and there is no automatic size bump. New strings in en and zh. Tested: internal/gui/tests/text-size.test.cjs in Chromium and WebKit, en and zh, light and dark — a pick posts and does not scroll the settings page, stays picked after a reload with --zoom from boot.js, the Settings page's other saves leave it, the shortcuts step and reset in the window and the panel, and at 150% (the smallest window, 840×630 points, as 560×420 CSS pixels at device scale 1.5) no view, the header or the panel runs off to the side, the Mac header is 50 points; screenshots at 100% and 150% looked at. currency.test.cjs's viewport is 480 tall instead of 420, as settings-groups' is: the new row put the Currency control under the footer, where WebKit's hover could not reach it. Go: TestTextSizeFrames (panel and window sizes) and TestTextSizeSetting (the endpoint saves, zooms the windows, rejects 133, survives the general save, boot.js carries it) in internal/gui, and the settings round trip. go build -tags nogui (and GOOS=linux, GOOS=windows, plain darwin), go test -tags nogui ./... (TestUserPath flaked once under load and passes alone) and the whole GUI suite with --test-concurrency=2 pass. Not tried in the real Wails window on any platform: the Mac pageZoom, WebView2's zoom factor with the resized panel and the Windows font are untested there.
2026-09-30 02:51:17 +08:00
settings: a Text size preference (文字大小) that makes everything in magpie's windows larger, 100/110/125/150%, with Ctrl/Cmd + = − 0 in the window and the tray panel, and Windows' text drawn in its own UI faces (Discord, Clarence Dan: the font size is hard on the eyes on Windows) — Settings → Preferences gains a Text size row under Language whose pick posts to a new POST /api/settings/text-size (saved as settings.TextSize, validated against 100/110/125/150, 0 read as 100, and kept by the Settings page's general save, which never sends it). The size is each webview's own zoom, as a browser zooms, not CSS zoom: CSS zoom leaves getBoundingClientRect and clientX in zoomed pixels while offsets, scrollTop and 100vh are not, and app.js, routing.js and library.js place menus, popovers and the panel's height by those measures; under the webview's zoom the page is laid out again in fewer, larger CSS pixels and every measure agrees. Windows and Linux use Wails' SetZoom (WebView2's zoom factor, WebKitGTK's zoom level; the Zoom window option at creation, so the pages open at the saved size), the Mac WKWebView.pageZoom through cgo (macOS 11+), since Wails' Mac zoom is magnification, which lays nothing out again. None is under 100% because Wails clamps SetZoom below 1 on Windows and Linux. The windows grow around the pages: the panel's width and the height its page asks for (still in CSS pixels) are multiplied by the zoom, capped at the screen's work area (textsize.go panelFrame), and resized at once when the size changes; the main window's minimum is 560×420 CSS pixels at the size, capped by the screen, so a window smaller than that grows. Runtime changes wait for the app to be ready (whenReady), and at startup the Mac applies the zoom once its webviews exist. The Mac header, drawn under the native traffic lights which do not grow, divides its height, left padding and the modal's top by --zoom (set from boot.js before the first paint and from the settings), so it stays 50 points tall and level with them. The shortcuts are Cmd on the Mac and Ctrl elsewhere (the other modifier does nothing), step through the sizes and 0 goes back to 100%, with a "Text size 125%" toast; in magpie web the row is hidden and the keys are left to the browser's own zoom. On Windows the page names its faces (html.win): Segoe UI Variable Text, Segoe UI, then Microsoft YaHei UI for Chinese rather than whatever WebView2 falls back to; the Mac and Linux stack is unchanged, and there is no automatic size bump. New strings in en and zh. Tested: internal/gui/tests/text-size.test.cjs in Chromium and WebKit, en and zh, light and dark — a pick posts and does not scroll the settings page, stays picked after a reload with --zoom from boot.js, the Settings page's other saves leave it, the shortcuts step and reset in the window and the panel, and at 150% (the smallest window, 840×630 points, as 560×420 CSS pixels at device scale 1.5) no view, the header or the panel runs off to the side, the Mac header is 50 points; screenshots at 100% and 150% looked at. currency.test.cjs's viewport is 480 tall instead of 420, as settings-groups' is: the new row put the Currency control under the footer, where WebKit's hover could not reach it. Go: TestTextSizeFrames (panel and window sizes) and TestTextSizeSetting (the endpoint saves, zooms the windows, rejects 133, survives the general save, boot.js carries it) in internal/gui, and the settings round trip. go build -tags nogui (and GOOS=linux, GOOS=windows, plain darwin), go test -tags nogui ./... (TestUserPath flaked once under load and passes alone) and the whole GUI suite with --test-concurrency=2 pass. Not tried in the real Wails window on any platform: the Mac pageZoom, WebView2's zoom factor with the resized panel and the Windows font are untested there.
2026-09-30 02:51:17 +08:00
2026-09-25 02:19:32 +08:00
2026-09-25 02:19:32 +08:00
2026-09-26 14:14:26 +08:00
routing: a group's member may be a model at an effort of its own, provider/model:low (#189, @luw2007: model + effort 才是完整的组合项) — a member was only a model, reasoning as the agent asked or as the group's classifier picked, so "the same model, cheap and quick" and "the same model, thinking hard" could not both be in a group, nor could a rule send to one of them. A member now may carry an effort (none … max): a request routed to it is asked for that much reasoning whatever the agent asked or effort=auto picked, at the level the model has nearest, while the vendor is asked for the model's own id. The same model at two efforts is two members that rules (use=m:high), stickiness and the trace tell apart; an id whose own last part is a colon (a :free, :7b, :0) stays the model's. The group's reasoning levels are those of its members that follow the agent, and the editor has a reasoning button on each member. Tested with a fake provider through a sandbox magpie: the upstream bodies carry the fixed effort in Chat, Responses and Anthropic shapes, and the routing view shows m1:low / m1:high as two seats, light and dark
2026-09-29 13:45:29 +08:00
2026-09-26 01:03:33 +08:00
2026-09-24 01:09:59 +08:00
2026-09-26 14:30:16 +08:00
2026-09-24 17:13:03 +08:00
2026-09-24 17:13:03 +08:00
2026-09-30 11:01:17 +08:00
omarchy: on Omarchy, magpie is drawn in Omarchy's own design language, follows its theme, drops its panel under the bar as Omarchy's own menus do, and can put its icon in Omarchy's bar (让整个UI/UX完全符合Omarchy的设计语言…单独对Omarchy做这个支持,现在的UI/UX当然要保留) — on Hyprland magpie looked like any other GTK app: its own light/dark palette, rounded shadowed popups, and a tray panel floated framed and dimmed in the middle of the screen, labelled with the program's name, never closing on a click elsewhere (focus follows the mouse there, so Wails turns off focus-lost hiding), and its tray icon was hidden in the bar's drawer. Now, only when Omarchy is detected (internal/omarchy: ~/.local/share/omarchy and its current theme), boot.js hands the page the current theme (colors.toml, the shell's theme TOML, Hyprland's border size, colour and rounding, Omarchy's font) as CSS variables before the first paint, and omarchy.css, all under html.omarchy, draws flat as Omarchy's shell does: the theme's background, no shadows or blur, corners as round as Hyprland's windows, popups and dialogs framed by the active border's colour, uppercase letter-spaced labels, rows and picks as a faint fill with the text in the accent. /api/omarchy is polled every 2.5s, so a theme picked in Omarchy's menu reaches the windows at once; Settings → Appearance shows the theme's name instead of Light/Dark/System. Under Hyprland the tray panel gets a title of its own ("magpie panel", set through GTK since Wails leaves frameless windows untitled), and each opening gives Hyprland a named Lua window rule placing it under the bar at the click, 6px in from the edges, pinned, opaque, borderless; its height is capped to the work area. While it is open a non-consuming left-click bind emits a custom event on Hyprland's socket2; a click outside the panel and below the bar closes it (the bar is left to its icons, so the icon toggles), and the bind is removed on close or, after Escape, on the next click. The tray item's SNI id is "magpie" instead of "Wails", so it can be pinned. Settings → Bar icon (状态栏图标), shown only in the app on Omarchy's Hyprland, puts an Omarchy bar-widget plugin (usemagpie.magpie, a bird glyph, in ~/.config/omarchy/plugins, then rescanPlugins and plugin enable) beside Omarchy's own icons: a click runs magpie panel, a right-click magpie app; Off disables and removes it; a widget pointing at a moved or older magpie is rewritten at start. magpie panel (new) opens the quick panel, starting magpie if needed, or toggles it in the running instance. Elsewhere nothing changes. Tested in a Hyper-V VM on the latest Omarchy (Hyprland 0.56, 2528×960 at scale 1.6): the look with tokyo-night; the panel at [1134,32] under the bar; clicks on the panel and the bar keep it open, a click on another window closes it, the icon toggles it, Escape closes it and the bind goes; Bar icon On adds the bird to the bar, its click opens the panel under it (also with magpie not running), a second click closes it, right-click opens the window, Off removes it; autostart becomes app-magpie@autostart through systemd's XDG generator; the launcher entry and icon are there. Go: internal/omarchy tests (theme parsing, panel placement on scaled and turned monitors, click-outside geometry, widget files quoted with the executable, KeepWidget rewriting only a stale one). A new internal/gui/tests/omarchy.test.cjs, Chromium and WebKit, en and zh: with no Omarchy theme the page has no omarchy class or theme style, the Appearance choices show, no Bar icon row, nothing asked of /api/omarchy; with one, the theme's background, square corners, its name, and Bar icon's On and Off each posted with nothing scrolled, hidden when the bar isn't there. old-webkit now lets omarchy.js load in the head beside boot.js (it does nothing off Omarchy). The full GUI suite, gofmt, go vet, go build (GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried: other Hyprland setups than Omarchy's, a multi-monitor VM, and the GTK4 build in the VM (gtk3 was used).
2026-09-30 04:58:11 +08:00
gui: the Windows tray panel no longer shows a faint close X over its Settings gear — its caption buttons are hidden there (#238 mintonight: a blurry red X at the panel's top-right corner, just above and right of the gear) — Wails v3 makes a frameless window on Windows WS_OVERLAPPEDWINDOW and, for the shadow and round corners, extends DWM's frame into the whole client area; the panel left its close button at the zero value, ButtonEnabled, which sets WS_SYSMENU, so DWM drew the caption's close X into that extended frame at the window's top right, and with the panel translucent (BackgroundTypeTranslucent, WS_EX_NOREDIRECTIONBITMAP, a see-through webview) it showed through the page, faint, over the gear. It was not the page: #winclose is removed everywhere but Linux's window, and is a grey pill in the header row. The panel's options move into panelOptions(goos, theme), unchanged, and on Windows its close, minimise and maximise buttons are ButtonHidden, which takes WS_SYSMENU and the min/max boxes off, so DWM has no caption buttons to draw; DisableFramelessWindowDecorations stays off, so the shadow and Windows 11's round corners stay. The Mac and Linux get the same options as before (their button states left at the zero value), and the main window is not touched. Tested with a new internal/gui/panel_options_test.go (!nogui): on windows the three buttons are hidden and the panel still frameless, translucent, off the taskbar and decorated; on darwin and linux the buttons are as before and URL, backdrop and corner radius unchanged; run on the Mac and compiled for Windows (GOOS=windows go test -c). go build -tags nogui (and GOOS=linux), GOOS=windows go build and go test -tags nogui ./... pass (TestUserPath, TestClaudeSignedOut and TestClaudeAccountNamedAsItsLogin timed out once at a load average near 60 and pass alone). Not tried on a real Windows desktop: that DWM stops drawing the X without WS_SYSMENU is from the Win32 custom-frame behaviour and Wails' code, not seen.
2026-09-30 02:15:48 +08:00
provider: Jev's endpoint can be given in the editor (ARNO: ui中没有地方给我填写自定义的端点) — v0.1.294 took Cloudflare's documented address, …/accounts/<id>/ai/run, but a Jev preset's editor only showed its endpoint, and a save rebuilt the provider from the preset, so there was nowhere to paste it. A Jev provider (TypeSafe, Vercel, Cloudflare) now has a "Jev endpoint" field, the preset's address to start with, kept on save and shown again when it's opened; a preset with no decision API is given none. Tested in a sandbox web UI (WebKit): Cloudflare Jev added with an /accounts/<id>/ai/run endpoint, saved as given, reopened with it and saved again unchanged
2026-09-28 19:51:46 +08:00
2026-09-29 10:17:30 +08:00
agents: a provider switched off or removed, or its last account signed out, moves the agents on its models to others (#200: 希望关闭某个llm provider的时候,更改agent选择的model到可用的model … 关闭这个provider之后,第一次使用会报错,因为copilot/ 开头的模型不存在) — switching Copilot off took copilot/… out of the catalog and the agents' model lists, but an agent picked on one kept it in its config and its next request was refused as switched off. Now every field on one of magpie's models (the model, Claude Code's opus/sonnet/haiku/fable tiers, any other) whose model the change stopped serving is moved: to the same model from a provider still on, the same id first, else one spelt another way (claude-sonnet-4.5 and claude-sonnet-4-5-20250929), else back to the agent's own default (a Claude Code tier: following the main model). It is done around switching off, removing, a key removed or off, and a sign-in signed out or off, in the window, the tray panel, the TUI and the CLI; the page's status line, the TUI and the CLI say which agent went to what. A session started before the switch still asks for the old model: the gateway now takes a switched-off provider's model as unserved, so Claude Code's stand-in (its model as set now) answers it rather than a refusal. Tested in a sandbox HOME: Claude Code on the main model and three tiers plus Hermes, switched off and removed (same id, other spelling, default, a tier following), switched on again moving nothing; /api/provider/off returns the moves; the gateway serves a switched-off model through the stand-in (fails without the change) and still refuses it to an agent left on it
2026-09-29 17:56:43 +08:00
2026-09-30 11:49:37 +08:00
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
2026-09-25 14:04:44 +08:00
2026-09-24 12:17:45 +08:00
2026-09-24 12:17:45 +08:00
2026-09-30 02:36:12 +08:00
agents: a model picked for Claude Code (or any agent) shows on its row at once, in the window and the tray panel, and /api/set answers in ~0.1s instead of seconds (Discord: switching Claude Code's model took 5–10s to show, magpie 0.1.410+) — /api/set writes the config and answers with the whole state, and the frontend drew the pick only from that answer. Every state asked the devin CLI (devin models list, ~1.5–3s a run) again several times whenever Devin was installed: its model's family, its options, its effort's options and Drift's re-read, and a CLI that gave no list (signed out, offline) was asked anew on every state, since only a list was cached. With a 4s CLI one set took 28s (measured, before). Now DevinFamilies keeps a failure for a minute, serves a list past its 5 minutes while it is read again in the background, and only a caller with nothing known waits — never one marked DevinNoWait, which Devin's field reads and options are (its Set still waits, so what is written is unchanged). Goose's detection read a binary's whole build info on every state (~150ms); the answer is kept while the file's size and time are the same. In the page, commit() draws the picked model and its flash before /api/set is sent, then draws the answer (a later pick's answer winning over an earlier one's); a refused pick puts the old model back and gives the reason. What is written to the agent's config is as before. Measured in a sandbox HOME with magpie web: /api/state 2.8–3.1s and /api/set 2.9s before, 0.1–0.5s after (state() ~110ms steady in-process); a provider whose endpoint never answers made no difference either way. Tested with internal/gui/set_fast_unix_test.go (devin CLI that sleeps 4s and a provider that never answers: three sets and the states after them each under 1.5s, ~5ms, settings.json as before; fails before the fix at 28s a set) and internal/gui/tests/model-pick.test.cjs (a set held 2.5s: the pick shown within 600ms in the window scrolled and in the tray panel's opened row and line, the page not moved, the answer keeping it, a refusal restoring the old model, en and zh, Chromium and WebKit; fails on main). click-scroll, panel-fold, menu-scroll, agy-launch, cli-update and old-webkit pass. go build -tags nogui (and GOOS=linux, GOOS=windows), go vet and go test -tags nogui ./... pass (TestClaudeAccountNamedAsItsLogin failed under load and passes alone). Not tried in the real Wails window or tray, nor with a real signed-in Devin CLI.
2026-09-30 03:21:24 +08:00
gui, update: saving the Settings page keeps the models hidden from each agent, and update checks go through magpie's proxy and say so (#294: 设置代理之后只有模型代理生效了,代理没有用于检查 magpie 是否有更新) — POST /api/settings carried over the models' names, levels and images but not HiddenModels, which the page never sends, so changing the theme, the language or anything else there showed every model hidden one by one on the Agents page again; it is carried over with the others. The update feed and the release came through http.DefaultTransport, proxied only because main installs netproxy first; the update client now takes netproxy.Func on a transport of its own (Settings' Proxy, else *_PROXY, else the system's). A check that failed at start-up, before a proxy was set, stayed failed for six hours: saving a new proxy now checks again through it. And the Settings row read "requests to vendors go through {proxy}", which says update checks don't: it now names both. TestSettingsSaveKeepsWhatItDoesNotSend (every field prefsKeep doesn't send survives a save of the theme alone; fails on main with HiddenModels emptied), TestUpdateGoesThroughTheProxy (feed and asset at hosts only a local proxy answers; fails without the transport), TestSettingsProxyRechecksAFailedUpdate (fails without the re-check). account-proxy, provider-proxy and click-scroll GUI tests pass; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin, known flakes under load, pass alone).
2026-09-30 16:03:52 +08:00
gui: the tray panel's link to one request opens the Routing page on it again — ShowMain escaped the whole view it was given (831df85, v0.1.458, for magpie gui <tab>), so "routing&req=42" reached the window as one view named that, which is none: the window came up on no tab, the request not picked. Found reviewing #239, whose "Open Usage" link hit the same. The view mainView builds keeps its req as its own parameter (mainURL); only a tab named on the command line — magpie gui settings, a restart to update — is escaped (argView). Tested with a new TestMainURL (routing&req=42 comes through as view=routing, req=42; a command-line tab is escaped); it fails with the old escaping. panel-routing.test.cjs passes; go vet, go build (GUI, -tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass.
2026-09-30 13:09:27 +08:00
2026-09-26 14:30:16 +08:00
2026-09-30 02:36:12 +08:00
2026-09-30 02:36:12 +08:00
2026-09-30 02:36:12 +08:00
2026-09-30 02:36:12 +08:00
2026-09-30 02:36:12 +08:00
2026-09-30 02:36:12 +08:00
settings: a Text size preference (文字大小) that makes everything in magpie's windows larger, 100/110/125/150%, with Ctrl/Cmd + = − 0 in the window and the tray panel, and Windows' text drawn in its own UI faces (Discord, Clarence Dan: the font size is hard on the eyes on Windows) — Settings → Preferences gains a Text size row under Language whose pick posts to a new POST /api/settings/text-size (saved as settings.TextSize, validated against 100/110/125/150, 0 read as 100, and kept by the Settings page's general save, which never sends it). The size is each webview's own zoom, as a browser zooms, not CSS zoom: CSS zoom leaves getBoundingClientRect and clientX in zoomed pixels while offsets, scrollTop and 100vh are not, and app.js, routing.js and library.js place menus, popovers and the panel's height by those measures; under the webview's zoom the page is laid out again in fewer, larger CSS pixels and every measure agrees. Windows and Linux use Wails' SetZoom (WebView2's zoom factor, WebKitGTK's zoom level; the Zoom window option at creation, so the pages open at the saved size), the Mac WKWebView.pageZoom through cgo (macOS 11+), since Wails' Mac zoom is magnification, which lays nothing out again. None is under 100% because Wails clamps SetZoom below 1 on Windows and Linux. The windows grow around the pages: the panel's width and the height its page asks for (still in CSS pixels) are multiplied by the zoom, capped at the screen's work area (textsize.go panelFrame), and resized at once when the size changes; the main window's minimum is 560×420 CSS pixels at the size, capped by the screen, so a window smaller than that grows. Runtime changes wait for the app to be ready (whenReady), and at startup the Mac applies the zoom once its webviews exist. The Mac header, drawn under the native traffic lights which do not grow, divides its height, left padding and the modal's top by --zoom (set from boot.js before the first paint and from the settings), so it stays 50 points tall and level with them. The shortcuts are Cmd on the Mac and Ctrl elsewhere (the other modifier does nothing), step through the sizes and 0 goes back to 100%, with a "Text size 125%" toast; in magpie web the row is hidden and the keys are left to the browser's own zoom. On Windows the page names its faces (html.win): Segoe UI Variable Text, Segoe UI, then Microsoft YaHei UI for Chinese rather than whatever WebView2 falls back to; the Mac and Linux stack is unchanged, and there is no automatic size bump. New strings in en and zh. Tested: internal/gui/tests/text-size.test.cjs in Chromium and WebKit, en and zh, light and dark — a pick posts and does not scroll the settings page, stays picked after a reload with --zoom from boot.js, the Settings page's other saves leave it, the shortcuts step and reset in the window and the panel, and at 150% (the smallest window, 840×630 points, as 560×420 CSS pixels at device scale 1.5) no view, the header or the panel runs off to the side, the Mac header is 50 points; screenshots at 100% and 150% looked at. currency.test.cjs's viewport is 480 tall instead of 420, as settings-groups' is: the new row put the Currency control under the footer, where WebKit's hover could not reach it. Go: TestTextSizeFrames (panel and window sizes) and TestTextSizeSetting (the endpoint saves, zooms the windows, rejects 133, survives the general save, boot.js carries it) in internal/gui, and the settings round trip. go build -tags nogui (and GOOS=linux, GOOS=windows, plain darwin), go test -tags nogui ./... (TestUserPath flaked once under load and passes alone) and the whole GUI suite with --test-concurrency=2 pass. Not tried in the real Wails window on any platform: the Mac pageZoom, WebView2's zoom factor with the resized panel and the Windows font are untested there.
2026-09-30 02:51:17 +08:00
settings: a Text size preference (文字大小) that makes everything in magpie's windows larger, 100/110/125/150%, with Ctrl/Cmd + = − 0 in the window and the tray panel, and Windows' text drawn in its own UI faces (Discord, Clarence Dan: the font size is hard on the eyes on Windows) — Settings → Preferences gains a Text size row under Language whose pick posts to a new POST /api/settings/text-size (saved as settings.TextSize, validated against 100/110/125/150, 0 read as 100, and kept by the Settings page's general save, which never sends it). The size is each webview's own zoom, as a browser zooms, not CSS zoom: CSS zoom leaves getBoundingClientRect and clientX in zoomed pixels while offsets, scrollTop and 100vh are not, and app.js, routing.js and library.js place menus, popovers and the panel's height by those measures; under the webview's zoom the page is laid out again in fewer, larger CSS pixels and every measure agrees. Windows and Linux use Wails' SetZoom (WebView2's zoom factor, WebKitGTK's zoom level; the Zoom window option at creation, so the pages open at the saved size), the Mac WKWebView.pageZoom through cgo (macOS 11+), since Wails' Mac zoom is magnification, which lays nothing out again. None is under 100% because Wails clamps SetZoom below 1 on Windows and Linux. The windows grow around the pages: the panel's width and the height its page asks for (still in CSS pixels) are multiplied by the zoom, capped at the screen's work area (textsize.go panelFrame), and resized at once when the size changes; the main window's minimum is 560×420 CSS pixels at the size, capped by the screen, so a window smaller than that grows. Runtime changes wait for the app to be ready (whenReady), and at startup the Mac applies the zoom once its webviews exist. The Mac header, drawn under the native traffic lights which do not grow, divides its height, left padding and the modal's top by --zoom (set from boot.js before the first paint and from the settings), so it stays 50 points tall and level with them. The shortcuts are Cmd on the Mac and Ctrl elsewhere (the other modifier does nothing), step through the sizes and 0 goes back to 100%, with a "Text size 125%" toast; in magpie web the row is hidden and the keys are left to the browser's own zoom. On Windows the page names its faces (html.win): Segoe UI Variable Text, Segoe UI, then Microsoft YaHei UI for Chinese rather than whatever WebView2 falls back to; the Mac and Linux stack is unchanged, and there is no automatic size bump. New strings in en and zh. Tested: internal/gui/tests/text-size.test.cjs in Chromium and WebKit, en and zh, light and dark — a pick posts and does not scroll the settings page, stays picked after a reload with --zoom from boot.js, the Settings page's other saves leave it, the shortcuts step and reset in the window and the panel, and at 150% (the smallest window, 840×630 points, as 560×420 CSS pixels at device scale 1.5) no view, the header or the panel runs off to the side, the Mac header is 50 points; screenshots at 100% and 150% looked at. currency.test.cjs's viewport is 480 tall instead of 420, as settings-groups' is: the new row put the Currency control under the footer, where WebKit's hover could not reach it. Go: TestTextSizeFrames (panel and window sizes) and TestTextSizeSetting (the endpoint saves, zooms the windows, rejects 133, survives the general save, boot.js carries it) in internal/gui, and the settings round trip. go build -tags nogui (and GOOS=linux, GOOS=windows, plain darwin), go test -tags nogui ./... (TestUserPath flaked once under load and passes alone) and the whole GUI suite with --test-concurrency=2 pass. Not tried in the real Wails window on any platform: the Mac pageZoom, WebView2's zoom factor with the resized panel and the Windows font are untested there.
2026-09-30 02:51:17 +08:00
omarchy: on Omarchy, magpie is drawn in Omarchy's own design language, follows its theme, drops its panel under the bar as Omarchy's own menus do, and can put its icon in Omarchy's bar (让整个UI/UX完全符合Omarchy的设计语言…单独对Omarchy做这个支持,现在的UI/UX当然要保留) — on Hyprland magpie looked like any other GTK app: its own light/dark palette, rounded shadowed popups, and a tray panel floated framed and dimmed in the middle of the screen, labelled with the program's name, never closing on a click elsewhere (focus follows the mouse there, so Wails turns off focus-lost hiding), and its tray icon was hidden in the bar's drawer. Now, only when Omarchy is detected (internal/omarchy: ~/.local/share/omarchy and its current theme), boot.js hands the page the current theme (colors.toml, the shell's theme TOML, Hyprland's border size, colour and rounding, Omarchy's font) as CSS variables before the first paint, and omarchy.css, all under html.omarchy, draws flat as Omarchy's shell does: the theme's background, no shadows or blur, corners as round as Hyprland's windows, popups and dialogs framed by the active border's colour, uppercase letter-spaced labels, rows and picks as a faint fill with the text in the accent. /api/omarchy is polled every 2.5s, so a theme picked in Omarchy's menu reaches the windows at once; Settings → Appearance shows the theme's name instead of Light/Dark/System. Under Hyprland the tray panel gets a title of its own ("magpie panel", set through GTK since Wails leaves frameless windows untitled), and each opening gives Hyprland a named Lua window rule placing it under the bar at the click, 6px in from the edges, pinned, opaque, borderless; its height is capped to the work area. While it is open a non-consuming left-click bind emits a custom event on Hyprland's socket2; a click outside the panel and below the bar closes it (the bar is left to its icons, so the icon toggles), and the bind is removed on close or, after Escape, on the next click. The tray item's SNI id is "magpie" instead of "Wails", so it can be pinned. Settings → Bar icon (状态栏图标), shown only in the app on Omarchy's Hyprland, puts an Omarchy bar-widget plugin (usemagpie.magpie, a bird glyph, in ~/.config/omarchy/plugins, then rescanPlugins and plugin enable) beside Omarchy's own icons: a click runs magpie panel, a right-click magpie app; Off disables and removes it; a widget pointing at a moved or older magpie is rewritten at start. magpie panel (new) opens the quick panel, starting magpie if needed, or toggles it in the running instance. Elsewhere nothing changes. Tested in a Hyper-V VM on the latest Omarchy (Hyprland 0.56, 2528×960 at scale 1.6): the look with tokyo-night; the panel at [1134,32] under the bar; clicks on the panel and the bar keep it open, a click on another window closes it, the icon toggles it, Escape closes it and the bind goes; Bar icon On adds the bird to the bar, its click opens the panel under it (also with magpie not running), a second click closes it, right-click opens the window, Off removes it; autostart becomes app-magpie@autostart through systemd's XDG generator; the launcher entry and icon are there. Go: internal/omarchy tests (theme parsing, panel placement on scaled and turned monitors, click-outside geometry, widget files quoted with the executable, KeepWidget rewriting only a stale one). A new internal/gui/tests/omarchy.test.cjs, Chromium and WebKit, en and zh: with no Omarchy theme the page has no omarchy class or theme style, the Appearance choices show, no Bar icon row, nothing asked of /api/omarchy; with one, the theme's background, square corners, its name, and Bar icon's On and Off each posted with nothing scrolled, hidden when the bar isn't there. old-webkit now lets omarchy.js load in the head beside boot.js (it does nothing off Omarchy). The full GUI suite, gofmt, go vet, go build (GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried: other Hyprland setups than Omarchy's, a multi-monitor VM, and the GTK4 build in the VM (gtk3 was used).
2026-09-30 04:58:11 +08:00
omarchy: on Omarchy, magpie is drawn in Omarchy's own design language, follows its theme, drops its panel under the bar as Omarchy's own menus do, and can put its icon in Omarchy's bar (让整个UI/UX完全符合Omarchy的设计语言…单独对Omarchy做这个支持,现在的UI/UX当然要保留) — on Hyprland magpie looked like any other GTK app: its own light/dark palette, rounded shadowed popups, and a tray panel floated framed and dimmed in the middle of the screen, labelled with the program's name, never closing on a click elsewhere (focus follows the mouse there, so Wails turns off focus-lost hiding), and its tray icon was hidden in the bar's drawer. Now, only when Omarchy is detected (internal/omarchy: ~/.local/share/omarchy and its current theme), boot.js hands the page the current theme (colors.toml, the shell's theme TOML, Hyprland's border size, colour and rounding, Omarchy's font) as CSS variables before the first paint, and omarchy.css, all under html.omarchy, draws flat as Omarchy's shell does: the theme's background, no shadows or blur, corners as round as Hyprland's windows, popups and dialogs framed by the active border's colour, uppercase letter-spaced labels, rows and picks as a faint fill with the text in the accent. /api/omarchy is polled every 2.5s, so a theme picked in Omarchy's menu reaches the windows at once; Settings → Appearance shows the theme's name instead of Light/Dark/System. Under Hyprland the tray panel gets a title of its own ("magpie panel", set through GTK since Wails leaves frameless windows untitled), and each opening gives Hyprland a named Lua window rule placing it under the bar at the click, 6px in from the edges, pinned, opaque, borderless; its height is capped to the work area. While it is open a non-consuming left-click bind emits a custom event on Hyprland's socket2; a click outside the panel and below the bar closes it (the bar is left to its icons, so the icon toggles), and the bind is removed on close or, after Escape, on the next click. The tray item's SNI id is "magpie" instead of "Wails", so it can be pinned. Settings → Bar icon (状态栏图标), shown only in the app on Omarchy's Hyprland, puts an Omarchy bar-widget plugin (usemagpie.magpie, a bird glyph, in ~/.config/omarchy/plugins, then rescanPlugins and plugin enable) beside Omarchy's own icons: a click runs magpie panel, a right-click magpie app; Off disables and removes it; a widget pointing at a moved or older magpie is rewritten at start. magpie panel (new) opens the quick panel, starting magpie if needed, or toggles it in the running instance. Elsewhere nothing changes. Tested in a Hyper-V VM on the latest Omarchy (Hyprland 0.56, 2528×960 at scale 1.6): the look with tokyo-night; the panel at [1134,32] under the bar; clicks on the panel and the bar keep it open, a click on another window closes it, the icon toggles it, Escape closes it and the bind goes; Bar icon On adds the bird to the bar, its click opens the panel under it (also with magpie not running), a second click closes it, right-click opens the window, Off removes it; autostart becomes app-magpie@autostart through systemd's XDG generator; the launcher entry and icon are there. Go: internal/omarchy tests (theme parsing, panel placement on scaled and turned monitors, click-outside geometry, widget files quoted with the executable, KeepWidget rewriting only a stale one). A new internal/gui/tests/omarchy.test.cjs, Chromium and WebKit, en and zh: with no Omarchy theme the page has no omarchy class or theme style, the Appearance choices show, no Bar icon row, nothing asked of /api/omarchy; with one, the theme's background, square corners, its name, and Bar icon's On and Off each posted with nothing scrolled, hidden when the bar isn't there. old-webkit now lets omarchy.js load in the head beside boot.js (it does nothing off Omarchy). The full GUI suite, gofmt, go vet, go build (GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried: other Hyprland setups than Omarchy's, a multi-monitor VM, and the GTK4 build in the VM (gtk3 was used).
2026-09-30 04:58:11 +08:00
omarchy: on Omarchy, magpie is drawn in Omarchy's own design language, follows its theme, drops its panel under the bar as Omarchy's own menus do, and can put its icon in Omarchy's bar (让整个UI/UX完全符合Omarchy的设计语言…单独对Omarchy做这个支持,现在的UI/UX当然要保留) — on Hyprland magpie looked like any other GTK app: its own light/dark palette, rounded shadowed popups, and a tray panel floated framed and dimmed in the middle of the screen, labelled with the program's name, never closing on a click elsewhere (focus follows the mouse there, so Wails turns off focus-lost hiding), and its tray icon was hidden in the bar's drawer. Now, only when Omarchy is detected (internal/omarchy: ~/.local/share/omarchy and its current theme), boot.js hands the page the current theme (colors.toml, the shell's theme TOML, Hyprland's border size, colour and rounding, Omarchy's font) as CSS variables before the first paint, and omarchy.css, all under html.omarchy, draws flat as Omarchy's shell does: the theme's background, no shadows or blur, corners as round as Hyprland's windows, popups and dialogs framed by the active border's colour, uppercase letter-spaced labels, rows and picks as a faint fill with the text in the accent. /api/omarchy is polled every 2.5s, so a theme picked in Omarchy's menu reaches the windows at once; Settings → Appearance shows the theme's name instead of Light/Dark/System. Under Hyprland the tray panel gets a title of its own ("magpie panel", set through GTK since Wails leaves frameless windows untitled), and each opening gives Hyprland a named Lua window rule placing it under the bar at the click, 6px in from the edges, pinned, opaque, borderless; its height is capped to the work area. While it is open a non-consuming left-click bind emits a custom event on Hyprland's socket2; a click outside the panel and below the bar closes it (the bar is left to its icons, so the icon toggles), and the bind is removed on close or, after Escape, on the next click. The tray item's SNI id is "magpie" instead of "Wails", so it can be pinned. Settings → Bar icon (状态栏图标), shown only in the app on Omarchy's Hyprland, puts an Omarchy bar-widget plugin (usemagpie.magpie, a bird glyph, in ~/.config/omarchy/plugins, then rescanPlugins and plugin enable) beside Omarchy's own icons: a click runs magpie panel, a right-click magpie app; Off disables and removes it; a widget pointing at a moved or older magpie is rewritten at start. magpie panel (new) opens the quick panel, starting magpie if needed, or toggles it in the running instance. Elsewhere nothing changes. Tested in a Hyper-V VM on the latest Omarchy (Hyprland 0.56, 2528×960 at scale 1.6): the look with tokyo-night; the panel at [1134,32] under the bar; clicks on the panel and the bar keep it open, a click on another window closes it, the icon toggles it, Escape closes it and the bind goes; Bar icon On adds the bird to the bar, its click opens the panel under it (also with magpie not running), a second click closes it, right-click opens the window, Off removes it; autostart becomes app-magpie@autostart through systemd's XDG generator; the launcher entry and icon are there. Go: internal/omarchy tests (theme parsing, panel placement on scaled and turned monitors, click-outside geometry, widget files quoted with the executable, KeepWidget rewriting only a stale one). A new internal/gui/tests/omarchy.test.cjs, Chromium and WebKit, en and zh: with no Omarchy theme the page has no omarchy class or theme style, the Appearance choices show, no Bar icon row, nothing asked of /api/omarchy; with one, the theme's background, square corners, its name, and Bar icon's On and Off each posted with nothing scrolled, hidden when the bar isn't there. old-webkit now lets omarchy.js load in the head beside boot.js (it does nothing off Omarchy). The full GUI suite, gofmt, go vet, go build (GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried: other Hyprland setups than Omarchy's, a multi-monitor VM, and the GTK4 build in the VM (gtk3 was used).
2026-09-30 04:58:11 +08:00
2026-09-30 11:22:21 +08:00
2026-09-30 11:22:21 +08:00
panel: a Routing tab shows the gateway's latest requests, and the allowances' tab is named Allowances (v on Discord #feedback: the panel's Usage tab and the window's Usage page mean different things, and the panel had no routing) — the tray panel had Agents, Usage and Profiles, its Usage being each subscription's allowance while the window's Usage counts requests and Routing shows where they went. The panel's tab now reads Allowances (额度; the window keeps Usage/用量, and the tab's id and remembered choice are unchanged), and a new Routing tab (路由) lists the gateway's last 8 requests as they come, from the trace the Routing page already long-polls (/api/gateway/trace, which routing.js polled in the panel too; no new endpoint): each a two-line row with the agent's dot, icon and name and the model it asked for, the time, then where it went (provider · account or key), the model that try sent and, when the reply named another model (the new served/swapped fields), the amber "served gpt-6-luna" (实际 …) tag of the Requests list, beside the tokens and time taken; a failed one says its status and why (429 · rate limited), one under way who is answering. Over them, today's calls and tokens (the Usage page's /api/usage?period=today, read when the tab is shown and after a request ends, at most every 5 s) and Open Routing. A click on a request opens the window's Routing page on it: POST /api/window/main takes req beside view=routing (mainView lets only a positive id through), and the page, loaded so, picks that request as a click in its list would (its story told) and drops req from the address. The panel's height counts the tab as its tallest, as the others; the tab redraws keeping the panel's scroll, the click moves nothing, no border stripe. Tested with a new internal/gui/tests/panel-routing.test.cjs in Chromium and WebKit, en and zh: the Routing and Allowances labels, four fixture requests listed newest first with agent, model, "Relay · team" and "Claude · ann@example.com", the served tag on the swapped one only (not on a dated name), the 429 row, times, no row overflowing, today's 42 calls · 1.2M tokens, a click with the panel scrolled asking for view=routing&req=100 and leaving the scroll as it was, Open Routing, and the window opened on ?view=routing&req=101 with that request picked and its story shown; and TestMainView. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (102 tests) pass. Not tried in the real tray panel or with a live gateway: the window opening on the request is tested in the page, not through Wails.
2026-09-29 20:22:19 +08:00
gui: the tray panel's link to one request opens the Routing page on it again — ShowMain escaped the whole view it was given (831df85, v0.1.458, for magpie gui <tab>), so "routing&req=42" reached the window as one view named that, which is none: the window came up on no tab, the request not picked. Found reviewing #239, whose "Open Usage" link hit the same. The view mainView builds keeps its req as its own parameter (mainURL); only a tab named on the command line — magpie gui settings, a restart to update — is escaped (argView). Tested with a new TestMainURL (routing&req=42 comes through as view=routing, req=42; a command-line tab is escaped); it fails with the old escaping. panel-routing.test.cjs passes; go vet, go build (GUI, -tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass.
2026-09-30 13:09:27 +08:00
2026-09-24 01:09:59 +08:00
2026-09-28 09:27:49 +08:00
2026-09-28 16:15:40 +08:00
2026-09-28 09:27:49 +08:00
gui, update: saving the Settings page keeps the models hidden from each agent, and update checks go through magpie's proxy and say so (#294: 设置代理之后只有模型代理生效了,代理没有用于检查 magpie 是否有更新) — POST /api/settings carried over the models' names, levels and images but not HiddenModels, which the page never sends, so changing the theme, the language or anything else there showed every model hidden one by one on the Agents page again; it is carried over with the others. The update feed and the release came through http.DefaultTransport, proxied only because main installs netproxy first; the update client now takes netproxy.Func on a transport of its own (Settings' Proxy, else *_PROXY, else the system's). A check that failed at start-up, before a proxy was set, stayed failed for six hours: saving a new proxy now checks again through it. And the Settings row read "requests to vendors go through {proxy}", which says update checks don't: it now names both. TestSettingsSaveKeepsWhatItDoesNotSend (every field prefsKeep doesn't send survives a save of the theme alone; fails on main with HiddenModels emptied), TestUpdateGoesThroughTheProxy (feed and asset at hosts only a local proxy answers; fails without the transport), TestSettingsProxyRechecksAFailedUpdate (fails without the re-check). account-proxy, provider-proxy and click-scroll GUI tests pass; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin, known flakes under load, pass alone).
2026-09-30 16:03:52 +08:00
2026-09-26 21:00:33 +08:00
update: a restart to update from the open window (Windows, Linux) opens the window again, on the tab it was asked from, instead of the tray icon alone (#275 Aimer779: 设置页更新重启后主窗口消失,只剩托盘) — RelaunchBinary always started magpie tray, autostart's argument, so the new version came up as a tray icon however the update was asked for; the Mac reopens its .app and was fine. The window's Update pill and Settings' "Restart to update" send the tab they're on, the new process starts as magpie gui <tab>; the tray menu's Restart to Update brings the window back if it was open and keeps to the tray if not; autostart stays tray. magpie gui <tab> / magpie app <tab> open the window on that tab, and hand it to a magpie already running. The MAGPIE_REPLACES handover is unchanged: the new process waits for the old one before its single-instance lock. Tested with TestRelaunchArgs and TestRelaunchBinaryArgs (a script in magpie's place is started with gui settings <pid> / tray <pid>); go vet, go build (GUI and -tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass. Not tried: a real restart to update on Windows or Linux.
2026-09-30 12:33:36 +08:00
usage: a Requests tab lists every request of the period, one row each, and exports them as CSV, from the window and from magpie usage --csv (Discord 范不着: a per-request ledger as sub2api keeps, to set beside the upstream's own bill) — the Usage page summed calls by agent and model, and the log did not keep the model the agent asked for or the one the reply said answered, so a single request could not be checked against a vendor's bill. usage.Record now keeps Requested (req, the model id the client sent, a magpie alias or group as it came) and Served (served, the model the vendor's reply named, only when it named one); every usage.Append in the gateway fills them (the relayed and translated paths, Codex's backend, image draws, decide), and records written before load as they did, without them. The swap test the Routing page uses (a dated or pinned name is the same model) moved to usage.Swapped so the ledger marks the same rows. usage.Ledger gives the period's records newest first with each one's list-price cost, the agent it is counted under and whether the model was swapped, filtered by agent, failures alone and a search over the models, provider, account, session and effort; usage.WriteCSV writes them (time, agent, requested_model, provider, host, model, served_model, swapped, effort, input, output, cache write, cache read and reasoning tokens, cost_usd, duration_ms, ttft_ms, status, error, session, kind). The Usage page gets a third tab, Requests (请求), between Overview and Sessions, under the same period picker: an agent filter, All/Failed, a search field and Export CSV over a table of time, agent, requested model, provider · account, model sent, served model (amber with the Routing page's sentence when another model answered, plain on a dated name, a dash when the reply named none), effort, in, out, cache write, cache read, cost, duration and status, a failure's row marked by a red dot and bold code; the totals over it and 100 rows a page with Newer and Older. GET /api/usage/requests serves a page, POST /api/usage/requests/export saves all the filtered rows to Downloads (never over an earlier file) and opens the folder, GET /api/usage/requests.csv hands a browser the file in magpie web. The table scrolls sideways in its own box; at the window's narrowest the words after the head's cost give way so the three tabs fit without the page scrolling sideways. No border stripe; clicks move nothing (the pager held where it was). en and zh strings together. Tested with TestLedger (order, cost, swap, a dated name, an old record without the fields, each filter, the CSV exactly), TestServedModelRecorded and TestServedModelUnnamed (a request through a fake upstream answering with another model records Requested fake/sol, Model sol and the served name; one naming none leaves Served empty), TestUsageCSV (magpie usage --csv, a period, a stray argument refused), TestUsageLedgerRoutes (paging, totals, filters, export to Downloads twice) and a new internal/gui/tests/usage-ledger.test.cjs in Chromium and WebKit, en and zh, light and dark: the tabs and columns, the swap tag on the swapped row only, the 429 row, Older and Newer over 130 requests with the pager left where it was, the agent, Failed, search and period filters asking the server from the first page, Export CSV posting the filters with no page and saying where the file went, at 560 wide no tab scrolling the page sideways and the cost uncut, no left border. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (122 tests) pass. Not tried in the real window through Wails or against a live gateway's log.
2026-09-29 21:26:01 +08:00
usage: a Requests tab lists every request of the period, one row each, and exports them as CSV, from the window and from magpie usage --csv (Discord 范不着: a per-request ledger as sub2api keeps, to set beside the upstream's own bill) — the Usage page summed calls by agent and model, and the log did not keep the model the agent asked for or the one the reply said answered, so a single request could not be checked against a vendor's bill. usage.Record now keeps Requested (req, the model id the client sent, a magpie alias or group as it came) and Served (served, the model the vendor's reply named, only when it named one); every usage.Append in the gateway fills them (the relayed and translated paths, Codex's backend, image draws, decide), and records written before load as they did, without them. The swap test the Routing page uses (a dated or pinned name is the same model) moved to usage.Swapped so the ledger marks the same rows. usage.Ledger gives the period's records newest first with each one's list-price cost, the agent it is counted under and whether the model was swapped, filtered by agent, failures alone and a search over the models, provider, account, session and effort; usage.WriteCSV writes them (time, agent, requested_model, provider, host, model, served_model, swapped, effort, input, output, cache write, cache read and reasoning tokens, cost_usd, duration_ms, ttft_ms, status, error, session, kind). The Usage page gets a third tab, Requests (请求), between Overview and Sessions, under the same period picker: an agent filter, All/Failed, a search field and Export CSV over a table of time, agent, requested model, provider · account, model sent, served model (amber with the Routing page's sentence when another model answered, plain on a dated name, a dash when the reply named none), effort, in, out, cache write, cache read, cost, duration and status, a failure's row marked by a red dot and bold code; the totals over it and 100 rows a page with Newer and Older. GET /api/usage/requests serves a page, POST /api/usage/requests/export saves all the filtered rows to Downloads (never over an earlier file) and opens the folder, GET /api/usage/requests.csv hands a browser the file in magpie web. The table scrolls sideways in its own box; at the window's narrowest the words after the head's cost give way so the three tabs fit without the page scrolling sideways. No border stripe; clicks move nothing (the pager held where it was). en and zh strings together. Tested with TestLedger (order, cost, swap, a dated name, an old record without the fields, each filter, the CSV exactly), TestServedModelRecorded and TestServedModelUnnamed (a request through a fake upstream answering with another model records Requested fake/sol, Model sol and the served name; one naming none leaves Served empty), TestUsageCSV (magpie usage --csv, a period, a stray argument refused), TestUsageLedgerRoutes (paging, totals, filters, export to Downloads twice) and a new internal/gui/tests/usage-ledger.test.cjs in Chromium and WebKit, en and zh, light and dark: the tabs and columns, the swap tag on the swapped row only, the 429 row, Older and Newer over 130 requests with the pager left where it was, the agent, Failed, search and period filters asking the server from the first page, Export CSV posting the filters with no page and saying where the file went, at 560 wide no tab scrolling the page sideways and the cost uncut, no left border. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (122 tests) pass. Not tried in the real window through Wails or against a live gateway's log.
2026-09-29 21:26:01 +08:00
2026-09-27 17:26:32 +08:00
2026-09-30 11:22:21 +08:00