@flowmails/cli - - - flowmails 命令
flowmail CLI:围绕官方SDK的一个瘦的、可编写脚本的shell
(@flowmails/flowmails-sdk). 它存在,所以一个代理
人-可以检查连接,查看邮箱帐户
拥有、跟踪入站日志并等待消息 没有
手动处理HTTP.
它实现了AP-06
docs/agent-platform.md (§6.3,§10.4)。
安装
npm i -g @flowmails/cli
二进制文件叫做 flowmails:
flowmails --help
它需要的SDK
CLI是建立在 @flowmails/flowmails-sdk 和 使它
外部 -发布的二进制文件在运行时导入SDK
而不是把它装在包里。因此,已公布的舱单
针一 确切的 SDK版本,CLI需要:
@flowmails/cli | 0.1.1 |
@flowmails/flowmails-sdk | 0.2.1 (完全) |
flowmails --version 在标准输出和中打印CLI的版本
标准误差所需的SDK; flowmails --help 也说了。
别针是一种契约,而不是一种形式: 0.2.0 是否打开了最新的SDK
公共登记处,它已经 否 fm.workerVersion() ——唯一的
代理可以询问“我的接收工作者是否足够新以填充我的事件。
日志吗?”一个固定在 0.2.0 我不能回答这个问题
user (audit p0 - 4,2026-10-31)。
发布订单事项。 SDK必须达到npm 之前 CLI, 因为CLI的安装会提取清单名称的确切版本。 从repo根目录:
pnpm run publish:sdk # @flowmails/flowmails-sdk 0.2.1
pnpm run publish:cli # @flowmails/cli 0.1.1
要使用CLI本身,可以通过签出方式安装它:
# from the repo root
pnpm install
pnpm --filter @flowmails/cli build
# put `flowmails` on your PATH (a symlink into the checkout)
cd packages/cli && npm link
如果没有链接,直接从checkout中运行bundle:
node packages/cli/dist/cli.js --help
构建需要SDK的包,因为CLI是构建在它上面的:
pnpm --filter @flowmails/flowmails-sdk build # builds packages/sdk/dist
pnpm --filter @flowmails/cli build # bundles packages/cli/dist
两个 build 和 typecheck 在此包中先运行SDK构建,
所以 pnpm --filter @flowmails/cli build 它本身就足够了。
检查:
flowmails --help
人类只做一次入职
命令行无法板载帐号,座席也不能。 这些 按照设计,步骤仅在仪表板上显示:
- 创建flowmail帐户并登录;
- 连接Cloudflare帐户;
- 添加并验证一个域(DNS记录是你的);
- 部署每个帐户的接收工作者;
- 生成API密钥本身。
每天做一次。 https://flowmails.net/dashboard/onboarding **,然后创建键at https://flowmails.net/dashboard/settings/api-keys **并把它交给 CLI。之后,CLI所做的一切都是从命令开始的 Line -包括创建一个邮箱并等待第一封邮件。
flowmails login -存储凭证
设备流程尚未实现 (AP-07)。没有 要与之通信的设备端点
flowmails login做 不 为您进行身份验证:它存储您粘贴的密钥。它是这么说的 运行的时间——CLI从来不会在没有登录的时候假装已经登录。
flowmails login # prompts for the key (input is not echoed)
flowmails login --key fm_… # non-interactive
cat key.txt | flowmails login # non-interactive, from stdin
该密钥通过形状进行验证,并以mode存储在配置文件中
0600. 没有任何命令打印原始密钥 -输出显示短
前缀(fm_012…),仅此而已。
凭证类型
| 前缀 | 它是什么? |
|---|---|
fm_… | SDK密钥。一个租户,绑定一个域发送。 |
agc_… | 代理凭证。同一个租户加上一个范围列表。 |
两者都被 flowmails login.
flowmails test -连接检查
这是安装说明告诉您要运行的第一件事 “到第一个代理行动的时间”指标中的第一个信号。它是 安静(标准输出上一行,标准输出上的步骤)和果断(标准输出上的步骤) 退出代码意味着什么)。
flowmails test
# flowmails test: OK — credential fm_012…, domain yourapp.com, API alive (no message sent), domain can send
它检查四件事:
- 身份验证 -该证书被平台接受。
- 域 -该帐户拥有哪个域,以及该帐户拥有哪个域
钥匙是绑定的。(平台不会将绑定暴露给
范围凭证-
GET /api/v1/meSDK密钥的表面是什么 对于几个域,CLI会说“未知”而不是猜测。) - API活性 -发送源 答案 对于这个证书。 没有邮件发送。
- 发送能力 -边界域是否可以
发送。平台将其报告在代理的域投影上
(
canSend+sendingState)等等GET /api/v1/me.
步骤3是活体检查,而不是发送
探针读取不存在的消息id的状态,因此a
404 是证明API可达的答案。这是 所有
它证明了。用于将其称为“发送可达性”并打印的命令
flowmails test: OK 对于发送失败的域 100% 的
Time—新用户运行的第一个命令(audit)为false positive
P0-2, 2026-10-31)。
所以索赔现在是索赔:支票上写着 “API活着”, 这个 能力 从平台读取。
判决结果
| 判决 | 退出 | 意义 |
|---|---|---|
OK | 0 | 通过认证,API是活的, 束缚域可以发送. |
UNVERIFIED | 0 | 通过身份验证后,API是活动的,但平台不报告域是否可以发送(旧的后端)。这是 不 通过验证 flowmails test --send-to <addr>. |
FAILED | 1 | 有些东西坏了:凭证被拒绝,平台无法访问,或者 绑定域无法发送. 消息命名域。 |
无法发送的域 从来没有 打印 flowmails test: OK.
flowmails test
# ✓ auth ok (fm_012…)
# ✓ domains: mysoul.fun
# ✓ bound domain: mysoul.fun
# ✓ API alive (no message sent)
# ✓ domain mysoul.fun cannot send (not_onboarded)
# ✗ mysoul.fun cannot send (sending state: not_onboarded)
# flowmails test: FAILED — fm_012…, mysoul.fun cannot send (sending state: not_onboarded)
# $? = 1
(前五行是进展轨迹 stderr;这个
FAILED 行是总结,也对stderr。与 --json 摘要
是标准输出上的一个JSON对象。)
发送真实信息是可选择的
默认情况下不发送任何内容。真正的信息只有在你请求的时候才会发送 一:
flowmails test --send-to [email protected]
--from <local@domain> 时,将覆盖发件人地址
拥有多个域名。平台记录为失败的发送
(status: "failed",审计p -1)也没有通过检查,与
平台给出的理由。
机器可读的输出
flowmails test --json
# {"ok":true,"verdict":"ok","credential":"fm_012…","domains":[…],"boundDomain":"yourapp.com",
# "api":{"alive":true},"send":{"canSend":true,"state":"ready","verifiedBy":"capability","sent":null}}
verdict 是 ok, unverified 或者 failed; send.canSend 是 null
当平台没有报告时。
flowmails addresses ——你自己的邮箱
flowmails addresses
# yourapp.com (catchall, ready)
# [email protected]
flowmails addresses --json
# {"domains":[{"id":"dom_1","name":"yourapp.com","routingMode":"catchall","ready":true,…}]}
在一个 catchall 域各局部交付;在一个 rules 域
只有列出的那些才有——清单会告诉你是哪些。
flowmails watch <addr> -跟踪入站日志
flowmails watch [email protected]
{"id":"evt_…","messageId":"<…>","event":"inbound.received","recipient":"[email protected]","sender":"[email protected]","subject":"Your invoice","createdAt":"…"}
每行一个JSON对象,换行分隔,因此它直接管道到
jq 或者行阅读器。事件携带路由事实和主题
- - - - - - 从来没有尸体;用SDK获取主体 messages.get().
flowmails wait <addr> -等待消息
flowmails wait [email protected]
# <3f8a…@stripe.example> # the resolved SMTP Message-ID
flowmails wait [email protected] --subject invoice --sender [email protected] --timeout 5m
平台上的等待是持久的:它立即回答 解析匹配的消息何时登陆,并在CLI运行时存活 死亡。标准输出只携带一样东西——已解决的 消息id -这样命令可以在替换中使用:
id=$(flowmails wait [email protected])
等待时观察到的事件是JSON行 stderr.
过期不是失败。 等待到了最后期限,没有
匹配的消息退出 3 (过期);一个无法完成它的等待
出口工作 1 (失败)。它们以前是相同的代码,剩下一个
脚本无法区分“超时”和“损坏”(审计P1-6)
2026-10-31)。
断开连接后继续
watch 和 wait 持久化它们的游标——最后一个事件的id
它们将-打印到状态文件,并在下次运行时从它恢复:
- 游标是 标识符,一个时间戳(两个事件)永远不能 在同一毫秒内着陆,可以跳过一行的游标就会丢失 邮件);
- 是这样写的 后 每个事件都被打印出来,这样之间就会崩溃 两个事件重播 最多是最后一个.
这是 至少一次交付这是一门正确的行业
另一种选择是无声地丢失邮件。如果你的消费者需要
正好一次,重复一次 messageId.
失败的页面(丢失的套接字,502)不会结束命令
在stderr上报告错误,并从游标恢复下一个轮询
它已经在磁盘上了。平台不知道的游标是A
不同的失败——平台回答 400,而不是空白页,所以
watch 停止并表示要删除状态文件,而不是旋转或
默默地重播整个日志。 wait 此外,还坚持
等待id,因此重新连接将恢复 相同 等一等,不要再打开了
一个。
文件
| 路径 | 模式 | 它包含什么 |
|---|---|---|
~/.config/flowmails/config.json | 0600 | 凭据,可选 baseURL / platformURL 覆盖。 |
~/.config/flowmails/state.json | 0600 | 每个命令和邮箱的游标(和等待id)。 |
使用mode创建目录 0700. 两条路径都是
重写:
flowmails --config /path/to/config.json test
FLOWMAILS_CONFIG=/path/to/config.json flowmails test
FLOWMAILS_STATE=/path/to/state.json flowmails watch [email protected]
$XDG_CONFIG_HOME 的默认位置。
命令表面
flowmails login [--key <key>] Store a credential (paste-key fallback)
flowmails test [--send-to <addr>] Connection check: auth, domain, API liveness, send capability
flowmails addresses [--json] List the account's domains and mailboxes
flowmails watch <addr> Tail inbound events as JSON lines
flowmails wait <addr> [--subject <s>] [--sender <s>] [--timeout <ms>]
Wait for a message and print its id
全局选项: --config <path>, --state <path>, --json,
-h/--help, -v/--version.
flowmails <command> --help 打印该命令自己的帮助- its
选项和退出代码表。
--timeout 接受毫秒数(60000)或持续时间(30s, 5m,
1h)。
退出代码
出口密码是a 合同:一个脚本分支在它们上面,所以a 有两种含义的代码是bug。
| 代码 | 意义 |
|---|---|
0 | 成功-命令完成了它被要求做的事情。 |
1 | 失败-凭证被拒绝,平台不可达,绑定域无法发送,或命令遇到错误。 |
2 | 使用错误-未解析参数。 |
3 | 过期, flowmails wait 到了最后期限,却没有收到匹配的信息。 |
3 是分开的 1 故意的:“timed out”和“broken”是
不同的答案,脚本无法区分它们
设置永远损坏,并放弃一个健康的邮箱,只是
没有邮件(审计P1-6, 2026-10-31)。
flowmails test 出口 0 对于 OK 和 UNVERIFIED -什么都不是
已知在第二种情况下是坏的-所以阅读 判决 在
总结(OK / UNVERIFIED / FAILED),而不仅仅是退出密码。
这个包裹不是什么
- 它是 不 一个入职工具。请看上面的边界。
- 它是 不 MCP服务器(即AP-09),它不公开 十个代理工具-它是一个命令行表面相同 SDK。
- 它 不 实现设备流程(AP-07)。
- 它 不 暴露每个工具的作用域(AP-03) - SDK密钥是 租户范围的读取加上域绑定的发送。
开发
pnpm --filter @flowmails/cli typecheck
pnpm --filter @flowmails/cli build
node --test ./test/cli-*.test.mjs # from the repo root
命令逻辑驻留在下面的小模块中 src/commands/,
SDK客户端是通过运行时注入的——所以测试驱动
命令不需要网络,不需要进程,也不需要
SDK的包。