Skip to content

Releases

插件 2.3.6(Clash + Magpie)

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 10 Nov 11:10

插件 2.3.6(Clash + Magpie)

Clash 修 #50(看门狗黑窗口);Magpie 修一处悬空引用并追平上游到 v0.1.3596(2.3.5 是 v0.1.3383)。
校准:FISH Dock ≥ 2.0.0、宿主 API 1、Windows x64。

Clash 2.3.6 — 看门狗改为隐藏启动(#50)

2.3.5 修好参数名之后,看门狗第一次真正建起来,也第一次把 node.exe 直接交给任务计划。任务计划在交互式会话(LogonType=InteractiveToken)里启动控制台子系统程序时会新建一个可见的控制台窗口,Node 的 windowsHide 管不到任务计划服务拉起的进程;Dock 内置的 node.exe 正是 PE subsystem=3 (CONSOLE)。结果是开启系统代理的瞬间,桌面弹出一个标题为 node.exe 路径的黑色窗口,并且一直挂着——看门狗常驻最长 12 小时,任务还设了每 5 分钟重复。

本版把任务动作从 node.exe 换成 wscript.exe:

  • 新增 plugins/clash/watchdog-launch.js(JScript),由 wscript.exe //B //Nologo //E:JScript 拉起,再用 WScript.Shell.Run(cmd, 0, true) 以 SW_HIDE 启动 node;
  • wscript.exe 是 GUI 子系统,自身不建控制台;node 的控制台窗口从创建起就是隐藏的;
  • 启动器等 node 退出,任务实例在 Running 状态一直保持,-MultipleInstances IgnoreNew 才真正挡住 5 分钟重复触发(若启动器立刻返回,每 5 分钟会再起一个看门狗);
  • //B 是批处理模式:脚本自身出错时不弹「Windows Script Host」对话框,失败写 <租约>.log,与 watchdog.mjs 的失败日志同一份;
  • 系统禁用 Windows Script Host(找不到 wscript.exe)时 start() 明确返回 ok:false 并记日志,不退回直接启动 node.exe——那正是本 issue 的窗口来源。

watchdog-launch.js 必须保持纯 ASCII:WSH 按 ANSI 读取无 BOM 的 .js,UTF-8 中文注释会吞掉下一行(实测 'return' statement outside of function)。单测断言文件里没有 >0x7F 的字节。

生命周期不变:系统代理接管成功才建任务,恢复成功、插件停止/关闭都注销;看门狗恢复完仍用 schtasks /Delete 删掉自己的任务。

Magpie 2.3.6 — 供应商编辑器打不开(foldNeeded is not defined)

现象

2.3.5 上点开任一供应商,Providers 页底部弹一个红色胶囊 foldNeeded is not defined,编辑器永远打不开。模型区一画就抛异常,整个页面停在错误提示上。

根因:补丁重放漏搬了一个 hunk

foldNeeded 是上游 app.js 里「模型芯片折叠」的模块级状态。fish.30 的两个相邻 hunk 是配套的:

hunk 位置 内容
@@ -11141,8 +11162,6 @@ 顶部声明区 删掉 const foldNeeded = {}
@@ -11300,19 +11304,13 @@ drawFold() 内 把 measure() 改成 requestAnimationFrame(...),从此不再引用 foldNeeded

fish.31 只搬了第一个,第二个整段丢了:声明没了,两处用法还在。node --check 只做语法分析(通过),git apply 干净应用(0 冲突),follow-upstream.ps1 只比对 hunk 数与树哈希(通过)——三重闸门都拦不住,直到运行时才 ReferenceError。

同一个缺口还漏了另一段:renderModels 里内联的 kindNow / KIND_NAMES(只有 Auto/Image/Video 三类)/ pickKind 没换成 kindNowOf / openModelKindMenu,于是 #42 的六类「Makes…」菜单在芯片右键上一直没生效(外层的六类表被内联的三类遮蔽)。

修法

  • drawFold() 改成 requestAnimationFrame + 直接量 scrollHeight,不再依赖 foldNeeded(补丁里删掉声明与两处用法);
  • renderModels 的内联三件套换成 kindNowOf / openModelKindMenu,六类标注菜单真正生效。

追平上游 v0.1.3596

基线从 v0.1.3383 走到 v0.1.3596(213 个 tag),补丁 magpie-v0.1.3596+fish.33.patch,158 文件 / 261 hunk,30 个冲突 hunk 逐条消化:

  • app.js 7 处:passUserAgent 改成真值语义、draftOf 与保存体带上 hiddenAudios/hiddenEmbeddings、编辑器补语音/向量/其他模型三节、更新页的「打开」走宿主受控入口、prefsKeep 带 speechModel/embedModel;
  • plugins/routing/client.js 3 处:「图片输入」三态 imagesSaid 进草稿与保存体;
  • 插件页:pagebridge.js 的 magpie.call 通道、pluginpages.js 的 call 分支、pluginpage.go 的 pluginCallRoutes 接线、plugin/page.go 的 PageCalls 与 callsKeeping(用上游的 lazyre);
  • providers.go 的 MarksServesKinds、settingsapi.go 的模型与超时键、gateway.go 的 MaterialsMCPPath 路由与 apis 清单、own_mcp.go 的 GenerateAudioTool、bun.go 的 registry 覆盖、registry.go 的 sync/atomic、provider/group.go 的 Images 指针深拷;
  • 两个 i18n.js 的新词条按键补齐(已有键一律不动,译文用上游的);
  • core_budget_test.go 的预算按实测上调到 app.js 1,318,466 / 核心脚本 1,543,404;
  • Cline 的上游提示文案保留上游版本,不回退。

新增闸门:补丁「删了声明、还在引用」直接拒绝

plugins/magpie/tools/check-assets-refs.mjs 只看一件事:补丁的 - 行删掉了某个顶格声明,而补丁应用后的文件里还在引用这个名字。判据刻意收窄(不做作用域分析、跳过语言内建与宿主全局),误报接近零。

接在两处,任一处不过都不出包:

  • follow-upstream.ps1 重放后检查,失败以退出码 3 停下并列出符号;
  • build-magpie.ps1 编译前检查,失败 throw。

实测:拿 2.3.5 那棵树 + fish.31 跑,准确报出 internal/gui/assets/app.js: foldNeeded(2 处引用);换 fish.33 则放行。

验证

项 结果
clash.fish-plugin 17,195,643 B,sha256 a50d8f0fe969505d6ec1f5241921af62b4a591f30daf5ddca24e830232bbb1bf;7z t 通过(29 文件)
magpie.fish-plugin 40,752,108 B,sha256 a969ee93cc48e944986fb73e20ddeccf6bc16fc115d85928d9a9ac64cecfc3e0;7z t 通过(65 文件)
magpie.exe 89,544,704 B,FileVersion 0.1.3596.33、ProductName magpie fish;包内 foldNeeded 0 次(2.3.5 是 2 次/0 声明)
补丁可复现 干净 v0.1.3596 + fish.33 → git apply --check 通过 → go build ./... 通过 → 悬挂闸门通过
go test ./internal/gateway -run 'Speaker|Speech|Embedding|Video|Kind|Materials|Audio' 通过
go test ./internal/gui -run 'TestCoreScriptBudget|TestSettingsSaveKeepsWhatItDoesNotSend' 通过
node --test --test-isolation=none "plugins/clash/*.test.mjs" 170 条,167 通过、0 失败、3 跳过(page.browser.test.mjs 需 Edge + playwright)
tools/verify-release.mjs 两个包的归档资源、页面依赖、清单摘要与 npm 字节一致

上游测试里 internal/gui / internal/plugin 的若干用例在本机失败(symlink ... A required privilege is not held、sh.exe ... couldn't create signal pipe、并发 rename Access is denied),在未打补丁的干净 v0.1.3383 基线上失败集完全相同,属本机权限与沙箱限制,不是本补丁引入;TestProxyCheckSaysAProxyPassedBy 在全量运行时偶发、单跑通过。

升级

在 Dock 的插件页更新即可。

  • Clash:无需重装 TUN 服务(本版没有改服务 exe)。若仍看到黑窗口,先确认任务计划里 FISH Dock clash watchdog-<SID> 的动作是 wscript.exe——2.3.5 建下的旧任务会被 Register-ScheduledTask -Force 覆盖,但只有在下次开启系统代理时才会覆盖;想立刻生效,关闭再开启一次系统代理。
  • Magpie:本版换了基线,magpie.exe 会以新的运行副本落盘(旧副本按既有规则保留一天再回收)。供应商编辑器恢复正常;芯片右键的「Makes…」菜单恢复六类(图像 / 视频 / 语音 / 转写 / 向量 / 重排)。

摘要见 SHA256SUMS.txt。

插件 2.3.5(Clash + Magpie)

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 09 Nov 12:04

插件 2.3.5(Clash + Magpie)

Clash 合入 PR #49 并补一处竞态;Magpie 修 #48,并追平上游到 v0.1.3383 + fish.31(2.3.4 是 v0.1.3240 + fish.30)。
校准:FISH Dock ≥ 2.0.0、宿主 API 1、Windows x64。

Clash 2.3.5 — 看门狗真正建起来,TUN 服务卸载后退休(#49)

  • 看门狗计划任务从未建成。 New-ScheduledTaskSettingsSet 没有 -DisallowStartIfOnBatteries / -StopIfGoingOnBatteries 这两个参数,参数绑定直接失败,任务一次也没注册上。改为真实存在的 -AllowStartIfOnBatteries / -DontStopIfGoingOnBatteries,测试断言旧参数名不得再出现。
  • TUN 服务随插件卸载退休。 插件卸载后,%ProgramData%\FishDock\clash-tun 里的服务不再常驻。
  • 退休条件加固(本仓追加)。 PR 原实现读 job.ini 判断内核是否空闲:文件写到一半时,会把启动中的内核当成空闲,还会在内核进程仍在接管流量时撤掉服务(删掉运行中的 exe 并不会结束进程)。现在只看内核进程句柄:内核 exe 不在、子进程也已退出,才退休。

已安装并点过「安装 TUN 服务」的用户:升级后请再点一次。 服务 exe 是安装时复制到 ProgramData 的,不重装就仍是旧逻辑。

Magpie 2.3.5 — 媒体模型的音频回退(#48)

generate_audio 用 NearToken 的语音模型时必定失败,报 404 expected /v1beta/models/{model}:generateContent。两个根因:

  • 进程内直接调 s.gemini。 那条路径依赖请求路由里的 {call} 参数,进程内调用时为空,于是 magpie 自己回了 404。现在解析 provider 后直连它的 Gemini API。
  • 媒体模型被当成聊天模型,走了流式请求。 走网关的转译路径时会请求 streamGenerateContent,NearToken 明确拒绝。现在音频工具发非流式 generateContent,请求体带 responseModalities: ["AUDIO"],模型名不再带 neartoken/ 之类的 provider 前缀。

两条路都失败时,错误会同时带出 audio/speech、generateContent、chat 三处上游原文,不再只给一句「没有可用音频端点」。只支持 chat 的模型(如 suno/suno_music)仍走 /v1/chat/completions,不会去问 Gemini。

Magpie 追平上游 v0.1.3383

补丁从 v0.1.3240 重放到 v0.1.3383,11 个文件、21 处冲突手工合并。合并口径:上游已有 VideoGen,放弃我们旧的视频模型字段,只补语音、向量模型行及视频 / 语音 / 向量三类超时;路由组补「图片输入」三态。

Claude Desktop 网关窗口没有中文:不是本版能修的

上游 v0.1.3142 那条说明是记录问题,不是修复;v0.1.3383 同样没有中文。本仓核对了 Claude Desktop 4.23118.0:

  • magpie 接入时,Desktop 运行在网关(3p)模式,界面是安装包自带的 ion-dist.asar,只有 11 种语言,没有中文;主进程的语言表也没有中文。
  • 每次启动,这个窗口都会从这 11 种语言里重新挑一种,写回 Claude-3p/config.json。magpie 写进去的中文会被 Desktop 自己改回 en-US。
  • 有中文的是 Anthropic 账号登录的窗口。它在线加载 claude.ai 网页,对话只发往 claude.ai 自己的后端,不接受自定义网关;网关配置又只在 3p 模式下生效。

所以 magpie 无法让网关窗口显示中文。需要中文界面时,在 magpie 里断开 Claude Desktop,回到 Anthropic 账号登录;想用 magpie 的模型,可以接入 Claude Code 等客户端。magpie 的 Agents 页在 Claude Desktop 一行也会提示这一点。

其他

  • Magpie 清理 tmp 时不再删除宿主写在那里的目录说明与事务日志(FISH-Dock#86)。之前闲置一天后升级插件会在提交阶段报「缺少旧版本目录说明」;Dock 2.2.1 宿主侧也已改为缺失时重建。

安装

在 Dock 的插件页更新即可;摘要见 SHA256SUMS.txt。

插件 2.3.4:Clash 断网修复 + Magpie #47

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 07 Nov 19:22

插件 2.3.4(Clash + Magpie 同版)。

Clash 2.3.4 — 关掉它不再断网

  • 停止顺序改成「先还系统代理、再收内核」,结尾不再重复恢复;宿主给停用的预算是 5 秒,排在后面的那一步等于没做。
  • 启动失败(取消 / 拉起失败 / 控制器没就绪)统一收尾:收候选内核、清运行态、还代理,原错误码不被掩盖。
  • 坏租约(schema 不符、缺 previous/owned、字段类型不对)一律丢弃并带 code;恢复不再被一条坏记录拖死。
  • 探活与收尾共享 1.6 秒预算:控制器永不回时 stop() 1.6 秒返回,代理已恢复、内核状态报「未确认停止」。
  • TUN:插件写 /host.json 宿主租约,服务侧 Tick 发现宿主消失(或 pid 被复用)就停内核并把 job.ini 置 0。
  • 看门狗改由任务计划拉起(独立于宿主的 Job),只在系统代理被接管期间存在,恢复/停用即注销,恢复完自删任务。

已在用 TUN 的用户需要重新点一次「安装 TUN 服务」:服务 exe 是安装时复制到 ProgramData 的。

Magpie 2.3.4 — #47

插件宿主被替换(换代理、更新、崩溃重启)时,provider 不再被说成「You removed it from magpie.」:

  • 仍在安装的插件 provider 被隐藏时报「插件重启中」(updating: true),且不给 provider 字段,前端不会出现「加回来」。
  • keepUnloaded 的「已安装」判据改用磁盘真值,不再依赖本轮的插件列表——宿主刚接手的那一瞬间正是旧判据失效的地方。
  • neartoken:relist 除放回 setAside,还会取消该 spec 下隐藏的记录。

安装

clash.fish-plugin / magpie.fish-plugin 可直接在 Dock 的插件页安装;摘要见 SHA256SUMS.txt。

Magpie 2.3.3 + Clash 2.3.3(生图超时行收尾、素材 MCP 中文化)

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 07 Nov 14:40

插件 2.3.3(Magpie + Clash)

2.3.2 的紧急补丁:只改 Magpie 管理页的两处界面问题,无行为变更。
Magpie 的 magpie.exe 重编到补丁 v0.1.3240 + fish.29(2.3.2 是 fish.28)。
校准:FISH Dock ≥ 2.0.0、宿主 API 1、Windows x64。

设置 › 图像:删掉重复的「生图超时」行

2.3.2 把生图 / 视频 / 语音 / 向量的超时做成了模型行右侧的胶囊(N 分钟 ▾),但上游原生的「Image generation timeout」整行没有删——页面上于是有两个入口:一个是中文标题配 5/10/15/30/60 的段选,另一个是胶囊。

本版删掉整行,生图超时只留胶囊,与另外三行一致。上游为那一行写的浏览器用例 image-timeout-setting.test.cjs 一并移除(该行已不存在)。

「素材 MCP 服务器」补上中文

「Materials MCP server」此前只有英文键,中文界面里直接露英文。本版补:

  • zh:素材 MCP 服务器
  • zh-TW:素材 MCP 伺服器
  • ja:素材 MCP サーバー
  • de:Material-MCP-Server

下方说明文案(generate_image / generate_video / generate_audio / generation_result 四个工具、图片与视频保留一小时的 URL、跨机访问的 Bearer 密钥)也一并翻译。

验证

项 结果
magpie.fish-plugin 37,236,260 B,sha256 15da4f15…758b;7z t 通过(60 文件)
clash.fish-plugin 17,188,560 B,sha256 c9db5303…0e6f;7z t 通过(28 文件)
magpie.exe 83,672,064 B,v0.1.3240+fish.29 / FileVersion 0.1.3240.29
上游补丁 magpie-v0.1.3240+fish.29.patch:150 文件 / 252 hunk,干净 v0.1.3240 上 git apply --check 通过
verify-release --dist 通过(两包身份、版本、sha256、字节、文件数一致)
node --check app.js、i18n.js 通过(构建脚本自带闸门)
Go go build -buildvcs=false ./... 通过;TestCoreScriptBudget 通过(app.js 变小、i18n 变大,合计仍在预算内)
npm @fish-under-sea/fish-dock-plugin-magpie@2.3.3、…-clash@2.3.3(双源 latest)

已知边界

  • 2.3.2 的已知边界继续适用:Usage 页只读实时日志(>128 MB 的旧明细在 usage.jsonl.1);NearToken 的 TTS/音乐仍缺站点侧音频渠道;#44 原始样本根因待现场复现。
  • 本版只有界面文案与设置项改动,Clash 仅版本位跟随。

Magpie 2.3.2 + Clash 2.3.2(存储不再无界、代理恢复可诊断)

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 07 Nov 14:12

插件 2.3.2(Magpie + Clash 同版)

两个插件同时到 2.3.2;Magpie 的 magpie.exe 重编到补丁 v0.1.3240 + fish.28(上一版是 v0.1.3207 + fish.26)。
校准:FISH Dock ≥ 2.0.0、宿主 API 1、Windows x64。

Magpie:追平上游 v0.1.3240

  • 基线 v0.1.3207 → v0.1.3240(33 个 tag);
  • 两处冲突手工消化:providers.go 的 MarksServesKinds 初始化字段、docs/subsystems/gateway-routing.md 的 #42 段落按上游新文重写。

Magpie:provider 掉出后的 sticky 与恢复(#41)

插件重载、崩溃或安装窗口里「这次没报 provider」,以前会被当成移除,分组与页面跟着掉。本版:

  • A(上游已实现,本版验证):keepUnloaded 对「插件仍装着、这次没报」保留上次的 provider;
  • B:插件清单可写 magpie.keepListedUntilRemoved,默认保留、写 false 才关(不改变上游对所有插件的默认语义);
  • C:专用恢复钩子 neartoken:relist → provider.RestorePluginProviders(spec),只恢复 PluginLeft 记录(崩溃/卸载窗口类),用户显式移除的不恢复。

Magpie:更新失败可见、首装进度(#41 的 P/Q)

  • 安装失败落盘 <data>/plugin-install-errors.json,页面可点「重试安装」(magpie:plugin-retry / POST /api/plugins/retry-install,页面 call 与 GUI API 共用一份实现,安装进行中再点直接返回 busy);
  • 失败后自动换国内镜像重试一次(NPMMirror);半装时清残留目录;单包失败不拖累其余;
  • 首装逐包进度 preinstallProgress 与总进度弹窗:只挡 magpie 本页、失败三出口(重试 / 稍后 / 以后不再提示),装完自动解除。

Magpie:设置页与素材 MCP

设置 → 图像的顺序改为:识图 → 生图 → 视频 → 语音 → 向量 → 识图 MCP → 素材 MCP;生图 / 视频 / 语音 / 向量四行右侧各一个响应超时胶囊(N 分钟 ▾,与「默认/思考强度」同一套度量)。

  • 新增 videoModel;生图与视频模型互斥;
  • 四类媒体各用自己的超时(imageTimeout / videoTimeout / speechTimeout / embedTimeout),网关四条媒体路径全部接线;
  • 素材 MCP:端点 /mcp/magpie/materials(旧 /mcp/magpie/image 继续服务),工具 generate_image / generate_video / generate_audio / generation_result;三个工具各自取「设置里选的那个模型」;
  • generate_audio 三级降级:标准 /v1/audio/speech → 同供应商 chat/completions(OpenAI 兼容的三种取音频形态)→ Gemini 原生 generateContent + responseModalities:["AUDIO"];供应商没有音频渠道时给明确文案,不甩原始 500;
  • 语音/向量行显示补齐为「图标 + 模型名 · provider」。

Magpie:自启动适配(#45)

  • startWithBackoff 对「start 抛错」与「返回 error 状态」同样按 0/600/1500 退避重试;自启判断与失败日志共用一份 view 快照;
  • Clash 的 autostartKernel 把读配置 / 修内核路径与 start() 放进同一轮 0/1.5/4 秒重试,每轮只读一次 view,失败不抛 activate()。

Magpie / Clash:数据根不再无界(#46)

  • usage.jsonl 到 128 MB 滚到 usage.jsonl.1(先删旧 .1,Windows 才能 rename);key 的日/月/总额花销上限跨轮转仍正确(窗口早于实时日志第一条时补读 .1),log-v1.bin 按文件身份自动重建;
  • masking 保留期不再删当天文件(以前总量超限会把刚写的记录一起丢),当天也不占总量;routing / masking 在 magpie web 启动时各扫一遍(此前只有「再写一条」才触发清理);
  • 插件侧:旧名二进制(magpie.exe / .exe.new / .before-*.exe,一天宽限)、TEMP 残片(tmp/magpie 等,一天宽限)在启动前回收;gateway-error.log 滚动先删 .1;
  • Clash:启动时清 tmp/import-* 与写了一半的候选配置;删订阅把 credentials/<id>.json 与缓存 YAML 一起删,不再留 0 字节残片;
  • 清理动作都写进日志([magpie] …清理 / [clash] TEMP 清理 / magpie 侧 routing:、maskrec:)。

Clash:系统代理恢复失败可诊断(#44)

  • PowerShell 失败应答改为 {ok:false, key, win32, message}:键级失败报 ProxyEnable / ProxyServer / ProxyOverride,刷新失败单独报 InternetSetOption(带 GetLastWin32Error());
  • 启动自愈、停止结果、看门狗三处日志都带键名与 Win32 码;看门狗写 <租约>.log(64 KB 封顶)并保留租约给下次重试;
  • 恢复失败仍只降级,不拦内核启停与页面。

验证

项 结果
magpie.fish-plugin 37,229,994 B,sha256 244d71fa…f28e;7z t 通过(60 文件)
clash.fish-plugin 17,188,560 B,sha256 62aa1b2e…2dd8;7z t 通过(28 文件)
magpie.exe 83,668,992 B,v0.1.3240+fish.28 / FileVersion 0.1.3240.28 / ProductName magpie fish
verify-release --dist 通过(两包身份、版本、sha256、字节、文件数一致)
上游补丁 magpie-v0.1.3240+fish.28.patch:149 文件 / 248 hunk,干净 v0.1.3240 上 git apply --check 通过
Go go build -buildvcs=false ./... 通过;internal/usage、internal/maskrec、internal/gateway(历史/保留期)、internal/cli(web 子集)通过
插件测试 91 pass / 0 fail(4 个环境相关 skip)
npm @fish-under-sea/fish-dock-plugin-magpie@2.3.2、…-clash@2.3.2 已发布;官方源与 npmmirror 的 latest 均为 2.3.2
管理页脚本 node --check 全部通过(构建脚本自带闸门)

已知边界

  • Usage 页只读实时日志:超过 128 MB 的旧明细(本机约 40 天)在 usage.jsonl.1 里,页面不展示;key 的花销上限不受影响。这是「有界」换来的,详见 docs/maintainers/storage-budget-magpie.md。
  • NearToken 的 TTS/音乐:站点侧暂无可用音频渠道(500/503/404 model_not_found),magpie 已按 audio → chat → Gemini 原生三级降级;chat 通道取音频按 OpenAI 兼容三种形态实现,成功响应样例仍未取得,站点恢复后若返回自有格式需补一条分支(不改协议)。
  • #44 的原始样本根因仍未定性:2026-11-03 那条日志没有可复现环境;本版起再出现会直接指出是哪个键/刷新调用、什么 Win32 码。
  • 真机未点验:设置页新排版、首装进度弹窗、generate_audio 的真实音频返回、Clash 系统代理开关(出包后建议各过一遍)。

Magpie 2.3.1(模型分类认插件 kind 与用户标注)

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 06 Nov 23:27

插件 2.3.1(Magpie)

只发 Magpie;Clash 仍是 2.3.0,包未动。
Magpie 的 magpie.exe 重编到补丁 v0.1.3207 + fish.26(上游从 v0.1.3140 追平 67 个 tag)。
校准:FISH Dock ≥ 2.0.0、宿主 API 1、Windows x64。

模型分类:官方判定 + 用户自定义标注(#42)

上一版(#24)只给出了四个分区,判据只有一条——catalog.ServesOf(id) 按模型 ID 名字猜,猜不出就丢弃或当成对话模型。插件 provider 声明的模型更彻底:plugin.Model 没有 kind 字段,capabilities.output 里的 audio / embedding 只用来判「能不能聊」,于是 NearToken 那类插件报上来的语音、向量模型既不进分区、也不在对话列表,直接消失。

本版把分类的来源补齐:

  • 插件自己的 kind 先说:plugin.Model 新增 kind(image / video / audio / embedding),pluginCatalog 按它落 Draws / Films / Serves;capabilities.output 与模型 id 只作兜底。kind: audio(或 embedding)的模型不再混进对话列表,哪怕它同时声明了 text 输出。
  • 用户可以自己标:settings.ModelKinds 从 image / video 扩到 speech / transcription / embedding / rerank,插件 provider 也能标(MarksServesKinds)。模型 chip 右键的 Makes… 菜单从两项变六项。
  • 设置页取数补齐:speakingOf 收进插件声明的另一类模型(PluginServing),设置 → 图像的「语音模型 / 向量模型」两行不再只有自定义中转的 live 列表;判据统一走 ServedAs(用户标注优先,其次模型自己的列表)。
  • 「其他模型」栏:插件说某个模型「给的不是对话」却没说是哪一类时(PluginUnkinded),编辑器单列一栏,点一下就能归类——否则这些模型三种列表里都看不到。
  • 顺带修一处:设置页保存的字段白名单 prefsKeep 补上 speechModel / embedModel,不再靠后端 merge 兜底。

上游追平

  • 基线 v0.1.3140 → v0.1.3207(67 个 tag);
  • 重放时两处冲突手工消化:providers.go 的 providerJSON 初始化行(上游加了相邻字段)、core_budget_test.go 的预算数(按新基线实测重设:app.js 1,317,737、核心脚本 1,542,234);
  • 上游已把「按 list 顺序列 unticked」内联进各处,fish.24 引入的 unticked() 不再需要,本次不带。

验证

项 结果
magpie.fish-plugin 36,903,448 B,sha256 6cb31f5d…54e82;7z t 通过(59 文件)
go build ./... 通过
新增单测 modelkind_serves_test.go(六类标注 / 插件可标)、plugin_kind_test.go(kind 挡出对话列表)、speakers_kinds_test.go(插件 kind 与用户标注进 Speakers/Embedders)——全绿
受影响回归 `go test ./internal/gateway -run 'Speakers
管理页脚本 node --check 全部通过(构建脚本自带闸门)

已知边界

  • 真机 UI 未点验:设置 → 图像的「语音模型」下拉、编辑器「其他模型」栏需要装上本版后过一遍。
  • NearToken 侧要配合:它的 kind 取值(chat|image|video|audio|embedding)本版已认;kindOf 对「能听音频但输出文本」的对话模型有误判,插件仓已开单(magpie-neartoken#1),修复前这类模型可能被标成音频。

FISH Dock 插件 2.3.0(Clash + Magpie:内置件改按 npm spec 登记)

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 06 Nov 21:30
e8f7aa7

插件 2.3.0(Clash + Magpie 同版)

两个插件同时到 2.3.0;Magpie 的 magpie.exe 仍是补丁 v0.1.3140 + fish.24(本版没有重编 exe)。
校准:FISH Dock ≥ 2.0.0、宿主 API 1、Windows x64。

Magpie:两个内置件改按 npm 包登记

2.2.9 的内置件是「同步目录副本 + 绝对路径」登记,那条 spec 不在 magpie 自己的更新循环里:目录副本停在发版那天的版本,上游(@fish-under-sea/magpie-checkin-relay-probe / @fish-under-sea/magpie-purge)发了修复用户也拿不到。

本版改成与 @magpie-community 那批预装供应商插件同一条路——只把 npm spec 写进 magpie 的 plugins.json:

"@fish-under-sea/magpie-checkin-relay-probe@latest"
"@fish-under-sea/magpie-purge@latest"
  • 首装与后续更新都由 magpie 自己的更新循环按 spec 完成;
  • magpie.fish-plugin 不再带 bundled-plugins/ 副本(包从 36.8 MB 降到 36.3 MB);
  • 迁移:2.2.9 的目录副本条目换成 npm spec(options / off 保留);用户自己钉的版本原样保留;2.2.8 及更早的 page-checkin / page-relay-probe 仍整条删除;
  • 代价:首次安装要联网一次。

Clash:无功能改动

版本位跟随统一到 2.3.0,包内容与 2.2.8 一致(mihomo 内核、GeoSite/GeoIP、tun-service 均未改)。

验证

项 结果
magpie.fish-plugin 36,263,931 B,sha256 f0fd7495…456f0;包内无 bundled-plugins,page-seed.mjs 为新实现(8,410 B)
clash.fish-plugin 17,185,169 B,sha256 dc6337f6…797ab6;service/mihomo.exe、GeoSite.dat、GeoIP.dat、tun-service.exe 齐全
单测 plugins/magpie/*.test.mjs 74 pass / 3 skip / 0 fail;tools/build-release.test.mjs 全绿
npm @fish-under-sea/fish-dock-plugin-clash@2.3.0、…-magpie@2.3.0 已发布

已知边界

  • 首装需要联网一次(magpie 的更新循环按 spec 安装);离线环境首启会登记成功但装不上,下一次更新循环重试。

FISH Dock 插件 2.2.9(签到&探针合并 + 破甲内置 + #36)

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 06 Nov 19:30

Magpie 2.2.9

插件版本 2.2.9;magpie.exe 补丁基线 v0.1.3140 + fish.24(文件版本 0.1.3140.24)。
校准:FISH Dock ≥ 2.0.0、宿主 API 1、Windows x64。

本版三件事:两个内置页面插件收成一个(解耦后重新内置)、新增内置破甲、#36 四项进宿主补丁。另有 #37 的日志落盘。

一、签到 + 中转站探针 → 一个插件

  • 新包:@fish-under-sea/magpie-checkin-relay-probe@1.0.0,单独维护在
    Fish-under-sea/magpie-checkin-relay-probe 与 npm 同名包。
  • 形态:一个页面插件、两个页面,页内标签切换(签到 / 中转站探针);侧边栏名称 签到&探针,
    图标沿用签到那套(page/icon.png + page/icon.svg)。
  • 两页的页面代码、图标、样式、各自的测试原样搬入(page/checkin/、page/relay/),
    新增的只有切换壳 page/index.html / app.js / style.css 与转发层 page/relay.js。
  • 为什么是帧:两页都按「整个文档就是我」写(全局 id、各自样式表),同文档必互相踩;
    帧里的 bridge.js 连的是本页,所以 relay.js 把子帧消息换成新 id 转发给 magpie 窗口,
    回程换回原 id,主题/可见性事件广播给两个帧(单测 8 条覆盖)。
  • 升级迁移:plugins.json 里旧的 page-checkin / page-relay-probe(npm 名或旧包内的绝对路径)
    整条删除,新条目按稳定路径写入;用户在这两条上设过的 off 与折叠状态随新条目保留。
    不删旧目录里的任何用户数据。

二、新增内置破甲

  • @fish-under-sea/magpie-purge@0.3.1 随 Magpie 包分发,首启同步到
    <magpie 数据>/plugins/magpie-purge 并以绝对路径登记;页面与网关钩子都从本地目录加载,离线可用。

    0.3.2 在本次发版期间才发布,只改图标与 README;2.2.9 内置的是 0.3.1,下一版同步。

三、#36 入宿主补丁(fish.24)

  1. 重列钩子:插件页的「刷新」现在会让宿主再列一次插件模型
    (plugin.Providers,与供应商编辑器「获取模型」同一条路径),点完 ≤5 秒即可看到
    plugin-providers.json / cache/providers-state.json 的 models 数变化。
  2. 交接防抖:handOver / settle / dropHostProvider 只认「插件自己列出来、且那条
    signedIn == true」;不再在删除时 catalog.SaveLive(..., nil)。providers.json 的
    deleted[] 不再出现「删→建→删」增长。
  3. 分组语义:ModelIDs() 只认模型名(宿主模型平面没有分组维度),口径钉在插件契约上——
    插件只在「该模型所有分组都停用」时才写条目;部分分组停用留在页面自己的明细里。
    新增测试固定这一条。
  4. 旧 options 清理:启动网关时清一次 @fish-under-sea/magpie-neartoken 的
    disabledModels / enabledByGroup / disabledByGroup 三个键;只动这个包,别的插件同名选项不碰。

四、页面宿主支撑(合并件必须)

  • frame-src 放行页面自己目录(此前是 'none');
  • _magpie/bridge.js 在页面目录的任意深度都可取(子帧在 checkin/、relay/ 下);
  • 页面文件补 Access-Control-Allow-Origin: *:sandbox 帧是不透明源,type="module" 脚本以
    Origin: null 取文件,没有这条整个脚本不执行(中转站探针页本来就是 module,之前也受这条影响);
  • 页面响应不再带 frame-ancestors:Chromium 不拿任何源与不透明祖先做匹配,'self'、地址、
    路径源、* 都会把子帧拦成 ERR_BLOCKED_BY_RESPONSE。页面 URL 自带 32 位一次性 token,
    且页面无表单、无导航、无网络,风险面收在这里。

五、#37 日志落盘

  • 适配层把 magpie.exe 的 stdout/stderr 同时写 <插件数据目录>/magpie.log:
    单文件 1 MB 滚动、保留 .1 一份,每次启动先落一行分隔(时间、端口、网关端口)。
  • gateway-error.log 保持原样(只记启动失败 JSON);host/plugin-logs/fish.magpie.log 仍是适配层自己的输出。

六、验证

项 结果
go test ./internal/neartoken ok
go test ./internal/plugin -run 'TestDropLegacyOptions' ok(TestLoadConcurrentWithSavesAndEdits 在本机 Windows 沙箱恒失败,清洗基线同样失败,属环境)
node --test plugins/magpie/*.test.mjs 76 项 / 73 pass / 3 skip / 0 fail
合并插件自测(test/ + page/relay/app.test.mjs) 34 项全绿
真窗口(Edge headless,真 magpie) 侧边栏「签到&探针」,两页切换均渲染;签到读到台账、探针读到 relay:view 配置
包内实物 service/magpie.exe 82,618,880 B;plugins/magpie/bundled-plugins/{magpie-checkin-relay-probe,magpie-purge} 齐全;无 page-plugins 残留
包摘要 magpie.fish-plugin 36,817,191 B,sha256 f8f45bfe…a619a

七、已知边界

  • frame-ancestors 取消是为内嵌帧让路的取舍,见第四节;如果以后要恢复,得让 magpie 的窗口
    以非 sandbox 方式托管插件页,那会打开更危险的口子(同源可读 /api)。
  • 分组的「部分停用」仍不会反映到 magpie 模型清单;这是宿主模型平面没有分组维度的直接结果,
    不是本版的遗漏。

FISH Dock 插件 2.2.8(修 Magpie 启动失败 + Clash 不动绕过表)

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 06 Nov 15:38

FISH Dock 插件 2.2.8(Magpie + Clash)

Magpie 2.2.8 —— 修好「准备 Magpie 资料目录失败」

2.2.7 引入的回归:runtime.mjs 用了 normalizePageTitles 但没有 import,于是
启动时的资料准备整段抛 ReferenceError,被外层 catch 成 DATA_MIGRATION_FAILED ——
就是 Dock 上那句「准备 Magpie 资料目录失败,原资料已保留」。2.2.7 在任何机器上都起不来,
升级到 2.2.8 即恢复。

顺带两处配套修正:

  • 目录指纹把 package.json 按「规范化后的文本」计算,避免每次启动都判定内容变了、
    重复发布整套页面目录;
  • 标题归一化保持幂等(第二遍改动为 0)。

沙箱用你的真实数据副本实测:@Fish-under-sea/签到 → 签到,包名仍是
@fish-under-sea/page-checkin,第二次归一化改动 0,目录指纹稳定。

Clash 2.2.8 —— 不再动别人的绕过表和地址

对照 Clash Verge 的做法,我们之前有两处越界:

  1. 写死了 ProxyOverride='<local>':Verge 和用户自己的绕过表
    (localhost;127.*;10.*;172.16.*…;<local>)会被我们覆盖掉——这就是「本机配置坏了」。
    现在只接管 ProxyEnable 与 ProxyServer,ProxyOverride 原样沿用当前值。
  2. 停止后地址还挂着我们的端口:开关虽然关了,但只看 ProxyServer 不看 ProxyEnable
    的程序(不少 Electron / Node 工具如此)会一直走死端口。现在开关已关、地址指向我们的
    端口时,把地址一并清空。

并保留上一版的两条兜底:内核一停就收 TUN;没有租约但注册表还指着我们端口时关开关。

校验

  • plugins/clash 65 项测试全过
  • page-seed 16 项(1 条已知 flaky 并发用例)通过;标题归一化与指纹稳定性实测通过
  • 两个包 verify-release 均通过

摘要

47427c60eb8a6f573f88ef034092dd3d28084fe5f76e9dd2b576135ab6a86115  magpie.fish-plugin
56366e08e093dd66fbdf3cee0c5b95805e8f02e8cb71b434c4aa4a202ca446db  clash.fish-plugin

FISH Dock 插件 2.2.7(侧边栏只留文字 + 内核停即收 TUN)

Choose a tag to compare

@Fish-under-sea Fish-under-sea released this 06 Nov 13:46

FISH Dock 插件 2.2.7(Magpie + Clash)

Magpie 2.2.7 —— 侧边栏只显示文字

侧边栏条目原来写着 @Fish-under-sea/签到、@Fish-under-sea/中转站探针。npm 包名
(@fish-under-sea/page-checkin / page-relay-probe)保持不变,但标题里的 scope 只是
噪声。现在启动时做一次幂等归一化:

  • magpie.page.title 与 magpie.page.titles.* 里以 @用户/ 开头的标题 → 去掉前缀,
    只剩「签到」「中转站探针」;
  • 没有前缀的标题一个字都不碰;去掉后为空则保留原样;
  • 包名、版本、其余字段全部不动,第二遍不会再写盘。

Clash 2.2.7 —— 内核一停就把 TUN 收掉

之前的停止路径只在「TUN 服务托管」时才收 TUN。如果上一次会话留了 enabled=1 的 TUN
服务,而这一次是普通模式,内核一停就变成有虚拟网卡、没有内核:所有流量打进死内核,
表现就是「偶发掉线、网络回环、整机没网」。

现在:

  1. 内核进程自己退出(崩溃 / 被杀 / 手动结束)→ 立刻检查 TUN,enabled 就 disable;
  2. stop() 的 tunStop 不再要求 viaService,只要服务还 enabled 就收;
  3. 系统代理同上一版一样:没有租约但注册表还指着我们的混合端口 → 直接关开关。

关于「环境变量代理」

排查时发现当前会话里有 HTTP_PROXY=http://127.0.0.1:7895(HTTPS_PROXY 同),而
用户级/机器级环境变量都是空的——它来自父进程继承,插件改不到。内核一停,所有继承
这个变量的程序(模型请求、git、npm)都会打进死端口。自查与清理:

"$env:HTTP_PROXY / $env:HTTPS_PROXY"                                  # 当前会话
[Environment]::GetEnvironmentVariable('HTTP_PROXY','User')            # 用户级
netsh winhttp show proxy                                              # WinHTTP(另一套)

自己启动 Dock 的那个进程(终端 / 启动器)里清掉再启动即可;插件不会、也不该去改
全局环境变量。

校验

  • plugins/magpie 全部用例通过(新增标题归一化 1 条,含幂等断言)
  • plugins/clash 142 通过 / 3 跳过 / 0 失败
  • 两个包 verify-release 均通过

摘要

e9bf3ced587b9880387319ce5ebcf0e1793e4a5c254314a026b52a16f99d7ab7  magpie.fish-plugin
96340e97b7ab920cef10c2d9b3cfbdbbb3ef150887f1c65fef838736ec8493fb  clash.fish-plugin