Files
magpie/internal/library
Lin Huazhong d8ebf2b893 test: one list of the agent folders a sandbox clears, so no sandbox misses an agent (yetone, on #522: A shared list of env vars for the other sandboxes would be a welcome follow-up) — every sandbox kept its own list of the variables that point at an agent's folder, and each had drifted: the gateway's cleared 5 of the 32 magpie reads, the provider package's 2, the tui's 10, the library's 20. A sandbox clearing 2 meets whatever Grok, Kimi, Hermes, MiniMax, Qoder or ZCode the developer has installed, which is how #522 came about — Qoder's two were in the library's list and in none of the four that failed. internal/agentenv is now the one list, and the 21 sandboxes that fake an environment with no agent in it clear it, each keeping beside it the variables that are not an agent's: APPDATA and LOCALAPPDATA, which a sandbox sets to a folder of its own rather than clearing, VISUAL and EDITOR. A name in the list is one magpie reads, and TestVarsAreRead walks the sources to say so, which is how two names a sandbox had been clearing turned out to be read by nothing at all — GEMINI_CLI_HOME and OPENCODE_CONFIG in internal/backup's, while OPENCODE_CONFIG_DIR, the one internal/agent reads (agents.go:545), was not in it. Where a sandbox set an agent's folder to a fixture of its own, the clearing now comes first, since a list of 32 wipes what a list of 5 left standing. Not converted: the omp tests' four variables, which are the ones omp's own lookup consults (a Pi fork) rather than every agent's, and the warm-up's Claude Code traffic flags, which are not folders — CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC stays out of the list for that reason too, its one test setting it on purpose. On Windows 11 the whole suite answers as it did before the change: 31 packages pass, and the same 15 tests in internal/library, internal/gateway and internal/agent fail for what they failed for before (symlinks this machine has no privilege for, and TestSuffixModesReachAgentFiles). go vet ./..., go build -tags nogui (windows, GOOS=linux, GOOS=darwin), and go vet -tags nogui for linux and darwin over every package touched pass. (#543)
2026-10-02 17:22:16 +08:00
..
library: an agent whose folder is a file isn't written, and skills reach 13 more agents with one link in ~/.agents/skills for those that share it (neiko on Discord: with DeepSeek Harness not installed the Library kept failing on "open ~/.dsh/AGENTS.md: not a directory" and ~/.dsh/config.yaml; inaction: the skills list is short of the Agents page, Kimi Code has none). An agent counted as there when its folder path existed or its command was on PATH, never asking whether the path was a folder — a file at ~/.dsh, or another dsh, made DeepSeek Harness look installed. Now an agent whose folder is a file (or under one) isn't detected (agent.Taken; Goose's, Cindy's and Claude Desktop's own checks want a folder too), a Library target leaves out each place a file stands in the way of, one with none left isn't listed, and an agent given no MCP server with none of magpie's isn't read. Skills: Kimi Code, Goose and Cindy get ~/.agents/skills (Kimi's ~/.config/agents/skills when there, as Kimi reads it first; never ~/.kimi/skills, which would hide Claude Code's from it); Command Code, Devin, Hermes, Droid, Cline, Qoder, Qoder CN, Grok, WorkBuddy, Hanako and fx their own skills folder; Kimi, Goose and Grok a project's .agents/skills. The shared folder is filled first, and an agent that reads ~/.agents/skills besides its own (Codex, Gemini CLI, OpenCode, Crush, DeepSeek Harness and those above) gets no second link to a skill already there. Tested with new taken_test.go (neiko's two errors without the change) and agent_skills_test.go (skills folders, written once, a shared skill imported for Kimi), in sandbox HOMEs; library-items and shared-skills 24/24 in Chromium and WebKit; go vet, go build (-tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass. Not tried with real Kimi Code, Goose or Cindy.
2026-09-30 14:40:41 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
2026-10-01 23:25:05 +08:00
2026-10-01 23:25:05 +08:00
test: one list of the agent folders a sandbox clears, so no sandbox misses an agent (yetone, on #522: A shared list of env vars for the other sandboxes would be a welcome follow-up) — every sandbox kept its own list of the variables that point at an agent's folder, and each had drifted: the gateway's cleared 5 of the 32 magpie reads, the provider package's 2, the tui's 10, the library's 20. A sandbox clearing 2 meets whatever Grok, Kimi, Hermes, MiniMax, Qoder or ZCode the developer has installed, which is how #522 came about — Qoder's two were in the library's list and in none of the four that failed. internal/agentenv is now the one list, and the 21 sandboxes that fake an environment with no agent in it clear it, each keeping beside it the variables that are not an agent's: APPDATA and LOCALAPPDATA, which a sandbox sets to a folder of its own rather than clearing, VISUAL and EDITOR. A name in the list is one magpie reads, and TestVarsAreRead walks the sources to say so, which is how two names a sandbox had been clearing turned out to be read by nothing at all — GEMINI_CLI_HOME and OPENCODE_CONFIG in internal/backup's, while OPENCODE_CONFIG_DIR, the one internal/agent reads (agents.go:545), was not in it. Where a sandbox set an agent's folder to a fixture of its own, the clearing now comes first, since a list of 32 wipes what a list of 5 left standing. Not converted: the omp tests' four variables, which are the ones omp's own lookup consults (a Pi fork) rather than every agent's, and the warm-up's Claude Code traffic flags, which are not folders — CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC stays out of the list for that reason too, its one test setting it on purpose. On Windows 11 the whole suite answers as it did before the change: 31 packages pass, and the same 15 tests in internal/library, internal/gateway and internal/agent fail for what they failed for before (symlinks this machine has no privilege for, and TestSuffixModesReachAgentFiles). go vet ./..., go build -tags nogui (windows, GOOS=linux, GOOS=darwin), and go vet -tags nogui for linux and darwin over every package touched pass. (#543)
2026-10-02 17:22:16 +08:00
library: MCP servers, skills and instructions are kept once in magpie and given to any agent from one place, with a market to find and add them (#29). Each agent reads MCP servers and skills from files of its own and in a format of its own, so one server was set up again in Claude Code, Codex, Gemini CLI, OpenCode, Pi, Goose, Cursor, Copilot CLI and Crush. The Library view keeps each once: a server is added (stdio, http or sse, its env and headers) and switched on per agent with its icon, and magpie writes it into each agent's config in that agent's format, leaving what the agent has of its own as it is; a server or skill an agent already has is shown, to bring into the library. A skill is a folder with a SKILL.md, kept in the library from GitHub (owner/repo, or a link to a folder in one; updated from it later) or linked from a folder on this machine, and linked into each agent's skills folder. The instructions every agent reads (CLAUDE.md, AGENTS.md, GEMINI.md…) can be kept as one too. The market offers checked MCP servers first, then the official MCP Registry's, filled in from what the registry says each needs (keys asked for in a form, never guessed), and skills.sh's most installed skills with what each says it is for; each shows its real icon (the vendor's own, else its GitHub owner's), fetched through magpie only for the icons the market or the library gave out, and an added server or skill keeps its icon in the library. What magpie changes in an agent's files is backed up first
2026-09-25 14:11:17 +08:00
settings: portable mode — a data folder beside magpie keeps everything magpie keeps (#508, suixinex) — like VS Code's portable mode, a folder named "data" (or a file named ".portable", the data folder then made beside it) next to magpie makes it keep all its own files there instead of the user's profile. Where magpie keeps its files is now decided in one place, internal/appdir: Config() (~/.config/magpie, $XDG_CONFIG_HOME/magpie; portable: data/), Cache() (~/.cache/magpie, $XDG_CACHE_HOME/magpie; portable: data/cache) and SystemCache() (the OS's cache folder, which the library's market lists and an update staged where magpie may not write used; portable: data/cache). settings.Dir()/Path(), provider.Path(), profile.Path(), the models.dev catalog, the exchange rate and the plugin market cache go through it, and everything built on them follows: providers, logins and saved accounts' folders, usage ledger, routing history and request archive, plugins, library, backups, sync state and lock, caller keys, redact key, stats. "Beside magpie" is the folder holding the executable with links followed; for a Mac app the folder holding Magpie.app (inside the bundle would break its signature), and for an AppImage the folder holding the .AppImage, not where it is mounted. The decision is made once, at start: an update moves the running copy aside (into .magpie-update on a Mac, to magpie.exe.old on Windows) and its files must not move with it; the updated copy replaces the executable or bundle only, so the data folder beside it is left alone. A portable magpie doesn't copy an old dial install's folders in. Not moved, as they aren't magpie's own: the agents' configs (~/.claude, ~/.codex…), the sign-ins agents keep in the system keychain (a saved Claude account's Claude Code keychain item is named after its folder's path on a Mac, so a portable folder moved elsewhere or to another Mac signs that account in again), autostart and link-handler registrations, and temporary folders. The single-instance id already covers the config folder, so a portable and an installed magpie run side by side, but the gateway port is one. Settings shows the config folder as portable. TestResolve (data folder, .portable, a file named data, a Mac bundle), TestResolveSymlinkedExe, TestResolveAppImage (Linux), TestFolders and TestPortableSettings (Path() lands in the data folder, Save writes there, ~/.config/magpie untouched); TestPortableSettings fails without the change (Path() is ~/.config/magpie/settings.json), TestResolveSymlinkedExe without following links. A nogui build run from a folder with data/ under a sandbox HOME wrote profiles.json, cli-identity.json and cache/models.json into data/ and nothing of magpie's into HOME. go vet ./internal/..., go build -tags nogui ./... (darwin, GOOS=linux), GOOS=windows go build ./..., go test -tags nogui ./... pass.
2026-10-02 13:00:22 +08:00
library: an agent's own copy of a library skill gives way to it, and one that differs is settled from the warning (StringKe, JasonLeeForOnly on Discord: after Bring in all, "Claude Code already has a skill of its own called impeccable", 这里没有强制覆盖的能力) — a skill is brought in from the agent with the very folder and given to the agents that had that folder; another agent's copy (CC Switch copies a skill into each agent) was listed as "differs in" and left out, and giving the skill to it, or a copy put back into an agent after its folder became magpie's link (by CC Switch or whatever installed it), was a hard failure with no way out. A folder there holding the same files as the library's (bytes compared; .DS_Store, .git and magpie's copy mark aside) is now set aside into backups/<when>/<agent>/skills and the library's linked in its place; a skill brought in takes the agents with such a copy too, which are no longer said to differ; a move that copied it all but couldn't remove the folder brings it in all the same, what was left set aside. One that differs keeps the warning, now in the reader's language with "Use the library's" (the agent's set aside, the library's linked) and "Keep <agent>'s" (the agent, and any reading the same folder, taken off the skill) on its row — skills/use-library and skills/keep-own, magpie library skill use-library|keep-own <name> <agent>, which the CLI suggests under the problem. Backups holding a skill set aside are never pruned. TestOwnSkillInTheWay, TestSameTree, TestPruneKeepsSkillsSetAside and own-skill.test.cjs (Chromium, WebKit, en/zh) fail without the change; TestSharedAgentsSkills now expects the byte copy to be the library's. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; own-skill, import-all-skills, library-items, shared-skills, market-have, click-scroll, old-webkit pass.
2026-09-30 19:42:43 +08:00
library: ZCode and Pi get a project's MCP servers too, and a project can be removed keeping what magpie wrote into it (#514, follow-up to #500: zcode支持项目级mcp添加 / pi也支持项目级mcp / 删除项目但保留mcp/skill) — a project's servers went only to Claude Code, Codex, Gemini CLI, Cursor and OpenCode, and Remove took every skill and server magpie had put in the folder away, so a project given some once had to stay in magpie for good. ZCode's project file is <project>/.zcode/config.json, servers under mcp.servers as in its user-wide ~/.zcode/cli/config.json (zcode.z.ai/en/docs/mcp-services, "Configuration Files and Default Load Paths": workspace scope, read before the user's, "enable": false the user's to set), written with fmtZCode (type, command/args/env or url/headers); Pi's is <project>/.pi/mcp.json, mcpServers as Pi's own MCP reads them once the project is trusted (pi.dev/docs/latest/mcp, "Configure servers"), written with fmtPiNative (command/args/env, url/headers, no type; SSE refused, as Pi refuses it), whatever extension the user's own Pi file is written for. Both are merged as the other agents' are: the user's keys, servers and comments stay, a server of the same name that isn't magpie's is left alone and said, a file magpie made (.pi/mcp.json) goes in the .gitignore and goes again once empty, and ZCode's user-wide file isn't touched. The page learns a project file's own SSE limit (projectNoSSE), so Pi's chip is greyed for an SSE server in a project even when its user-wide file (pi-mcp-adapter's) takes SSE; the trust note now names Pi beside Codex. The Remove dialog of a project magpie put anything in has "Keep its skills and MCP servers" / 保留项目里的技能和 MCP 服务器 (a checkbox row in the library's pick style, no coloured left border): checked, the text says what stays and Remove posts projects/remove with keep, and RemoveProject(dir, keep) only takes the project off the list — skills (links still following the library's), servers in the agents' files and magpie's .gitignore lines stay as they are, and nothing magpie does later (a sync, the server removed from the library) touches them; unchecked it removes as before. A one-off add without a project first (pick a folder from a server or skill) is not in this change. TestProjectServersZCodePi (ZCode's file with the user's model, server, enable:false and key kept beside magpie's three; Pi's file made in its shape, the SSE server refused with its reason, listed in .gitignore; ZCode's user-wide file unchanged; removing takes out only magpie's and the file it made) and TestRemoveProjectKeep (every file byte for byte after the removal, after a sync and after the server leaves the library) fail without the change, as does project-remove-keep.test.cjs (WebKit, and Chromium through a temp copy on plain chromium.launch(); en and zh: the box unchecked, its text, no stripe, pressing it scrolls nothing and swaps the text, Remove posts keep: true and says they were kept; a project with nothing written has no box and posts as before) against HEAD's assets. project-servers, click-scroll, library-items, library-all pass; menu-scroll and old-webkit fail the same on HEAD. No live config was read or written. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... (under a temp HOME) pass (TestFXInState failed on a TempDir cleanup race twice in the full gui run, passes alone and on the rerun; untouched).
2026-10-02 14:10:55 +08:00
library: ZCode and Pi get a project's MCP servers too, and a project can be removed keeping what magpie wrote into it (#514, follow-up to #500: zcode支持项目级mcp添加 / pi也支持项目级mcp / 删除项目但保留mcp/skill) — a project's servers went only to Claude Code, Codex, Gemini CLI, Cursor and OpenCode, and Remove took every skill and server magpie had put in the folder away, so a project given some once had to stay in magpie for good. ZCode's project file is <project>/.zcode/config.json, servers under mcp.servers as in its user-wide ~/.zcode/cli/config.json (zcode.z.ai/en/docs/mcp-services, "Configuration Files and Default Load Paths": workspace scope, read before the user's, "enable": false the user's to set), written with fmtZCode (type, command/args/env or url/headers); Pi's is <project>/.pi/mcp.json, mcpServers as Pi's own MCP reads them once the project is trusted (pi.dev/docs/latest/mcp, "Configure servers"), written with fmtPiNative (command/args/env, url/headers, no type; SSE refused, as Pi refuses it), whatever extension the user's own Pi file is written for. Both are merged as the other agents' are: the user's keys, servers and comments stay, a server of the same name that isn't magpie's is left alone and said, a file magpie made (.pi/mcp.json) goes in the .gitignore and goes again once empty, and ZCode's user-wide file isn't touched. The page learns a project file's own SSE limit (projectNoSSE), so Pi's chip is greyed for an SSE server in a project even when its user-wide file (pi-mcp-adapter's) takes SSE; the trust note now names Pi beside Codex. The Remove dialog of a project magpie put anything in has "Keep its skills and MCP servers" / 保留项目里的技能和 MCP 服务器 (a checkbox row in the library's pick style, no coloured left border): checked, the text says what stays and Remove posts projects/remove with keep, and RemoveProject(dir, keep) only takes the project off the list — skills (links still following the library's), servers in the agents' files and magpie's .gitignore lines stay as they are, and nothing magpie does later (a sync, the server removed from the library) touches them; unchecked it removes as before. A one-off add without a project first (pick a folder from a server or skill) is not in this change. TestProjectServersZCodePi (ZCode's file with the user's model, server, enable:false and key kept beside magpie's three; Pi's file made in its shape, the SSE server refused with its reason, listed in .gitignore; ZCode's user-wide file unchanged; removing takes out only magpie's and the file it made) and TestRemoveProjectKeep (every file byte for byte after the removal, after a sync and after the server leaves the library) fail without the change, as does project-remove-keep.test.cjs (WebKit, and Chromium through a temp copy on plain chromium.launch(); en and zh: the box unchecked, its text, no stripe, pressing it scrolls nothing and swaps the text, Remove posts keep: true and says they were kept; a project with nothing written has no box and posts as before) against HEAD's assets. project-servers, click-scroll, library-items, library-all pass; menu-scroll and old-webkit fail the same on HEAD. No live config was read or written. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... (under a temp HOME) pass (TestFXInState failed on a TempDir cleanup race twice in the full gui run, passes alone and on the rerun; untouched).
2026-10-02 14:10:55 +08:00
library: ZCode and Pi get a project's MCP servers too, and a project can be removed keeping what magpie wrote into it (#514, follow-up to #500: zcode支持项目级mcp添加 / pi也支持项目级mcp / 删除项目但保留mcp/skill) — a project's servers went only to Claude Code, Codex, Gemini CLI, Cursor and OpenCode, and Remove took every skill and server magpie had put in the folder away, so a project given some once had to stay in magpie for good. ZCode's project file is <project>/.zcode/config.json, servers under mcp.servers as in its user-wide ~/.zcode/cli/config.json (zcode.z.ai/en/docs/mcp-services, "Configuration Files and Default Load Paths": workspace scope, read before the user's, "enable": false the user's to set), written with fmtZCode (type, command/args/env or url/headers); Pi's is <project>/.pi/mcp.json, mcpServers as Pi's own MCP reads them once the project is trusted (pi.dev/docs/latest/mcp, "Configure servers"), written with fmtPiNative (command/args/env, url/headers, no type; SSE refused, as Pi refuses it), whatever extension the user's own Pi file is written for. Both are merged as the other agents' are: the user's keys, servers and comments stay, a server of the same name that isn't magpie's is left alone and said, a file magpie made (.pi/mcp.json) goes in the .gitignore and goes again once empty, and ZCode's user-wide file isn't touched. The page learns a project file's own SSE limit (projectNoSSE), so Pi's chip is greyed for an SSE server in a project even when its user-wide file (pi-mcp-adapter's) takes SSE; the trust note now names Pi beside Codex. The Remove dialog of a project magpie put anything in has "Keep its skills and MCP servers" / 保留项目里的技能和 MCP 服务器 (a checkbox row in the library's pick style, no coloured left border): checked, the text says what stays and Remove posts projects/remove with keep, and RemoveProject(dir, keep) only takes the project off the list — skills (links still following the library's), servers in the agents' files and magpie's .gitignore lines stay as they are, and nothing magpie does later (a sync, the server removed from the library) touches them; unchecked it removes as before. A one-off add without a project first (pick a folder from a server or skill) is not in this change. TestProjectServersZCodePi (ZCode's file with the user's model, server, enable:false and key kept beside magpie's three; Pi's file made in its shape, the SSE server refused with its reason, listed in .gitignore; ZCode's user-wide file unchanged; removing takes out only magpie's and the file it made) and TestRemoveProjectKeep (every file byte for byte after the removal, after a sync and after the server leaves the library) fail without the change, as does project-remove-keep.test.cjs (WebKit, and Chromium through a temp copy on plain chromium.launch(); en and zh: the box unchecked, its text, no stripe, pressing it scrolls nothing and swaps the text, Remove posts keep: true and says they were kept; a project with nothing written has no box and posts as before) against HEAD's assets. project-servers, click-scroll, library-items, library-all pass; menu-scroll and old-webkit fail the same on HEAD. No live config was read or written. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... (under a temp HOME) pass (TestFXInState failed on a TempDir cleanup race twice in the full gui run, passes alone and on the rerun; untouched).
2026-10-02 14:10:55 +08:00
library: ZCode and Pi get a project's MCP servers too, and a project can be removed keeping what magpie wrote into it (#514, follow-up to #500: zcode支持项目级mcp添加 / pi也支持项目级mcp / 删除项目但保留mcp/skill) — a project's servers went only to Claude Code, Codex, Gemini CLI, Cursor and OpenCode, and Remove took every skill and server magpie had put in the folder away, so a project given some once had to stay in magpie for good. ZCode's project file is <project>/.zcode/config.json, servers under mcp.servers as in its user-wide ~/.zcode/cli/config.json (zcode.z.ai/en/docs/mcp-services, "Configuration Files and Default Load Paths": workspace scope, read before the user's, "enable": false the user's to set), written with fmtZCode (type, command/args/env or url/headers); Pi's is <project>/.pi/mcp.json, mcpServers as Pi's own MCP reads them once the project is trusted (pi.dev/docs/latest/mcp, "Configure servers"), written with fmtPiNative (command/args/env, url/headers, no type; SSE refused, as Pi refuses it), whatever extension the user's own Pi file is written for. Both are merged as the other agents' are: the user's keys, servers and comments stay, a server of the same name that isn't magpie's is left alone and said, a file magpie made (.pi/mcp.json) goes in the .gitignore and goes again once empty, and ZCode's user-wide file isn't touched. The page learns a project file's own SSE limit (projectNoSSE), so Pi's chip is greyed for an SSE server in a project even when its user-wide file (pi-mcp-adapter's) takes SSE; the trust note now names Pi beside Codex. The Remove dialog of a project magpie put anything in has "Keep its skills and MCP servers" / 保留项目里的技能和 MCP 服务器 (a checkbox row in the library's pick style, no coloured left border): checked, the text says what stays and Remove posts projects/remove with keep, and RemoveProject(dir, keep) only takes the project off the list — skills (links still following the library's), servers in the agents' files and magpie's .gitignore lines stay as they are, and nothing magpie does later (a sync, the server removed from the library) touches them; unchecked it removes as before. A one-off add without a project first (pick a folder from a server or skill) is not in this change. TestProjectServersZCodePi (ZCode's file with the user's model, server, enable:false and key kept beside magpie's three; Pi's file made in its shape, the SSE server refused with its reason, listed in .gitignore; ZCode's user-wide file unchanged; removing takes out only magpie's and the file it made) and TestRemoveProjectKeep (every file byte for byte after the removal, after a sync and after the server leaves the library) fail without the change, as does project-remove-keep.test.cjs (WebKit, and Chromium through a temp copy on plain chromium.launch(); en and zh: the box unchecked, its text, no stripe, pressing it scrolls nothing and swaps the text, Remove posts keep: true and says they were kept; a project with nothing written has no box and posts as before) against HEAD's assets. project-servers, click-scroll, library-items, library-all pass; menu-scroll and old-webkit fail the same on HEAD. No live config was read or written. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... (under a temp HOME) pass (TestFXInState failed on a TempDir cleanup race twice in the full gui run, passes alone and on the rerun; untouched).
2026-10-02 14:10:55 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
library: an agent's own copy of a library skill gives way to it, and one that differs is settled from the warning (StringKe, JasonLeeForOnly on Discord: after Bring in all, "Claude Code already has a skill of its own called impeccable", 这里没有强制覆盖的能力) — a skill is brought in from the agent with the very folder and given to the agents that had that folder; another agent's copy (CC Switch copies a skill into each agent) was listed as "differs in" and left out, and giving the skill to it, or a copy put back into an agent after its folder became magpie's link (by CC Switch or whatever installed it), was a hard failure with no way out. A folder there holding the same files as the library's (bytes compared; .DS_Store, .git and magpie's copy mark aside) is now set aside into backups/<when>/<agent>/skills and the library's linked in its place; a skill brought in takes the agents with such a copy too, which are no longer said to differ; a move that copied it all but couldn't remove the folder brings it in all the same, what was left set aside. One that differs keeps the warning, now in the reader's language with "Use the library's" (the agent's set aside, the library's linked) and "Keep <agent>'s" (the agent, and any reading the same folder, taken off the skill) on its row — skills/use-library and skills/keep-own, magpie library skill use-library|keep-own <name> <agent>, which the CLI suggests under the problem. Backups holding a skill set aside are never pruned. TestOwnSkillInTheWay, TestSameTree, TestPruneKeepsSkillsSetAside and own-skill.test.cjs (Chromium, WebKit, en/zh) fail without the change; TestSharedAgentsSkills now expects the byte copy to be the library's. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; own-skill, import-all-skills, library-items, shared-skills, market-have, click-scroll, old-webkit pass.
2026-09-30 19:42:43 +08:00
library: ZCode and Pi get a project's MCP servers too, and a project can be removed keeping what magpie wrote into it (#514, follow-up to #500: zcode支持项目级mcp添加 / pi也支持项目级mcp / 删除项目但保留mcp/skill) — a project's servers went only to Claude Code, Codex, Gemini CLI, Cursor and OpenCode, and Remove took every skill and server magpie had put in the folder away, so a project given some once had to stay in magpie for good. ZCode's project file is <project>/.zcode/config.json, servers under mcp.servers as in its user-wide ~/.zcode/cli/config.json (zcode.z.ai/en/docs/mcp-services, "Configuration Files and Default Load Paths": workspace scope, read before the user's, "enable": false the user's to set), written with fmtZCode (type, command/args/env or url/headers); Pi's is <project>/.pi/mcp.json, mcpServers as Pi's own MCP reads them once the project is trusted (pi.dev/docs/latest/mcp, "Configure servers"), written with fmtPiNative (command/args/env, url/headers, no type; SSE refused, as Pi refuses it), whatever extension the user's own Pi file is written for. Both are merged as the other agents' are: the user's keys, servers and comments stay, a server of the same name that isn't magpie's is left alone and said, a file magpie made (.pi/mcp.json) goes in the .gitignore and goes again once empty, and ZCode's user-wide file isn't touched. The page learns a project file's own SSE limit (projectNoSSE), so Pi's chip is greyed for an SSE server in a project even when its user-wide file (pi-mcp-adapter's) takes SSE; the trust note now names Pi beside Codex. The Remove dialog of a project magpie put anything in has "Keep its skills and MCP servers" / 保留项目里的技能和 MCP 服务器 (a checkbox row in the library's pick style, no coloured left border): checked, the text says what stays and Remove posts projects/remove with keep, and RemoveProject(dir, keep) only takes the project off the list — skills (links still following the library's), servers in the agents' files and magpie's .gitignore lines stay as they are, and nothing magpie does later (a sync, the server removed from the library) touches them; unchecked it removes as before. A one-off add without a project first (pick a folder from a server or skill) is not in this change. TestProjectServersZCodePi (ZCode's file with the user's model, server, enable:false and key kept beside magpie's three; Pi's file made in its shape, the SSE server refused with its reason, listed in .gitignore; ZCode's user-wide file unchanged; removing takes out only magpie's and the file it made) and TestRemoveProjectKeep (every file byte for byte after the removal, after a sync and after the server leaves the library) fail without the change, as does project-remove-keep.test.cjs (WebKit, and Chromium through a temp copy on plain chromium.launch(); en and zh: the box unchecked, its text, no stripe, pressing it scrolls nothing and swaps the text, Remove posts keep: true and says they were kept; a project with nothing written has no box and posts as before) against HEAD's assets. project-servers, click-scroll, library-items, library-all pass; menu-scroll and old-webkit fail the same on HEAD. No live config was read or written. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... (under a temp HOME) pass (TestFXInState failed on a TempDir cleanup race twice in the full gui run, passes alone and on the rerun; untouched).
2026-10-02 14:10:55 +08:00
library: an agent whose folder is a file isn't written, and skills reach 13 more agents with one link in ~/.agents/skills for those that share it (neiko on Discord: with DeepSeek Harness not installed the Library kept failing on "open ~/.dsh/AGENTS.md: not a directory" and ~/.dsh/config.yaml; inaction: the skills list is short of the Agents page, Kimi Code has none). An agent counted as there when its folder path existed or its command was on PATH, never asking whether the path was a folder — a file at ~/.dsh, or another dsh, made DeepSeek Harness look installed. Now an agent whose folder is a file (or under one) isn't detected (agent.Taken; Goose's, Cindy's and Claude Desktop's own checks want a folder too), a Library target leaves out each place a file stands in the way of, one with none left isn't listed, and an agent given no MCP server with none of magpie's isn't read. Skills: Kimi Code, Goose and Cindy get ~/.agents/skills (Kimi's ~/.config/agents/skills when there, as Kimi reads it first; never ~/.kimi/skills, which would hide Claude Code's from it); Command Code, Devin, Hermes, Droid, Cline, Qoder, Qoder CN, Grok, WorkBuddy, Hanako and fx their own skills folder; Kimi, Goose and Grok a project's .agents/skills. The shared folder is filled first, and an agent that reads ~/.agents/skills besides its own (Codex, Gemini CLI, OpenCode, Crush, DeepSeek Harness and those above) gets no second link to a skill already there. Tested with new taken_test.go (neiko's two errors without the change) and agent_skills_test.go (skills folders, written once, a shared skill imported for Kimi), in sandbox HOMEs; library-items and shared-skills 24/24 in Chromium and WebKit; go vet, go build (-tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass. Not tried with real Kimi Code, Goose or Cindy.
2026-09-30 14:40:41 +08:00