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 改名同处一个文件,无法文件级拆分,故一并纳入。
49 lines
2.1 KiB
JavaScript
49 lines
2.1 KiB
JavaScript
// Unit tests for desktop plugin-directory configuration (plain node).
|
|
const test = require("node:test");
|
|
const assert = require("node:assert");
|
|
const fs = require("fs");
|
|
const os = require("os");
|
|
const path = require("path");
|
|
const { ensurePluginDirConfigured } = require("./plugin-sync");
|
|
|
|
const tmp = () => fs.mkdtempSync(path.join(os.tmpdir(), "plugin-sync-"));
|
|
|
|
test("back-fills plugin_dir into an existing profile without it", () => {
|
|
const dir = tmp();
|
|
const cfg = path.join(dir, "config.yaml");
|
|
fs.writeFileSync(cfg, "listen: 127.0.0.1:8787\ndefault_model: AUTO\nkeys:\n - key: k\n role: admin\n");
|
|
const plugins = path.join(dir, "plugins");
|
|
assert.equal(ensurePluginDirConfigured(cfg, plugins, null), "added");
|
|
const out = fs.readFileSync(cfg, "utf-8");
|
|
assert.match(out, /^plugin_dir: "/m);
|
|
assert.match(out, /^listen: 127.0.0.1:8787$/m);
|
|
});
|
|
|
|
test("leaves a profile that already sets plugin_dir alone", () => {
|
|
const dir = tmp();
|
|
const cfg = path.join(dir, "config.yaml");
|
|
const orig = 'plugin_dir: "/custom/plugins"\nlisten: ":1"\n';
|
|
fs.writeFileSync(cfg, orig);
|
|
assert.equal(ensurePluginDirConfigured(cfg, "/whatever", null), "present");
|
|
assert.equal(fs.readFileSync(cfg, "utf-8"), orig);
|
|
});
|
|
|
|
test("missing config is not created by the back-fill", () => {
|
|
const dir = tmp();
|
|
const cfg = path.join(dir, "config.yaml");
|
|
assert.equal(ensurePluginDirConfigured(cfg, path.join(dir, "p"), null), "absent");
|
|
assert.equal(fs.existsSync(cfg), false);
|
|
});
|
|
|
|
test("desktop upgrade never modifies operator plugin files", () => {
|
|
const dir = tmp();
|
|
const plugins = path.join(dir, "plugins");
|
|
fs.mkdirSync(plugins, { recursive: true });
|
|
fs.writeFileSync(path.join(plugins, "channels.lua"), "OPERATOR FILE");
|
|
fs.writeFileSync(path.join(plugins, "my-own.lua"), "MINE");
|
|
// There is deliberately no version stamp and no upgrade synchronizer.
|
|
assert.equal(fs.readFileSync(path.join(plugins, "channels.lua"), "utf-8"), "OPERATOR FILE");
|
|
assert.equal(fs.readFileSync(path.join(plugins, "my-own.lua"), "utf-8"), "MINE");
|
|
assert.equal(fs.readdirSync(dir).includes(".plugin-seed-version"), false);
|
|
});
|