# @ganju/cli 中文文档

规范地址：https://npmcn.com/package/%40ganju/cli/

版本：0\.0\.26
npm 元数据更新时间：2026-11-12T19:44:41.376Z
中文译文更新时间：2026-11-15T22:41:00.099Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40ganju/cli
原文对照：https://npmcn.com/package/%40ganju/cli/?lang=original
项目主页：https://ganju.ai/
源码仓库：https://github.com/MontoyaAndres/ganju

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：2.4 MB，9 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- Node.js 要求：\>=20
- 运行依赖：1 个
- 首次发布：2026-08-28T19:21:06.601Z
- 最新版本发布：2026-11-12T19:44:41.024Z
- 近 30 天下载量：2743（2026-10-16 至 2026-11-14，npm 官方下载统计）
- 已发布版本数：24（近 12 个月 24 个）

## 中文简介

从终端写入、部署并调试 Ganju 自定义工具

## 安装

```sh
npm install @ganju/cli
```

也可以使用：`pnpm add @ganju/cli`、`yarn add @ganju/cli`、`bun add @ganju/cli`

## README

# `ganju` - 国家行动倡议

从终端写入、部署并调试自定义工具,并管理工程的 数据库。 这里的一切都是薄的 端点的客户端已经使用; 它中没有任何是第二个写入 路径.

```bash
npm install -g @ganju/cli

ganju init my-tools
cd my-tools
ganju login
ganju link
ganju deploy
```

{\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}从盒子里出来 {\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}这话要说 **`https://api.ganju.ai`**,所以新安装需要 没有配置 。 指别的地方——你自己的例子,或者当地API—— 与 `GANJU_API_URL`。 。 。 .

## 图标

| 命令 | 它会做什么 |
| --- | --- |
| `ganju init [dir]` | 脚手架a `ganju.json` 和部署在现场的操作员 |
| `ganju login` 编号 : `logout` 编号 : `whoami` | 签到这台机器,然后离开 |
| `ganju link` | 点 `ganju.json` 在一个组织和项目中,如果没有,则创建文件(`--status` 读它) |
| `ganju build` | 打开工具, 编译并修改、 写入 `.ganju/bundle.js`报告大小. `--strict` 提示失败 |
| `ganju deploy` | 构建、上传和发布( E)`--draft` 在出版前停下来, `--force` 替换应用程序中制作的活版) |
| `ganju test <tool>` | 在不发布的情况下对一个样本输入运行一个工具 |
| `ganju logs` | 最近打来的电话 `ctx.log` 产出(`--follow` 继续看) |
| `ganju versions` 编号 : `ganju rollback <n>` | 什么存在,哪个是活的,然后回去 |
| `ganju secret set|list|rm` | 价值 `ctx.secret()` 读取 |
| `ganju token create|list|revoke` | CI 的个人访问令牌, 范围为链接项目 |
| `ganju data …` | 该项目的数据库:表格、行、导入、导出、恢复和计划作为代码—— [下级](https://npmcn.com/package/%40ganju/cli/#readme-ganju-data) |

## `ganju data`

项目数据库(Pro and Entertainment),从终端. 每个命令 呼唤 [数据 API](https://ganju.ai/docs/data-api) 路由仪表板使用, 项目 `ganju.json` 链接到 (`ganju link` 在空文件夹中 一个,没有 `ganju init` 因此,此处的文字由 相同的规则和记录方式: `ganju login`, (中文(简体) ), 或作为 `cli:<token id>` 与 `GANJU_API_TOKEN` 设置为个人访问符. A 类 `429` {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}而不是失败 {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}我从一个符号的每分钟限数里 长导入半径.

### 数据库

| 命令 | 它会做什么 |
| --- | --- |
| `ganju data create [--name <name>]` | 制作数据库. `--replace --yes` 开始的时候,删除的仍然可以恢复,放弃它 |
| `ganju data info` | 现状、规模、表格和表格副本 |
| `ganju data index add|dismiss <id>` | 就指数建议采取行动. `info` 列出它们, 并附上它们的ID: 甘珠建议索引一个列, 在读取比它们返回的多很多行时, 经常过滤查询。 它还在写给很多的表格上标出一个在30天内没有使用的索引查询;没有删除任何信息 |
| `ganju data drop --yes --confirm <name>` | 删去,可以休息七天 |
| `ganju data restore` | 撤消删除 |
| `ganju data restore --at <ISO time> --yes` | 把所有东西都放回原样(30天内). 时间需要抵消: `2026-10-30T09:15:00-05:00` 或者说 `…Z` |
| `ganju data restore --bookmark <b> --yes` | 全部放回书签上: 一滴一滴, 类型更改, 导入 `--replace` 或印出检查站 |
| `ganju data checkpoint` | 现在的书签, 独自在Stdout: `B=$(ganju data checkpoint)` |
| `ganju data time-zone [<zone>] [--clear]` | 区约会时间回 助理,职能和任何人 谁不发送,例如. `America/Bogota`没有区域,就打印出来 |
| `ganju data export [--format jsonl|csv] [--out <dir>]` | `schema.json` 和每个表格的一个文件,下载到文件夹中 |
| `ganju data changes` | 计划更改日志:谁改变了什么,何时 |
| `ganju data copy [status|wait|dismiss]` | 表格上超过10万行的字型变化会在背景中复制; 跟着它, 或者清除一个失败的 |

### 表格和栏

| 命令 | 它会做什么 |
| --- | --- |
| `ganju data tables` | 每张表格及其栏目 |
| `ganju data table create <name> --schema <file>` | 文件持有 `{ "columns": [...] }`,或 `ganju.data.json` (使用该名称的表格) |
| `ganju data table rename <name> <new-name>` |  |
| `ganju data table rm <name> --yes --confirm <name>` | 放下枪 打印带回来的书签 |
| `ganju data column add <table> <name> <type> [--input '<json>']` | `--input` 持有其余: `'{"required":true,"min":0}'`, (中文(简体) ), `'{"table":"menu","onDelete":"cascade"}'` |
| `ganju data column rename <table> <name> <new-name>` | 保留每个值 |
| `ganju data column change <table> <name> --input '<json>'` | 任何设置。 一个新的 `type` 或关系 `table` 复制表格和需要 `--yes` |
| `ganju data column rm <table> <name> --yes` | 放下枪 打印带回来的书签 |

复制大表格的更改等待复制并显示其进展; `--no-wait` 把终端拿回来,然后 `ganju data copy wait` 捡起. 当它运行时,表格拒绝其他更改并写到它.

### 行数

| 命令 | 它会做什么 |
| --- | --- |
| `ganju data rows <table>` | 一行一页. `--where`, (中文(简体) ), `--sort -price,name`, (中文(简体) ), `--search <text>`, (中文(简体) ), `--limit` (最多500个), `--cursor`, (中文(简体) ), `--include <relation columns>`, (中文(简体) ), `--all` 每页, `--json` |
| `ganju data get <table> <id>` | 一行,还有它 `version` |
| `ganju data insert <table> --input '<json>' | --input-file rows.jsonl` | 一行,JSON列表或JSONL文件. 最多五千行是一行的,要么全写,要么全写,要么全写,要么全不写 |
| `ganju data update <table> <id> --input '<json>' [--version <n>]` | 数值,或相对变化: `'{"stock":{"decrement":2}}'`与 `--version`,一行更改后被拒绝,显示谁改变了,现在如何 |
| `ganju data delete <table> <id>... [--yes]` | 显示级联会先移除什么, 当限制时拒绝。 多个 ids 一起删除或根本不删除 |
| `ganju data history <table> <id>` | 过去90天的每一个变化,是谁做的 |
| `ganju data write --input-file ops.json` | 多个表格插入、更新和删除,全部或无(`{ "$ref": <step> }` 用于较早插入的 id) |
| `ganju data import <table> <file>` | A 类 `.csv`, (中文(简体) ), `.tsv`, (中文(简体) ), `.json` 或者说 `.jsonl` 文档,分批500份 |

### 命名的查询

A 类 `SELECT` 以命名参数保存一次( e)`:from`),用于报告行 过滤器无法表达. 保存时选中它: 一个声明, 只读 这个数据库的表格。 函数运行它 `ctx.data.run`; 与 `"assistant": true` 频道bots也可以运行它.

| 命令 | 它会做什么 |
| --- | --- |
| `ganju data queries` | 保存的查询、其参数和所读表格 |
| `ganju data query save --input-file sales.json` | `{ "name", "description", "sql", "params": [{ "name": "from", "type": "datetime" }], "assistant" }`。保存现有名称取而代之 |
| `ganju data query rm <name> --yes` | 删除它 |
| `ganju data run <name> [--input '{"from":"2026-10-01T00:00:00-05:00"}'] [--limit 100] [--json]` | 它的行数,最多500行 |

**`--where`** 每个旗帜都有一个条件,每个旗帜必须持有:

| 您输入 | API获得 |
| --- | --- |
| `--where status=open` | `{"status":"open"}` |
| `--where 'price<30000'` (另见: `<=` `>` `>=` `!=`(中文(简体) ) | `{"price":{"lt":30000}}` |
| `--where 'name~pizza'` 编号 : `--where 'name^=Marg'` | `{"name":{"contains":"pizza"}}` 编号 : `{"name":{"startsWith":"Marg"}}` |
| `--where 'status=[open,done]'` 编号 : `--where 'id!=[1,2]'` | `{"status":{"in":["open","done"]}}` 编号 : `{"id":{"notIn":[1,2]}}` |
| `--where note=null` 编号 : `--where note!=null` | `{"note":null}` 编号 : `{"note":{"ne":null}}` |
| `--where phone=3001234567` | `{"phone":"3001234567"}` ——在文本一栏中,数值为已键入文本 |
| `--where 'code="007"'` | `{"code":"007"}` ——引文在任意一栏中保留一个值作为文本 |
| `--where 'price>=10' --where 'price<20'` | `{"price":{"gte":10,"lt":20}}` |
| `--where 'product.name=Margherita'` | 表格中的一列关系点 |
| `--where '{"price":{"lt":30000}}'` | jSON本身,就像 |

文本、长文本、电话、电子邮件、 URL、 enum、 日期或日期时间列、 a 值为已键入的文本(只有) `null` 意思是空的),从表格读取 列类型,通过关系。 其他列,数字, `true`, (中文(简体) ), `false` 财务报告和审定财务报表 `null` 意思是自己,其他东西都是文字。 Raw JSON 作为 写作. 引用你壳壳的完整条件 `<`, (中文(简体) ), `>` 或空间.

**`import`** 使用相同的代码: 按名称或标签与列相匹配(大小写、口音和标出), `--map 'Precio (COP)=price'` 逐个点数`--map 'Notes='` 离开它 数字如 `28.000` 财务报告和审定财务报表 `1.234,5` 与他们的数千人一起阅读 分离器`--decimal-mark . | ,` 当文件模糊不清时),和关系 列与其它表格的显示值相匹配,因此“Margherita”成为其 排的身份证。 在发送任何信息之前检查每个单元格;批次拒绝 一行被分割,直到找到, 所以它只花费自己。 这些行 拒绝,为什么,写给 `<file>.refused.csv` (或 `--out`),准备 修复并再次导入.

`--replace` 将表格的每行换回文件。 这需要 `--yes` 财务报告和审定财务报表 `--confirm <table>`,显示其它位置的行(并停止) 如果限制会挡住它,则先取一个检查站,打印 撤销的书签。 两边最多有五千行,只有一行: 老一行只有每个新一行着陆 当写字被拒绝时,行 在它的后面发现有从未犯罪过的试字 整个文件写入 `<file>.marked.csv` 每一个问题,除了它的 行; 表中没有任何变化 .

电子表格( E)`.xlsx`, (中文(简体) ), `.xls`, (中文(简体) ), `.ods`直接读取:其第一个工作表,或 一个 `--sheet <name>` 名称。 空行被跳过,日期作为 日期.

### 作为代码的Schema : `ganju.data.json`

```bash
ganju data schema pull     # write the database's schema to ganju.data.json
ganju data schema diff     # what push would change
ganju data schema push     # apply it
```

文件为 `{ "tables": [...] }`,每个表格写的方式,你会打它 来创建它——与导出形状相同 `schema.json`,所以无论工作 与 `--schema <file>`。 。 。 . `pull` 之后 `push` 给回同样的文件,所以它 diff in a pull request is a change to the schema and nothing else. 在拉力请求中, diff in a puff request 是一种对策略的改变, 没有什么别的.

`push` 数据库的更改日志中还指出,其表格来自 文档。 仪表板的助手然后警告说,一个表格或一栏的更改 下个会放回去的 `push`。 。 。 .

`diff` 匹配表格和列 **按名称**数字 :

```
+ create table orders (customer, status)
+ add column menu.notes long_text
~ change table menu: label "Menu"
~ change menu.stock: default 5 (copies the table)
- change menu.price: type "decimal" (copies the table) (needs --yes)
- drop column menu.code (needs --yes)
- drop table promos (needs --yes)
```

-   命名的查询进入 `"queries": [...]`,每个 `ganju data query save` 取下它, 并按名字排序 : `+ save query sales_by_dish (:from, :to)`。 。 。 . `pull` 当数据库有时,就写。 没有文件 `queries` 保留数据库的查询; 与此相关, 缺少一个查询 文件被删除, 需要 `--yes`。 。 。 .
-   文件被忽略的密钥表示它们的默认值( E)`access` `read`, (中文(简体) ), `history` 没错, `onDelete` `restrict`,第一个文本栏为 `displayColumn`因此,一个 手写文件短而取出的文件相等.
-   新建表格的顺序, 每个关系的目标都存在 先说 创建两个相互对应的新表格 栏,一旦两者存在,就添加该栏.
-   丢弃的表格按 API 接受的顺序进行: 它拒绝丢弃表格 而其他的点。 每个点的表格一起下降 其他则先失去一个关系栏,这样可以释放其余部分.
-   `push` 应用新表格、新列和已更改的设置. **投放和类型变化** (包括将关系指到另一个表格) 仅与 `--yes`,在一个书签的检查站之后 解除他们。 无 `--yes` 在脚本中,按下其余部分并退出 1 点出它遗漏的东西; 在终端里它会问.
-   重命名的表格或一栏读作下放并添加,其中 `--yes` 将 应用方式为清空旧的。 重命名为 `ganju data table rename` 或者说 `ganju data column rename`,则 `pull`。 。 。 .

### 破坏命令

任何需要删除、删除或重写的数据 `--yes`; 丢弃 数据库或表格,以及 `import --replace`,也需要输入的名称 `--confirm`。在终点站需要一面失踪的旗帜。 没有一个人——CI, a 管子——命令拒绝并改变一无所有,而不是等待一个快取.

## `ganju.json`

```jsonc
{
  "artifact": "acme-support",
  "organizationId": "…", // written by `ganju link`
  "projectId": "…",

  // Row-level, because that is the level they are enforced at: one script per
  // artifact, one set of rules for all of it. They travel with the deploy.
  "connections": ["google-gmail"],
  "allowedHosts": ["api.acme.com"],
  "timeoutMs": 10000,
  "resourceAccess": "own",

  // Upload this folder's readable source beside the bundle (default true).
  "uploadSource": true,

  "tools": [
    {
      "name": "lookup-order",
      "title": "Look up order",
      "description": "Find an order by its id. Use when the customer gives an order number.",
      "entry": "src/lookupOrder.js",
      "input": {
        "type": "object",
        "properties": { "orderId": { "type": "string" } },
        "required": ["orderId"]
      },
      "output": { "type": "object", "properties": { "status": { "type": "string" } } },
      "annotations": { "readOnlyHint": true }
    }
  ]
}
```

`annotations` 这是 [MCP 工具说明](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#tool-annotations), (中文(简体) ), 带有 spec 名称 : `readOnlyHint`, (中文(简体) ), `destructiveHint`, (中文(简体) ), `idempotentHint`, (中文(简体) ), `openWorldHint`。它们能传送到 MCP 客户端作为提示,它们决定频道是什么 bot确认组织何时启动 **确认敏感行动**(单位:千美元) 无法声明的工具 `readOnlyHint: true` 也没有 `destructiveHint: false` 实值 问起它运行之前。 标记只读的外观; 留下任何发送, 收费或删除无标记.

**档案里没有秘密 绝对没有.** `ctx.secret('ACME_KEY')` 在电话时间通过经纪人解决身份证明问题 所以秘密是一回事 您发送一次而不是一个值 承诺在您的源。 使用 `ganju secret set`它从下一个呼叫开始直播,之后没有部署.

### 两个写路由器的方法

给每个工具一个 **`entry`** 路由是从舱中产生 工具名称完全写在一个地方,以及 `lookup-order` 对 `lookupOrder` 不再成为可能发生的事情:

```js
// src/lookupOrder.js
import { defineTool } from '@ganju/sdk';

export default defineTool(async (input, ctx) => {
  const { accessToken } = await ctx.connection('google-gmail');
  return { status: 'shipped' };
});
```

或者给 **无** 其中之一,然后自己写地图, 在文件命名 `main` (默认) `src/index.ts`:

```js
import { createHandler, defineTool } from '@ganju/sdk';

export default createHandler({
  'lookup-order': defineTool(async (input, ctx) => ({ status: 'shipped' }))
});
```

由于这两项决议都遭到拒绝而不是解决 默地放下了作者所写的一半.

## 那栋楼做什么

`esbuild`,捆绑在一个ES模块上——这不是优化而是步骤 因为一个已部署的脚本是一个 单单元。 TypeScript 工作; 类型被剥离, 从未检查, 所以运行 `tsc` 如果你想要强制他们的话.

`@ganju/sdk` 实值 **没有** 捆绑了 重写为 `./ganju-sdk.js`,兄弟们 模块,发布管道附着在每次上传中——所以在 捆绑会是死体重, 和一个版本冷冻到它会从 帮它说话.

上传是 `bundle`,这意味着仪表盘的编辑器显示它只读 而不是邀请某人 覆盖一个真正的建筑与内容 文本框中输入的。 使用仪表板进行代码, 您想在那里编辑 .

### 源头 除了捆绑

`ganju deploy` 上传工程的可读源, 所以仪表板 显示您的真实文件( 仅读) , 而不是已修改的捆绑 。 只不过 显示; 捆绑是运行的 .

-   **哪些文件 :** 意味着跟踪文件加上未跟踪文件 你们的 `.gitignore` 这并不排斥。 在Git仓库外 `.gitignore` 项目中的文件直接被读取.
-   **从未上传 :** `node_modules`, (中文(简体) ), `.ganju`, (中文(简体) ), `.git`, (中文(简体) ), `.env*`,锁文件 (单位:千美元)`package-lock.json`, (中文(简体) ), `yarn.lock`, (中文(简体) ), `pnpm-lock.yaml`, (中文(简体) ), `bun.lock[b]`二进制 文档.
-   **大小 :** 超过256 KB的文件被单独忽略。 超过 2 MB (或 500个文件)上传到没有任何来源,说到此,反正部署.
-   **关机:** 设定 `"uploadSource": false` 内 `ganju.json`。 。 。 .

### 替换应用程序中的代码

一个部署将这个文件夹作为整个项目发布。 如果现场版本是 (由助理或仪表板编辑), `ganju deploy` 先说,然后列出 函数将停止工作。 在终点站,它问 之前继续 脚本停止,除非你通过 `--force`A级 `--draft` 部署不取代任何东西, 所以它没有检查.

## 工具内插

`ganju build` 检查每个工具是如何在 `ganju.json` 以模特儿盟誓 关于:

-   缺少或非常简短的描述,或从未说明何时使用 工具;
-   没有 `annotations` - 然后,工具被视作一个可能改变事物的工具, 当组织确认敏感时 行动;
-   没有描述的输入属性;
-   两个在名字或描述上相像的工具.

警告不会停止建设,除非你通过 `--strict`这是给中情局的. `ganju deploy` 打印与 API 运行的相同的检查, API 也查看 服务器的其他工具—— 与它们重叠, 太多启用的工具出现 在这里.

## 环境

| 变量 | 对于 |
| --- | --- |
| `GANJU_API_URL` | 哪个部门要跟谁说话? 每个项目的固定表如下: `apiUrl` 内 `ganju.json` |
| `GANJU_API_TOKEN` | 一个没有浏览器的机器(CI,一个容器,SSH)的访问符. 绕过存储的登录 . `ganju token create` 薄荷 耐用 |
| `GANJU_SECRET_VALUE` | `ganju secret set NAME` 从这里读取值, 让它远离外壳历史 |
| `GANJU_CONFIG_DIR` | 代币店住的地方. 默认 `~/.ganju` |

## 签名于

`ganju login` 是对同一授权进行回转(RFC 8252) 服务器 MCP 客户端使用: CLI 持有端口打开,将您的浏览器发送到 授权端点, 并读取代码 从方向。 客户是公众 - 没有秘密, PKCE, 因为用 npm 包运来的秘密是一个秘密 软件包的每个用户都有 它通过RFC 7591动态进行自我注册 在第一个登录时进行注册,所以不需要手工提供.

托肯斯住在这里 `~/.ganju/credentials.json`模式 `0600`,由 API 来源键入 - 因此,反对当地API和同时反对生产不是 每次你碰另一只时,就把你从其中记录下来.

## 从这回购开始建造

`npm run build -w @ganju/cli` 类型检查 `tsc` 然后捆绑在一起 建立为单身 `dist/index.js`。 。 。 .

它捆绑而不是宣布 `@ganju/utils` 作为依赖,尽管 软件包已经发布:全球安装的 CLI 不应拖动 zod, dayjs 和密码套房在某人的机器上读取8个常数和3个 在锁步中释放的软件包不应对每个软件包进行半解析 其他费用。 这8个价值观存在于 `@ganju/utils/cliConstants`,模块 输入主常数模块将包含整个 对象字形,因为捆绑者不能摇起一棵树. `ganju data` 携带 `@ganju/utils/dataImport` 及其所需的模块,所以每个导入检查 带有数据库本身规则的单元格,但不为 Zod: Data API 路由列表 仅输入其类型,复制的CLI呼叫由 `tsc`。 。 。 .

`npm test -w @ganju/cli` 运行单元测试(`node:test`: `--where` 简写, schema diff 及其订单, 以及 CSV 读取器.

`esbuild` 保持一个真正的依赖性,因为它运送一个特定平台的二进制 无法捆绑.

## 常见问题

### @ganju/cli 是什么？

从终端写入、部署并调试 Ganju 自定义工具

### 如何安装 @ganju/cli？

在项目目录运行 npm install @ganju/cli，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 ganju，可以用 npx ganju 直接运行。

### @ganju/cli 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/ganju\_\_cli 是否存在。

### @ganju/cli 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @ganju/cli 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @ganju/cli 可以商用吗？

@ganju/cli 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @ganju/cli 的下载量有多少？

根据 npm 官方下载统计，@ganju/cli 在 2026/10/16 – 2026/11/14 这 30 天内被下载 2,743 次，日均约 91 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @ganju/cli 还在维护吗？

最新版本 0\.0\.26 发布于 2026/11/13（3 天前）；至今共发布 24 个版本，其中过去 12 个月发布了 24 个；首次发布于 2026/08/29。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

