b6bbff19e9
fix(packaging): 包内 unit 指向 /usr/bin;core-dist 支持无 nfpm 打包
...
两个都是发布链上的真缺陷,构建 v3.0.0 产物时才暴露:
1. **unit 与包内二进制路径不一致**:deb/rpm 把二进制装到 `/usr/bin/modelrouter`,
而 `modelrouter.service` 的 `ExecStart` 写 `/usr/local/bin/modelrouter`。
装包后 `systemctl start` 只会给 203/EXEC,看起来像"装好了但起不来"。
- 包内 unit 改 `/usr/bin/modelrouter`(FHS,装包即用)
- 源码部署仍用 `/usr/local/bin`,`deploy.sh` 增加校验:unit 的 ExecStart
指向不存在的文件时**中止**并说明两种布局的区别
- docs/deployment.md 同步说明
2. **core-dist 硬依赖 nfpm**:构建机离线(GOPROXY 不可达)时装不上 nfpm,
发布直接被堵死。现在 nfpm 优先,缺失时回退 dpkg-deb + rpmbuild,
两者产出同一套文件布局,并继续由末尾的 archive-content 门禁校验。
- rpm 回退踩到的坑:postinst/prerm 末尾无换行时,`%preun` 会粘在
`exit 0` 后面,整个 `%files` 段被吞,rpmbuild 报
"Installed (but unpackaged) file(s) found"。
- `%dir /etc/modelrouter` 要求 buildroot 里存在该目录,否则
"Directory not found"。
验证:`./packaging/core-dist.sh 3.0.0` 产出 deb(4220KB)/rpm(4229KB)/tar(4145KB);
包内 unit `ExecStart=/usr/bin/modelrouter`,`systemd-analyze verify --root` 通过;
deb/rpm 均不含 `plugins/`,adapters=14。
2026-10-27 00:32:14 +08:00
688dce88d1
refactor(rename)!: llmsproxy → modelrouter(module / 二进制 / 路径 / env)
...
产品名早已是 ModelRouter,但仓库标识符仍沿用旧名。这次统一,读写两侧都做兼容,
已部署的机器不会因为顺序问题立刻失效。
- go module `llmsproxy` → `modelrouter`;全仓 import 与 `cmd/modelrouter` 同步。
- `Makefile BINARY=modelrouter`;发行包名、systemd unit、/usr/share 资源、
`/usr/local/bin` 目标全部改为 modelrouter。
- 默认配置目录 `/etc/llmsproxy` → `/etc/modelrouter`。**读取侧回退**:插件与
`storeDir` 仍会检查旧路径,所以"先换二进制、后改 unit"不会立即失效。
- 环境变量 `LLMSPROXY_*`(PLUGIN_DIR / XDISPLAY_BASE / ARCH / LIVE_ZEN /
BUILD_DIR)改为 `MODELROUTER_*`;`LLMS_PROXY_MASTER_KEY` →
`MODELROUTER_MASTER_KEY`。旧名在读取侧继续接受。
- 桌面端内嵌核心 `bin/llmsproxy` → `bin/modelrouter`,并保留旧文件名回退,
避免升级到一半的 profile 被判成"core binary missing"。
- 新增 `packaging/migrate-to-modelrouter.sh`:**默认 dry-run**,复制而非移动、
旧目录永不删除、支持 `--rollback`;随 release tar 分发并由 core-dist 校验。
- `deploy.sh` 增加改名保护:发现旧 `/etc/llmsproxy` 而新配置不存在时**中止**,
否则会部署出一个"能启动但没有 key、没有源"的空实例。
- 临时目录前缀 `/tmp/llmsproxy-*` → `/tmp/modelrouter-*`;清理逻辑同时回收两代。
兼容别名(`__llmsproxy_*` 全局、`llmsproxy` SDK 别名、旧路径/旧 env)刻意保留,
它们是升级路径而非遗留;docs/plugins.md 已标注为废弃。
本提交未包含:`adapters/opencodezen.lua`、`adapter_opencodezen_test.go`、
`adapter_opencodezen_live_test.go`(OpenCode UA/免费池的既有改动,另批提交)。
2026-10-26 22:28:08 +08:00
6fe6014d92
chore: 清理 emoji 与修正发布脚本仓库名
...
产品代码统一为纯文本风格(照参考实现),去掉 emoji:billing/quota/usage 插件、
channels 的提示文案、WebUI 文案,以及 go 测试、docs、packaging 脚本中的
注意/OK/FAIL 等符号化写法。第三方目录(vendor、node_modules、.probe)不动。
另:packaging/upload-release.sh 的仓库名改为真实全名
JianFeeeee/ModelRouter → HeNanMU-EEA/ModelRouter(前者是重定向,POST/PUT 不跟随
会 404)。
2026-10-13 13:42:57 +08:00
ba01da937b
fix(packaging): 打包带上计费插件,并修复一个让所有产物校验形同虚设的缺陷
...
发 v1.8.0 时发现包里没有 billing.lua —— 而 v1.8.0 的主打特性就是计费插件,
发布说明明写「随核心发布的示例插件(billing)」。
功能本身没坏:internal/lua/vm.go 用 //go:embed plugins/*.lua 把插件编进二进制,
writeBundledPlugins 在 plugin_dir 不存在时把它写出来。实测确认(用正确格式的
配置):全新 plugin_dir 启动后自动生成 billing.lua 70031 字节,插件正常加载。
所以这是产物内容与发布说明不符,不是功能缺失 —— 运维解包检查时看不到它,
只能等首次启动后才发现。
三处改动:
1) tar.gz 现在带 plugins/。让运维能在安装前读它、改它,而不是启动后才知道。
2) 修复 dpkg-deb 那行。`dpkg-deb -I "$DIST"/llmsproxy_*.deb` 的 glob 展开成三个
.deb(dist 里堆着 1.5.9 / 1.6.0 / 本次产物),dpkg-deb 只认第一个归档,其余
参数被当成 control component 名,退出码 2。脚本是 set -euo pipefail,于是
在这里直接终止 —— 「done」从未打印,我加在后面的产物内容校验从来没有执行过,
真正跑过的只有上面那道 100KB 大小下限。改为取最新的那个 deb。
这个缺陷早于本次改动,是被它暴露出来的。
3) 新增产物内容校验:tar.gz 必须含 llmsproxy / config.example.yaml /
llmsproxy.service / plugins/billing.lua,adapters 至少 10 个 .lua。
大小下限抓不到这个问题 —— 少 70KB 仍然远超 100KB,而首次启动自动 seed 的
行为会在运行时把它藏起来,运维看到插件正常工作就以为包是完整的。
目录按内容而非名字匹配:tar 列出的是 …/adapters/openai.lua,不存在裸
…/adapters 条目,第一版按名字 grep 把完整包判成了坏包。
两个变异验证:去掉 plugins 拷贝 → 「archive is missing plugins/billing.lua」
退出 1;只留 1 个 adapter → 「archive has only 1 adapters」退出 1。
2026-10-02 23:31:29 +08:00
7e33d11d15
fix(packaging): 发行包不再内置可用的 admin key
...
打包时把本地 config.yaml(gitignored,含运维真实密钥)原样复制成
config.example.yaml,而 postinst 在首次安装且 /etc 无配置时又把它
cp 成生产配置 ⇒ 每次安装都得到一个同值的、公开已知的 admin key。
实测该 key(sk-gw-local-0001)在生产上真实有效(/v1/models 返回 200,
而网关监听 0.0.0.0)。
三处修正:
- 新增 packaging/config.example.yaml(受 git 跟踪的净化模板),
gateway_keys 留空、sources 留空,并写明不要填死值。
- core-dist.sh / nfpm.yaml 改为打包该模板,不再碰本地 config.yaml。
- postinst.sh 不再投递示例配置:留空文件会让网关启动但拒绝所有请求
(无门可入)。改为让二进制首启时自行生成随机 admin key 并打印 ——
每次安装都不同,且开箱可用。示例文件仅作为 /usr/share 下的参考保留。
实测首启:生成 sk-gw-838d66a1... 并打印,与旧的共享固定值不同。
2026-09-28 23:27:42 +08:00
ed05cccb72
feat(packaging): core distribution packages (deb + rpm + tar.gz) via nfpm
...
Previously only the Electron GUI had installers; server admins had to build the
core by hand (`make build` -> bare binary). This adds a first-class server
distribution:
- `make core-dist` -> packaging/core-dist.sh -> cmd/build/dist/
llmsproxy_<ver>_amd64.deb (systemd unit + adapters + example config)
llmsproxy-<ver>.x86_64.rpm
llmsproxy-<ver>-linux-amd64.tar.gz
- nfpm config (packaging/nfpm.yaml): binary to /usr/bin, systemd unit with the
measured memory tuning (GOGC=50, MALLOC_ARENA_MAX=2) baked in, Lua adapters to
/usr/share/llmsproxy/adapters, repo's config.yaml as the example.
- postinst seeds /etc/llmsproxy/config.yaml on first install and keeps existing
runtime state across reinstalls; prerm stops the service on removal.
Gotchas handled: nfpm v2 here does not render `{{ .Env.VERSION }}`, so the script
stamps the version into a throwaway config copy; and under `set -o pipefail` the
idiom `strings | grep -q` is broken (grep -q closes the pipe and strings dies on
SIGPIPE -> spurious 141), so the symbol sanity-gate stages strings in a temp file.
README (zh/en) updated: memory figures replaced with production-measured
32-35 MB settled (was 37-42), and the packaging docs now describe core-dist and
the dockerized Windows build.
2026-08-30 10:49:25 +08:00