{"version":3,"file":"reset-command.mjs","names":[],"sources":["../../../src/commands/reset-command.ts"],"sourcesContent":["/**\n * /reset command — wipe onboarding state, sessions, WC pairing, and credentials.\n * Requires double confirmation: /reset → /reset confirm\n *\n * After reset, the next message from any user triggers pairing + onboarding again.\n */\n\nimport { existsSync, rmSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { resetOnboardingFlows } from '../services/onboarding-flow.js';\nimport { resetModes } from '../services/mode-service.js';\n\n/** Track pending confirmations by sender (expire after 60s). */\nconst pendingConfirmations = new Map<string, number>();\n\n/** Resolve persistent state dir (volume mount). Checks both old and new names. */\nfunction getStateRoot(): string {\n  return '/workspace/.openclaw-state';\n}\n\n/** Resolve OpenClaw/OpenClawnch home state dir. */\nfunction getOpenClawHome(): string {\n  const base = process.env.HOME ?? '/root';\n  // Check both old (.openclaw) and new (.openclawnch) directory names\n  const newPath = join(base, '.openclawnch');\n  const oldPath = join(base, '.openclaw');\n  try {\n    const { existsSync } = require('node:fs');\n    if (existsSync(newPath)) return newPath;\n  } catch {}\n  return oldPath; // fallback to legacy path\n}\n\nexport const resetCommand = {\n  name: 'factoryreset',\n  description: 'Factory reset: wipe all state. Tap /factoryreset_confirm after.',\n  acceptsArgs: true,\n  requireAuth: true,\n\n  handler: async (ctx: any) => {\n    const senderId = ctx?.senderId ?? ctx?.from ?? 'unknown';\n    const args = (ctx?.args ?? ctx?.commandBody ?? '').trim().toLowerCase();\n\n    // ── Step 2: Confirm (via /factoryreset confirm or /factoryreset_confirm) ──\n    if (args === 'confirm') {\n      const pending = pendingConfirmations.get(senderId);\n      if (!pending || Date.now() - pending > 60_000) {\n      return {\n        text: 'No pending reset. Run /factoryreset first, then /factoryreset_confirm within 60 seconds.',\n      };\n      }\n\n      pendingConfirmations.delete(senderId);\n\n      const wiped: string[] = [];\n      const errors: string[] = [];\n      const stateRoot = getStateRoot();\n      const openclawHome = getOpenClawHome();\n\n      // 1. Wipe onboarding state (volume)\n      const onboardingDir = join(stateRoot, 'onboarding');\n      if (existsSync(onboardingDir)) {\n        try {\n          rmSync(onboardingDir, { recursive: true, force: true });\n          wiped.push('onboarding state');\n        } catch (e) {\n          errors.push(`onboarding: ${e instanceof Error ? e.message : String(e)}`);\n        }\n      }\n\n      // 2. Wipe WalletConnect session (volume)\n      const wcDir = join(stateRoot, 'wc');\n      if (existsSync(wcDir)) {\n        try {\n          rmSync(wcDir, { recursive: true, force: true });\n          wiped.push('WalletConnect session');\n        } catch (e) {\n          errors.push(`wc: ${e instanceof Error ? e.message : String(e)}`);\n        }\n      }\n\n      // 3. Wipe sessions (volume)\n      const sessionsDir = join(stateRoot, 'sessions');\n      if (existsSync(sessionsDir)) {\n        try {\n          // Remove contents but keep the directory (symlink target)\n          for (const f of readdirSync(sessionsDir)) {\n            rmSync(join(sessionsDir, f), { recursive: true, force: true });\n          }\n          wiped.push('conversation sessions');\n        } catch (e) {\n          errors.push(`sessions: ${e instanceof Error ? e.message : String(e)}`);\n        }\n      }\n\n      // 4. Wipe credentials (volume) — this removes pairing approvals\n      const credsDir = join(stateRoot, 'credentials');\n      if (existsSync(credsDir)) {\n        try {\n          for (const f of readdirSync(credsDir)) {\n            rmSync(join(credsDir, f), { force: true });\n          }\n          wiped.push('credentials/pairing');\n        } catch (e) {\n          errors.push(`credentials: ${e instanceof Error ? e.message : String(e)}`);\n        }\n      }\n\n      // 5. Also wipe the OpenClaw home copies (symlinked, but just in case)\n      for (const sub of ['credentials', 'agents/main/sessions']) {\n        const dir = join(openclawHome, sub);\n        if (existsSync(dir)) {\n          try {\n            for (const f of readdirSync(dir)) {\n              rmSync(join(dir, f), { recursive: true, force: true });\n            }\n          } catch {\n            // Best effort — volume wipe is primary\n          }\n        }\n      }\n\n      // 6. Reset in-memory caches\n      resetOnboardingFlows();\n      resetModes();\n\n      // 6b. Wipe mode state (volume)\n      const modesDir = join(stateRoot, 'modes');\n      if (existsSync(modesDir)) {\n        try {\n          rmSync(modesDir, { recursive: true, force: true });\n          wiped.push('mode preferences');\n        } catch (e) {\n          errors.push(`modes: ${e instanceof Error ? e.message : String(e)}`);\n        }\n      }\n\n      // 7. Wipe tx history (volume)\n      const txDir = join(stateRoot, 'tx');\n      if (existsSync(txDir)) {\n        try {\n          rmSync(txDir, { recursive: true, force: true });\n          wiped.push('transaction history');\n        } catch (e) {\n          errors.push(`tx: ${e instanceof Error ? e.message : String(e)}`);\n        }\n      }\n\n      let msg = `Factory reset complete.\\n\\nWiped: ${wiped.length > 0 ? wiped.join(', ') : 'nothing found'}`;\n      if (errors.length > 0) {\n        msg += `\\n\\nErrors:\\n${errors.map(e => `  - ${e}`).join('\\n')}`;\n      }\n      msg += '\\n\\nYour next message will require re-pairing. Send any message to start fresh.';\n\n      return { text: msg };\n    }\n\n    // ── Step 1: Warn ───────────────────────────────────────────────\n    pendingConfirmations.set(senderId, Date.now());\n\n    return {\n      text: `WARNING: This will permanently delete:\n\n  - Onboarding preferences (persona, capabilities)\n  - Conversation history (all sessions)\n  - WalletConnect wallet pairing\n  - Sender credentials (you'll need to re-pair)\n  - Transaction history\n\nThis cannot be undone.\n\nTo confirm, tap /factoryreset_confirm within 60 seconds.`,\n    };\n  },\n};\n\n/** Tappable alias for /factoryreset confirm. */\nexport const resetConfirmCommand = {\n  name: 'factoryreset_confirm',\n  description: 'Confirm a pending factory reset',\n  acceptsArgs: false,\n  requireAuth: true,\n  handler: async (ctx: any) => {\n    // Delegate to the main handler with args='confirm'\n    return resetCommand.handler({ ...ctx, args: 'confirm', commandBody: 'confirm' });\n  },\n};\n"],"mappings":"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"}