import type { PlanMessage } from '@/lib/api'; import type { DashboardOverview, JournalEntry, Mission, MissionStep, SkillSummary, } from '@/lib/consoleDataAdapter'; import type { DebugPlan, DebugRun, DebugTask, FlowResponse } from '@/types/api'; function todayAt(hour: number, minute: number): string { const date = new Date(); date.setHours(hour, minute, 0, 0); return date.toISOString(); } function makeTask( missionId: string, stepId: string, title: string, status: string, skillId: string, startedAt: string | null, finishedAt: string | null, ): MissionStep['tasks'][number] { return { id: `${missionId}-${stepId}-task`, title, status, assignedSkillId: skillId, startedAt, finishedAt, }; } function makeMission( id: string, title: string, objective: string, status: string, updatedAt: string, steps: MissionStep[], ): Mission { return { id, title, objective, status, createdAt: todayAt(8, 0), updatedAt, steps, sourceIds: { planId: id, taskIds: steps.flatMap((step) => step.tasks.map((task) => task.id)) }, }; } const DEMO_SKILLS: SkillSummary[] = [ { id: 'qimingclaw-client-health-check', name: '客户端自检', version: '1.0.0', enabled: true, description: '检查 Agent、MCP、Computer Server 和会话状态。', category: '执行', capabilityLevel: 'core', source: 'skill-api' }, { id: 'qimingclaw-remote-task-ingress', name: '远程任务接入', version: '1.0.0', enabled: true, description: '接收管理端下发任务并投射到本地执行队列。', category: '通信', capabilityLevel: 'core', source: 'skill-api' }, { id: 'qimingclaw-acp-session-runner', name: 'ACP 会话执行', version: '1.0.0', enabled: true, description: '通过 qimingclaw ACP 引擎执行任务并记录 Run/Event。', category: '执行', capabilityLevel: 'specialized', source: 'skill-api' }, { id: 'qimingclaw-mcp-capability-scan', name: 'MCP 能力扫描', version: '1.0.0', enabled: true, description: '读取 MCP server 和工具清单,生成数字员工技能能力池。', category: '工具', capabilityLevel: 'standard', source: 'skill-api' }, { id: 'qimingclaw-approval-sync', name: '审批同步', version: '1.0.0', enabled: true, description: '把待确认事项回写到本地 approval 表并同步管理端。', category: '治理', capabilityLevel: 'specialized', source: 'skill-api' }, { id: 'qimingclaw-artifact-report', name: '产物整理', version: '1.0.0', enabled: true, description: '整理本地执行产物、文件路径和日报输出。', category: '产物', capabilityLevel: 'standard', source: 'skill-api' }, { id: 'qimingclaw-sync-diagnostics', name: '同步诊断', version: '1.0.0', enabled: true, description: '汇总 outbox 失败、重试历史和管理端同步状态。', category: '运维', capabilityLevel: 'standard', source: 'skill-api' }, { id: 'qimingclaw-daily-report', name: '本地日报', version: '1.0.0', enabled: true, description: '基于 qimingclaw workday 投影生成本地文本日报。', category: '报表', capabilityLevel: 'standard', source: 'skill-api' }, ]; const DEMO_MISSIONS: Mission[] = [ makeMission( 'qimingclaw-client-readiness', 'qimingclaw 客户端运行自检', '检查客户端数字员工运行所需的 Agent、ACP、MCP、Computer Server 和同步配置。', 'active', todayAt(10, 35), [ { id: 'agent', title: '检查 Agent 服务', status: 'completed', preferredSkills: ['qimingclaw-client-health-check'], tasks: [makeTask('qimingclaw-client-readiness', 'agent', '读取 Agent 运行状态', 'completed', 'qimingclaw-client-health-check', todayAt(8, 30), todayAt(8, 33))] }, { id: 'mcp', title: '扫描 MCP server', status: 'completed', preferredSkills: ['qimingclaw-mcp-capability-scan'], tasks: [makeTask('qimingclaw-client-readiness', 'mcp', '生成 MCP 能力清单', 'completed', 'qimingclaw-mcp-capability-scan', todayAt(8, 35), todayAt(8, 41))] }, { id: 'computer', title: '检查 Computer Server', status: 'completed', preferredSkills: ['qimingclaw-client-health-check'], tasks: [makeTask('qimingclaw-client-readiness', 'computer', '确认电脑控制入口', 'completed', 'qimingclaw-client-health-check', todayAt(8, 45), todayAt(8, 51))] }, { id: 'sync', title: '读取同步队列', status: 'running', preferredSkills: ['qimingclaw-sync-diagnostics'], tasks: [makeTask('qimingclaw-client-readiness', 'sync', '汇总 outbox 状态', 'running', 'qimingclaw-sync-diagnostics', todayAt(10, 28), null)] }, ], ), makeMission('qimingclaw-remote-task-ingress', '09:00 远程任务接入', '接收管理端下发任务,进入 /computer/chat 与 ACP 执行链路。', 'completed', todayAt(9, 6), [ { id: 'ingress', title: '接收管理端任务', status: 'completed', preferredSkills: ['qimingclaw-remote-task-ingress'], tasks: [makeTask('qimingclaw-remote-task-ingress', 'ingress', '解析远程任务 payload', 'completed', 'qimingclaw-remote-task-ingress', todayAt(9, 0), todayAt(9, 6))] }, ]), makeMission('qimingclaw-acp-run-0930', '09:30 ACP 会话执行', '用 qimingclaw ACP 会话执行本地任务并记录运行事件。', 'completed', todayAt(9, 32), [ { id: 'run-session', title: '创建 ACP 会话', status: 'completed', preferredSkills: ['qimingclaw-acp-session-runner'], tasks: [makeTask('qimingclaw-acp-run-0930', 'run-session', '执行客户端任务', 'completed', 'qimingclaw-acp-session-runner', todayAt(9, 30), todayAt(9, 32))] }, ]), makeMission('qimingclaw-mcp-tools-1030', '10:30 MCP 工具能力投射', '读取当前 MCP 配置、server 状态和工具限制,生成技能库能力项。', 'running', todayAt(10, 35), [ { id: 'scan-tools', title: '扫描 MCP 工具', status: 'running', preferredSkills: ['qimingclaw-mcp-capability-scan'], tasks: [makeTask('qimingclaw-mcp-tools-1030', 'scan-tools', '整理 MCP 工具清单', 'running', 'qimingclaw-mcp-capability-scan', todayAt(10, 30), null)] }, ]), makeMission('qimingclaw-approval-review-1130', '11:30 本地审批确认', '把数字员工待确认事项写回 formal approval 表并进入同步队列。', 'approved', todayAt(11, 20), [ { id: 'approval', title: '处理 approval 决策', status: 'pending', preferredSkills: ['qimingclaw-approval-sync'], tasks: [makeTask('qimingclaw-approval-review-1130', 'approval', '回写 approval 状态', 'pending', 'qimingclaw-approval-sync', null, null)] }, ]), makeMission('qimingclaw-artifact-1430', '14:30 执行产物整理', '提取 Run/Event payload 中的文件、路径和输出,投射到 artifact 列表。', 'draft', todayAt(14, 10), [ { id: 'artifact', title: '整理执行产物', status: 'pending', preferredSkills: ['qimingclaw-artifact-report'], tasks: [makeTask('qimingclaw-artifact-1430', 'artifact', '生成产物索引', 'pending', 'qimingclaw-artifact-report', null, null)] }, ]), makeMission('qimingclaw-sync-1630', '16:30 管理端同步诊断', '检查 outbox 失败、退避状态和最近同步尝试。', 'draft', todayAt(16, 10), [ { id: 'sync-diagnostics', title: '生成同步诊断', status: 'pending', preferredSkills: ['qimingclaw-sync-diagnostics'], tasks: [makeTask('qimingclaw-sync-1630', 'sync-diagnostics', '导出同步诊断', 'pending', 'qimingclaw-sync-diagnostics', null, null)] }, ]), makeMission('qimingclaw-daily-report', '18:00 本地日报生成', '基于 qimingclaw workday 投影生成可下载文本日报。', 'draft', todayAt(17, 10), [ { id: 'daily-report', title: '生成数字员工日报', status: 'pending', preferredSkills: ['qimingclaw-daily-report'], tasks: [makeTask('qimingclaw-daily-report', 'daily-report', '整理日报文本', 'pending', 'qimingclaw-daily-report', null, null)] }, ]), makeMission('zhihu-hotlist-monitor', '知乎热榜采集', '通过计划模板调用知乎热榜采集技能,导出表格文件并生成当天热点摘要。', 'approved', todayAt(10, 12), [ { id: 'collect-zhihu', title: '采集知乎热榜', status: 'pending', preferredSkills: ['zhihu-hotlist'], tasks: [makeTask('zhihu-hotlist-monitor', 'collect-zhihu', '采集知乎热榜', 'pending', 'zhihu-hotlist', null, null)] }, { id: 'export-xlsx', title: '导出表格文件', status: 'pending', preferredSkills: ['office-export-xlsx'], tasks: [makeTask('zhihu-hotlist-monitor', 'export-xlsx', '导出热榜表格', 'pending', 'office-export-xlsx', null, null)] }, ]), ]; function cloneMission(mission: Mission): Mission { return { ...mission, steps: mission.steps.map((step) => ({ ...step, preferredSkills: [...step.preferredSkills], tasks: step.tasks.map((task) => ({ ...task })), })), sourceIds: { planId: mission.sourceIds.planId, taskIds: [...mission.sourceIds.taskIds] }, }; } export function getDemoMissions(): Mission[] { return DEMO_MISSIONS.map(cloneMission); } export function getDemoSkills(): SkillSummary[] { return DEMO_SKILLS.map((skill) => ({ ...skill })); } export function buildDemoTasks(missions: Mission[]): DebugTask[] { return missions.flatMap((mission) => mission.steps.flatMap((step) => step.tasks.map((task) => ({ task_id: task.id, title: task.title, status: task.status, plan_id: mission.id, step_id: step.id, assigned_skill_id: task.assignedSkillId || '', description: `${mission.title} · ${step.title}`, created_at: mission.createdAt || todayAt(8, 0), updated_at: mission.updatedAt || mission.createdAt || todayAt(8, 0), started_at: task.startedAt, finished_at: task.finishedAt, })))); } export function buildDemoRuns(tasks: DebugTask[]): DebugRun[] { return tasks .filter((task) => ['completed', 'running'].includes(task.status)) .map((task, index) => ({ run_id: `qimingclaw-fallback-run-${index + 1}`, task_id: task.task_id, plan_id: task.plan_id, attempt_no: 1, lifecycle: task.status === 'running' ? 'Running' : 'Succeeded', created_at: task.started_at || task.created_at, completed_at: task.finished_at, })); } export function buildDemoOverview(tasks: DebugTask[]): DashboardOverview { return { generatedAt: new Date().toISOString(), isPartial: true, sources: [{ endpoint: 'qimingclaw-fallback', ok: true, loadedAt: new Date().toISOString() }], taskTotals: { total: tasks.length, queued: tasks.filter((task) => task.status === 'pending').length, running: tasks.filter((task) => task.status === 'running').length, succeeded: tasks.filter((task) => task.status === 'completed').length, failed: 0, }, approvals: { total: 1, pending: 1 }, health: { activeTasks: tasks.filter((task) => task.status === 'running').length, failedTasks: 0, pendingConfirmations: 1 }, }; } export function buildDemoPlans(missions: Mission[]): DebugPlan[] { return missions.map((mission) => ({ plan_id: mission.id, title: mission.title, objective: mission.objective, status: mission.status, created_at: mission.createdAt || todayAt(8, 0), steps: mission.steps.map((step) => ({ step_id: step.id, title: step.title, depends_on: [], preferred_skills: step.preferredSkills, tasks: step.tasks.map((task) => ({ task_id: task.id, title: task.title, status: task.status, })), })), })); } export function buildDemoJournalEntries(missions: Mission[]): JournalEntry[] { return missions .slice(0, 8) .map((mission, index) => ({ id: `qimingclaw-fallback-journal-${index + 1}`, kind: mission.status === 'completed' ? 'completed' : mission.status === 'active' || mission.status === 'running' ? 'start' : 'pending_authorization', source: 'qimingclaw-fallback', message: `${mission.title}:${mission.objective}`, occurredAt: mission.updatedAt, planId: mission.id, taskId: mission.sourceIds.taskIds[0] || null, })); } export function buildDemoFlowEvents(mission: Mission): NonNullable { const activeStep = mission.steps.find((step) => step.status === 'running') || mission.steps.find((step) => step.status === 'pending') || mission.steps[0]; const events: NonNullable = [ { event_id: `${mission.id}-event-1`, kind: 'entered_session', occurred_at: mission.createdAt || todayAt(8, 0), message: `已接收场景:${mission.title}` }, { event_id: `${mission.id}-event-2`, kind: 'start', occurred_at: mission.updatedAt || mission.createdAt || todayAt(8, 0), message: `当前目标:${mission.objective}` }, ]; if (activeStep) { events.push({ event_id: `${mission.id}-event-3`, kind: mission.status === 'completed' ? 'completed' : mission.status === 'approved' || mission.status === 'draft' ? 'pending_authorization' : 'RunStarted', occurred_at: mission.updatedAt || mission.createdAt || todayAt(8, 0), message: `${activeStep.title}`, }); } if (mission.status === 'completed') { events.push({ event_id: `${mission.id}-event-4`, kind: 'RunCompleted', occurred_at: mission.updatedAt || mission.createdAt || todayAt(8, 0), message: '已完成本场景执行并回写结果。', }); } return events; } export function buildDemoPlanMessages(mission: Mission): PlanMessage[] { const completedSteps = mission.steps.filter((step) => step.status === 'completed').length; const runningStep = mission.steps.find((step) => step.status === 'running'); const closing = mission.status === 'completed' ? `当前已完成全部 ${mission.steps.length} 个步骤,结果已整理完毕。` : runningStep ? `当前正在处理“${runningStep.title}”,已完成 ${completedSteps} 个步骤。` : `当前场景已准备就绪,可直接发起执行。`; return [ { role: 'user', content: `请执行场景:${mission.title}` }, { role: 'assistant', content: `已接收。业务目标:${mission.objective}` }, { role: 'assistant', content: closing }, ]; } export function runDemoMissionOnce(missions: Mission[], missionId: string): Mission[] { return missions.map((mission) => { if (mission.id !== missionId) return mission; return { ...mission, status: 'running', updatedAt: new Date().toISOString(), steps: mission.steps.map((step, index) => ({ ...step, status: index === 0 ? 'running' : step.status === 'completed' ? 'completed' : 'pending', tasks: step.tasks.map((task) => ({ ...task, status: index === 0 ? 'running' : task.status === 'completed' ? 'completed' : 'pending', startedAt: index === 0 ? new Date().toISOString() : task.startedAt, finishedAt: index === 0 ? null : task.finishedAt, })), })), }; }); } export function completeDemoMissionOnce(missions: Mission[], missionId: string): Mission[] { return missions.map((mission) => { if (mission.id !== missionId) return mission; return { ...mission, status: 'completed', updatedAt: new Date().toISOString(), steps: mission.steps.map((step) => ({ ...step, status: 'completed', tasks: step.tasks.map((task) => ({ ...task, status: 'completed', startedAt: task.startedAt || new Date().toISOString(), finishedAt: new Date().toISOString(), })), })), }; }); }