{"version":3,"file":"index.mjs","names":["restartOnboardingCommand","restartCommand","getWalletStateFn"],"sources":["../index.ts"],"sourcesContent":["/**\n * @clawnch/openclaw-crypto — OpenClaw extension for crypto/DeFi\n * \n * Registers tools, commands, and hooks with the OpenClaw plugin system.\n * This is the entry point loaded by OpenClaw's plugin loader.\n * \n * Works both as:\n * 1. Bundled extension in OpenClawnch (thin wrapper)\n * 2. Standalone extension for vanilla OpenClaw (`clawhub install @clawnch/openclaw-crypto`)\n */\n\n// ── Plugin API type from OpenClaw SDK ────────────────────────────────────\n// Type-only import: provides compile-time checking without runtime coupling.\nimport type { OpenClawPluginApi } from 'openclaw/plugin-sdk/core';\n\n// Tools — Core (13 original)\nimport { createClawnchConnectTool } from './src/tools/clawnchconnect.js';\nimport { createDefiPriceTool } from './src/tools/defi-price.js';\nimport { createDefiBalanceTool } from './src/tools/defi-balance.js';\nimport { createDefiSwapTool } from './src/tools/defi-swap.js';\nimport { createClawnchLaunchTool } from './src/tools/clawnch-launch.js';\nimport { createClawnchFeesTool } from './src/tools/clawnch-fees.js';\nimport { createMarketIntelTool } from './src/tools/market-intel.js';\nimport { createHummingbotTool } from './src/tools/hummingbot.js';\nimport { createManageOrdersTool } from './src/tools/manage-orders.js';\nimport { createWatchActivityTool } from './src/tools/watch-activity.js';\nimport { createClawnXTool } from './src/tools/clawnx.js';\nimport { createHerdIntelligenceTool } from './src/tools/herd-intelligence.js';\nimport { createCryptoWorkflowTool } from './src/tools/crypto-workflow.js';\n\n// Tools — Phase 2 (4 new: critical gap coverage)\nimport { createTransferTool } from './src/tools/transfer.js';\nimport { createLiquidityTool } from './src/tools/liquidity.js';\nimport { createWayfinderTool } from './src/tools/wayfinder.js';\nimport { createClawnchInfoTool } from './src/tools/clawnch-info.js';\n\n// Tools — Phase 3 (4 new: Permit2, cost basis, analytics, block explorer)\nimport { createPermit2Tool } from './src/tools/permit2.js';\nimport { createCostBasisTool } from './src/tools/cost-basis.js';\nimport { createAnalyticsTool } from './src/tools/analytics.js';\nimport { createBlockExplorerTool } from './src/tools/block-explorer.js';\n\n// Tools — Phase 4 (bridge aggregation)\nimport { createBridgeTool } from './src/tools/bridge.js';\n\n// Tools — Phase 5 (Molten agent-to-agent matching)\nimport { createMoltenTool } from './src/tools/molten.js';\n\n// Tools — Phase 6 (Bankr Agent API)\nimport { createBankrLaunchTool } from './src/tools/bankr-launch.js';\nimport { createBankrAutomateTool } from './src/tools/bankr-automate.js';\nimport { createBankrPolymarketTool } from './src/tools/bankr-polymarket.js';\nimport { createBankrLeverageTool } from './src/tools/bankr-leverage.js';\n\n// Tools — Phase 7 (Compound Operations Engine)\nimport { createCompoundActionTool } from './src/tools/compound-action.js';\n\n// Tools — Phase 10 (DeFi Primitives Expansion)\nimport { createDefiLendTool } from './src/tools/defi-lend.js';\nimport { createApprovalsTool } from './src/tools/approvals.js';\nimport { createDefiStakeTool } from './src/tools/defi-stake.js';\nimport { createNftTool } from './src/tools/nft.js';\nimport { createYieldTool } from './src/tools/yield.js';\nimport { createGovernanceTool } from './src/tools/governance.js';\nimport { createFarcasterTool } from './src/tools/farcaster.js';\nimport { createSafeTool } from './src/tools/safe.js';\nimport { createAirdropTool } from './src/tools/airdrop.js';\n\n// Tools — Phase 11 (External Integrations)\nimport { createPrivacyTool } from './src/tools/privacy.js';\nimport { createBrowserTool } from './src/tools/browser.js';\n\n// Tools — V3 (Fiat & Traditional Finance Rails)\nimport { createFiatPaymentTool } from './src/tools/fiat-payment.js';\n\n// Commands\nimport { walletCommand } from './src/commands/wallet-command.js';\nimport { policyCommand } from './src/commands/policy-command.js';\nimport { txCommand } from './src/commands/tx-command.js';\nimport { resetCommand, resetConfirmCommand } from './src/commands/reset-command.js';\nimport {\n  professionalCommand, degenCommand, chillCommand, technicalCommand, mentorCommand,\n  capAllCommand, capCommands, skipCommand, backCommand, restartCommand as restartOnboardingCommand,\n  createWalletCommand, importWalletCommand,\n} from './src/commands/onboarding-commands.js';\nimport {\n  safemodeCommand, dangermodeCommand, walletsignCommand, autosignCommand, modeCommand, readonlyCommand,\n} from './src/commands/mode-commands.js';\nimport { doctorCommand } from './src/commands/doctor-command.js';\nimport { rpcCommand } from './src/commands/rpc-command.js';\nimport { connectCommand, walletConnectCommands, setConnectCommandApi, connectBankrCommand, disconnectCommand } from './src/commands/connect-command.js';\nimport { modelCommand, llmShortcutCommands } from './src/commands/model-command.js';\nimport { moltenCommand } from './src/commands/molten-command.js';\nimport { creditsCommand, usageCommand, automationsCommand, topupCommand, autotopupCommand } from './src/commands/bankr-commands.js';\nimport {\n  providerCommand, providerAnthropicCommand, providerBankrCommand, providerOpenrouterCommand,\n  providerOpenaiCommand, flykeysCommand, flystatusCommand, flyrestartCommand,\n} from './src/commands/fly-commands.js';\nimport { setupCommand } from './src/commands/setup-command.js';\nimport { recoverCommand, exportWalletCommand, walletBackupCommand } from './src/commands/wallet-manage-commands.js';\nimport { plansCommand, plansActiveCommand, plansCancelCommand, plansClearCommand } from './src/commands/plans-command.js';\nimport { triggersCommand, triggersPriceCommand, triggersCronCommand, deadLetterCommand } from './src/commands/trigger-commands.js';\nimport { approveCommand, denyCommand } from './src/commands/confirm-commands.js';\nimport { helpCommand, portfolioCommand, balanceCommand, chainCommand } from './src/commands/help-command.js';\nimport { reportCommand, reportOptInCommand, reportOptOutCommand } from './src/commands/report-command.js';\nimport { isReadonly } from './src/services/mode-service.js';\n\n// Services\nimport { initWalletService, getWalletState as getWalletStateFn } from './src/services/walletconnect-service.js';\nimport { getOnboardingFlow, type OnboardingMessage } from './src/services/onboarding-flow.js';\nimport { getCredentialVault } from './src/services/credential-vault.js';\nimport { getHeartbeatMonitor } from './src/services/heartbeat-monitor.js';\nimport { getScheduler } from './src/services/plan-scheduler.js';\nimport { createPendingConfirmation } from './src/services/confirmation-store.js';\nimport { persistForumTopics, restoreForumTopics } from './src/services/forum-topics.js';\nimport { persistThreadBindings, restoreThreadBindings } from './src/services/thread-bindings.js';\nimport { persistOrders, restoreOrders } from './src/tools/manage-orders.js';\n\n// Self-improvement services (sprint 4)\nimport { getEvolutionMode } from './src/services/evolution-mode.js';\nimport { getSessionRecall } from './src/services/session-recall.js';\n\n// Self-improvement tools (sprint 4)\nimport { createAgentMemoryTool } from './src/tools/agent-memory.js';\nimport { createSkillEvolveTool } from './src/tools/skill-evolve.js';\nimport { createSessionRecallTool } from './src/tools/session-recall.js';\n\n// Self-improvement commands (sprint 4)\nimport { evolveCommand, stableCommand, evolutionCommand } from './src/commands/evolve-command.js';\n\n// Forum topics + thread bindings commands (sprint 8)\nimport { topicsCommand, topicsSetupCommand, topicBindCommand, topicUnbindCommand } from './src/commands/forum-commands.js';\n\n// V3: Fiat commands\nimport { fiatCommand } from './src/commands/fiat-command.js';\n\n// V4: User-defined tools\nimport { toolsCommand } from './src/commands/tools-command.js';\nimport { compileAllEnabledTools } from './src/services/tool-compiler.js';\nimport type { ToolDispatcher } from './src/services/sandbox-runtime.js';\n\n// V5: Multi-agent + Webhooks\nimport { createAgentDelegateTool } from './src/tools/agent-delegate.js';\nimport { agentsCommand } from './src/commands/agents-command.js';\nimport { webhooksCommand } from './src/commands/webhooks-command.js';\n\n// Skill registry + /skills command\nimport { skillsCommand } from './src/commands/skills-command.js';\n\n// Interrupt commands + service\nimport { interruptCommand, interruptPlanCommand } from './src/commands/interrupt-command.js';\nimport { getInterruptService } from './src/services/interrupt-service.js';\n\n// API key management\nimport { apiCommand } from './src/commands/api-command.js';\n\n// Usage reporting\nimport { usageNewCommand } from './src/commands/usage-command.js';\n\n// Update + restart from Telegram\nimport { updateCommand, restartCommand, setUpdateCommandSender } from './src/commands/update-command.js';\n\n// Pull files from the running bot\nimport { pullCommand } from './src/commands/pull-command.js';\n\n// Policy engine — spending policies, approval rules, autonomy bounds\nimport { createPolicyManageTool } from './src/tools/policy-manage.js';\nimport { policiesCommand } from './src/commands/policies-command.js';\nimport { evaluatePolicies, extractActionContext, recordToolExecution, getPolicyConfirmationStore, extractPolicyUserId } from './src/services/policy-evaluator.js';\n\n// Delegation — EIP-7710 on-chain policy enforcement\nimport { delegateCommand } from './src/commands/delegate-command.js';\nimport { policymodeCommand } from './src/commands/policymode-command.js';\nimport { profileCommand } from './src/commands/profile-command.js';\nimport { upgradeCommand } from './src/commands/upgrade-command.js';\nimport { agentAccountCommand } from './src/commands/agent-account-command.js';\nimport { commandsAllCommand } from './src/commands/commands-list.js';\nimport { tryDelegationExecution } from './src/services/delegation-executor.js';\n\n// Typing indicator — Telegram \"typing...\" action during agent thinking\nimport { getTypingIndicator } from './src/services/typing-indicator.js';\n\n// Extracted hook logic\nimport { buildPromptContext } from './src/hooks/prompt-builder.js';\nimport { handleAfterToolCall } from './src/hooks/after-tool-call.js';\n\n// Channel abstraction — multi-channel message sending\nimport {\n  createChannelSender,\n  parseSessionKey,\n  extractSenderId,\n  extractChannelId,\n  type ChannelId,\n} from './src/services/channel-sender.js';\n\n/**\n * OpenClaw Plugin Definition\n * \n * The `api` parameter is typed via `OpenClawPluginApi` from the plugin SDK.\n * This gives compile-time safety against upstream API changes.\n */\nconst plugin = {\n  id: 'crypto',\n  name: 'Crypto DeFi Tools',\n  description: 'ClawnchConnect wallet, DeFi trading, token launchpad, and market intelligence',\n  version: '0.1.0',\n\n  register(api: OpenClawPluginApi) {\n    // ─── Write Tool Names (for readonly enforcement + ledger recording) ───\n    // Single source of truth: all tools that perform on-chain writes or\n    // financial state changes. Used by readonly gate and tx ledger.\n    const WRITE_TOOL_NAMES = new Set([\n      'defi_swap', 'transfer', 'bridge', 'permit2', 'clawnch_launch',\n      'clawnch_fees', 'liquidity', 'compound_action', 'manage_orders',\n      'bankr_launch', 'bankr_automate', 'bankr_polymarket', 'bankr_leverage',\n      'clawnchconnect', 'molten', 'hummingbot', 'clawnx',\n      'defi_lend', 'approvals', 'defi_stake', 'nft', 'privacy', 'yield', 'browser',\n      'governance', 'farcaster', 'safe', 'airdrop',\n      'fiat_payment',    // V3: fiat off/on-ramp execution\n      // Added in audit: these tools have sub-actions that write on-chain\n      'wayfinder',       // execute_swap, strategy\n      'clawnch_info',    // vault_claim, agent_register\n      'crypto_workflow',  // safe_swap, launch_and_promote\n    ]);\n\n    /**\n     * Wrap a tool with a hard readonly gate + policy enforcement gate.\n     * If the user is in readonly mode, write tools return an error.\n     * If active policies block the action, it returns an error.\n     * If policies require confirmation, it returns a confirmation request.\n     * This is defense-in-depth — the LLM can't bypass by ignoring instructions.\n     */\n    function registerToolWithReadonlyGate(tool: any): void {\n      if (WRITE_TOOL_NAMES.has(tool.name)) {\n        const originalExecute = tool.execute;\n        tool.execute = async (toolCallId: string, args: unknown, ctx?: any) => {\n          // Check if the requesting user is in readonly mode\n          const userId = extractPolicyUserId(ctx);\n          if (isReadonly(userId)) {\n            return {\n              content: [{ type: 'text', text: `BLOCKED: Read-only mode is active. The tool \"${tool.name}\" writes to the blockchain and cannot be used in readonly mode. Use /safemode or /dangermode to re-enable write operations.` }],\n              isError: true,\n            };\n          }\n          // Policy enforcement gate\n          const argsObj = (args ?? {}) as Record<string, unknown>;\n          const actionCtx = extractActionContext(tool.name, argsObj, userId);\n          const decision = evaluatePolicies(actionCtx);\n          if (decision.action === 'block') {\n            return {\n              content: [{ type: 'text' as const, text: `BLOCKED by policy: ${decision.reason ?? 'Policy violation.'}` }],\n              details: { blocked: true, policy: decision.policyName, rule: decision.ruleSummary },\n              isError: true,\n            };\n          }\n          if (decision.action === 'confirm') {\n            // Check if the caller provided a valid confirmation nonce\n            const nonce = argsObj.policyConfirmationNonce as string | undefined;\n            if (nonce) {\n              const confirmStore = getPolicyConfirmationStore();\n              if (confirmStore.consume(nonce, userId, tool.name)) {\n                // Nonce valid — user confirmed, proceed to execution\n                // Try delegation execution first (on-chain), fall back to normal\n                const delegationResult = await tryDelegationExecution(actionCtx, argsObj);\n                if (delegationResult.executed) {\n                  try { recordToolExecution(actionCtx); } catch { /* best-effort */ }\n                  return {\n                    content: [{ type: 'text' as const, text: `Executed via on-chain delegation. Tx: ${delegationResult.txHash} (chain ${delegationResult.chainId})` }],\n                    details: { delegationExecution: true, txHash: delegationResult.txHash, chainId: delegationResult.chainId },\n                  };\n                }\n                // Delegation not available or failed — fall through to normal execution\n                if (delegationResult.skipReason || delegationResult.error) {\n                  console.info(`[delegation] Bypassed for ${tool.name}: ${delegationResult.skipReason ?? delegationResult.error}`);\n                }\n                const result = await originalExecute.call(tool, toolCallId, args, ctx);\n                if (!result?.isError) {\n                  try { recordToolExecution(actionCtx); } catch { /* best-effort */ }\n                }\n                return result;\n              }\n              // Invalid/expired nonce — fall through to hold\n            }\n            // Generate a new nonce for the user to confirm\n            const confirmStore = getPolicyConfirmationStore();\n            const newNonce = confirmStore.create(userId, tool.name);\n            return {\n              content: [{ type: 'text' as const, text: `POLICY HOLD: ${decision.reason ?? 'Confirmation required.'}\\n\\nAsk the user to confirm. Once confirmed, retry this tool call with the parameter policyConfirmationNonce=\"${newNonce}\".` }],\n              details: { needsConfirmation: true, policy: decision.policyName, rule: decision.ruleSummary, confirmationNonce: newNonce },\n              isError: true,\n            };\n          }\n          // action === 'allow' — try delegation execution first, fall back to normal\n          const delegationResult = await tryDelegationExecution(actionCtx, argsObj);\n          if (delegationResult.executed) {\n            try { recordToolExecution(actionCtx); } catch { /* best-effort */ }\n            return {\n              content: [{ type: 'text' as const, text: `Executed via on-chain delegation. Tx: ${delegationResult.txHash} (chain ${delegationResult.chainId})` }],\n              details: { delegationExecution: true, txHash: delegationResult.txHash, chainId: delegationResult.chainId },\n            };\n          }\n          // Delegation not available or failed — normal tool execution\n          if (delegationResult.skipReason || delegationResult.error) {\n            console.info(`[delegation] Bypassed for ${tool.name}: ${delegationResult.skipReason ?? delegationResult.error}`);\n          }\n          const result = await originalExecute.call(tool, toolCallId, args, ctx);\n          // Record usage on success (not on error)\n          if (!result?.isError) {\n            try { recordToolExecution(actionCtx); } catch { /* best-effort */ }\n          }\n          return result;\n        };\n      }\n      api.registerTool(tool);\n    }\n\n    // ─── Register Tools (31 total) ────────────────────────────────\n    // Core tools (13)\n    // Write-operation tools: ownerOnly = true (security: only bot owner can execute financial ops)\n    // Read-only tools: ownerOnly = false (paired users can view prices, balances, etc.)\n    registerToolWithReadonlyGate(createClawnchConnectTool(api));   // ownerOnly: true (wallet management)\n    registerToolWithReadonlyGate(createDefiPriceTool());            // ownerOnly: false (read-only)\n    registerToolWithReadonlyGate(createDefiBalanceTool());           // ownerOnly: false (read-only)\n    registerToolWithReadonlyGate(createDefiSwapTool());              // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createClawnchLaunchTool());         // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createClawnchFeesTool());            // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createMarketIntelTool());           // ownerOnly: false (read-only)\n    registerToolWithReadonlyGate(createHummingbotTool());             // ownerOnly: true (trading bot control)\n    registerToolWithReadonlyGate(createManageOrdersTool());           // ownerOnly: true (order management)\n    registerToolWithReadonlyGate(createWatchActivityTool());          // ownerOnly: false (read-only)\n    registerToolWithReadonlyGate(createClawnXTool());                 // ownerOnly: true (social actions)\n    registerToolWithReadonlyGate(createHerdIntelligenceTool());       // ownerOnly: false (read-only)\n    registerToolWithReadonlyGate(createCryptoWorkflowTool());         // ownerOnly: false (read-only)\n\n    // Phase 2 tools (4) — critical gap coverage\n    registerToolWithReadonlyGate(createTransferTool());              // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createLiquidityTool());             // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createWayfinderTool());             // ownerOnly: false (read-only discovery)\n    registerToolWithReadonlyGate(createClawnchInfoTool());           // ownerOnly: false (read-only)\n\n    // Phase 3 tools (4) — Permit2, cost basis, analytics, block explorer\n    registerToolWithReadonlyGate(createPermit2Tool());               // ownerOnly: true (token approvals)\n    registerToolWithReadonlyGate(createCostBasisTool());             // ownerOnly: false (read-only)\n    registerToolWithReadonlyGate(createAnalyticsTool());             // ownerOnly: false (read-only)\n    registerToolWithReadonlyGate(createBlockExplorerTool());         // ownerOnly: false (read-only)\n\n    // Phase 4 tools (1) — cross-chain bridge\n    registerToolWithReadonlyGate(createBridgeTool());                // ownerOnly: true (financial write)\n\n    // Phase 5 tools (1) — Molten agent-to-agent matching\n    registerToolWithReadonlyGate(createMoltenTool());                // ownerOnly: true (agent registration)\n\n    // Phase 6 tools (4) — Bankr Agent API (launch, automate, polymarket, leverage)\n    registerToolWithReadonlyGate(createBankrLaunchTool());           // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createBankrAutomateTool());         // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createBankrPolymarketTool());       // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createBankrLeverageTool());         // ownerOnly: true (financial write)\n\n    // Phase 7 tools (1) — Compound operations engine\n    registerToolWithReadonlyGate(createCompoundActionTool());        // ownerOnly: true (can trigger financial writes)\n\n    // Phase 10 tools — DeFi Primitives Expansion\n    registerToolWithReadonlyGate(createDefiLendTool());              // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createApprovalsTool());             // ownerOnly: true (can revoke approvals)\n    registerToolWithReadonlyGate(createDefiStakeTool());             // ownerOnly: true (financial write)\n    registerToolWithReadonlyGate(createNftTool());                   // ownerOnly: true (buy/sell/transfer NFTs)\n    registerToolWithReadonlyGate(createYieldTool());                  // ownerOnly: true (vault deposits/withdrawals)\n    registerToolWithReadonlyGate(createGovernanceTool());             // ownerOnly: true (on-chain voting + delegation)\n    registerToolWithReadonlyGate(createFarcasterTool());              // ownerOnly: true (social posting)\n    registerToolWithReadonlyGate(createSafeTool());                   // ownerOnly: true (multisig management)\n    registerToolWithReadonlyGate(createAirdropTool());                // ownerOnly: true (claim airdrops)\n\n    // Phase 11 tools — External Integrations\n    registerToolWithReadonlyGate(createPrivacyTool());               // ownerOnly: true (financial write, ZK deposits)\n    registerToolWithReadonlyGate(createBrowserTool());               // ownerOnly: true (browser automation, can interact with dApps)\n\n    // V3 tools — Fiat & Traditional Finance Rails\n    registerToolWithReadonlyGate(createFiatPaymentTool());           // ownerOnly: true (fiat on/off-ramp)\n\n    // V5 tools — Multi-agent orchestration\n    // The dispatcher and registeredTools closures are filled at gateway_start\n    // when the runtime is available. Pre-registration ensures the tool is\n    // in the registry for count assertions.\n    let agentDispatcher: ToolDispatcher = { call: async () => { throw new Error('Agent dispatcher not ready'); } };\n    let registeredToolsList: Array<{ name: string; description: string; parameters: any }> = [];\n    registerToolWithReadonlyGate(createAgentDelegateTool(\n      () => agentDispatcher,\n      () => registeredToolsList,\n    ));                                                               // ownerOnly: false (read-only delegation)\n\n    // Sprint 4 tools (3) — Self-improvement (agent memory, skill evolution, session recall)\n    // These tools have an evolution mode gate: write actions are blocked in stable mode.\n    {\n      const memoryTool = createAgentMemoryTool();\n      const skillTool = createSkillEvolveTool();\n      const recallTool = createSessionRecallTool();\n\n      // Wrap memory + skill tools with evolution mode gate for write actions\n      const WRITE_ACTIONS_MEMORY = new Set(['add', 'replace', 'remove', 'user_add', 'user_remove']);\n      const WRITE_ACTIONS_SKILL = new Set(['create', 'patch', 'delete']);\n\n      const wrapWithEvoGate = (tool: any, writeActions: Set<string>) => {\n        const originalExecute = tool.execute;\n        tool.execute = async (toolCallId: string, args: unknown, ctx?: any) => {\n          const params = args as Record<string, unknown>;\n          const action = (params?.action as string) ?? '';\n          if (writeActions.has(action)) {\n            const userId = ctx?.senderId ?? ctx?.from ?? ctx?.metadata?.senderId;\n            if (userId && !getEvolutionMode().isEvolving(userId)) {\n              return {\n                content: [{ type: 'text', text: `Self-improvement is in stable mode. The \"${action}\" action requires evolving mode. Use /evolve to enable self-improvement.` }],\n                isError: true,\n              };\n            }\n          }\n          return originalExecute.call(tool, toolCallId, args, ctx);\n        };\n        return tool;\n      };\n\n      api.registerTool(wrapWithEvoGate(memoryTool, WRITE_ACTIONS_MEMORY));\n      api.registerTool(wrapWithEvoGate(skillTool, WRITE_ACTIONS_SKILL));\n      api.registerTool(recallTool); // session_recall is always read-only\n    }\n\n    // V6 tools — Policy engine (spending policies, approval rules, autonomy bounds)\n    api.registerTool(createPolicyManageTool());                      // ownerOnly: true (policy management)\n\n    // ─── Register Chat Commands ────────────────────────────────────\n    api.registerCommand(walletCommand);\n    api.registerCommand(policyCommand);\n    api.registerCommand(txCommand);\n    api.registerCommand(resetCommand);\n    api.registerCommand(resetConfirmCommand);\n\n    // Onboarding: persona selection\n    api.registerCommand(professionalCommand);\n    api.registerCommand(degenCommand);\n    api.registerCommand(chillCommand);\n    api.registerCommand(technicalCommand);\n    api.registerCommand(mentorCommand);\n\n    // Onboarding: capability selection\n    api.registerCommand(capAllCommand);\n    for (const cmd of capCommands) {\n      api.registerCommand(cmd);\n    }\n\n    // Onboarding: skip, back, restart, wallet creation\n    api.registerCommand(skipCommand);\n    api.registerCommand(backCommand);\n    api.registerCommand(restartOnboardingCommand);\n    api.registerCommand(createWalletCommand);\n    api.registerCommand(importWalletCommand);\n\n    // Wallet management: recover, export, backup\n    api.registerCommand(recoverCommand);\n    api.registerCommand(exportWalletCommand);\n    api.registerCommand(walletBackupCommand);\n\n    // Mode: safety and signing\n    api.registerCommand(safemodeCommand);\n    api.registerCommand(dangermodeCommand);\n    api.registerCommand(readonlyCommand);\n    api.registerCommand(walletsignCommand);\n    api.registerCommand(autosignCommand);\n    api.registerCommand(modeCommand);\n\n    // Wallet connect (direct slash commands, not routed through LLM)\n    // /connect shows menu, /connect_metamask etc. initiate pairing\n    setConnectCommandApi(api);\n    api.registerCommand(connectCommand);\n    for (const cmd of walletConnectCommands) {\n      api.registerCommand(cmd);\n    }\n\n    // Disconnect\n    api.registerCommand(disconnectCommand);\n\n    // Model switching\n    api.registerCommand(modelCommand);\n    for (const cmd of llmShortcutCommands) {\n      api.registerCommand(cmd);\n    }\n\n    // Molten status\n    api.registerCommand(moltenCommand);\n\n    // Bankr LLM Gateway + Agent API\n    api.registerCommand(creditsCommand);\n    api.registerCommand(usageCommand);\n    api.registerCommand(connectBankrCommand);\n    api.registerCommand(automationsCommand);\n    api.registerCommand(topupCommand);\n    api.registerCommand(autotopupCommand);\n\n    // Fly.io runtime control (provider switching, secrets, restart)\n    api.registerCommand(providerCommand);\n    api.registerCommand(providerAnthropicCommand);\n    api.registerCommand(providerBankrCommand);\n    api.registerCommand(providerOpenrouterCommand);\n    api.registerCommand(providerOpenaiCommand);\n    api.registerCommand(flykeysCommand);\n    api.registerCommand(flystatusCommand);\n    api.registerCommand(flyrestartCommand);\n\n    // Setup / configuration status\n    api.registerCommand(setupCommand);\n\n    // Plans management\n    api.registerCommand(plansCommand);\n    api.registerCommand(plansActiveCommand);\n    api.registerCommand(plansCancelCommand);\n    api.registerCommand(plansClearCommand);\n    api.registerCommand(approveCommand);\n    api.registerCommand(denyCommand);\n\n    // Trigger management\n    api.registerCommand(triggersCommand);\n    api.registerCommand(triggersPriceCommand);\n    api.registerCommand(triggersCronCommand);\n    api.registerCommand(deadLetterCommand);\n\n    // Help, portfolio, balance, chain, diagnostics\n    api.registerCommand(helpCommand);\n    api.registerCommand(portfolioCommand);\n    api.registerCommand(balanceCommand);\n    api.registerCommand(chainCommand);\n    api.registerCommand(doctorCommand);\n    api.registerCommand(rpcCommand);\n\n    // Self-improvement mode\n    api.registerCommand(evolveCommand);\n    api.registerCommand(stableCommand);\n    api.registerCommand(evolutionCommand);\n\n    // Forum topics + thread bindings\n    api.registerCommand(topicsCommand);\n    api.registerCommand(topicsSetupCommand);\n    api.registerCommand(topicBindCommand);\n    api.registerCommand(topicUnbindCommand);\n\n    // V3: Fiat rails\n    api.registerCommand(fiatCommand);\n\n    // V4: User-defined tool management\n    api.registerCommand(toolsCommand);\n\n    // V5: Multi-agent + Webhooks\n    api.registerCommand(agentsCommand);\n    api.registerCommand(webhooksCommand);\n\n    // Skill registry\n    api.registerCommand(skillsCommand);\n\n    // Interrupt\n    api.registerCommand(interruptCommand);\n    api.registerCommand(interruptPlanCommand);\n\n    // Issue reporting\n    api.registerCommand(reportCommand);\n    api.registerCommand(reportOptInCommand);\n    api.registerCommand(reportOptOutCommand);\n\n    // API key management\n    api.registerCommand(apiCommand);\n\n    // Usage reporting\n    api.registerCommand(usageNewCommand);\n\n    // Update + restart from Telegram\n    api.registerCommand(updateCommand);\n    api.registerCommand(restartCommand);\n\n    // File pull\n    api.registerCommand(pullCommand);\n\n    // V6: Policy engine\n    api.registerCommand(policiesCommand);\n\n    // V7: On-chain delegation (EIP-7710)\n    api.registerCommand(delegateCommand);\n    api.registerCommand(policymodeCommand);\n    api.registerCommand(profileCommand);\n    api.registerCommand(upgradeCommand);\n    api.registerCommand(agentAccountCommand);\n    api.registerCommand(commandsAllCommand);\n\n    // ─── Gateway Startup Hook ──────────────────────────────────────\n    // Only init wallet at boot for private key mode (headless).\n    // WalletConnect init is deferred to the clawnchconnect tool to avoid\n    // double-init of WC Core which breaks the pairing handshake.\n    api.on('gateway_start', async () => {\n      // ─── Hydrate API Keys from Keychain ───────────────────────────\n      try {\n        const { hydrateApiKeys } = await import('./src/services/keychain-secrets.js');\n        const { loaded, skipped } = hydrateApiKeys();\n        if (loaded.length > 0) {\n          api.logger?.info?.(`[crypto] Loaded API keys from Keychain: ${loaded.join(', ')}`);\n        }\n        if (skipped.length > 0) {\n          api.logger?.info?.(`[crypto] API keys already in env (skipped Keychain): ${skipped.join(', ')}`);\n        }\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] Failed to hydrate API keys from Keychain: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n\n      const projectId = process.env.WALLETCONNECT_PROJECT_ID;\n      const privateKey = process.env.CLAWNCHER_PRIVATE_KEY;\n\n      const bankrApiKey = process.env.BANKR_API_KEY;\n\n      // ── Wallet initialization (runs before scheduler) ──────────\n      if (!projectId && !privateKey && !bankrApiKey) {\n        api.logger?.info?.(\n          '[crypto] No wallet configured. Set WALLETCONNECT_PROJECT_ID, CLAWNCHER_PRIVATE_KEY, or BANKR_API_KEY to enable write operations.'\n        );\n      } else if (privateKey) {\n        // C6 FIX: Gate private key mode behind explicit opt-in flag\n        if (process.env.ALLOW_PRIVATE_KEY_MODE !== 'true') {\n          api.logger?.warn?.(\n            '[crypto] CLAWNCHER_PRIVATE_KEY is set but ALLOW_PRIVATE_KEY_MODE is not \"true\". ' +\n            'Private key mode is disabled for safety. Set ALLOW_PRIVATE_KEY_MODE=true to enable.'\n          );\n        } else {\n          try {\n            const result = await initWalletService({\n              privateKey,\n              rpcUrl: process.env.CLAWNCHER_RPC_URL,\n              network: (process.env.CLAWNCHER_NETWORK as 'mainnet' | 'sepolia') || 'mainnet',\n            });\n            api.logger?.warn?.(`[crypto] WARNING: Wallet running in PRIVATE KEY mode (auto-sign). Address: ${result.address}`);\n          } catch (err) {\n            api.logger?.warn?.(\n              `[crypto] Private key wallet init failed: ${err instanceof Error ? err.message : String(err)}`\n            );\n          }\n        }\n      }\n\n      if (projectId && !privateKey && !bankrApiKey) {\n        api.logger?.info?.(\n          `[crypto] WalletConnect available (project ID configured). ` +\n          `Use the clawnchconnect tool to pair a wallet.`\n        );\n      }\n\n      // Mode 3: Bankr (auto-connect at boot when no other wallet is configured)\n      if (bankrApiKey && !privateKey) {\n        try {\n          const result = await initWalletService({ bankrApiKey });\n          if (result.mode === 'bankr') {\n            api.logger?.info?.(\n              `[crypto] Bankr wallet ready: ${result.address}${result.solAddress ? ` (+ Solana: ${result.solAddress})` : ''}`\n            );\n          } else {\n            api.logger?.warn?.('[crypto] Bankr wallet init returned unexpected mode');\n          }\n        } catch (err) {\n          api.logger?.warn?.(\n            `[crypto] Bankr wallet init failed: ${err instanceof Error ? err.message : String(err)}`\n          );\n        }\n      }\n\n      // ─── Restore Persisted State ─────────────────────────────────\n      // Reload forum topics, thread bindings, and orders from disk.\n      try {\n        restoreForumTopics();\n        restoreThreadBindings();\n        restoreOrders();\n        api.logger?.info?.('[crypto] Restored persisted state (forum topics, thread bindings, orders)');\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] Failed to restore some persisted state: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n\n      // ─── V4: Register User-Defined Tools ─────────────────────────\n      // Compile all enabled user tools and register them dynamically.\n      // User tools don't affect the static count assertions (43 tools) —\n      // they are additive and loaded from ~/.openclawnch/user-tools/.\n      try {\n        // Build a lightweight dispatcher for user tools to call built-in tools.\n        // This uses the same api.runtime.tools.getAll() pattern as the plan executor.\n        const runtimeRef = api.runtime as any;\n        const userToolDispatcher: ToolDispatcher = {\n          call: async (toolName: string, args: Record<string, unknown>): Promise<any> => {\n            const tools = runtimeRef?.tools?.getAll?.() ?? [];\n            const tool = tools.find((t: any) => t.name === toolName);\n            if (!tool) throw new Error(`Tool \"${toolName}\" not found in registry`);\n            const toolCallId = `user-tool-${Date.now()}-${toolName}`;\n            return tool.execute(toolCallId, args, {});\n          },\n        };\n\n        const compiledUserTools = compileAllEnabledTools(userToolDispatcher);\n        for (const userTool of compiledUserTools) {\n          // Apply the same readonly gate as built-in tools\n          registerToolWithReadonlyGate(userTool);\n        }\n        if (compiledUserTools.length > 0) {\n          api.logger?.info?.(\n            `[crypto] Registered ${compiledUserTools.length} user-defined tool(s): ${compiledUserTools.map(t => t.name).join(', ')}`\n          );\n        }\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] Failed to load user-defined tools: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n\n      // ─── V5: Wire Agent Dispatcher + Start Webhook Server ────────\n      // Fill in the agent_delegate tool's closures now that runtime is available.\n      try {\n        const runtimeForAgents = api.runtime as any;\n        agentDispatcher = {\n          call: async (toolName: string, args: Record<string, unknown>): Promise<any> => {\n            const tools = runtimeForAgents?.tools?.getAll?.() ?? [];\n            const tool = tools.find((t: any) => t.name === toolName);\n            if (!tool) throw new Error(`Tool \"${toolName}\" not found in registry`);\n            const toolCallId = `agent-${Date.now()}-${toolName}`;\n            return tool.execute(toolCallId, args, {});\n          },\n        };\n        registeredToolsList = (runtimeForAgents?.tools?.getAll?.() ?? []).map((t: any) => ({\n          name: t.name,\n          description: t.description ?? '',\n          parameters: t.parameters ?? { type: 'object', properties: {} },\n        }));\n        api.logger?.info?.(`[crypto] Agent delegate ready: ${registeredToolsList.length} tools available for sub-agents`);\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] Agent dispatcher setup failed: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n\n      // Start webhook server if configured\n      try {\n        const { getWebhookServer } = await import('./src/services/webhook-server.js');\n        const { getEventBus } = await import('./src/services/event-bus.js');\n\n        const webhookServer = getWebhookServer();\n        webhookServer.onEvent(async (event) => {\n          // Emit on event bus for plan triggers to pick up\n          const bus = getEventBus();\n          bus.emit('webhook_received', {\n            type: 'webhook_received',\n            route: event.route,\n            source: event.source,\n            payload: event.payload,\n            headers: event.headers,\n            receivedAt: event.receivedAt,\n            timestamp: Date.now(),\n          });\n          api.logger?.info?.(`[crypto] Webhook received: ${event.route} from ${event.source}`);\n        });\n\n        const started = await webhookServer.start();\n        if (started) {\n          const config = webhookServer.getConfig();\n          api.logger?.info?.(\n            `[crypto] Webhook server listening on ${config.host}:${config.port}`\n          );\n        }\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] Webhook server failed to start: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n\n      // ─── Start Plan Scheduler + Executor ─────────────────────────\n      // Wire real resolvers, tool dispatcher, and Telegram notifications.\n      try {\n        const { getScheduler } = await import('./src/services/plan-scheduler.js');\n        const { PlanExecutor, formatExecutionSummary } = await import('./src/services/plan-executor.js');\n        const { getPrice } = await import('./src/services/price-service.js');\n        const { getGasEstimator } = await import('./src/services/gas-estimator.js');\n        const { getRpcManager } = await import('./src/services/rpc-provider.js');\n\n        // ── Runtime Resolver: real service calls ─────────────────\n        const scheduler = getScheduler({\n          resolver: {\n            price: async (token: string) => {\n              try {\n                const data = await getPrice(token);\n                if (!data?.priceUsd) return NaN; // NaN signals \"unknown\" — conditions won't fire\n                return data.priceUsd;\n              } catch (err) {\n                api.logger?.warn?.(`[plan-resolver] price fetch failed for ${token}: ${err}`);\n                return NaN;\n              }\n            },\n            balance: async (token: string, chainId?: number) => {\n              try {\n                const cid = chainId ?? 8453; // Default to Base\n                const rpc = getRpcManager();\n                const client = await rpc.getClient(cid);\n                const walletState = getWalletStateFn();\n                if (!walletState.address) return NaN;\n                if (!token || token.toUpperCase() === 'ETH') {\n                  const balance = await client.getBalance({ address: walletState.address as `0x${string}` });\n                  return Number(balance) / 1e18;\n                }\n                // ERC-20: resolve decimals via shared utility, then read balanceOf\n                const { resolveTokenDecimals } = await import('./src/lib/token-decimals.js');\n                const decimals = await resolveTokenDecimals(token, client);\n                const balanceOfAbi = [{ name: 'balanceOf', type: 'function', stateMutability: 'view', inputs: [{ name: 'account', type: 'address' }], outputs: [{ name: '', type: 'uint256' }] }] as const;\n                const data = await client.readContract({\n                  address: token as `0x${string}`,\n                  abi: balanceOfAbi,\n                  functionName: 'balanceOf',\n                  args: [walletState.address as `0x${string}`],\n                });\n                return Number(data) / (10 ** decimals);\n              } catch (err) {\n                api.logger?.warn?.(`[plan-resolver] balance fetch failed for ${token} on chain ${chainId ?? 8453}: ${err}`);\n                return NaN;\n              }\n            },\n            gasPrice: async (chainId?: number) => {\n              try {\n                const estimator = getGasEstimator();\n                const gas = await estimator.getGasPrice(chainId ?? 8453);\n                return gas.totalStandard; // baseFee + standard priority fee\n              } catch (err) {\n                api.logger?.warn?.(`[plan-resolver] gas price fetch failed for chain ${chainId ?? 8453}: ${err}`);\n                return NaN;\n              }\n            },\n            timestamp: () => Math.floor(Date.now() / 1000),\n            blockNumber: async (chainId?: number) => {\n              try {\n                const rpc = getRpcManager();\n                const client = await rpc.getClient(chainId ?? 8453);\n                const block = await client.getBlockNumber();\n                return Number(block);\n              } catch (err) {\n                api.logger?.warn?.(`[plan-resolver] block number fetch failed for chain ${chainId ?? 8453}: ${err}`);\n                return NaN;\n              }\n            },\n          },\n        });\n\n        // ── Tool Dispatcher: calls real registered tools ──────────\n        // We build a dispatcher that invokes tools through the plugin API.\n        //\n        // NOTE: api.runtime.tools.getAll() is an internal OpenClaw API not\n        // exposed in the plugin SDK types. We access it via type assertion.\n        // If upstream removes/renames it, we need an alternative dispatch path.\n        // Track: FEATURE_PARITY.md — \"Needs verification each release\".\n        const runtimeInternal = api.runtime as any;\n        const toolDispatcher = {\n          call: async (toolName: string, params: Record<string, unknown>, userId?: string): Promise<unknown> => {\n            // Find the tool in the registered tools\n            const tools = runtimeInternal?.tools?.getAll?.() ?? [];\n            const tool = tools.find((t: any) => t.name === toolName);\n            if (!tool) throw new Error(`Tool \"${toolName}\" not found in registry`);\n\n            // Execute the tool with correct signature: (toolCallId, args, ctx)\n            // Pass userId in ctx so readonly gate and evolution gate can check it.\n            const toolCallId = `plan-${Date.now()}-${toolName}`;\n            const ctx = userId ? { senderId: userId } : {};\n            const result = await tool.execute(toolCallId, params, ctx);\n            // Extract the meaningful result\n            if (result && typeof result === 'object') {\n              const r = result as Record<string, unknown>;\n              return r.details ?? r.text ?? result;\n            }\n            return result;\n          },\n          exists: (toolName: string): boolean => {\n            const tools = runtimeInternal?.tools?.getAll?.() ?? [];\n            return tools.some((t: any) => t.name === toolName);\n          },\n        };\n\n        // ── Executor: wired to real dispatcher and scheduler ─────\n        const executor = new PlanExecutor({\n          dispatcher: toolDispatcher,\n          scheduler,\n          onConfirmRequired: async (step, resolvedParams, planUserId) => {\n\n            // Send confirmation request to user\n            if (planUserId && planUserId !== 'owner') {\n              try {\n                const parsed = parseSessionKey(planUserId);\n                const paramLines = Object.entries(resolvedParams)\n                  .filter(([, v]) => v !== undefined && v !== null)\n                  .slice(0, 6)\n                  .map(([k, v]) => `  ${k}: ${String(v)}`)\n                  .join('\\n');\n\n                const msg = `**Confirmation required**\\n\\n` +\n                  `Step: **${step.label}**\\n` +\n                  `Tool: ${step.tool}\\n` +\n                  (paramLines ? `Params:\\n${paramLines}\\n\\n` : '\\n') +\n                  `Reply /approve to continue or /deny to skip.`;\n\n                if (parsed) {\n                  await sender.send(parsed.channel, parsed.userId, msg);\n                } else {\n                  await sender.send('telegram', planUserId, msg);\n                }\n              } catch { /* best effort */ }\n            }\n\n            // Wait for user response (or timeout after 5 min)\n            return createPendingConfirmation({\n              executionId: `${step.id}-${Date.now()}`,\n              planName: step.label,\n              stepLabel: step.label,\n              tool: step.tool,\n              params: resolvedParams,\n              userId: planUserId,\n            });\n          },\n          onDeadLetter: (entry) => {\n            // Persist terminal failure to disk\n            scheduler.saveDeadLetter(entry);\n            api.logger?.warn?.(`[crypto] Dead-letter: plan=${entry.planId} node=${entry.nodeId} error=${entry.error}`);\n\n            // Notify user\n            if (entry.userId && entry.userId !== 'owner') {\n              const parsed = parseSessionKey(entry.userId);\n              const msg = `**Plan step failed permanently**\\n` +\n                `Plan: \\`${entry.planId}\\`\\n` +\n                `Step: \\`${entry.nodeId}\\`${entry.tool ? ` (${entry.tool})` : ''}\\n` +\n                `Error: ${entry.error}\\n` +\n                `Retries: ${entry.retryCount}\\n` +\n                `Use \\`/plans dead_letter\\` to view all failures.`;\n              try {\n                if (parsed) {\n                  sender.send(parsed.channel, parsed.userId, msg).catch(() => {});\n                } else {\n                  sender.send('telegram', entry.userId, msg).catch(() => {});\n                }\n              } catch { /* best effort */ }\n            }\n          },\n        });\n\n        // ── Scheduler Event Handler: channel-agnostic notifications ──\n        // Plans store userId as \"<channel>-<id>\" (e.g. \"telegram-123456\",\n        // \"discord-789\") so we can route notifications to any channel.\n        // Legacy plans with bare numeric IDs default to Telegram.\n        const sender = createChannelSender(api);\n\n        scheduler.on(async (event: any) => {\n          if (event.type === 'trigger_fired') {\n            const plan = event.plan;\n            api.logger?.info?.(`[crypto] Plan trigger fired: ${plan.name} (${plan.id})`);\n\n            // Notify user that the plan is executing\n            const planUserId = plan.userId;\n            if (planUserId && planUserId !== 'owner') {\n              try {\n                const parsed = parseSessionKey(planUserId);\n                if (parsed) {\n                  await sender.send(parsed.channel, parsed.userId, `**Plan executing:** ${plan.name}\\nTrigger fired — running steps now...`);\n                } else {\n                  // Legacy: bare numeric ID assumed Telegram\n                  await sender.send('telegram', planUserId, `**Plan executing:** ${plan.name}\\nTrigger fired — running steps now...`);\n                }\n              } catch { /* best effort notification */ }\n            }\n\n            // Execute the plan\n            try {\n              const execution = await executor.execute(plan, event.executionId);\n              const summary = formatExecutionSummary(execution, plan);\n              api.logger?.info?.(`[crypto] Plan execution complete: ${plan.name} — ${execution.status}`);\n\n              // Notify user of result\n              if (planUserId && planUserId !== 'owner') {\n                try {\n                  const parsed = parseSessionKey(planUserId);\n                  if (parsed) {\n                    await sender.send(parsed.channel, parsed.userId, summary);\n                  } else {\n                    await sender.send('telegram', planUserId, summary);\n                  }\n                } catch { /* best effort notification */ }\n              }\n            } catch (execErr) {\n              api.logger?.warn?.(\n                `[crypto] Plan execution failed: ${plan.name} — ${execErr instanceof Error ? execErr.message : String(execErr)}`\n              );\n            }\n          } else if (event.type === 'plan_expired') {\n            api.logger?.info?.(`[crypto] Plan expired: ${event.plan.name} — ${event.reason}`);\n            const planUserId = event.plan.userId;\n            if (planUserId && planUserId !== 'owner') {\n              try {\n                const parsed = parseSessionKey(planUserId);\n                if (parsed) {\n                  await sender.send(parsed.channel, parsed.userId, `**Plan expired:** ${event.plan.name}\\nReason: ${event.reason}`);\n                } else {\n                  await sender.send('telegram', planUserId, `**Plan expired:** ${event.plan.name}\\nReason: ${event.reason}`);\n                }\n              } catch { /* best effort */ }\n            }\n          } else if (event.type === 'condition_check_error') {\n            api.logger?.warn?.(`[crypto] Condition check error for plan ${event.planId}: ${event.error}`);\n          }\n        });\n\n        scheduler.start();\n        api.logger?.info?.(`[crypto] Plan scheduler started (${scheduler.activeCount} active plans)`);\n\n        // ── Price Watcher + Event Bus Wiring ─────────────────────\n        // Start the PriceWatcher, register watches for price-triggered plans,\n        // and subscribe to price_crossed events to fire plan triggers.\n        try {\n          const { getPriceWatcher } = await import('./src/services/price-watcher.js');\n          const { getEventBus } = await import('./src/services/event-bus.js');\n\n          const priceWatcher = getPriceWatcher();\n          const eventBus = getEventBus();\n\n          // Scan active plans for price triggers and register watches\n          const activePlans = scheduler.getActivePlans();\n          let priceWatchCount = 0;\n          for (const plan of activePlans) {\n            if (plan.trigger?.type === 'price') {\n              priceWatcher.addFromTrigger(plan.id, plan.trigger);\n              priceWatchCount++;\n            }\n          }\n\n          // Subscribe: when PriceWatcher detects a threshold cross, fire the plan\n          eventBus.on('price_crossed', async (event) => {\n            // Find which watch(es) this event corresponds to\n            // PriceWatcher emits with the watch ID = planId, but the event\n            // contains token + condition + threshold. We iterate active watches\n            // and match by token.\n            for (const watch of priceWatcher.getWatches()) {\n              if (\n                watch.token.toUpperCase() === event.token.toUpperCase() &&\n                watch.condition === event.condition &&\n                watch.threshold === event.threshold\n              ) {\n                try {\n                  await scheduler.firePriceTrigger(watch.id);\n                  api.logger?.info?.(\n                    `[crypto] Price trigger fired: plan=${watch.id} token=${event.token} ` +\n                    `price=$${event.currentPrice.toFixed(2)} condition=${event.condition} threshold=$${event.threshold}`\n                  );\n                } catch (err) {\n                  api.logger?.warn?.(\n                    `[crypto] Failed to fire price trigger for plan ${watch.id}: ${err instanceof Error ? err.message : String(err)}`\n                  );\n                }\n              }\n            }\n          });\n\n          // Subscribe: when plans are added/cancelled, manage watches dynamically\n          scheduler.on(async (event: any) => {\n            if (event.type === 'plan_added' && event.plan?.trigger?.type === 'price') {\n              priceWatcher.addFromTrigger(event.plan.id, event.plan.trigger);\n              // Auto-start watcher if it's not running and we now have watches\n              if (!priceWatcher.isRunning && priceWatcher.watchCount > 0) {\n                priceWatcher.start();\n                api.logger?.info?.(`[crypto] Price watcher auto-started for plan ${event.plan.id}`);\n              }\n            } else if (event.type === 'plan_cancelled') {\n              priceWatcher.removeWatch(event.planId);\n              // Auto-stop if no more watches (save resources)\n              if (priceWatcher.isRunning && priceWatcher.watchCount === 0) {\n                priceWatcher.stop();\n                api.logger?.info?.('[crypto] Price watcher stopped (no active watches)');\n              }\n            }\n          });\n\n          // Start the watcher (30s tick by default)\n          if (priceWatchCount > 0) {\n            priceWatcher.start();\n            api.logger?.info?.(`[crypto] Price watcher started (${priceWatchCount} active watches)`);\n          } else {\n            api.logger?.info?.('[crypto] Price watcher ready (no active price triggers — will start on first price-triggered plan)');\n          }\n        } catch (err) {\n          api.logger?.warn?.(\n            `[crypto] Price watcher/event bus failed to start: ${err instanceof Error ? err.message : String(err)}`\n          );\n        }\n\n        // Register as a managed service so OpenClaw can stop it on shutdown\n        api.registerService?.({\n          id: 'crypto-plan-scheduler',\n          start: () => { /* already started above */ },\n          stop: () => {\n            scheduler.stop();\n            // Also stop price watcher\n            import('./src/services/price-watcher.js')\n              .then(({ getPriceWatcher }) => getPriceWatcher().stop())\n              .catch(() => {});\n          },\n        });\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] Plan scheduler failed to start: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n\n      // ─── Start Heartbeat Position Monitor ──────────────────────────\n      try {\n        const heartbeat = getHeartbeatMonitor({\n          intervalMs: parseInt(process.env.OPENCLAWNCH_HEARTBEAT_INTERVAL_MS ?? '300000', 10),\n          priceDropAlertPercent: parseFloat(process.env.OPENCLAWNCH_HEARTBEAT_DROP_PCT ?? '10'),\n          priceGainAlertPercent: parseFloat(process.env.OPENCLAWNCH_HEARTBEAT_GAIN_PCT ?? '20'),\n          portfolioDropAlertUsd: parseFloat(process.env.OPENCLAWNCH_HEARTBEAT_DROP_USD ?? '100'),\n          enabled: process.env.OPENCLAWNCH_HEARTBEAT_ENABLED !== 'false',\n        });\n\n        const hbSender = createChannelSender(api);\n\n        // Resolve the owner's chat ID for heartbeat alerts.\n        // Try OPENCLAWNCH_OWNER_CHAT_ID first, then fall back to config allowFrom.\n        const ownerChatId = process.env.OPENCLAWNCH_OWNER_CHAT_ID\n          ?? (api.config as any)?.channels?.telegram?.allowFrom?.[0]\n          ?? null;\n\n        heartbeat.onAlert(async (alert) => {\n          if (!ownerChatId) return; // No known owner to alert\n\n          const severity = alert.severity === 'critical' ? '**CRITICAL**' : alert.severity === 'warning' ? '**WARNING**' : 'INFO';\n          const message = `${severity} [Heartbeat] ${alert.message}`;\n\n          // Send to all available channels that have the owner configured\n          const availableChannels = hbSender.availableChannels();\n          for (const ch of availableChannels) {\n            try {\n              await hbSender.send(ch, ownerChatId, message);\n              break; // Sent successfully to one channel — don't spam all\n            } catch { /* try next channel */ }\n          }\n        });\n\n        heartbeat.start();\n        api.logger?.info?.('[crypto] Heartbeat position monitor started');\n\n        // Register as a managed service so OpenClaw can stop it on shutdown\n        api.registerService?.({\n          id: 'crypto-heartbeat-monitor',\n          start: () => { /* already started above */ },\n          stop: () => { heartbeat.stop(); },\n        });\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] Heartbeat monitor failed to start: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n\n      // ─── Start LLM Credit Monitor ─────────────────────────────────────\n      if (process.env.BANKR_LLM_KEY) {\n        try {\n          const { getCreditMonitor } = await import('./src/services/credit-monitor.js');\n          const creditMonitor = getCreditMonitor({\n            intervalMs: parseInt(process.env.OPENCLAWNCH_CREDIT_CHECK_INTERVAL_MS ?? '300000', 10),\n            warningThresholdUsd: parseFloat(process.env.OPENCLAWNCH_CREDIT_WARNING_USD ?? '5'),\n            criticalThresholdUsd: parseFloat(process.env.OPENCLAWNCH_CREDIT_CRITICAL_USD ?? '1'),\n          });\n\n          const creditSender = createChannelSender(api);\n          const creditOwnerChatId = process.env.OPENCLAWNCH_OWNER_CHAT_ID\n            ?? (api.config as any)?.channels?.telegram?.allowFrom?.[0]\n            ?? null;\n\n          creditMonitor.onAlert(async (alert) => {\n            if (!creditOwnerChatId) return;\n            const severity = alert.severity === 'critical' ? '**CRITICAL**' : '**WARNING**';\n            const message = `${severity} ${alert.message}`;\n\n            const availableChannels = creditSender.availableChannels();\n            for (const ch of availableChannels) {\n              try {\n                await creditSender.send(ch, creditOwnerChatId, message);\n                break;\n              } catch { /* try next channel */ }\n            }\n          });\n\n          creditMonitor.start();\n          api.logger?.info?.('[crypto] LLM credit monitor started');\n\n          api.registerService?.({\n            id: 'crypto-credit-monitor',\n            start: () => { /* already started */ },\n            stop: () => { creditMonitor.stop(); },\n          });\n        } catch (err) {\n          api.logger?.warn?.(\n            `[crypto] Credit monitor failed to start: ${err instanceof Error ? err.message : String(err)}`\n          );\n        }\n      }\n\n      // ─── Graceful Shutdown Handler ──────────────────────────────────\n      // The host process (openclaw gateway) receives SIGTERM from Docker/Fly.\n      // registerService uses optional chaining — if the host doesn't support\n      // managed services, these intervals leak. Install process-level handlers\n      // as a safety net to ensure clean shutdown.\n      const shutdownServices = (): void => {\n        try { getScheduler().stop(); } catch { /* already stopped or never started */ }\n        try { getHeartbeatMonitor().stop(); } catch { /* already stopped or never started */ }\n        try {\n          import('./src/services/credit-monitor.js')\n            .then(({ getCreditMonitor }) => getCreditMonitor().stop())\n            .catch(() => {});\n        } catch { /* already stopped */ }\n        // Persist in-memory forum topics and thread bindings\n        try { persistForumTopics(); } catch { /* best effort */ }\n        try { persistThreadBindings(); } catch { /* best effort */ }\n        try { persistOrders(); } catch { /* best effort */ }\n        api.logger?.info?.('[crypto] Graceful shutdown: services stopped, state persisted');\n      };\n\n      let shutdownCalled = false;\n      const onShutdownSignal = (signal: string): void => {\n        if (shutdownCalled) return; // Prevent double-shutdown\n        shutdownCalled = true;\n        api.logger?.info?.(`[crypto] Received ${signal}, shutting down...`);\n        shutdownServices();\n        // Don't call process.exit — let the host process handle that\n      };\n\n      process.on('SIGTERM', () => onShutdownSignal('SIGTERM'));\n      process.on('SIGINT', () => onShutdownSignal('SIGINT'));\n\n      // Also handle 'beforeExit' for non-signal shutdowns\n      process.on('beforeExit', () => {\n        if (!shutdownCalled) {\n          shutdownCalled = true;\n          shutdownServices();\n        }\n      });\n    });\n\n    // ─── Onboarding State Tracking ──────────────────────────────────────\n    // Track which conversations are currently being handled by onboarding\n    // so the message_sending hook can cancel the LLM response.\n    //\n    // Uses a Map<chatId, timestamp> with a 30-second TTL instead of a bare\n    // Set to prevent stale entries from permanently silencing the agent.\n    const ONBOARDING_FLAG_TTL_MS = 30_000;\n    const onboardingHandledConversations = new Map<string, number>();\n\n    /** Add a chatId flag with a TTL. */\n    function markConversationHandled(chatId: string): void {\n      onboardingHandledConversations.set(chatId, Date.now());\n    }\n\n    /** Check and consume a flag, returning true if valid (not expired). */\n    function consumeConversationFlag(chatId: string): boolean {\n      const ts = onboardingHandledConversations.get(chatId);\n      if (ts == null) return false;\n      onboardingHandledConversations.delete(chatId);\n      // Expired entries are stale — don't cancel the response\n      if (Date.now() - ts > ONBOARDING_FLAG_TTL_MS) return false;\n      return true;\n    }\n\n    /** Periodic sweep: purge expired entries to prevent unbounded Map growth. */\n    const onboardingSweepTimer = setInterval(() => {\n      const now = Date.now();\n      for (const [key, ts] of onboardingHandledConversations) {\n        if (now - ts > ONBOARDING_FLAG_TTL_MS) {\n          onboardingHandledConversations.delete(key);\n        }\n      }\n    }, 60_000); // Every 60 seconds\n    onboardingSweepTimer.unref(); // Don't prevent clean process exit\n\n    // ── Channel-agnostic sender for onboarding + notifications ────────\n    const channelSender = createChannelSender(api);\n\n    // Wire channel sender to /update command for progress messages\n    setUpdateCommandSender(channelSender);\n\n    /** Send an onboarding message to a chat on the given channel. */\n    async function sendOnboardingMessage(channel: ChannelId, chatId: string, msg: OnboardingMessage): Promise<void> {\n      try {\n        const ok = await channelSender.send(channel, chatId, msg.text);\n        if (!ok) {\n          api.logger?.warn?.(`[crypto] sendMessage for ${channel} not available on runtime`);\n        }\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] Failed to send onboarding message via ${channel}: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n    }\n\n    // ─── Onboarding: Message Received Hook ─────────────────────────────\n    // Detects new/in-progress onboarding users and sends the onboarding\n    // response directly via the channel's API (bypassing the LLM). Sets a\n    // flag so message_sending can cancel the LLM's response.\n    //\n    // Works on ALL channels (Telegram, Discord, Slack, etc.).\n    //\n    // Hook signature: (event: PluginHookMessageReceivedEvent, ctx: PluginHookMessageContext) => void\n    // event.from = sender ID, event.content = message text\n    // ctx.channelId = channel name, ctx.conversationId = chat ID\n    api.on('message_received', async (event: any, ctx: any) => {\n      try {\n        const channel = extractChannelId(ctx);\n        if (!channel) return; // Unknown channel — skip\n\n        // The sender's user ID (channel-agnostic)\n        const userId = extractSenderId(event, ctx);\n        if (!userId) return;\n\n        // The chat ID to send replies to (same as user ID in DMs)\n        const chatId = ctx?.conversationId ?? String(userId);\n\n        // ── Typing indicator: start immediately so user knows agent is alive ──\n        if (channel === 'telegram') {\n          try { getTypingIndicator().start(String(chatId)); } catch { /* non-critical */ }\n        }\n\n        const message = event?.content ?? '';\n\n        // Don't intercept slash commands — let OpenClaw's command system handle them.\n        // Our onboarding slash commands (like /professional, /degen) are registered\n        // as proper commands and will call back into the onboarding flow themselves.\n        // EXCEPTION: /start is Telegram's auto-sent command when a user first opens\n        // the bot. We need to intercept it to trigger onboarding.\n        const msgStr = String(message);\n        if (msgStr.startsWith('/') && msgStr !== '/start') return;\n\n        const flow = getOnboardingFlow(String(userId));\n        if (!flow.isActive) return;\n\n        const response = await flow.processMessage(String(message));\n\n        if (response) {\n          // Mark this conversation as handled by onboarding\n          markConversationHandled(chatId);\n\n          // Send the onboarding response directly via the detected channel\n          await sendOnboardingMessage(channel, chatId, response);\n\n          api.logger?.info?.(\n            `[crypto] Onboarding step for user ${userId} on ${channel}: ${flow.currentStep}`\n          );\n        }\n\n        // ── Session recall: index inbound messages ─────────────────\n        try {\n          const sessionKey = ctx?.sessionKey ?? `${channel}-${chatId}`;\n          getSessionRecall().recordTurn({\n            sessionKey,\n            role: 'user',\n            content: String(message).slice(0, 2000),\n            userId: String(userId),\n            timestamp: Date.now(),\n          });\n        } catch {\n          // Non-critical\n        }\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] Onboarding message hook error: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n    });\n\n    // ─── Onboarding: Cancel LLM Response ───────────────────────────────\n    // When onboarding handled the inbound message, suppress the LLM's reply.\n    //\n    // Hook signature: (event: PluginHookMessageSendingEvent, ctx: PluginHookMessageContext)\n    //   => { cancel?: boolean, content?: string } | void\n    api.on('message_sending', (event: any, ctx: any) => {\n      try {\n        const chatId = ctx?.conversationId ?? event?.to;\n        if (!chatId) return;\n\n        // ── Typing indicator: stop — response is being sent ──────────\n        try { getTypingIndicator().stop(String(chatId)); } catch { /* non-critical */ }\n\n        if (consumeConversationFlag(String(chatId))) {\n          api.logger?.info?.(`[crypto] Suppressing LLM response for onboarding chat ${chatId}`);\n          return { cancel: true };\n        }\n\n        // ── Interrupt check ──────────────────────────────────────────\n        // If /interrupt was called, suppress the LLM response.\n        try {\n          const sessionKey = ctx?.sessionKey ?? String(chatId);\n          if (getInterruptService().consume(sessionKey)) {\n            api.logger?.info?.(`[crypto] Response interrupted for session ${sessionKey}`);\n            return { cancel: true };\n          }\n        } catch { /* Non-critical */ }\n\n        // ── Credential leak scanning ─────────────────────────────────\n        // Scan outbound messages for accidentally leaked secrets before\n        // they reach the user (and potentially logs, channel histories, etc.)\n        const content = event?.content ?? event?.text ?? '';\n        if (typeof content === 'string' && content.length > 0) {\n          const vault = getCredentialVault();\n          const scan = vault.scanForLeaks(content);\n          if (!scan.clean) {\n            api.logger?.warn?.(\n              `[crypto] Credential leak detected in outbound message! ` +\n              `${scan.leaks.length} leak(s): ${scan.leaks.map(l => l.type).join(', ')}. Redacting.`\n            );\n            // Return the redacted version\n            return { content: scan.redactedText };\n          }\n        }\n      } catch (err) {\n        api.logger?.warn?.(\n          `[crypto] message_sending hook error: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n    });\n\n    // ─── System Prompt Injection ──────────────────────────────────────\n    // Extracted to src/hooks/prompt-builder.ts for maintainability.\n    // Uses prependSystemContext for static/cacheable content and\n    // prependContext for dynamic per-user content.\n    api.on('before_prompt_build', (event: any, ctx: any) => {\n      return buildPromptContext(event, ctx, {\n        getWalletState: getWalletStateFn,\n        logger: api.logger,\n      });\n    });\n\n    // ─── After Tool Call Hook ────────────────────────────────────────\n    // Extracted to src/hooks/after-tool-call.ts for maintainability.\n    // Handles: onboarding progression, config hints, cost basis,\n    // tx ledger, budget tracking, session recall, evolution nudges.\n    api.on('after_tool_call', async (event: any, ctx: any) => {\n      await handleAfterToolCall(event, ctx, {\n        writeToolNames: WRITE_TOOL_NAMES,\n        sendOnboardingMessage,\n        markOnboardingHandled: markConversationHandled,\n        getWalletState: getWalletStateFn,\n        logger: api.logger,\n      });\n    });\n  },\n};\n\nexport default plugin;\n"],"mappings":"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"}