mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
- 新增唯一公开接口表 `modelrouter`(sdk_version=1.0):http / secrets / kernel / adapters / plugin_dir。成员与内部桥是**同一对象**而非副本 —— 复制会让凭据保险库分叉(插件写 A、内核读 B)。 - `llmsproxy` 与 `__llmsproxy_*` 降为同对象兼容别名,只为已装插件继续可用。 仓库内 4 个插件(channels / billing / quota / usage)全部改用 `modelrouter.*`:此前它们直接依赖内核私有全局,内核无法在不炸插件的前提下 改实现(重命名、加守卫、换实现都算破坏性变更)。 - 插件不再由网关安装:`SeedBundled()` 变彻底 no-op,`core.New` 不再调用; `ReadBundledPlugin` 改为按源文件定位(脱离 cwd),只服务测试与开发工具。 - 桌面端删除 `BUILTIN_PLUGINS` 与 `syncBundledPluginsOnUpgrade`:升级不再 删除、改名或覆盖用户插件文件。插件是运维资产,不是内核资源。 - `Builtin` 不再靠"源码与仓库示例逐字节相同"推断,插件一律视为外部文件。 - 判据:SDK 存在/版本/形状、别名与内部桥同一张表、适配器 VM 拿不到 SDK、 经 SDK 真实写读凭据并驱动内核动作、GUI 升级不动插件文件、release 包不含插件。 说明:channels.lua / quota.lua 同时带有此前的渠道与额度改动(含 OpenCode 免费池 监控),与 SDK 改名同处一个文件,无法文件级拆分,故一并纳入。
34 lines
1.4 KiB
JavaScript
34 lines
1.4 KiB
JavaScript
// Plugin-tree maintenance for the desktop profile (no Electron imports, so this
|
|
// is unit-testable with plain node).
|
|
//
|
|
// The desktop may configure an operator-selected plugin directory, but it never
|
|
// owns the files in that directory. In particular, upgrades must not seed,
|
|
// replace, rename, or delete plugins. Plugin installation is an explicit
|
|
// operator action (or an external package manager action).
|
|
const fs = require("fs");
|
|
|
|
// ensurePluginDirConfigured back-fills `plugin_dir` into an existing config.
|
|
// Appending a top-level YAML key is safe for the shapes this file can have
|
|
// (flat mapping + a keys list). Returns "added" | "present" | "absent" | "error".
|
|
function ensurePluginDirConfigured(configFile, pluginsDir, log) {
|
|
try {
|
|
if (!fs.existsSync(configFile)) return "absent";
|
|
const cur = fs.readFileSync(configFile, "utf-8");
|
|
if (/^\s*plugin_dir\s*:/m.test(cur)) return "present";
|
|
fs.writeFileSync(
|
|
configFile,
|
|
cur.replace(/\s*$/, "") +
|
|
"\n# added by ModelRouter Desktop: enables the operator plugin directory\n" +
|
|
"plugin_dir: " + JSON.stringify(pluginsDir) + "\n",
|
|
"utf-8",
|
|
);
|
|
if (log) log("[gui] plugin_dir back-filled into " + configFile);
|
|
return "added";
|
|
} catch (e) {
|
|
if (log) log("[gui] ensurePluginDirConfigured failed: " + e.message);
|
|
return "error";
|
|
}
|
|
}
|
|
|
|
module.exports = { ensurePluginDirConfigured };
|