Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CLI checks

on:
push:
pull_request:

permissions:
contents: read

concurrency:
group: cli-checks-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: jdx/mise-action@v2
- name: Validate translation catalogs
run: |
python3 scripts/check-i18n.py
python3 scripts/test_i18n_checks.py
- name: Check formatting
run: mise exec -- cargo fmt --all --check
- name: Test CLI and library
run: mise exec -- cargo test --locked
- name: Check lints
run: mise exec -- cargo clippy --locked --all-targets --all-features -- -D warnings
- name: Check packaged locale files
run: |
mise exec -- cargo package --list --locked > package-files.txt
grep -Fx 'locales/en.json' package-files.txt
grep -Fx 'locales/zh-CN.json' package-files.txt
grep -Fx 'README.zh-CN.md' package-files.txt
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ homepage = "https://api.lmm.best"
readme = "README.md"
keywords = ["lmm", "cli", "oauth", "ai"]
categories = ["command-line-utilities"]
include = ["Cargo.toml", "Cargo.lock", "README.md", "LICENSE", "src/**", "tests/**", "docs/**", "NOTICE", "third_party/**", "scripts/*.py"]
include = ["Cargo.toml", "Cargo.lock", "README.md", "README.zh-CN.md", "locales/**", "LICENSE", "src/**", "tests/**", "docs/**", "NOTICE", "third_party/**", "scripts/*.py"]

[lib]
name = "lmm"
Expand Down
176 changes: 65 additions & 111 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,153 +1,107 @@
# lmm

**LMM API · 连接模型与工具,让智能自由流动**
<div align="center">

LMM = **Language Model Mesh**,中文「语言模型网络」。Mesh 表达互联与协作,呼应多模型路由、渠道共享和微服务协作的方向。
# lmm

这是 [TokenNotIncluded/lmm](https://github.com/TokenNotIncluded/lmm) 独立维护的 Rust CLI。crates.io 包名为 `lmm-cli`,可执行文件名为 `lmm`;父仓库通过子模块锁定版本,CLI 的构建和依赖独立管理。
**Language Model Mesh, from your terminal.**

**当前是开发预览,已实现服务商预设查询、只读发现、桌面 OAuth 登录和模型目录读取,不是可完成应用接入的产品版本。**
`setup`、安装、同步、更新、恢复、解除接入、卸载和启动目前会明确返回阻塞原因,
不会以空操作返回成功。没有修改第三方软件或生产服务。
Explore provider presets, inspect local tools, and read your LMM model catalog.

完整产品要求见 [原始需求](docs/requirements.zh-CN.md)。完整需求保留为目标,不因当前实现范围而缩减。
与 Magpie 的功能对照及下一步任务见 [Magpie 对照](docs/magpie-parity.md)。实现使用 Rust,不包装或启动 Magpie,也不依赖 Go 运行时。
[![Rust](https://img.shields.io/badge/Rust-1.88%2B-000000?style=flat-square&logo=rust)](Cargo.toml)
[![CLI](https://img.shields.io/badge/CLI-lmm-2563eb?style=flat-square)](#quick-start)
[![Languages](https://img.shields.io/badge/languages-English%20%7C%20简体中文-0f766e?style=flat-square)](#language)
[![License](https://img.shields.io/badge/license-AGPL--3.0-64748b?style=flat-square)](LICENSE)

## 从 crates.io 安装
**English** · [简体中文](README.zh-CN.md)

```bash
cargo install lmm-cli --version 0.1.0 --locked
lmm --help
```
[Quick start](#quick-start) · [Commands](#commands) · [Usage guide](docs/usage.md) · [Contribute translations](docs/i18n.md)

服务商预设查询是本仓库的新实现,本轮尚未发布;体验这项功能请使用下文的源码构建命令。
</div>

这是开发预览版,功能边界见上文。Cargo 安装需要 Rust 1.88 或更新版本及本机编译工具;
面向无需开发环境用户的二进制安装器尚未提供。
Linux OAuth 功能另需运行中的 Secret Service;Windows/macOS 使用系统凭据库。
---

## 当前可用
## Quick start

- `lmm presets [关键词] [--json]`:查询 56 项内置服务商预设,离线运行,不读取密钥、不访问服务商。
- `lmm catalog [关键词]`:搜索明确项目身份的软件目录,分别说明安装、接入、维护能力。
- `lmm status [软件]`:当前进程 OS/架构、WSL/容器/SSH 线索、PATH 候选文件及显式实例路径检查。
- `lmm doctor [软件] --report`:只读诊断摘要,移除实例和文件路径,不读取配置内容。
- `lmm setup [软件] --dry-run`:生成带阻塞原因的预览;无目标且有终端时可选择软件。
- `--json`:结构化结果;自动禁用交互。`--non-interactive` 同样禁止等待输入。
- `lmm login`:桌面浏览器 PKCE 登录;凭据保存于系统凭据库。
- `lmm models [--json]`:获取当前授权模型及价格,不调用模型、不切换配置。
- `lmm logout`:撤销当前 issuer 下的 CLI 令牌族,成功后删除本地凭据;不影响 Pi/DSH 等其他应用。
Build the current source with the tools pinned in `mise.toml`:

## 服务商预设
```sh
git clone https://github.com/TokenNotIncluded/lmm.git
cd lmm
mise install
mise exec -- cargo install --path . --locked

```bash
lmm presets
lmm --help
lmm presets deepseek --json
lmm catalog
```

预设来自 [Magpie 的固定版本](https://github.com/yetone/magpie/blob/d5cae267a727e23f4b6e2b28aa107ecdeac5aa9c/internal/provider/presets.go),是服务商地址及相关元数据的静态目录。它不是已经配置的服务商列表,不代表当前账号有权限或额度,也不代表已完成服务商接入、模型发现或调用验证。端点和模型信息可能随服务商变化,不能作为实时承诺。
The Cargo package is **`lmm-cli`**; the executable is **`lmm`**. This repository builds independently of the LMM backend. Source builds require Rust and native build tools. Linux OAuth also needs a running Secret Service.

`presets` 查询服务商预设,`catalog` 查询软件目录,`models` 读取 LMM 账号的授权模型;三者分别表示不同内容。
## Commands

## 登录与模型目录
| Task | Command | What it does |
| --- | --- | --- |
| Explore providers | `lmm presets [query]` | Search the bundled Magpie snapshot, offline |
| Explore software | `lmm catalog [query]` | Search project identities and software descriptions |
| Inspect a tool | `lmm status astrbot --instance /absolute/path` | Check local path evidence without reading configuration contents |
| Share diagnostics | `lmm doctor astrbot --report --json` | Remove local paths from an incomplete diagnostic report |
| Read account models | `lmm login` → `lmm models --json` | Authorize the CLI, then read models and prices without model calls |
| Preview integration | `lmm setup astrbot --dry-run --json` | Show a blocked plan; do not change software or configuration |

```bash
lmm login
lmm models --json
lmm logout
# 自托管必须明确指定可信的 HTTPS origin,三个命令使用同一 issuer
lmm login --issuer https://lmm.example.com --no-browser
```
**Development preview.** Software installation, integration writes, sync, updates, restore, disconnection, removal, and launch are not implemented. These commands report blockers instead of claiming success. Catalog entries are not compatibility guarantees.

服务端需要注册 `lmm` 客户端并启用已有 OAuth 服务。使用前应确认目标服务支持这些接口,并验证实际账号的浏览器登录流程。
CLI 只申请 `catalog:read balance:read` 和同意页显示的分组快照;没有 `models:invoke`、
MCP 或账号管理权限。CLI 登录成功不代表 AstrBot 或 CC Switch 已授权。
`presets` lists bundled provider metadata. `catalog` lists software. `models` reads models authorized for your account. These are separate resources.

浏览器回调只监听 `127.0.0.1` 随机端口,等待默认 180 秒,可用 `--timeout 10..600` 调整。
`--no-browser` 仅关闭自动打开浏览器,**不是设备码登录**:浏览器仍须能访问本机回环端口。
无图形服务器跨设备授权尚未实现;非交互 `login` 直接返回,不暗中等待授权。
切换账号先 `logout` 再 `login`;已有 CLI 登录不会被新登录静默覆盖。
## Language

Windows 使用 Credential Manager,macOS 使用 Keychain,Linux 使用 Secret Service。
凭据库可能显示系统解锁提示;不可用时明确报错,不使用明文文件后备。
因此认证命令暂不支持 `--non-interactive`,会在访问凭据库之前退出;`models --json` 只禁用 CLI 文本交互,系统仍可能要求解锁。
源码构建将 Linux D-Bus 库静态编入,
运行时仍需要可用的 Secret Service;不能将开发机单测当作三个系统的实际凭据库验收。
English and Simplified Chinese are bundled in the binary. No translation download or extra runtime files are needed.

认证操作使用当前用户状态目录中的无密钥 `oauth.lock`,防止并发登录/刷新/退出。
Linux 为 `$XDG_STATE_HOME/lmm` 或 `~/.local/state/lmm`,macOS 为
`~/Library/Application Support/lmm`,Windows 为 `%LOCALAPPDATA%/lmm`。
Unix 目录/锁文件新建权限分别为 0700/0600;已有不安全目录会被拒绝。
刷新前将“不可重试”状态存入凭据库,响应丢失或保存失败后不会自动重放旧 refresh token。
此时需要退出再登录;退出撤销失败保留本地记录供重试,不能报告已完成。
```sh
lmm --lang en --help
lmm status astrbot --lang zh-CN
LMM_LANG=zh-CN lmm catalog
```

模型目录只表示账号可见范围,不表示某个软件已经兼容。未知价格保留 null,
价格包含服务端返回的倍率,不重复计算;本命令不执行付费测试。
Selection order: **`--lang` → `LMM_LANG` → `LC_ALL` → `LC_MESSAGES` → `LANG` → English**.

## 本地软件检查
Environment values such as `zh_CN.UTF-8` and `zh-Hans` are recognized. Empty values are ignored. Unsupported languages fall back to English. `LC_ALL=C` selects English unless overridden by `LMM_LANG` or `--lang`.

显式实例目前只接受 AstrBot 部署根目录、CC Switch 配置根目录:
JSON field names, status values, identifiers, prices, and timestamps do not change with language. Human-readable descriptions and messages do. Original provider names and upstream data are preserved.

```bash
lmm status astrbot --instance /absolute/path/to/AstrBot
lmm status cc-switch --instance /absolute/path/to/.cc-switch
lmm doctor astrbot --instance /absolute/path/to/AstrBot --report --json
lmm setup astrbot --dry-run --json
```
## Login

Windows 使用当前 Windows 环境的绝对路径。AstrBot 只检查所选根目录的
`data/cmd_config.json` 路径;CC Switch 检查 `cc-switch.db` 路径,不打开数据库。
不自动搜索项目、其他用户、Docker 实例、局域网或远程机器。
PATH 文件可能是包装脚本或来自其他环境,因此只标为线索;不执行 `--version`。
符号链接和不可访问项显示 `unknown`,文件缺失只描述被检查的那个位置。
```sh
lmm login
lmm models --json
lmm logout
```

目前所有软件目录条目的兼容版本/平台/场景列表为空,均未验证。
配置管理者、授权状态、实际服务商、模型及真实调用路径不会凭路径推断。
`status` 的退出码 0 只表示完成线索查询,不能用于判断“软件可使用”。
`doctor` 尚不能完成语义检查,会返回 3。`status`、`doctor`、`setup --dry-run` 没有网络调用或付费验证。
Login requests **catalog and balance read access only**. It does not grant model invocation or authorize other applications. Credentials stay in the system credential store; there is no plaintext-file fallback.

`--all` 不把目录视为安装列表;当前没有合格适配器,因此返回空计划与退出码 3。
`--yes` 不能消除能力缺失,不能代表支付、重新授权或切换服务商的同意。
单独 `install` 的计划不要求登录。
A browser must reach the CLI's local callback port. `--no-browser` prints the link but is **not** device-code login. Authentication commands do not support `--non-interactive`; even `models --json` may require the operating system to unlock its credential store.

## 开发
See the [usage guide](docs/usage.md) for trusted self-hosted issuers, callback timeouts, credential storage, and revocation behavior.

从这个独立仓库的根目录执行,工具版本由 `mise.toml` 固定:
## Develop

```bash
mise install
mise exec -- cargo run --locked -- presets deepseek --json
mise exec -- cargo run --locked -- catalog
```sh
python3 scripts/check-i18n.py
python3 scripts/test_i18n_checks.py
mise exec -- cargo fmt --all --check
mise exec -- cargo test --locked
mise exec -- cargo clippy --locked --all-targets --all-features -- -D warnings
mise exec -- cargo fmt --all --check
mise exec -- cargo build --locked --release
```

不需要先构建或启动父仓库中的核心、扩展或 Web 服务。独立 Cargo 工程与后端分开锁定依赖,避免将 CLI 发布绑定到后端构建。
源码开发需要 Rust;面向普通用户的签名二进制、安装器和更新渠道尚待发布,
当前没有声称普通用户已经能“一键安装”。CI 构建产物仅作开发预览,不自动发布。
[Contributor guide](AGENTS.md) · [Translation guide](docs/i18n.md) · [Product requirements (Chinese)](docs/requirements.zh-CN.md) · [Magpie comparison (Chinese)](docs/magpie-parity.md)

## 退出码与安全边界
## Exit codes

| 退出码 | 含义 |
| Code | Meaning |
| --- | --- |
| 0 | 目录/只读查询已输出;请继续检查各层状态 |
| 2 | 参数不完整、目标未知、无法选择目标或输出失败 |
| 3 | 能力未实现、检查未完成或操作被阻止 |

`restore_fields` 是内存中的三方字段恢复算法:仅在字段仍等于 LMM 写入值时撤销,
保留用户后续修改;任一冲突使整个目标的计算失败。它拒绝整对象、数组及数组索引恢复。
它没有连接文件写入、日志、授权或命令执行,不能当作 `lmm restore` 已完成的证据。
同样,付费检查函数只是客户端规划规则,**不能代替服务端消费限制**。

指纹函数只用于有界配置快照的内容比较,不是原子写锁。未来接入必须使用目标软件原生
事务/管理接口解决并发写入;“比较哈希后覆盖文件”不满足完整并发修改验收。

只读环境查询不建立状态目录;OAuth 操作会创建上述锁目录并使用系统凭据库。
LMM 不复制第三方凭据、不上传遥测、不进行付费调用。
分享前建议使用 `doctor --report --json`;普通 `status` 会显示本地路径。
| `0` | A query completed; inspect its reported state before assuming a tool is usable |
| `2` | Invalid or missing arguments, unknown target, selection failure, or output error |
| `3` | Blocked operation, unavailable capability, or incomplete diagnostic check |

## 来源与许可证
## Attribution

项目按 [AGPL-3.0-only](LICENSE) 发布。服务商预设参考 Magpie 的 MIT 许可源码;来源及保留的许可说明见 [NOTICE](NOTICE)。参考预设数据不意味着具备 Magpie 的全部能力。
Licensed under [AGPL-3.0-only](LICENSE). Provider preset data is derived from a pinned, MIT-licensed [Magpie](third_party/magpie/NOTICE.md) snapshot. LMM is implemented in Rust and does not wrap or run Magpie. See [NOTICE](NOTICE) for source attribution.
107 changes: 107 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<div align="center">

# lmm

**在终端使用 Language Model Mesh。**

查询服务商预设、检查本地工具、读取 LMM 模型目录。

[![Rust](https://img.shields.io/badge/Rust-1.88%2B-000000?style=flat-square&logo=rust)](Cargo.toml)
[![CLI](https://img.shields.io/badge/CLI-lmm-2563eb?style=flat-square)](#开始使用)
[![Languages](https://img.shields.io/badge/languages-English%20%7C%20简体中文-0f766e?style=flat-square)](#语言)
[![License](https://img.shields.io/badge/license-AGPL--3.0-64748b?style=flat-square)](LICENSE)

[English](README.md) · **简体中文**

[开始使用](#开始使用) · [命令](#命令) · [使用指南](docs/usage.zh-CN.md) · [贡献翻译](docs/i18n.md)

</div>

---

## 开始使用

使用 `mise.toml` 固定的开发工具,从当前源码构建:

```sh
git clone https://github.com/TokenNotIncluded/lmm.git
cd lmm
mise install
mise exec -- cargo install --path . --locked

lmm --help
lmm presets deepseek --json
lmm catalog
```

Cargo 包名为 **`lmm-cli`**,命令名为 **`lmm`**。本仓库独立构建,不需要先启动 LMM 后端。源码构建需要 Rust 和本机编译工具;Linux 的 OAuth 登录还需要运行中的 Secret Service。

## 命令

| 用途 | 命令 | 实际行为 |
| --- | --- | --- |
| 查询服务商 | `lmm presets [关键词]` | 离线搜索内置 Magpie 预设快照 |
| 查询软件 | `lmm catalog [关键词]` | 搜索项目名称和用途说明 |
| 检查软件 | `lmm status astrbot --instance /绝对路径` | 检查本地路径线索,不读取配置内容 |
| 分享诊断 | `lmm doctor astrbot --report --json` | 输出未完成的诊断摘要,并移除本地路径 |
| 读取账号模型 | `lmm login` → `lmm models --json` | 授权 CLI,再读取模型与价格,不调用模型 |
| 预览接入 | `lmm setup astrbot --dry-run --json` | 列出计划和阻塞原因,不修改软件或配置 |

**当前为开发预览。** 安装、接入写入、同步、更新、恢复、解除接入、卸载和启动尚未实现。这些命令会返回阻塞原因,不会把空操作报告为成功。目录条目不代表软件已经通过兼容性验证。

`presets` 是服务商预设,`catalog` 是软件目录,`models` 是当前账号获准读取的模型。三者不混用。

## 语言

英文和简体中文随程序一起打包,不需要联网下载翻译,也不需要额外放置语言文件。

```sh
lmm --lang en --help
lmm status astrbot --lang zh-CN
LMM_LANG=zh-CN lmm catalog
```

选择顺序:**`--lang` → `LMM_LANG` → `LC_ALL` → `LC_MESSAGES` → `LANG` → 英文**。

环境变量支持 `zh_CN.UTF-8`、`zh-Hans` 等常见写法。空值会被忽略,不支持的语言使用英文。`LC_ALL=C` 使用英文,但可被 `LMM_LANG` 或 `--lang` 覆盖。

JSON 字段名、状态值、标识符、价格和时间戳不随语言改变;面向人的说明和消息会翻译。服务商原名和上游数据保持原样。

## 登录

```sh
lmm login
lmm models --json
lmm logout
```

CLI 只申请**模型目录和余额读取权限**,不申请模型调用权限,也不替其他应用授权。凭据存入系统凭据库,不会退回到明文文件。

浏览器必须能访问 CLI 所在机器的回环端口。`--no-browser` 只显示链接,**不是设备码登录**。认证命令暂不支持 `--non-interactive`;即使使用 `models --json`,系统仍可能要求解锁凭据库。

自托管地址、回调等待时间、凭据保存和撤销行为见[使用指南](docs/usage.zh-CN.md)。

## 开发

```sh
python3 scripts/check-i18n.py
python3 scripts/test_i18n_checks.py
mise exec -- cargo fmt --all --check
mise exec -- cargo test --locked
mise exec -- cargo clippy --locked --all-targets --all-features -- -D warnings
mise exec -- cargo build --locked --release
```

[贡献指南](AGENTS.md) · [翻译指南](docs/i18n.md) · [产品需求](docs/requirements.zh-CN.md) · [Magpie 功能对照](docs/magpie-parity.md)

## 退出码

| 退出码 | 含义 |
| --- | --- |
| `0` | 查询已完成;仍需检查各层状态,不能据此认定软件可用 |
| `2` | 参数不完整或无效、目标未知、选择失败或输出失败 |
| `3` | 操作被阻止、能力未实现或诊断未完成 |

## 来源与许可证

项目使用 [AGPL-3.0-only](LICENSE)。服务商预设来自固定版本的 [Magpie](third_party/magpie/NOTICE.md),保留其 MIT 许可与来源说明。LMM 使用 Rust 实现,不包装或启动 Magpie。详见 [NOTICE](NOTICE)。
Loading
Loading