# Qoder Global QMind CLI

[English](./README.md)

面向 Qoder Global 的 QMind 命令行工具，可用于登录、管理知识库和来源、检索内容、运行 RAG 与任务工作流，以及把本地目录同步到知识库。

npm 包：`@qoder-ai/qmind-cli` · 命令：`qmind`

## 安装

需要 Node.js `>=22.19.0`。

```sh
npm install --global @qoder-ai/qmind-cli
qmind version
qmind --help
```

升级和卸载交给 npm。`qmind self-update` 只提示 npm 升级命令，不会修改 npm 管理的文件。

```sh
npm update --global @qoder-ai/qmind-cli
npm uninstall --global @qoder-ai/qmind-cli
```

Native standalone CLI 改为使用经过验证的 Global release channel。由官方 installer 管理的 Native
可执行文件无需 Node.js 或 npm 即可检查并安装最新版本：

```sh
qmind update --check
qmind update
```

`self-update` 保留为 `update` 的别名。updater 会拒绝 channel/URL 覆盖、降级、非 installer
管理的可执行文件、release 校验和冲突及被修改的 installer。Windows 会在当前进程退出后执行替换，
并在可执行文件旁记录结果。

## 快速开始

```sh
qmind login
qmind notebook list
qmind source list --nb <notebook-id>
qmind retrieve --nb <notebook-id> "发布前要检查什么？"
```

交互式登录会打开浏览器并把登录态保存到本机文件 vault。CI 或 Agent 场景建议使用环境变量和结构化输出：

```sh
export QMIND_TOKEN='<token>'
qmind notebook list --non-interactive --format json
qmind retrieve --nb <notebook-id> --format agent "部署流程是什么？"
```

不要把 token 写进命令参数、仓库或日志。使用完本机凭证后执行 `qmind logout`。

## 命令

| 命令                     | 用途                             |
| ------------------------ | -------------------------------- |
| `login` / `logout`       | 登录或清除本机凭证               |
| `notebook`               | 管理知识库                       |
| `source`                 | 管理知识库来源                   |
| `retrieve`               | 检索上下文，不发起 LLM 调用      |
| `rag`                    | 基于知识库提问                   |
| `task`                   | 管理任务运行                     |
| `scheduled-task`         | 管理知识库定时任务配置           |
| `upload-folder` / `sync` | 同步本地目录                     |
| `image`                  | 获取图片上传地址或访问地址       |
| `version`                | 查看版本和构建信息               |
| `update` / `self-update` | 更新 installer 管理的 Native CLI |

`task create` 不会启动 `compilation` 或 `lint` 运行；仍可通过 `task list` 和 `task get` 查询这些场景的历史运行。`source import-site` 不提供自动编译选项。

使用 `qmind <command> --help` 查看完整参数。领域命令支持 `table`、`json`、`agent`、`ndjson` 等输出格式。stdout 只输出结果，进度与诊断信息输出到 stderr。退出码 `0` 表示成功，`1` 表示运行失败、部分成功或取消，`2` 表示参数错误。

## 多库检索

`retrieve --nb` 支持逗号分隔或重复传入 Notebook ID，去重后最多选择 5 个知识库：

```sh
qmind retrieve --nb nb-1,nb-2 "部署流程是什么？" --format json
qmind retrieve --nb nb-1 --nb nb-2 "部署流程是什么？" --format agent
```

- 必须显式选择知识库，不会默认枚举所有可访问库。
- 多库检索只发送一次统一请求，由服务端联合召回并重排 Source chunks；输出保留服务端排序，以及每条 chunk/citation 的 `notebookId` 和 `notebookTitle`。
- `--top-k` 控制每路、每个查询变体、每种召回通道的联合候选预算，不按知识库数量相乘；`--max-results` 限制全部选中库的最终结果总数。零值使用服务端默认配置。
- `--sources` 仅支持单库。去重后只有一个库时，保留原单库检索接口和输出，包括知识卡片及原有兜底行为。
- 多库 JSON 返回 `{ chunks, citations, promptContext, total, reranked }`；NDJSON 按服务端顺序逐条输出 `kind: "chunk"` 记录，零命中时不输出记录。table 和 agent 格式也会标明证据所属知识库。
- 目标无效或无权限时，统一请求整体失败。CLI 输出错误，不逐库重试或构造部分成功结果。多库检索不返回知识卡片。

## 同步目录

先审阅计划，再决定是否执行远端删除：

```sh
qmind upload-folder --nb <notebook-id> --dir ./docs --mode if-changed --dry-run
```

移除 `--dry-run` 后才会写入远端。`--delete` 会把远端来源根目录视为本地目录镜像，并删除多余项。并发范围为 `1..10`。

## 配置与认证

本包固定为 Qoder Global 产品身份。不能通过改名、安装路径或产品选择环境变量切换产品。默认使用正式环境；`--env test` 和 `--env daily` 选择受支持的调试环境。自定义目标必须同时提供 `--sash` 与 `--dashboard`，且不能与显式 `--env` 组合。

```sh
qmind login --env test
QMIND_DEBUG_TOKEN='<debug-token>' qmind notebook list --env test --non-interactive --format json
qmind login --sash http://localhost:8080 --dashboard http://localhost:3000
```

正式环境 Token 优先级为 `--token > QMIND_TOKEN > 当前正式 vault`；调试环境为 `--token > QMIND_DEBUG_TOKEN > 当前调试 vault`，不会跨目标借用凭证。

状态保存在 `<状态根>/cli/global/<目标>/`，状态根为 `QMIND_HOME` 或 `~/.qmind`。CLI 不安装、加载或访问 OS Keyring。凭证文件是明文 JSON，不是加密存储。POSIX 平台分区目录为 `0700`、文件为 `0600`；这些 mode 不代表 Windows ACL。写入使用原子替换、文件锁及 refresh compare-and-swap 保护。

从旧版未分区存储升级后需要重新登录。旧根目录 config/credentials、`~/.qmind-env` 和旧 Keyring 项不会被读取、导入或自动删除。

共享 3.x Global/CN 发行版相对 Global 2.x 是 breaking upgrade。通过 npm 升级本包后执行 `qmind login`，不要把旧凭证复制到新分区。共同发行版之前的历史版本只描述 Global/共享实现，不代表 CN 曾经发布。

常用变量包括 `QMIND_TOKEN`、`QMIND_DEBUG_TOKEN`、`QMIND_HOME`、`QMIND_CLIENT`、`QMIND_NON_INTERACTIVE`、`QMIND_REQUEST_TIMEOUT_MS`、`QMIND_STREAM_IDLE_TIMEOUT_MS` 和 `QMIND_TLS_CA_FILE`。支持 `HTTP_PROXY`、`HTTPS_PROXY` 和 `NO_PROXY`。TLS 默认严格校验，访问签名对象存储地址时不会转发凭证。

## 共享知识库发现与权限

```sh
qmind notebook list --shared --page 1 --page-size 20
qmind notebook list --shared --format json
qmind notebook get <notebook-id> --format json
```

普通列表和共享列表均支持 `--page`、`--page-size`；`--shared` 不可与 `--filter-client` 组合。共享列表使用与普通列表一致的扁平 `notebooks` 输出，并保留共享关系的 `permission`。JSON/NDJSON 保留服务端返回的 `access`（当前角色、成员数及各操作权限）；Agent 输出展开这些字段，表格列表显示角色与成员数，详情显示操作权限。缺失的权限不进行推断，表格显示 `unknown`。

## 与 Agent 工具一致的命令

复用 Core 的 workflow（`notebook discover`、`source import-url/read/delete-batch`、`mkdir --derive-path`、`mv --to/--to-root`、统一检索和 `scheduled-task`）在进入 Agent Core 后返回 `{ ok, data/error, meta }`，其中 `meta.operationId` 标识本次操作。`--format ndjson` 每次操作输出一行完整结果；`table` 和 `agent` 也使用这个 JSON 结果。进入 Core 前的 CLI 参数校验、Host/凭据错误沿用原 CLI 错误格式：JSON/NDJSON 向 stdout 输出 `{ error }`，其他格式向 stderr 输出文本。命令用法错误和取消确认写入 stderr。`source list --parent` 保留原 Source 列表输出。成功退出 0，部分成功/运行失败/取消退出 1，参数错误退出 2。写入成功不表示 Source 已完成解析或调度任务已执行。

```sh
# 从可检索的自有/共享库中选库；有 hasMore 时继续使用 nextCursor
qmind notebook discover --relationship all --page-size 20
qmind notebook discover --relationship all --cursor '<nextCursor>'

# 普通单页导入；上传后用 source get / source read 查看状态和正文
qmind source import-url --nb <notebook-id> --url https://example.com/guide
qmind source list --nb <notebook-id> --parent <directory-id>
qmind source read <source-id> --nb <notebook-id> --offset 0 --max-chars 20000

# 按真实目录推导路径，移动时保留原始 basename
qmind source mkdir --nb <notebook-id> --title guides --parent <directory-id> --derive-path
qmind source mv <source-id> --nb <notebook-id> --to <directory-id>
qmind source mv <source-id> --nb <notebook-id> --to-root

# 1..100 个不同 ID；交互确认或显式 --force 后执行
qmind source delete-batch <source-id-1> <source-id-2> --nb <notebook-id> --force
```

`notebook list/get` 的 JSON/NDJSON 保留服务端 overview、sourceCount 和 materialCount；Agent 输出展开 summary/topics，表格列表增加摘要与 Source 数量。`discover` 支持 owned/shared/all 和游标，默认 all，只返回检索可用库；管理清单仍用 `list`。空页也可能 `hasMore:true`，不要直接判断已结束，续页须保持 relationship。

`source read` 先检查解析状态，返回 `content/contentType/truncated/nextOffset`。它仍取回全文再切片，只限制输出大小。原 `source content` 的全文输出/下载不变。`source list --parent` 不能与 `--all` 组合。

`mkdir --derive-path` 不能与 `--path` 组合；`mv --to/--to-root` 不能与旧 parent/path/rename/status 参数组合，仅移动当前库内可操作的叶子文档，保留原 basename。原来的低层 mkdir/mv patch 入口仍可使用。

批删返回提交的 sourceIds 和 successCount/failureCount，sourceIds 不是成功 ID 清单。部分失败退出 1，不能猜测失败对象或重放整批；先重新查询对账。

## 精确与统一检索

旧的 `retrieve --nb` 默认行为和输出形状保持不变。显式 `--unified` 或 `--targets` 使用与 Agent 工具一致的统一检索，单库也返回携带 Notebook 身份的 chunks：

```sh
qmind retrieve --nb <notebook-id> --unified --score-threshold 0.6 '部署流程'
qmind retrieve --targets '[{"notebookId":"nb-1","sourceIds":["source-1"]},{"notebookId":"nb-2","sourceIds":["source-2"]}]' --max-results 8 '部署流程'
```

`--targets` 不能与 `--nb` 或 `--sources` 组合，每库可独立过滤 Source。统一检索默认 maxResults=8（1..50），topK 可选（1..100），0 表示使用该 workflow 的默认值；最多五个唯一目标。结果采用上述结构化 envelope，读取 `data.chunks/data.promptContext`；`--score-threshold` 范围为 0..1，旧检索入口也支持。旧路径的零预算继续使用服务端默认值，不隐式切换旧脚本。

## 定时任务配置

```sh
qmind scheduled-task create --nb <notebook-id> --scene source_refresh --schedule 'CRON_TZ=Asia/Shanghai 0 9 * * *'
qmind scheduled-task list --nb <notebook-id> --enabled true --page 1 --page-size 20
qmind scheduled-task update <task-id> --nb <notebook-id> --schedule 'CRON_TZ=Asia/Shanghai 0 10 * * *'
qmind scheduled-task pause <task-id> --nb <notebook-id>
qmind scheduled-task resume <task-id> --nb <notebook-id>
qmind scheduled-task delete <task-id> --nb <notebook-id>
```

`update --enabled false/true` 等价于暂停/恢复。创建默认启用、config 固定为空，不能提交任意 prompt/config；更新仅支持时间或 enabled。scene 为 compilation、condensation、lint、source_refresh、source_binding_sync，实际可用性和完整 Cron 语法由服务端裁决。必须显式提供 IANA 时区，不能依赖本机时区。compilation 可能已退役；source_binding_sync 当前是单库单例且间隔至少五分钟。`list` 可用 `--task/--scene/--enabled` 过滤，pageSize 最大 20；底层仍读取本库全量配置。过大的 config 会显示 `configTruncated:true`。

定时配置与执行记录分开：`task list --scheduled-task <task-id>` 查看执行记录。暂停/删除不取消已派发任务；恢复过期任务可能立即触发一次。调度沿用最初创建者身份，成员撤权不保证自动停任务。

## 写入结果不确定

新命令返回 `error.code=outcome_unknown`、`retryable:false` 时，先查询当前状态再决定后续操作，不能自动重试。旧直接写入命令在 JSON/NDJSON 错误中也区分该状态并保留原 causeCode/requestId。未知结果不证明请求已到达服务器；同名资源也不能证明是本次创建。

`notebook delete` 和 `source delete` 支持 JSON/NDJSON 成功回执。单 Source 删除的预读失败会停止，只有显式 `--force` 才跳过目录确认；原默认文本成功输出保持 `deleted`。
