SKILL.md 8.3 KB


name: voc-token-preflight description: VOC工作坊 Token 预飞检测。在 Session 1 调用任何付费 skill 之前强制执行,确保 vocToken 有效且余额充足,否则返回可直接展示给用户的支付引导文案+专属充值链接。 version: 1.0.0

author: nkkj-BrainHack

VOC Token 预飞 (voc-token-preflight)

技能名称

voc-token-preflight

技能目的

在 VOC 工作坊从 Session 0 进入 Session 1 之前(或任何付费 skill 调用之前),结构化地检测:

  1. ~/.openclaw/voc-credentials.json 是否存在且包含 vocToken
  2. 该 token 是否仍有效(调用 /parse/users/me 验证)
  3. 对应 APIG 的 APIGAuth.count 余额是否 >0

返回明确的 status 和可直接输出给用户的 displayMessage,让 OpenClaw 不用自己组装支付引导文案,避免"仅说'暂无权限'就停止"的断崖式体验。

核心业务场景

  • Session 0 Step 0.4:建档完成后、切换 currentPhase 到 session-1 之前强制检查
  • Session 1 Step 1.0:对话开场前的快检(可复用 Session 0 的 30 分钟缓存结果)
  • 跨天恢复工作坊:用户第二天回来"继续"时,检测 token 是否仍有效
  • 付费 skill 失败兜底:当某个付费 skill 返回 unauthorized 或 balanceInsufficient 时重跑

调用方式

这是本地脚本型 skill,不走 HTTP,Agent 直接运行:

node scripts/tools/voc-token-preflight.js [apigId]

参数

参数 必填 默认 说明
apigId 否 7HwdQZk55B 要检测的 APIG objectId。Session 1 的 category-landscape 等付费 skill 都走 voc-ecom (7HwdQZk55B)
--json 否 off 纯 JSON 输出到 stdout(适合被其他脚本 pipe)

输出解析

stderr:人类可读的日志(Agent 可选择性展示给用户做调试)

stdout(默认模式):最后一行格式为 PREFLIGHT_RESULT={...},Agent 按以下步骤解析:

// 伪代码
const output = await runCommand('node scripts/tools/voc-token-preflight.js 7HwdQZk55B');
const lastLine = output.stdout.split('\n').filter(l => l.startsWith('PREFLIGHT_RESULT=')).pop();
const json = lastLine.slice('PREFLIGHT_RESULT='.length);
const result = JSON.parse(json);

退出码

退出码 含义 对应 status
0 预飞通过 valid
1 业务问题(token 缺失/过期/余额不足) missing / expired / insufficient_balance
2 系统/网络错误 error

返回结果结构

interface PreflightResult {
  status: 'valid' | 'missing' | 'expired' | 'insufficient_balance' | 'error';
  userId: string | null;        // Parse _User.objectId (valid/insufficient_balance 时有)
  username: string | null;      // Parse _User.username
  authId: string | null;        // APIGAuth.objectId
  balance: number;              // APIGAuth.count 剩余次数
  paymentUrl: string;           // 专属充值/开通链接(带 ?user=... 参数)
  displayMessage: string;       // 已格式化好的 Markdown,Agent 可一字不差展示
  nextAction: 'proceed' | 'showPaymentAndWait' | 'retry';
  apigId: string;               // 检测的 APIG id
  timestamp: string;            // ISO 时间戳
}

Agent 执行协议(重要)

严格遵循以下流程,否则视为违反 Token 预飞协议:

1. 调用预飞

node scripts/tools/voc-token-preflight.js 7HwdQZk55B

2. 解析最后一行 PREFLIGHT_RESULT=... 的 JSON

3. 按 status 分支执行

status = valid

  • 简短确认:"🔐 VOC-AI 服务已就绪(余额 {{balance}} 次)"
  • 更新 workshop-progress.json:

    {
    "preflight": {
      "lastValidatedAt": "{timestamp}",
      "userId": "{userId}",
      "balance": {balance},
      "apigId": "{apigId}",
      "status": "valid"
    }
    }
    
  • 继续下一步(如进入 Session 1 对话开场)

status = missing 或 expired

  • 一字不差输出 displayMessage 字段给用户
  • HARD STOP 等待用户粘贴 session token
  • 收到 token 后:
    1. 运行 node scripts/tools/set-voc-token.js <token>
    2. 再跑一次 本 skill 确认 status = valid
    3. 若仍非 valid → 重复展示 displayMessage

status = insufficient_balance

  • 一字不差输出 displayMessage 字段(paymentUrl 已带 ?user={userId})
  • 告诉用户:"扫码付款后回复'已支付',我会再查余额"
  • 用户回复"已支付"后,再跑一次 本 skill 确认 status = valid

status = error

  • 展示 displayMessage + 网络错误细节
  • 建议用户检查网络,等 10 秒后重试
  • 不要自动推进工作坊

4. 禁止行为

❌ 不得跳过本 skill 直接调 category-landscape / keyword-search 等付费 skill
❌ 不得忽略 displayMessage,自己组装支付文案
❌ 不得把 status = error 当作 missing 处理
❌ 不得在 status != valid 时推进 workshop-progress.currentPhase

调用示例

示例 1:完整预飞(理想路径)

$ node scripts/tools/voc-token-preflight.js 7HwdQZk55B
# stderr:
══════════════════════════════════════════════
  VOC Token Preflight v1
  APIG: 7HwdQZk55B
══════════════════════════════════════════════
✅ Token: r:aa5f...79a7
✅ Token 有效
👤 用户: 陈斌 (kI6aUwfiBE)
💰 APIGAuth: abc123, 余额: 98 次, 已用: 2 次
✅ 预飞通过,可进入 Session 1

# stdout:
PREFLIGHT_RESULT={"status":"valid","userId":"kI6aUwfiBE","balance":98,"paymentUrl":"https://app.fmode.cn/dev/apig-pay/?user=kI6aUwfiBE&apigid=7HwdQZk55B&fun_id=HOkkX72PMF","displayMessage":"🔐 VOC-AI 服务已就绪\n   👤 账号 kI6aUwfiBE\n   💰 余额 98 次","nextAction":"proceed","apigId":"7HwdQZk55B","timestamp":"2026-04-17T12:00:00Z"}

# exit code: 0

示例 2:Token 缺失(首次开营)

$ node scripts/tools/voc-token-preflight.js 7HwdQZk55B
# stderr:
══════════════════════════════════════════════
  VOC Token Preflight v1
  APIG: 7HwdQZk55B
══════════════════════════════════════════════
❌ 未找到 vocToken (voc-credentials.json 不存在或为空)

# stdout:
PREFLIGHT_RESULT={"status":"missing","userId":null,"balance":0,"paymentUrl":"https://app.fmode.cn/dev/apig-pay/?apigid=7HwdQZk55B&fun_id=HOkkX72PMF","displayMessage":"🔐 需要开通 VOC-AI 数据服务\n━━━━━━━━━━━━━━━━━━━━\n👉 点击开通:https://app.fmode.cn/dev/apig-pay/?apigid=7HwdQZk55B&fun_id=HOkkX72PMF\n\n📋 操作步骤:\n1. 打开上方链接完成手机号登录\n2. 选择套餐扫码支付(最低 ¥0.01 体验 1 次)\n3. 支付成功后,点击页面顶部\"📋 复制 Token\"\n4. 将 token 粘贴到对话框发给我\n\n⏸️ 我会等你,粘过来就能继续。","nextAction":"showPaymentAndWait","apigId":"7HwdQZk55B","timestamp":"..."}

# exit code: 1

示例 3:余额不足(已开通但用完了)

$ node scripts/tools/voc-token-preflight.js 7HwdQZk55B
# stderr:
...
💰 APIGAuth: abc123, 余额: 0 次, 已用: 10 次
❌ 余额不足,需要充值

# stdout:
PREFLIGHT_RESULT={"status":"insufficient_balance","userId":"kI6aUwfiBE","balance":0,"paymentUrl":"https://app.fmode.cn/dev/apig-pay/?user=kI6aUwfiBE&apigid=7HwdQZk55B&fun_id=HOkkX72PMF",...}

# exit code: 1

相关文件

  • 执行脚本:scripts/tools/voc-token-preflight.js
  • 伴侣脚本:scripts/tools/set-voc-token.js (收到 token 后写入本地)
  • 全局规则:workshop/workshop-global-rules.md 「🔐 Token 预飞协议」章节
  • 调用位置:
    • workshop/workshop-session-0-intake.md Step 0.4
    • workshop/workshop-session-1-category.md Step 1.0
    • 其他 Session 的付费 skill 前置检查

版本历史

  • v1.0.0 (2026-04-17) — 初版
    • 支持 status = valid / missing / expired / insufficient_balance / error
    • 输出带 ?user=... 的专属充值链接
    • 内置可直接展示的 Markdown displayMessage
    • 支持 --json 模式(纯 JSON stdout)