Refly CLI 状态诊断实战:用 refly status 排查配置、认证与 Skill 安装问题
【免费下载链接】reflyThe first open-source agent skills builder. Define skills by vibe workflow, run on Claude Code, Cursor, Codex & more. Build Clawdbot 🦞· APIs for Lovable · Bots for Slack & Lark/Feishu · Skills are infrastructure, not prompts.项目地址: https://gitcode.com/GitHub_Trending/re/refly
本文以 Refly CLI 的refly status命令及配套 Claude Code 斜杠命令 refly-status.md 为主体,讲清楚这条诊断命令检查了哪些内容、输出 JSON 的每个字段从哪来、认证状态如何被后端二次校验,以及如何根据输出中的错误码与退出码完成故障排查。读完本文,你可以用一条命令判断 CLI 是否可用、登录是否有效、Skill 是否安装到位,并能读懂其背后的配置、令牌刷新与符号链接机制。
一、refly status 是什么
refly status是 Refly CLI 的"体检"命令,用于一次性检查四件事:CLI 版本与配置目录、API 端点、认证状态(含过期判断)、Skill 安装状态。它的实现在 status.ts,基于 commander 注册:
refly status仓库中还有一个同名文件 refly-status.md,它不是给人直接读的文档,而是一个Claude Code 斜杠命令定义。该文件带 frontmatter:
--- name: refly-status description: Check Refly CLI configuration and authentication status ---其正文要求 Agent 执行refly status,解析 JSON 并汇总五个要点:CLI 版本、当前用户、API 端点、认证状态与有效期、Skill 安装状态;若未认证,则建议执行refly login。
这个.md文件会随refly init一起安装:installer.ts 中的installSlashCommands()会把packages/cli/commands/目录下的所有.md文件复制到~/.claude/commands/,于是 Claude Code 中就能直接调用/refly-status让 Agent 完成这套状态汇总。也就是说,refly status既是人工排查工具,也是 Agent 自动化诊断的入口。
二、输出字段逐字段解读
2.1 成功响应
认证有效时,命令通过ok('status', payload)输出成功响应。payload 的构造见 status.ts#L52-L65:
| 字段 | 来源 | 说明 |
|---|---|---|
cli_version | getCliVersion() | 读取 CLI 包自身package.json的 version,读取失败时回退为0.1.0(见 paths.ts#L12-L20) |
config_dir | getReflyDir() | 固定为~/.refly,目录不存在会自动创建 |
api_endpoint | getApiEndpoint() | 当前生效的 API 端点,取值优先级见下文 3.2 节 |
auth_status | 后端校验结果 | 三态:valid/expired/missing |
auth_method | 配置的认证方式 | oauth、apikey或null |
auth_details | 按方式展开 | OAuth 时输出{ provider }(google/github);API Key 时输出{ keyId, keyName };无则null |
user | GET /v1/user/me | 当前用户{ uid, name?, email? },未认证时为null |
skill.installed | isSkillInstalled() | ~/.refly/skills/base/SKILL.md是否存在 |
skill.version | SKILL.md frontmatter | Skill 版本,取不到时为null |
skill.up_to_date | 本地比对结果 | 本地 Skill 是否与当前 CLI 包内版本一致 |
需要说明的是:payload 本身不直接输出 token 过期时间戳。斜杠命令文档中提到的"expiry"对应两处事实——配置文件~/.refly/config.json中记录的auth.expiresAt(登录时写入,设备流登录固定为 1 小时,见 login.ts#L218-L224),以及 API 客户端在请求前比较该时间戳并自动刷新令牌的机制(见 client.ts#L87-L99)。refly status把"本地凭证看似存在、但后端已不认"的情况归为expired状态返回。
2.2 输出格式自动检测
输出并不是固定 JSON。formatter.ts#L47-L67 的resolveFormat()实现了三级优先级:
- 命令行显式指定的 format 参数;
- 环境变量
REFLY_FORMAT(取值pretty/json/compact/plain,始终生效); - 自动检测:TTY 交互环境用
pretty(人类可读),管道/重定向环境自动切到json(供脚本和 Agent 解析)。
这正是斜杠命令能"解析 JSON"的前提:在 Claude Code 中命令走管道,输出天然就是 JSON。统一 JSON 结构定义在 output.ts#L21-L49:
{ "ok": true, "type": "status", "version": "1.0", "payload": { "...": "上述字段" } }2.3 失败响应与退出码
当auth_status不是valid时,命令不会输出成功响应,而是以错误码AUTH_REQUIRED失败退出(status.ts#L68-L77),消息区分两种情况:
- 本地有凭证但后端校验不通过 →
"Authentication expired"; - 本地根本没有凭证 →
"Not authenticated"。
两种情况都会带上完整 payload 作为details,并给出hint: "refly login"。错误结构为:
{ "ok": false, "type": "error", "version": "1.0", "error": { "code": "AUTH_REQUIRED", "message": "Not authenticated", "details": { "cli_version": "...", "auth_status": "missing", "...": "..." }, "hint": "refly login" } }若命令执行过程本身抛异常(如读取配置失败),则返回INTERNAL_ERROR,并提示"Try runningrefly initfirst"。退出码映射规则在 output.ts#L232-L238:AUTH_*类为 2,校验/输入类为 3,网络/超时段为 4,NOT_FOUND类为 5,其余为 1——脚本中可以用$?区分"该重新登录"还是"该先 init"。
三、认证状态是如何判定的
refly status的认证判断分两步:本地检查 + 后端在线校验。
3.1 本地检查:isAuthenticated()
config.ts#L170-L180 中,本地检查只看凭证是否存在:
auth.method === 'apikey'时,要求auth.apiKey非空;- 其余情况(即 OAuth)要求
auth.accessToken非空。
注意这一步不判断 token 是否过期,所以本地"看起来已登录"不代表真的可用。
3.2 后端校验:verifyConnection()
本地通过后才调用 client.ts#L415-L452 的verifyConnection():
- 按认证方式取出凭证(API Key 或 access token),取不到直接返回
authenticated: false; - 发起
GET /v1/user/me请求(status.ts 中verification.user即来自这里); - 根据结果归类:
- 请求成功 →
connected: true, authenticated: true,并带回authMethod与用户信息; - 抛出
AuthError(HTTP 401/403 等)→connected: true, authenticated: false,即"网络通、登录失效",对应expired; - 抛出
NetworkError(连不上 API)→connected: false, authenticated: false。
- 请求成功 →
status 命令最终把三者映射为:authenticated→valid;connected但未认证 →expired;本地就没有凭证 →missing。
3.3 令牌刷新机制(为什么 OAuth 会话能长期保持 valid)
API 客户端在每次带认证的请求前都会比较auth.expiresAt与当前时间(client.ts#L87-L99):若已过期,先调用POST /v1/auth/cli/oauth/refresh用 refresh token 换新令牌,成功后写回config.json(新的 access/refresh token 与 1 小时后到期的expiresAt);刷新失败才抛出 "Session expired, please login again"。API Key 方式则不需要刷新,直接使用X-API-Key请求头。
3.4 API 端点的取值优先级
api_endpoint字段的来源在 config.ts#L140-L150,优先级为:
- 环境变量
REFLY_API_ENDPOINT; ~/.refly/config.json中的api.endpoint;- 构建时注入的默认值,源码默认
https://refly.ai(config.ts#L83)。
这意味着自部署或测试环境下,只需设置REFLY_API_ENDPOINT即可让refly status指向自建后端。
四、配置文件与凭证的安全存储
所有状态都落在~/.refly/config.json。其结构由 zod schema 校验(config.ts#L34-L72),关键字段:
{ "version": 1, "auth": { "method": "oauth", "accessToken": "...", "refreshToken": "...", "expiresAt": "ISO-8601 时间戳", "provider": "google", "user": { "uid": "...", "email": "...", "name": "..." } }, "api": { "endpoint": "https://refly.ai" }, "skill": { "installedVersion": "0.1.26", "installedAt": "..." } }auth.method只有oauth与apikey两个枚举值;API Key 方式额外存apiKey/apiKeyId/apiKeyName;- 写入采用"临时文件 + 原子 rename",文件权限强制
0600(仅属主可读写),非 Windows 平台还会对已存在的文件补做chmod(config.ts#L116-L135); - 配置文件缺失或 JSON 解析失败时,
loadConfig()静默回退到默认配置,而不是报错——这也是refly status能把"从未登录"识别为missing而不是崩溃的原因。
两种登录方式的差异(对应refly login,即 status 失败时的修复动作):
- 设备流(默认):
refly login先POST /v1/auth/cli/device/init拿deviceId/userCode,打开浏览器授权页,然后以 2 秒间隔轮询GET /v1/auth/cli/device/status,最长 5 分钟;授权成功后存储 OAuth 令牌。Ctrl-C 会先调device/cancel清理会话再退出(login.ts#L109-L273); - API Key:
refly login -k rf_xxx,key 必须以rf_开头,先经POST /v1/auth/cli/api-key/validate在线校验,通过后连同用户信息写入配置(login.ts#L39-L83)。
五、Skill 安装状态是怎么判定的
skill字段由 installer.ts#L226-L250 的isSkillInstalled()提供,它检查的是符号链接式 Skill 架构:
- 安装判定:
~/.refly/skills/base/SKILL.md存在即installed: true。refly init安装时,会把包内 SKILL.md 和references/下规则文件(workflow/node/file/skill 等)拷贝到~/.refly/skills/base/,再创建符号链接~/.claude/skills/refly -> ~/.refly/skills/base/(路径逻辑见 paths.ts#L118-L150); - 版本判定:从 SKILL.md frontmatter 中提取
version: x.y.z,取不到则回退到 CLI 包package.json的版本; - 符号链接健康:同时校验
~/.claude/skills/refly指向是否有效(isSkillSymlinkValid),用于判断 Claude Code 端是否真的能加载到 Skill。
如果skill.installed为false,说明还没跑过refly init;这也解释了 status 命令异常分支为何提示"Try runningrefly initfirst"。
六、故障排查速查表
| 现象 | 输出特征 | 原因(源码依据) | 处理 |
|---|---|---|---|
| 未登录 | auth_status: "missing",code: AUTH_REQUIRED,退出码 2 | 配置中无 accessToken/apiKey(status.ts#L68-L77) | refly login(默认设备流)或refly login -k <rf_key> |
| 登录过期 | auth_status: "expired",消息 "Authentication expired",退出码 2 | 本地有凭证但GET /v1/user/me被拒(401/403) | 重新refly login;若 refresh 也失败,说明 refresh token 已失效 |
| 连不上 API | verifyConnection返回connected: false,请求超时/网络错误 | NetworkError(client.ts#L446-L448) | 检查网络/代理,或设置REFLY_API_ENDPOINT指向正确端点 |
| 命令内部异常 | code: INTERNAL_ERROR,hint 指向refly init | 命令执行抛异常(status.ts#L80-L86) | refly init重建配置与 Skill 目录 |
| Skill 缺失 | skill.installed: false | ~/.refly/skills/base/SKILL.md不存在 | refly init |
日常使用建议:在脚本或 Agent 流程中,refly status是最轻量的"前置检查"——管道调用时自动输出 JSON,直接读ok/error.code即可分流处理;交互终端里则会以 pretty 格式呈现,便于人工快速扫一眼五个关键状态。
七、相关文件索引
- 斜杠命令定义(本文主体文档):packages/cli/commands/refly-status.md
- 命令实现:packages/cli/src/commands/status.ts
- 连接与认证校验、令牌刷新:packages/cli/src/api/client.ts
- 配置 schema、端点优先级、凭证读写:packages/cli/src/config/config.ts
- 目录与路径约定(
~/.refly、~/.claude/skills):packages/cli/src/config/paths.ts - Skill 安装与状态检测:packages/cli/src/skill/installer.ts
- 统一输出格式与退出码:packages/cli/src/utils/output.ts、packages/cli/src/utils/formatter.ts
- 命令总览与 JSON 输出规范:packages/cli/README.md
- 包元信息(版本 0.1.26、Node >= 18、bin 名
refly):packages/cli/package.json
适用前提:以上行为以当前仓库@powerformer/refly-cli(package.json 中声明,版本 0.1.26,Node >= 18)源码为准;api_endpoint、构建环境(production/test/staging 等)会随构建参数注入默认值,自部署场景请以REFLY_API_ENDPOINT实际指向为准。
【免费下载链接】reflyThe first open-source agent skills builder. Define skills by vibe workflow, run on Claude Code, Cursor, Codex & more. Build Clawdbot 🦞· APIs for Lovable · Bots for Slack & Lark/Feishu · Skills are infrastructure, not prompts.项目地址: https://gitcode.com/GitHub_Trending/re/refly
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考