# @fabianactor/brew-cli 中文文档

规范地址：https://npmcn.com/package/%40fabianactor/brew-cli/

版本：0\.3\.6
npm 元数据更新时间：2026-11-08T11:46:23.387Z
中文译文更新时间：2026-11-14T15:04:23.982Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40fabianactor/brew-cli
原文对照：https://npmcn.com/package/%40fabianactor/brew-cli/?lang=original
项目主页：https://github.com/FabianActor/brew-cli#readme
源码仓库：https://github.com/FabianActor/brew-cli

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

- 包体积（解压后）：232 kB，11 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- Node.js 要求：\>=18
- 运行依赖：3 个
- 首次发布：2026-11-04T12:27:55.190Z
- 最新版本发布：2026-11-08T11:46:23.044Z
- 近 30 天下载量：2008（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：11（近 12 个月 11 个）

## 中文简介

在Supabase操作酿酒-制导数据的CLI:豆子,酿酒笔记,设备和方法.

## 安装

```sh
npm install @fabianactor/brew-cli
```

也可以使用：`pnpm add @fabianactor/brew-cli`、`yarn add @fabianactor/brew-cli`、`bun add @fabianactor/brew-cli`

## README

# brew-cli

在终端里管理 [brew-guide](https://github.com/chuthree/brew-guide) 的数据：咖啡豆、冲煮记录、器具与配方、烘焙商，直接读写它用的 Supabase 表。

数据和应用里看到的是同一份——手机上刷新就能看到你在终端里记的那一杯。

每个版本改了什么见 [CHANGELOG.md](https://npmcn.com/package/%40fabianactor/brew-cli/CHANGELOG.md)。

* * *

## 安装

需要 Node.js >= 18。

```bash
npm install -g @fabianactor/brew-cli
brew-guide --version
```

包名是 `@fabianactor/brew-cli`（`brew-cli` 在 npm 上被人下架过，名字锁死了，用不了），装完的命令叫 `brew-guide`（跟它操作的那款应用同名）。不想全局装就用 `npx @fabianactor/brew-cli bean list`。

macOS 上用系统自带的 Node 装可能会 `EACCES: permission denied` —— 那是系统目录不给写，别用 `sudo`，改用 nvm / fnm 这类版本管理器，或者把前缀指到用户目录：`npm install -g @fabianactor/brew-cli --prefix ~/.npm-global`（之后把 `~/.npm-global/bin` 加进 `PATH`）。

从源码装：

```bash
git clone https://github.com/FabianActor/brew-cli.git
cd brew-cli
npm install
npm run build
npm link        # 把 brew-guide 挂到全局 PATH
```

之后改代码只要再跑一次 `npm run build` 就生效，不用重装。

想装内嵌的 Agent skill（让 AI 助手知道怎么用这套命令）：

```bash
npx skills add github.com/FabianActor/brew-cli -y -g
```

## 配置

```bash
brew-guide init
```

会依次问两样东西：

| 项 | 说明 |
| --- | --- |
| Supabase URL | 你的项目地址，结尾的 `/` 会自动去掉 |
| API key | **publishable** key 就够（旧名 `anon`，在 Legacy API keys 标签里）；**不需要** service\_role / secret key。输入时不回显，存在配置文件的 `supabaseKey` 字段 |
| User ID | **不问**，固定写 `default_user`。App 侧的同步标识是硬编码的（`syncOperations.ts` 的 `DEFAULT_USER_ID`），换别的名字只会得到一份 App 看不到的数据。真要换，用环境变量 `BREW_GUIDE_USER_ID` |

为什么 publishable 就够：brew-guide 自带的 schema 对五张表都开了 `USING (true)` 宽 RLS，还对 `anon` 显式授了增删改查——权限边界**就是** RLS 本身，换个人拿到同一把 key 也是这个权限。**它不能绕过 RLS**：表上没有对应策略的库，这把 key 一样被拒。想收窄的话得改策略，不是换 key。

配置写到 `~/.config/brew-guide/config.json`，想换位置就设 `BREW_GUIDE_CONFIG_PATH`。老版本写下的 `supabaseServiceRoleKey` 字段仍能读（会提示一次改名），新写的都是 `supabaseKey`。

> **前置条件**：`roasters` 命令需要库里存在 `public.get_all_roasters()` 函数，brew-guide 自带的 schema 里没有。没建也不会默默失败——跑 `roasters` 时它会把下面的 SQL 直接打给你，贴进 Supabase SQL Editor 跑一次即可。

建函数的 SQL

```sql
create or replace function public.get_all_roasters()
returns table (roaster text)
language sql
stable
as $$
  select distinct trim(both from r.roaster) as "roaster"
  from (
    select jsonb_extract_path_text("data", 'roaster') as roaster
    from "public"."coffee_beans"
    where "deleted_at" is null

    union all

    select jsonb_extract_path_text("data", 'roaster') as roaster
    from "public"."brewing_notes"
    where "deleted_at" is null
  ) as r
  where r.roaster is not null
    and btrim(r.roaster) <> ''
  order by 1;
$$;
```

想换配置就跑 `brew-guide init`，或直接改那个 JSON。

* * *

## 四个常用场景

### 1\. 查豆

```bash
# 最近加的 10 款
brew-guide bean list --limit 10

# 按产区 / 处理法 / 品种 / 产国 / 批次找（包含匹配，--region 古吉 能命中「古吉 罕贝拉」）
brew-guide bean list --region 古吉 --has-remaining true
brew-guide bean list --country Ethiopia --batch "Lot 26"

# 看一款的完整字段（照片默认不打印，要原图加 --with-images）
brew-guide bean get bean_xxx
brew-guide bean get bean_xxx --with-images --format json > bean.json

# 还剩什么烘焙商
brew-guide roasters
```

### 2\. 加一款豆

> **先在 App 里打开这些字段**：设置 → 咖啡豆 → 咖啡豆字段，勾选 烘焙商、产地、产区、庄园、处理站、海拔、处理法、品种。没勾的字段在应用里看不到，等于白写。
> 
> 一个当前限制：**产国与产地在后端是同一个字段**（开产国就得把国家从产地搬走，否则同一信息存两处）。批次写在 `blendComponents[0].batch`，App 里勾了批次就能看到。

```bash
brew-guide bean add \
  --name "罕贝拉 日晒" --roaster "MAME" \
  --country "埃塞俄比亚" --region "古吉 罕贝拉" \
  --estate "Buku Sayisa" --process "日晒" \
  --variety "原生种" --altitude "2350-2460m" \
  --roast-level "浅度烘焙" --capacity 100 --price 128
```

只有 `--name` 是必填 —— 和 App 一致：它的表单里也只有「咖啡豆名称」带必填星号，产地、处理法、烘焙商都能空着存。烘焙度不给就留空（以前会按豆种猜一个，猜错就污染 App 的筛选）。`--start-day` / `--end-day` 不给时按烘焙度取 App 的同一套预设：浅烘 7/60、中烘 10/60、深烘 14/90 —— 但这套天数只有在**有烘焙日期**时才生效：没给 `--roast-date` 的豆子，App 判到烘焙日期为空会直接显示「未设置烘焙日期」，养豆期、赏味期都不算（App 源码 `flavorPeriodUtils.ts:217`）。想让它真的开始计天，`--roast-date 2026-11-01` 一起给。

状态相关的三个开关：

```bash
# 还没到手
brew-guide bean add --name "..." --roaster "..." --origin "肯尼亚" --process "水洗" --in-transit

# 冷冻保存（和在途互斥，开一个就把另一个关掉；取消用 --no-in-transit / --no-frozen）
brew-guide bean update bean_xxx --is-frozen

```

**生豆暂不支持**（`--bean-state green`、`--purchase-date` 会被拒绝，报「暂不支持生豆系列操作，请至 APP 查看并操作」）。原因不是偷懒：App 的生豆是一整套流程 —— 记购买日期、按库存算余量、详情页把「冲煮记录」换成「烘焙记录」，「转为生豆」还要新建烘焙记录和一颗新熟豆（`RoastingManager`）。CLI 只改字段的话，会写出 App 里看不见的状态（老记录挂在生豆上但不显示、生豆被标成「在途」）。所以生豆相关的读和写统一交给 App；`bean list` 也会把生豆隐藏起来并提示数量。

`--price` 只收数字（`88`、`88.5`，也认 `¥88`、`88元` 这种写法），存成字符串给 App 算「元/克」。

封面图/背面图可以直接从本地文件塞进去：

```bash
brew-guide bean add --name "..." --image "D:\photos\cover.jpg" --back-image "D:\photos\back.jpg"
brew-guide bean update bean_xxx --image "D:\photos\new-cover.jpg"   # 换图
brew-guide bean update bean_xxx --clear image                        # 清掉
```

照片和 App 一样存进 `data.image` / `data.backImage`（`data:image/...;base64,` 那种字符串）。CLI 不做压缩，只做两件事：认扩展名（`.jpg` / `.jpeg` / `.png` / `.webp` / `.gif`），以及超过 1.5 MB 直接拒绝（base64 会膨胀 4/3，一行太大既拖慢列表也占库）。想更小就先自己缩到 800px 宽——App 上传时也是这么压的。

拼配用可重复的 `--component`：

```bash
brew-guide bean add --name "三重奏" --roaster "TRIOON" \
  --component "region=卡哈马卡;process=水洗" \
  --component "region=库斯科;process=日晒;percentage=40"
```

字段怎么拆（产地/产区/庄园/处理站怎么分工）见 `skills/brew-guide/references/bean-add.md`。

### 3\. 记一杯

```bash
# 记完自动扣余量（--with-note 会连记录一起写）
brew-guide note add --bean-id bean_xxx --method "三段式" \
  --equipment "V60" --rating 4.5 --notes "莓果，尾段偏甜" \
  --coffee 15g --water 225g --water-temp 92

# 翻最近的记录，按日期/评分筛
brew-guide note list --limit 10
brew-guide note list --from 2026-10-01 --to 2026-10-31 --min-rating 4

# 只想扣粉量、不记记录
brew-guide bean consume bean_xxx --amount 15
```

`note add` 没有必填项 —— App 里豆子和手法都能不选（方法那一步本身可以跳过），CLI 照此对齐。`--rating` 和 `--taste-*` 只收 0-5（超范围直接报错）；`--water-temp` 收 `92` 或 `92°C`，一律写成 `92°C`；`--equipment` 会校验，内置 V60 / CleverDripper / Kalita / Origami / Orea / Sinloy / Espresso 直接认，自定义器具要写 `equipment list` 里的 ID。

`--image` 可以附一张照片（本地文件，同样存成 data URL）。给了 `--bean-id` 时，会先确认豆子还在，记录里再自动存一份豆子快照（名字、烘焙度、烘焙日期、烘焙商），和 App 里点「记录一杯」一样；以后豆子改名，旧记录仍显示当时的样子。

### 4\. 管器具和配方

```bash
brew-guide equipment list
brew-guide equipment add --name "V60" --id "V60" --animation-type v60
brew-guide method list
brew-guide method add --name "三段式" --equipment-id "V60" --stages-json '[{"label":"焖蒸","water":"30g","duration":15,"detail":"注入 30g 水，等 15 秒"}]'
```

`--id` 撞已有器具会报错停下，确认要替换才加 `--force`。

### 备份

```bash
brew-guide backup                       # 默认 brew-guide-backup-<timestamp>.json
brew-guide backup --out "D:\bk\brew.json"
```

导出 `coffee_beans` / `brewing_notes` / `custom_equipments` / `custom_methods` / `user_settings` 的原始行（含软删），可以直接当离线快照。**批量改库之前先跑一次。**

### 更新检查

```bash
brew-guide update-check                 # 现在就去 npm 上查一次
brew-guide update-check --format json   # {"current","latest","upgradable","source"}
```

平时不用管：每条命令结束前会看一眼本地缓存，发现 npm 上有更新的版本就在 stderr 提醒一次（24 小时最多查一次，同一个版本只提示一次）。提示永远不联网等结果，所以不会拖慢命令；离线、被墙、registry 抽风都只是静默不提示。

不想被提醒就设 `BREW_GUIDE_NO_UPDATE_CHECK=1`（`update-check` 子命令本身不受影响，它只是不自动查）。

* * *

## 命令总览

| 命令 | 干什么 |
| --- | --- |
| `bean add / get / update / delete / consume` | 咖啡豆：新增、详情、修改、软删、扣余量 |
| `bean list` | 列表，支持烤度、豆种、烘焙商、产区、处理法、品种、产国、批次、有无余量筛选 |
| `note add / get / update / delete` | 冲煮记录：新增、详情、修改、软删 |
| `note list` | 列表，支持器具、方法、豆子、评分、日期区间筛选 |
| `equipment add / get / update / delete / list` | 器具 |
| `method add / get / update / delete / list` | 冲煮配方（`--stages-json` 传分段注水步骤） |
| `roasters` | 库里出现过的烘焙商 |
| `backup` | 整库导出成 JSON |
| `update-check` | 查 npm 上有没有新版本 |
| `init` | 写配置 |

每个命令的完整参数用 `--help` 看，例如 `brew-guide bean add --help`。

## 全局选项

| 选项 | 行为 |
| --- | --- |
| `--format json` | 输出紧凑单行 JSON，走 stdout；警告、进度、错误一律走 stderr，可以直接 \` |
| `--dry-run` | 写入类命令打印将要发送的载荷，不写库（读取类校验照做；连不上库时只给提示） |
| `--clear <字段>` | `bean update` 清空某个字段，如 `--clear price --clear flavor`；成分字段（origin/region/…）与 `image` / `back-image` 同样可清。可重复 |

**参数名写错会直接 `exit 2` 并列出可用参数**，不会静默忽略。开关型参数（`--has-remaining` 这类）必须带取值：`--has-remaining true` 是「只看还有余量的」，`false` 是「只看余量为 0 的」，裸写不生效。

## 退出码

| 码 | 含义 |
| --- | --- |
| 0 | 成功 |
| 1 | 运行时失败（记录不存在、写入被拒等） |
| 2 | 参数用法错误（缺必填、取值非法、空字符串、拼错的 flag） |
| 64 | 配置缺失或非法（先跑 `brew-guide init`） |
| 65 | 网络 / Supabase 请求失败 |

## 常见问题

**中文 Windows 上 `brew-guide ... --format json | ConvertFrom-Json` 报 JSON 解析错误。** 0.3.2 起不会了：Windows 上输出被管道/重定向（不是交互终端）时，JSON 里的非 ASCII 字符会自动转成 `\uXXXX`，不管控制台是哪个代码页都能解析 —— 你看到的是转义码，`ConvertFrom-Json` / `jq` 读出来仍是中文。交互终端里还是原样中文。

老版本（0.3.1 及以前）或在别的程序里遇到同样报错，是控制台用 GBK 解码了 UTF-8 输出，中文把引号吃掉了；两种解法任选：

```powershell
chcp 65001                                  # 只影响当前窗口
[Console]::OutputEncoding = [Text.Encoding]::UTF8   # 当前会话生效
```

想强制关掉转义：`BREW_GUIDE_JSON_ASCII=0`（强制打开用 `1`）。

在意的是「CLI 的输出是 UTF-8」这件事 —— 写文件再用 `Get-Content -Encoding utf8` 读也一样可靠。

**`list` 只出来 20 条。** 默认 `--limit 20`，命中上限时 stderr 会提示；要看更多就 `--limit 200`。

## 数据模型备注

-   业务字段都在各表的 `data` JSONB 里；`data` 里的时间值是**毫秒数**，不是 ISO 字符串。
-   产地写在 `data.blendComponents[]`；写入时扁平字段（`--origin` 等）会被合并进第一个成分并从顶层删除。
-   主键是 `(id, user_id)`，写入走 upsert，没有物理删除。
-   **写入会复活软删记录**：所有写入都带 `deleted_at: null`，对一条已软删的 `id` 再 `add`/`update` 会让它重新出现。
-   `list` 默认只读 `deleted_at is null` 的行。

更细的约定见 [docs/supabase.md](https://npmcn.com/package/%40fabianactor/brew-cli/docs/supabase.md)。

## 开发

```bash
npm install
npm run dev -- bean list      # 直接跑源码
npm run typecheck             # tsc --noEmit
npm test                      # typecheck + node --test
npm run build                 # tsup → dist/
npm link                      # 改完只想本地用：build 一次就生效
```

改完 skill 文档记得同步：`npx skills add ./skills/brew-guide -y -g`。

> **发布**：改 `package.json` 版本号 → 提交 → `git tag v0.3.x && git push origin v0.3.x`。CI 跑 typecheck / build / test 后，用 npm trusted publishing（OIDC）直接发布并自动附 provenance — **不需要任何 npm token**。
> 
> 发布链的前置条件（一次性）：npm 包里登记 trusted publisher（user `FabianActor`、repo `brew-cli`、workflow `publish.yml`），Publishing access 设为「Require 2FA and disallow tokens」。配置建好后**两天内必须成功发布一次**，否则作废。`0.2.0` 是手动发的一次性引导，`0.2.1` 起全部走 tag + OIDC。
> 
> 想验证包内容但不发布：`npm pack --dry-run`。
> 
> 改了用户可见的行为，记得在 [CHANGELOG.md](https://npmcn.com/package/%40fabianactor/brew-cli/CHANGELOG.md) 里补一条。

## License

MIT。本仓库是 [swiftwind0405/brew-guide-cli](https://github.com/swiftwind0405/brew-guide-cli) 的 fork，现由 FabianActor 维护；上游部分的版权归原作者，改动部分的版权与责任归本仓库维护者，改动的归属写在 [NOTICE](https://npmcn.com/package/%40fabianactor/brew-cli/NOTICE) 里，具体改了哪些见 `git log`。

## 常见问题

### @fabianactor/brew-cli 是什么？

在Supabase操作酿酒-制导数据的CLI:豆子,酿酒笔记,设备和方法\.

### 如何安装 @fabianactor/brew-cli？

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

### @fabianactor/brew-cli 支持 TypeScript 吗？

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

### @fabianactor/brew-cli 支持 ESM 还是 CommonJS？

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

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

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

### @fabianactor/brew-cli 可以商用吗？

@fabianactor/brew-cli 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @fabianactor/brew-cli 的下载量有多少？

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

### @fabianactor/brew-cli 还在维护吗？

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

