{"version":3,"file":"doctor-command.mjs","names":[],"sources":["../../../src/commands/doctor-command.ts"],"sourcesContent":["/**\n * /doctor command — comprehensive diagnostic check for OpenClawnch.\n *\n * Inspired by ZeroClaw's `zeroclaw doctor` and `zeroclaw channel doctor`.\n * Checks: wallet connectivity, RPC health, API key validity, channel auth,\n * plan scheduler state, endpoint allowlist, and credential vault status.\n *\n * Zero-cost: bypasses the LLM entirely for instant results.\n */\n\nimport { getWalletState } from '../services/walletconnect-service.js';\nimport { getRpcManager } from '../services/rpc-provider.js';\nimport { getAllToolStatus } from '../services/tool-config-service.js';\nimport { getUserMode } from '../services/mode-service.js';\nimport { getCredentialVault } from '../services/credential-vault.js';\nimport { getAllowedHosts } from '../services/endpoint-allowlist.js';\nimport { getBudgetService } from '../services/budget-service.js';\nimport { getTxLedger } from '../services/tx-ledger.js';\nimport { getHeartbeatMonitor } from '../services/heartbeat-monitor.js';\nimport { getMarketCache } from '../services/market-cache.js';\n\nfunction getSenderId(ctx: any): string {\n  return ctx?.senderId ?? ctx?.from ?? ctx?.metadata?.senderId ?? 'unknown';\n}\n\ninterface DiagnosticResult {\n  label: string;\n  status: 'ok' | 'warn' | 'fail' | 'skip';\n  detail: string;\n}\n\nasync function runDiagnostics(userId: string): Promise<DiagnosticResult[]> {\n  const results: DiagnosticResult[] = [];\n\n  // ── 1. Wallet Connectivity ──────────────────────────────────────────\n  try {\n    const state = getWalletState();\n    if (state.connected && state.address) {\n      results.push({\n        label: 'Wallet',\n        status: 'ok',\n        detail: `Connected (${state.mode}) — ${state.address.slice(0, 6)}...${state.address.slice(-4)}`,\n      });\n    } else {\n      results.push({\n        label: 'Wallet',\n        status: 'warn',\n        detail: 'Not connected. Use /connect to pair a wallet.',\n      });\n    }\n  } catch (err) {\n    results.push({\n      label: 'Wallet',\n      status: 'fail',\n      detail: `Error checking wallet: ${err instanceof Error ? err.message : String(err)}`,\n    });\n  }\n\n  // ── 2. RPC Health ───────────────────────────────────────────────────\n  try {\n    const rpc = getRpcManager();\n    const client = await rpc.getClient('base');\n    const blockNumber = await client.getBlockNumber();\n    results.push({\n      label: 'RPC (Base)',\n      status: 'ok',\n      detail: `Connected — latest block #${blockNumber}`,\n    });\n  } catch (err) {\n    results.push({\n      label: 'RPC (Base)',\n      status: 'fail',\n      detail: `Cannot reach Base RPC: ${err instanceof Error ? err.message : String(err)}`,\n    });\n  }\n\n  // ── 3. RPC Provider Health Report ───────────────────────────────────\n  try {\n    const rpc = getRpcManager();\n    const health = rpc.getHealthReport(8453);\n    const available = health.filter(h => h.available).length;\n    const total = health.length;\n    const circuitOpen = health.filter(h => h.circuitOpen);\n\n    if (circuitOpen.length > 0) {\n      results.push({\n        label: 'RPC Providers',\n        status: 'warn',\n        detail: `${available}/${total} available. Circuit open: ${circuitOpen.map(h => h.name).join(', ')}`,\n      });\n    } else {\n      results.push({\n        label: 'RPC Providers',\n        status: 'ok',\n        detail: `${available}/${total} providers available`,\n      });\n    }\n  } catch {\n    results.push({ label: 'RPC Providers', status: 'skip', detail: 'Could not check provider health' });\n  }\n\n  // ── 4. API Keys Status ──────────────────────────────────────────────\n  try {\n    const vault = getCredentialVault();\n    const summary = vault.getConfigurationSummary();\n    const critical = summary.filter(s => s.sensitive === 'critical');\n    const high = summary.filter(s => s.sensitive === 'high');\n    const configured = summary.filter(s => s.configured);\n\n    const criticalMissing = critical.filter(s => !s.configured);\n    if (criticalMissing.length > 0) {\n      results.push({\n        label: 'Secrets',\n        status: 'warn',\n        detail: `Missing: ${criticalMissing.map(s => s.envVar).join(', ')}`,\n      });\n    } else {\n      results.push({\n        label: 'Secrets',\n        status: 'ok',\n        detail: `All ${critical.length} required secrets configured`,\n      });\n    }\n\n    results.push({\n      label: 'API Keys',\n      status: configured.length > summary.length / 2 ? 'ok' : 'warn',\n      detail: `${configured.length}/${summary.length} configured`,\n    });\n  } catch {\n    results.push({ label: 'API Keys', status: 'skip', detail: 'Could not check credential vault' });\n  }\n\n  // ── 5. Tool Configuration ──────────────────────────────────────────\n  try {\n    const toolStatus = getAllToolStatus();\n    const configured = toolStatus.filter(t => t.configured);\n    const unconfigured = toolStatus.filter(t => !t.configured);\n\n    results.push({\n      label: 'Tools',\n      status: unconfigured.length > 5 ? 'warn' : 'ok',\n      detail: `${configured.length}/${toolStatus.length} tools ready` +\n        (unconfigured.length > 0 ? `. Missing config: ${unconfigured.slice(0, 3).map(t => t.label).join(', ')}${unconfigured.length > 3 ? ` +${unconfigured.length - 3} more` : ''}` : ''),\n    });\n  } catch {\n    results.push({ label: 'Tools', status: 'skip', detail: 'Could not check tool config' });\n  }\n\n  // ── 6. Safety Mode ─────────────────────────────────────────────────\n  try {\n    const mode = getUserMode(userId);\n    const isDualDanger = mode.safetyMode === 'danger' && mode.signingMode === 'autosign';\n    results.push({\n      label: 'Safety Mode',\n      status: isDualDanger ? 'warn' : 'ok',\n      detail: `Safety: ${mode.safetyMode} | Signing: ${mode.signingMode}` +\n        (isDualDanger ? ' — MAXIMUM RISK: danger + autosign active!' : ''),\n    });\n  } catch {\n    results.push({ label: 'Safety Mode', status: 'skip', detail: 'Could not check mode' });\n  }\n\n  // ── 7. Endpoint Allowlist ──────────────────────────────────────────\n  try {\n    const mode = process.env.OPENCLAWNCH_ALLOWLIST_MODE ?? 'enforce';\n    const hosts = getAllowedHosts();\n    results.push({\n      label: 'Endpoint Allowlist',\n      status: mode === 'off' ? 'warn' : 'ok',\n      detail: `Mode: ${mode} | ${hosts.length} hosts allowed` +\n        (mode === 'off' ? ' — WARNING: allowlist disabled, all endpoints reachable' : ''),\n    });\n  } catch {\n    results.push({ label: 'Endpoint Allowlist', status: 'skip', detail: 'Could not check allowlist' });\n  }\n\n  // ── 8. Budget Service ──────────────────────────────────────────────\n  try {\n    const budget = getBudgetService();\n    const activeSession = budget.getActiveSession(userId);\n    if (activeSession) {\n      const check = budget.checkBudget(activeSession.id);\n      results.push({\n        label: 'Budget Tracker',\n        status: check.ok ? 'ok' : 'warn',\n        detail: `Active session: $${check.totalCostUsd.toFixed(2)} spent, $${check.remainingTotalUsd.toFixed(2)} remaining`,\n      });\n    } else {\n      results.push({\n        label: 'Budget Tracker',\n        status: 'ok',\n        detail: 'No active budget session',\n      });\n    }\n  } catch {\n    results.push({ label: 'Budget Tracker', status: 'skip', detail: 'Could not check budget service' });\n  }\n\n  // ── 9. Plan Scheduler ──────────────────────────────────────────────\n  try {\n    const { getScheduler } = await import('../services/plan-scheduler.js');\n    const scheduler = getScheduler();\n    const activeCount = scheduler.activeCount;\n    results.push({\n      label: 'Plan Scheduler',\n      status: 'ok',\n      detail: `Running — ${activeCount} active plan${activeCount !== 1 ? 's' : ''}`,\n    });\n  } catch {\n    results.push({\n      label: 'Plan Scheduler',\n      status: 'warn',\n      detail: 'Scheduler not initialized (may not have started yet)',\n    });\n  }\n\n  // ── 10. Transaction Ledger ──────────────────────────────────────\n  try {\n    const ledger = getTxLedger();\n    const stats = ledger.getStats();\n    results.push({\n      label: 'Transaction Ledger',\n      status: 'ok',\n      detail: `${stats.totalEvents} events recorded` +\n        (stats.totalEvents > 0 ? ` (${Object.entries(stats.byType).map(([k, v]) => `${k}: ${v}`).join(', ')})` : ''),\n    });\n  } catch {\n    results.push({ label: 'Transaction Ledger', status: 'skip', detail: 'Could not check ledger' });\n  }\n\n  // ── 11. Heartbeat Monitor ──────────────────────────────────────\n  try {\n    const heartbeat = getHeartbeatMonitor();\n    const status = heartbeat.getStatus();\n    results.push({\n      label: 'Heartbeat Monitor',\n      status: status.running ? 'ok' : (status.enabled ? 'warn' : 'ok'),\n      detail: status.running\n        ? `Running — ${status.trackedPositions} positions tracked, ${status.totalAlerts} alerts, interval: ${status.intervalMs / 1000}s`\n        : status.enabled\n          ? 'Enabled but not running (will start on gateway_start)'\n          : 'Disabled (set OPENCLAWNCH_HEARTBEAT_ENABLED=true to enable)',\n    });\n  } catch {\n    results.push({ label: 'Heartbeat Monitor', status: 'skip', detail: 'Could not check heartbeat' });\n  }\n\n  // ── 12. Market Cache ──────────────────────────────────────────\n  try {\n    const cache = getMarketCache();\n    const stats = cache.getStats();\n    results.push({\n      label: 'Market Cache',\n      status: 'ok',\n      detail: `${stats.entries} entries, ${stats.hitRate}% hit rate (${stats.hits} hits, ${stats.misses} misses, ${stats.staleServes} stale serves)`,\n    });\n  } catch {\n    results.push({ label: 'Market Cache', status: 'skip', detail: 'Could not check market cache' });\n  }\n\n  // ── 13. Channel Status ─────────────────────────────────────────────\n  const channels = [\n    { name: 'Telegram', envVar: 'TELEGRAM_BOT_TOKEN' },\n    { name: 'Discord', envVar: 'DISCORD_TOKEN' },\n    { name: 'Slack', envVar: 'SLACK_BOT_TOKEN' },\n  ];\n\n  for (const ch of channels) {\n    const configured = !!process.env[ch.envVar];\n    if (configured) {\n      results.push({\n        label: `Channel: ${ch.name}`,\n        status: 'ok',\n        detail: `${ch.envVar} configured`,\n      });\n    }\n  }\n\n  const anyChannel = channels.some(ch => !!process.env[ch.envVar]);\n  if (!anyChannel) {\n    results.push({\n      label: 'Channels',\n      status: 'warn',\n      detail: 'No messaging channels configured. Set TELEGRAM_BOT_TOKEN, DISCORD_TOKEN, or SLACK_BOT_TOKEN.',\n    });\n  }\n\n  return results;\n}\n\nconst STATUS_ICONS: Record<string, string> = {\n  ok: '[OK]',\n  warn: '[!!]',\n  fail: '[FAIL]',\n  skip: '[--]',\n};\n\n/** Section groupings for diagnostics output. */\nconst SECTIONS: Array<{ title: string; labels: string[] }> = [\n  {\n    title: 'Infrastructure',\n    labels: ['Wallet', 'RPC (Base)', 'RPC Providers', 'Channel: Telegram', 'Channel: Discord', 'Channel: Slack', 'Channels'],\n  },\n  {\n    title: 'Security',\n    labels: ['Safety Mode', 'Endpoint Allowlist', 'API Keys', 'Secrets'],\n  },\n  {\n    title: 'Services',\n    labels: ['Tools', 'Plan Scheduler', 'Heartbeat Monitor', 'Market Cache', 'Transaction Ledger', 'Budget Tracker'],\n  },\n];\n\nexport const doctorCommand = {\n  name: 'doctor',\n  description: 'Run diagnostics — check wallet, RPC, API keys, channels, security, and scheduler health',\n  acceptsArgs: false,\n  requireAuth: true,\n  handler: async (ctx: any) => {\n    const userId = getSenderId(ctx);\n    const results = await runDiagnostics(userId);\n\n    const lines = ['**Diagnostics**', ''];\n\n    // Build a lookup by label for sectioned output\n    const byLabel = new Map(results.map(r => [r.label, r]));\n    const rendered = new Set<string>();\n\n    for (const section of SECTIONS) {\n      const sectionResults = section.labels\n        .map(l => byLabel.get(l))\n        .filter((r): r is DiagnosticResult => r != null);\n\n      if (sectionResults.length > 0) {\n        lines.push(`**${section.title}**`);\n        for (const r of sectionResults) {\n          lines.push(`  ${STATUS_ICONS[r.status]} ${r.label}: ${r.detail}`);\n          rendered.add(r.label);\n        }\n        lines.push('');\n      }\n    }\n\n    // Any results not in a section (future-proofing)\n    const ungrouped = results.filter(r => !rendered.has(r.label));\n    if (ungrouped.length > 0) {\n      lines.push('**Other**');\n      for (const r of ungrouped) {\n        lines.push(`  ${STATUS_ICONS[r.status]} ${r.label}: ${r.detail}`);\n      }\n      lines.push('');\n    }\n\n    const okCount = results.filter(r => r.status === 'ok').length;\n    const warnCount = results.filter(r => r.status === 'warn').length;\n    const failCount = results.filter(r => r.status === 'fail').length;\n\n    lines.push(`${okCount} ok, ${warnCount} warnings, ${failCount} failures`);\n\n    if (failCount > 0) {\n      lines.push('', 'Fix failures above to ensure proper operation.');\n    } else if (warnCount > 0) {\n      lines.push('', 'Warnings are non-critical but worth reviewing.');\n    } else {\n      lines.push('', 'All checks passed.');\n    }\n\n    return { text: lines.join('\\n') };\n  },\n};\n"],"mappings":"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"}