/** * 星环OPC中心 — 新手引导工具 */ import { Type, type Static } from "@sinclair/typebox"; import type { OpenClawPluginApi } from "openclaw/plugin-sdk"; import type { OpcDatabase } from "../db/index.js"; import { getOnboardingState, getCurrentQuestion, answerQuestion, completeChecklistItem, resetOnboarding, ONBOARDING_QUESTIONS, } from "../opc/onboarding-flow.js"; import { json, toolError } from "../utils/tool-helper.js"; const OnboardingSchema = Type.Union([ Type.Object({ action: Type.Literal("start_onboarding"), company_id: Type.String({ description: "公司 ID" }), }), Type.Object({ action: Type.Literal("get_current_question"), company_id: Type.String({ description: "公司 ID" }), }), Type.Object({ action: Type.Literal("answer_question"), company_id: Type.String({ description: "公司 ID" }), question_id: Type.String({ description: "问题 ID(stage/business_type/revenue_expectation)" }), answer: Type.String({ description: "答案值(选项的 value)" }), }), Type.Object({ action: Type.Literal("get_checklist"), company_id: Type.String({ description: "公司 ID" }), }), Type.Object({ action: Type.Literal("complete_item"), company_id: Type.String({ description: "公司 ID" }), item_id: Type.String({ description: "清单项 ID" }), }), Type.Object({ action: Type.Literal("reset_onboarding"), company_id: Type.String({ description: "公司 ID" }), }), ]); type OnboardingParams = Static; export function registerOnboardingTool(api: OpenClawPluginApi, db: OpcDatabase): void { api.registerTool({ name: "opc_onboarding", label: "OPC 新手引导", description: [ "新手引导工具,帮助用户快速上手 OPC 平台。", "操作:start_onboarding(开始引导), get_current_question(获取当前问题),", "answer_question(回答问题), get_checklist(获取清单), complete_item(完成清单项),", "reset_onboarding(重置引导)", ].join(" "), parameters: OnboardingSchema, async execute(_toolCallId, params) { const p = params as OnboardingParams; try { switch (p.action) { case "start_onboarding": { // 检查公司是否存在 const company = db.queryOne( "SELECT id, name FROM opc_companies WHERE id = ?", p.company_id, ); if (!company) { return toolError("公司不存在", "COMPANY_NOT_FOUND"); } // 获取或初始化引导状态 let state = getOnboardingState(db, p.company_id); if (!state) { resetOnboarding(db, p.company_id); state = getOnboardingState(db, p.company_id); } if (state?.completed) { return json({ message: "你已完成新手引导!", completed: true, checklist: state.checklist, }); } const currentQuestion = getCurrentQuestion(db, p.company_id); if (!currentQuestion) { // 所有问题已回答,返回清单 return json({ message: "问题已全部回答,开始完成启动清单吧!", checklist: state?.checklist ?? [], totalItems: state?.checklist.length ?? 0, completedItems: state?.checklist.filter(i => i.completed).length ?? 0, }); } return json({ message: "欢迎使用 OPC 平台!让我通过几个问题了解你的情况,为你生成个性化的启动清单。", currentQuestion: { id: currentQuestion.id, question: currentQuestion.question, options: currentQuestion.options, }, progress: `问题 ${state!.currentQuestionIndex + 1}/${ONBOARDING_QUESTIONS.length}`, }); } case "get_current_question": { const currentQuestion = getCurrentQuestion(db, p.company_id); if (!currentQuestion) { const state = getOnboardingState(db, p.company_id); if (state?.completed) { return json({ message: "引导已完成", completed: true, }); } return json({ message: "问题已全部回答,请查看清单", allQuestionsAnswered: true, }); } const state = getOnboardingState(db, p.company_id); return json({ currentQuestion: { id: currentQuestion.id, question: currentQuestion.question, options: currentQuestion.options, }, progress: `问题 ${(state?.currentQuestionIndex ?? 0) + 1}/${ONBOARDING_QUESTIONS.length}`, }); } case "answer_question": { const result = answerQuestion(db, p.company_id, p.question_id, p.answer); if (!result.success) { return toolError(result.message, "ANSWER_ERROR"); } if (result.nextQuestion) { return json({ message: result.message, nextQuestion: { id: result.nextQuestion.id, question: result.nextQuestion.question, options: result.nextQuestion.options, }, }); } else { // 所有问题已回答,生成清单 const state = getOnboardingState(db, p.company_id); return json({ message: "问题已全部回答!已为你生成个性化启动清单。", checklist: state?.checklist ?? [], totalItems: state?.checklist.length ?? 0, estimatedTime: state?.checklist.reduce((sum, i) => sum + i.estimatedMinutes, 0) ?? 0, }); } } case "get_checklist": { const state = getOnboardingState(db, p.company_id); if (!state) { return toolError("公司不存在", "COMPANY_NOT_FOUND"); } if (state.checklist.length === 0) { return json({ message: "请先完成引导问题", needsOnboarding: true, }); } const completedItems = state.checklist.filter(i => i.completed); const pendingItems = state.checklist.filter(i => !i.completed); return json({ message: state.completed ? "恭喜!你已完成所有启动任务!" : `还有 ${pendingItems.length} 项待完成`, totalItems: state.checklist.length, completedItems: completedItems.length, completed: state.completed, checklist: state.checklist, pending: pendingItems, }); } case "complete_item": { const result = completeChecklistItem(db, p.company_id, p.item_id); if (!result.success) { return toolError(result.message, "COMPLETE_ERROR"); } const state = getOnboardingState(db, p.company_id); const remaining = state?.checklist.filter(i => !i.completed).length ?? 0; return json({ message: result.message, allCompleted: result.allCompleted ?? false, remainingItems: remaining, congratulations: result.allCompleted ? "🎉 恭喜!你已完成所有启动任务,正式开始你的一人公司之旅!" : undefined, }); } case "reset_onboarding": { resetOnboarding(db, p.company_id); return json({ message: "引导已重置,可以重新开始", success: true, }); } default: return toolError("未知操作", "UNKNOWN_ACTION"); } } catch (err) { return toolError( `操作失败: ${err instanceof Error ? err.message : String(err)}`, "EXECUTION_ERROR", ); } }, }); }