Files
qinglong/cli/README.md
T
whyour 801a71d740 feat(cli): cover OpenAPI with a remote npm CLI and internal panel tools (#3074)
* feat(cli): add unified Commander CLI for QingLong 2.x

* fix(cli): publish via npm and address security review feedback

* ci(cli): package npm artifacts and remove evaluation collateral

* test(cli): use a fixed shell fixture for log retention

* refactor(cli): separate remote npm client from panel tools

* feat(cli): cover active panel OpenAPI resources

* docs(cli): unify authentication and skill guidance

* refactor(cli): isolate internal commands and generate Commander help

* refactor(cli): organize remote and internal modules by responsibility

* ci(cli): publish verified npm archives from master

* fix(cli): publish under the whyour npm scope

* ci: use npm trusted publishing for both packages

* docs: introduce the published CLI on the project homepage

* fix(cli): preserve server log truncation and correct login hints

* fix(cli): accept dashboard record request bodies

* fix(cli): preserve stdin for local task execution

* fix(cli): resolve task executables after changing directory

* fix(cli): preserve shell function tasks and sanitize test failures

* fix(cli): preserve shell hook state and resolve workdir after hooks

* fix(cli): preserve cleanup across shared shell task timeouts

* fix(cli): isolate shell control descriptors and reap timed-out descendants
2026-09-25 23:24:41 +08:00

157 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# QingLong 2.x 远程管理 CLI
**简体中文** | [English](README.en.md)
npm 与面板内部入口都叫 `ql`,但使用独立的 Commander 命令树:npm 入口只调用远程 API,内部入口只运行本机工具。使用前确认可执行文件的绝对路径和 `--help`;安装 npm 包不会迁移内置 Shell 命令。
`@whyour/qinglong-cli` 是独立 npm 包,覆盖当前 develop 的有效 OpenAPI,只注册一个 `ql` 命令。它不包含脚本执行器或本机运维实现;`task exec`、`repo/raw`、`reload/update/reset*` 等属于面板内部工具,不随 npm 包分发。开发发布也不属于 CLI 范围。
## 安装与使用
要求 Node >=22.12,推荐 Node 24。Commander 在构建时打包,无额外运行时 npm 依赖,不单独发布 CLI 镜像。
```sh
npm install -g @whyour/qinglong-cli
ql --help
# 临时使用,不覆盖面板已有的 ql
npm exec --package=@whyour/qinglong-cli -- ql --help
```
也可以从源码构建:执行 `npm ci --prefix cli`、`npm run build:cli`,在 cli 目录执行 `npm pack`,然后安装本地 tgz。全局安装会占用 `ql` 名称;已有面板的机器建议使用独立 npm prefix 或直接执行 `node /absolute/path/to/cli/dist/npm/ql.js`。
```sh
ql login --url https://ql.example.com
ql auth status --json
ql task list --search 示例 --page 1 --size 50 --json
ql task get 12 --json
ql task logs 12 --tail 200 --json
ql task run 12 --json
ql task stop 12 --json
ql auth status --scope subscriptions --json
ql subscription list --json
ql subscription get 5 --json
ql subscription run 5 --json
ql subscription stop 5 --json
ql subscription logs 5 --tail 200 --json
ql subscription enable 5 --json
ql subscription disable 5 --json
ql auth logout --json
```
各命令支持 `--help`,`QL_LANG=en` 切换英文帮助;命令和 JSON 字段不随语言变化。`ql task` 中只包含 API 操作,不会把无效命令解释为本机脚本,也不提供独立 `task` npm 入口。
## 全量 OpenAPI 管理
现在还支持任务/订阅创建、修改、删除,应用管理与密钥重置,以及环境变量、配置、脚本、日志、依赖、系统、仪表盘和用户管理。`ql api routes --json` 列出全部 143 条有效路由;3 条已下线文件读取接口不包含在内。新增命令在 [完整双语参考](skills/qinglong-cli/references/openapi.md) 中逐项列出,路由覆盖由 CI 与后端代码核对。
```sh
ql task create --name demo --command 'task demo.js' --schedule '0 0 * * *' --json
ql subscription create --type public-repo --url https://example.com/repo.git --alias demo --schedule-type crontab --schedule '0 0 * * *' --json
ql app create --name agent --scopes crons,subscriptions --show-secrets --json
ql env create --data @envs.json --json
ql api request PUT /open/crons/run --data '[12,13]' --json
```
请求体使用 --data JSON/@file/-,查询使用 --query,上传 --file,下载 --output。新命令支持 --timeout 秒数;旧命令行为保留,完整参数可用 api request。下载不覆盖现有文件,应用密钥默认隐藏,明确加 --show-secrets 才输出。新增资源通常保留原始返回字段,注意环境、配置和会话信息可能敏感。
远程 `ql system ...` 调用面板 API;本机 reload/reset 等仍不在 npm 包中。不要将远程 API 覆盖理解为本机运维重新混入包。
## 认证
受保护的请求均使用 `Authorization: Bearer <token>`,支持以下两种凭据来源:
| 方式 | 提供方式 | 保存与刷新 |
| --- | --- | --- |
| 应用凭据登录 | `ql login --url <面板地址>`,输入 Client ID / Client Secret;自动化通过 `QL_CLIENT_ID`、`QL_CLIENT_SECRET` 注入 | 通过 `/open/auth/token` 换取 token,凭据和 token 保存到本机,过期自动刷新 |
| 直接访问令牌 | 环境中同时设置 `QL_URL`、`QL_ACCESS_TOKEN`,支持有效应用 token 或面板会话 token | 优先于保存的配置,不落盘、不自动刷新 |
### 应用凭据登录
在面板创建专用应用,按需授予 crons、subscriptions、envs 等权限。`login` 与 `auth login` 等价;交互输入 Client ID 和不回显的 Client Secret,密钥不支持命令行参数。
```sh
ql login --url https://ql.example.com
ql auth status --scope crons --json
# 自动化环境事先注入 QL_CLIENT_ID 和 QL_CLIENT_SECRET,再运行同一 login 命令
```
凭据和 token 保存到 `~/.config/qinglong/cli.json`,为当前用户所有的 0600 明文文件。`QL_CLI_CONFIG` 可选择其他配置文件。登录只验证应用凭据,不意味着具备所有资源权限。
### 直接使用访问令牌
在终端或 CI 的凭据配置中注入 `QL_URL` 与 `QL_ACCESS_TOKEN` 后,直接调用命令,无需再执行 login:
```sh
ql auth status --scope apps --json
ql app list --json
```
两个变量必须同时提供给受保护命令;只提供一个会报参数错误。此方式优先于 `QL_CLI_CONFIG` 指定的配置。即使重新执行 login 写入了应用配置,后续请求仍使用环境令牌;切回保存的应用配置时,在自己的终端执行 `unset QL_URL QL_ACCESS_TOKEN`。
应用管理需要 apps 权限或有效的授权面板会话;当前面板 UI 没有列出所有后端 scope,CLI 不自动提权。匿名 `user login` 可在仅设置 QL_URL 时使用 `--data @credentials.json` 或 `--data -` 提交凭据;返回的会话不会自动保存。启用双因素认证时,服务端 420 对应 CLI 退出码 3,随后使用 `user two-factor-login`,请求体包含 username/password/code。不要将凭据写入命令参数或聊天。
### 权限检查、退出与失败
`auth status` 默认检查 crons 读取权限,可用 `--scope subscriptions`、`--scope apps` 等检查对应资源。它只验证代表性读取,不代表所有写操作都获授权。2.x 的 crons scope 同时覆盖读取和执行。
`auth logout` 仅删除本机应用配置,不撤销服务端 token,也不清除父进程中的 QL_ACCESS_TOKEN。令牌模式仍可能继续访问;如需撤销访问,使用面板提供的应用或会话管理。重置应用密钥会使旧应用 token 失效,需要使用新密钥重新 login。
URL 使用面板根地址,可包含代理路径前缀,不附加 `/open`。远程连接要求 HTTPS,回环地址允许 HTTP;不跟随重定向。2.x 应用 token 接口以查询参数传递凭据,代理应避免记录该查询字符串。401/403 不自动重放操作;直接令牌失效时需更换,CLI 不会转而使用保存的应用凭据。
## 输出契约
订阅支持 create/update/delete/list/get/run/stop/logs/enable/disable/status/log-files。`subscription list/get` 保留管理字段投影;run/stop/enable/disable 返回 subscriptionId/action/accepted。创建、修改、删除及通用 API 请求保留服务端响应,可能包含敏感字段;不能将所有变更都解释为 accepted。
命令默认输出缩进 JSON,`--json` 输出单行 JSON;成功写 stdout,错误写 stderr,互不混用。帮助在 `--json` 下也使用 `{code:200,data:{help:"..."}}`。
- `task list`:`{code:200,data:{data:[...tasks],total:123}}`,默认每页 50,最多 200;任务字段保留服务端内容。
- `task get`:`{code:200,data:{id:12,...}}`。
- `task logs`:`{code:200,data:"日志尾部",logStatus:"completed",truncated:true}`。默认 200 行,最多 10000;旧接口若不返回 logStatus,该字段省略。
- `task run/stop`:`{code:200,data:{taskId:12,action:"run",accepted:true}}`。仅表示请求被接受,不表示任务成功完成。
- 错误:`{code:1,message:"..."}`;退出码 1 为 API/网络/配置错误,2 为参数错误,3 为未登录、HTTP/API 401/403 或需要双因素验证;成功退出码 0。
ID 必须为正整数,运行/停止一次操作一个任务。2.x 没有为此提供独立运行 ID 或幂等键,失败响应可能意味着执行结果未知,应先查询状态,禁止盲目重试。CLI 不自动重试 HTTP 请求。
日志是该任务最新日志,可能属于先前运行;`completed` 不代表成功。`--tail` 在客户端截取,不减少服务端读取量或网络传输量。日志与任务字段不自动脱敏,应按需读取并避免向聊天中暴露敏感信息。
## Skill、构建与验证
npm 包附带 `skills/qinglong-cli`,覆盖全部远程命令。复制到所用 Agent 的 skills 目录,并确认使用 npm 远程入口。Skill 不存放凭据,也不替代服务端权限。
源码使用 TypeScript 严格检查和 Commander 解析;共用参数/输出逻辑,分别构建远程入口和面板内部入口。`dist/npm/ql.js` 是可独立运行的远程 bundle,构建依赖图会拒绝引入本机运维模块;npm 文件白名单仅包含该 bundle、source map、许可证、中英文说明和远程 Skill。完整 `dist` 用于面板内部构建,不随 npm 发布。
```sh
npm ci --prefix cli
npm run check:cli
npm run test:cli
node cli/scripts/verify-package.cjs
```
测试覆盖请求格式、认证刷新、输出、错误、禁止自动重试、权限和独立安装。打包验证会离线安装 tgz,并确认唯一入口是 `ql`,本机命令不可调用。
CLI package 工作流在相关 PR、develop/master 推送和手动触发时执行 Node 22.12/24 类型检查、构建及测试。Node 24 上传通过离线安装验证的 `qinglong-cli-<commit>` artifact。两个矩阵任务成功后,master 推送会将这份已验证的 tgz 发布到 npm 的 latest 标签,通过 GitHub Actions OIDC 可信发布,无需 `NPM_TOKEN` Secret。手动运行需选择 master 并勾选 publish;PR、develop 和 fork 不发布。npm 的 Trusted Publisher 需绑定仓库 `whyour/qinglong` 和工作流 `cli-package.yml`,允许 `npm publish`;面板包 `@whyour/qinglong` 单独绑定 `build-docker-image.yml`。发布 job 使用 Node 24,并仅在该 job 授予 `id-token: write`。新包需先完成首次发布,再配置对应包的可信发布关系。
CLI 版本独立维护在 cli/package.json 和 cli/package-lock.json。发布改动前执行 `npm version patch --prefix cli --no-git-tag-version`(也可用 minor/major),提交这两个文件。已发布的版本会提示并跳过;registry 查询失败则停止发布。该流程仅发布 X.Y.Z 稳定版本,不重新构建产物或执行包生命周期脚本。
## 面板内部工具
本机执行、订阅同步和运维随面板源码/构建交付,使用完整内部 `dist` 与独立 `qinglong-local` Skill;源码说明见 `cli/LOCAL.md` 和 `cli/LOCAL.en.md`。npm 包不能用作 `QL_CLI_ROOT`。账号恢复、服务重载必须在实际面板宿主机或容器中执行;Docker 使用 `docker exec` 调用容器内选定入口。
API `task run` 返回请求接受,本机执行器等待脚本结束,二者耗时不能直接对比。Shell 迁移性能应比较相同配置和脚本下的内部 TS 执行器与原 Shell;远程 API 操作没有对应的旧 Shell 管理命令。
## 源码结构
```text
src/
entrypoints/ # 可执行入口组装
remote/ # commands / api / auth
internal/ # commands / execution / subscription / maintenance / runtime / integration
compatibility/ # 旧入口和参数适配
shared/ # cli / i18n / 响应类型与错误
```
shared 不能引用业务模块;remote 与 internal 只能引用各自区域及 shared,集成测试检查这些依赖边界。两套业务注册表分别注入共享 Commander 解析器。
测试按同样的区域分组。仓库根目录 `npm run test:cli` 或 cli/ 下 `npm test` 自动发现标准测试;test/linux 保持为显式执行的容器集成测试。scripts/entrypoints.cjs 保留现有 dist 可执行入口,以及 dist/local/entrypoints.js、cronEntrypoint.js;移动源码不要求修改 QL_CLI_ROOT 或 cron 命令。