{ "name": "voc-token-preflight", "displayName": "VOC Token 预飞", "description": "VOC 工作坊 Token 预飞检测:在 Session 1 调用付费 skill 之前,结构化地检查 vocToken 是否有效、余额是否充足,并返回可直接展示给用户的支付引导文案+专属充值链接,避免'暂无权限'的断崖式体验。", "category": "workshop", "version": "1.0.0", "type": "local-script", "execution": { "kind": "command", "command": "node", "args": [ "scripts/tools/voc-token-preflight.js", "{{apigId}}" ], "cwd": "{{workspaceRoot}}", "outputParser": { "type": "stdout-prefix-json", "prefix": "PREFLIGHT_RESULT=", "description": "解析 stdout 中以 'PREFLIGHT_RESULT=' 开头的行,去掉前缀后即为 JSON" }, "exitCodes": { "0": "valid", "1": "missing | expired | insufficient_balance", "2": "error" } }, "parameters": { "type": "object", "required": [], "properties": { "apigId": { "type": "string", "description": "要检测的 APIG objectId。默认 7HwdQZk55B(voc-ecom),覆盖 Session 1 的 category-landscape 等付费 skill。若要检测 voc-social 相关 skill,可传 Vo3ROWEvDy。", "default": "7HwdQZk55B", "enum": [ "7HwdQZk55B", "Vo3ROWEvDy" ] } } }, "output": { "type": "object", "description": "预飞检测结果,Agent 按 status 字段分支处理", "properties": { "status": { "type": "string", "enum": [ "valid", "missing", "expired", "insufficient_balance", "error" ], "description": "预飞状态。valid=通过;missing=无token;expired=token失效;insufficient_balance=余额不足;error=系统错误" }, "userId": { "type": "string", "nullable": true, "description": "Parse _User.objectId(token 有效时返回)" }, "username": { "type": "string", "nullable": true, "description": "Parse _User.username" }, "authId": { "type": "string", "nullable": true, "description": "APIGAuth.objectId(账号已开通该 APIG 时返回)" }, "balance": { "type": "integer", "description": "APIGAuth.count 剩余调用次数" }, "paymentUrl": { "type": "string", "description": "充值/开通链接。valid/insufficient_balance 时带 ?user={userId} 参数(专属),missing/expired 时为通用链接" }, "displayMessage": { "type": "string", "description": "已格式化好的 Markdown 文案,Agent 应一字不差展示给用户(status=missing/expired/insufficient_balance 时特别重要)" }, "nextAction": { "type": "string", "enum": [ "proceed", "showPaymentAndWait", "retry" ], "description": "建议的下一步动作" }, "apigId": { "type": "string", "description": "检测的 APIG id(回显)" }, "timestamp": { "type": "string", "description": "ISO 时间戳,用于更新 workshop-progress.preflight.lastValidatedAt" } } }, "memoryFiles": { "read": [ "~/.openclaw/voc-credentials.json" ], "write": [ "memory/workshop-progress.json" ] }, "usageExamples": [ { "name": "Session 0 Step 0.4 默认预飞", "input": { "apigId": "7HwdQZk55B" }, "description": "品牌档案建档完成后的预飞检查,验证用户可进入 Session 1 的付费分析阶段" }, { "name": "Session 1 Step 1.0 入口快检", "input": { "apigId": "7HwdQZk55B" }, "description": "跨天恢复工作坊时,在调用 category-landscape 前快速检验 token 仍有效" }, { "name": "付费 skill 失败后重新预飞", "input": { "apigId": "7HwdQZk55B" }, "description": "当某个付费 skill 返回 unauthorized/balanceInsufficient 时,重新预飞以确定是 token 问题还是余额问题" } ], "agentProtocol": { "description": "OpenClaw Agent 必须严格按以下顺序执行,否则视为违反 Token 预飞协议", "steps": [ "1. 运行 `node scripts/tools/voc-token-preflight.js `", "2. 在 stdout 中找到以 'PREFLIGHT_RESULT=' 开头的最后一行,去掉前缀得到 JSON", "3. 解析 JSON,读取 result.status", "4. 若 status = 'valid':简短确认 + 更新 memory/workshop-progress.json.preflight 字段", "5. 若 status = 'missing' 或 'expired':一字不差输出 result.displayMessage → HARD STOP 等用户粘 token → 收到后运行 set-voc-token.js + 再跑本 skill", "6. 若 status = 'insufficient_balance':一字不差输出 result.displayMessage → 等用户支付后回复'已支付' → 再跑本 skill 确认 valid", "7. 若 status = 'error':告知用户网络/系统错误,等待后重试", "8. 除非 status = 'valid',否则绝不推进 workshop-progress.currentPhase" ], "forbidden": [ "跳过本 skill 直接调 category-landscape / keyword-search 等付费 skill", "忽略 displayMessage 自己组装支付文案(易遗漏链接或步骤)", "把 status = 'error' 当成 'missing' 处理(会让用户误以为需要重新支付)", "在 status != 'valid' 时更新 workshop-progress.currentPhase 到 session-1" ] }, "relatedFiles": { "executor": "scripts/tools/voc-token-preflight.js", "companion": "scripts/tools/set-voc-token.js", "protocolDocs": "workshop/workshop-global-rules.md#token-预飞协议", "callers": [ "workshop/workshop-session-0-intake.md (Step 0.4)", "workshop/workshop-session-1-category.md (Step 1.0)" ] } }