{"version":3,"sources":["../../src/core/clipboard.ts"],"names":["moduleDir","path","fileURLToPath","packageRoot","sourceExePath","FALLBACKS_DIR","WINDOWS_DIR","WINDOWS_CLIPBOARD_EXE_NAME","checkLinuxClipboardDependencies","logger","exitCode","executeShellCommand","error","getErrorMessage","WINDOWS_FALLBACK_DIR","WINDOWS_CLIPBOARD_PATH","createDirectWindowsClipboardReader","resolve","fs","command","exec","stdout","stderr","syncError","ensureClipboardExecutable","shouldCopy","createClipboardWatcher","pollInterval","callback","reader","clipboardReader","clipboardy","lastContent","intervalId","checkClipboard","content","start","stop","createBulkClipboardWatcher","bulkCallback","bulkSize","bulkTimeout","bulkTimer","clipboardBuffer","processBulk","contentsToProcess"],"mappings":"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","file":"clipboard.cjs","sourcesContent":["import clipboardy from 'clipboardy';\nimport { logger, getErrorMessage } from '../utils/logger';\nimport fs from 'fs';\nimport path from 'path';\nimport { exec, type ExecException } from 'child_process';\nimport { executeShellCommand } from '../utils/shell';\nimport { FALLBACKS_DIR, WINDOWS_CLIPBOARD_EXE_NAME, WINDOWS_DIR } from '../utils/constants';\nimport { fileURLToPath } from 'url';\n\ntype ClipboardCallback = (content: string) => void;\ntype ClipboardReader = () => Promise<string>;\ntype BulkClipboardCallback = (contents: string[]) => void;\n\n// Path to the directory of the current module (e.g., /path/to/relaycode/dist)\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n// Path to the root of the relaycode package\nconst packageRoot = path.join(moduleDir, '..');\n// Path to the clipboard executable within the package\nconst sourceExePath = path.join(packageRoot, FALLBACKS_DIR, WINDOWS_DIR, WINDOWS_CLIPBOARD_EXE_NAME);\n\n\nconst checkLinuxClipboardDependencies = async () => {\n  if (process.platform === 'linux') {\n      logger.debug('Checking for clipboard dependencies on Linux (xsel or xclip)...');\n      try {\n          // Using `command -v` is more portable than `which`. Redirect stdout/stderr to keep it clean.\n          const { exitCode } = await executeShellCommand('command -v xsel >/dev/null 2>&1 || command -v xclip >/dev/null 2>&1');\n          if (exitCode !== 0) {\n              logger.error('-----------------------------------------------------------------------');\n              logger.error('ACTION REQUIRED: Clipboard support on Linux requires `xsel` or `xclip`.');\n              logger.error('Please install one of these tools to enable clipboard monitoring.');\n              logger.error('Example on Debian/Ubuntu: sudo apt install xsel');\n              logger.error('Example on Fedora/CentOS: sudo dnf install xsel');\n              logger.error('Example on Arch Linux:    sudo pacman -S xsel');\n              logger.error('-----------------------------------------------------------------------');\n          } else {\n              logger.debug('Linux clipboard dependency check passed.');\n          }\n      } catch (error) {\n          logger.warn(`An error occurred while checking for clipboard dependencies: ${getErrorMessage(error)}`);\n      }\n  }\n};\n\nconst WINDOWS_FALLBACK_DIR = path.join(process.cwd(), FALLBACKS_DIR, WINDOWS_DIR);\nconst WINDOWS_CLIPBOARD_PATH = path.join(WINDOWS_FALLBACK_DIR, WINDOWS_CLIPBOARD_EXE_NAME);\n\n// Direct Windows clipboard reader that uses the executable directly\nconst createDirectWindowsClipboardReader = (): ClipboardReader => {\n  return () => new Promise((resolve) => {\n    try {\n      if (!fs.existsSync(WINDOWS_CLIPBOARD_PATH)) {\n        logger.error('Windows clipboard executable not found. Cannot watch clipboard on Windows.');\n        // Resolve with empty string to avoid stopping the watcher loop, but log an error.\n        return resolve('');\n      }\n      \n      const command = `\"${WINDOWS_CLIPBOARD_PATH}\" --paste`;\n      \n      exec(command, { encoding: 'utf8' }, (error: ExecException | null, stdout: string, stderr: string) => {\n        if (error) {\n          // It's common for the clipboard executable to fail if the clipboard is empty\n          // or contains non-text data (e.g., an image). We can treat this as \"no content\".\n          // We don't log this as an error to avoid spamming the console during normal use.\n          logger.debug(`Windows clipboard read command failed (this is often normal): ${stderr.trim()}`);\n          resolve('');\n        } else {\n          resolve(stdout);\n        }\n      });\n    } catch (syncError) {\n      // Catch synchronous errors during setup (e.g., path issues).\n      logger.error(`A synchronous error occurred while setting up clipboard reader: ${getErrorMessage(syncError)}`);\n      resolve('');\n    }\n  });\n};\n\n// Check if the clipboard executable exists and fix path issues on Windows\nconst ensureClipboardExecutable = () => {\n  if (process.platform === 'win32') {\n    try {\n      // Create fallbacks directory in the current project if it doesn't exist\n      if (!fs.existsSync(WINDOWS_FALLBACK_DIR)) {\n        fs.mkdirSync(WINDOWS_FALLBACK_DIR, { recursive: true });\n      }\n      \n      if (fs.existsSync(sourceExePath)) {\n        let shouldCopy = true;\n        if (fs.existsSync(WINDOWS_CLIPBOARD_PATH)) {\n          // If the file exists, check if the size is the same.\n          // This is a simple way to check if it's the same file.\n          if (fs.statSync(sourceExePath).size === fs.statSync(WINDOWS_CLIPBOARD_PATH).size) {\n            shouldCopy = false;\n          }\n        }\n        \n        if (shouldCopy) {\n          fs.copyFileSync(sourceExePath, WINDOWS_CLIPBOARD_PATH);\n          logger.info('Copied Windows clipboard executable to local fallbacks directory');\n        }\n      } else {\n        logger.error(`Windows clipboard executable not found in package at: ${sourceExePath}`);\n      }\n    } catch (error) {\n      logger.warn('Error ensuring clipboard executable: ' + getErrorMessage(error));\n    }\n  }\n};\n\nexport const createClipboardWatcher = (\n  pollInterval: number,\n  callback: ClipboardCallback,\n  reader?: ClipboardReader,\n) => {\n  // Ensure clipboard executable exists before starting\n  ensureClipboardExecutable();\n  // Check for Linux dependencies. This is fire-and-forget.\n  checkLinuxClipboardDependencies();\n  \n  // On Windows, use the direct Windows reader\n  // Otherwise use the provided reader or clipboardy\n  const clipboardReader = process.platform === 'win32' ? \n    createDirectWindowsClipboardReader() : \n    reader || clipboardy.read;\n  \n  let lastContent = '';\n  let intervalId: NodeJS.Timeout | null = null;\n\n  const checkClipboard = async () => {\n    try {\n      const content = await clipboardReader();\n      if (content && content !== lastContent) {\n        lastContent = content;\n        callback(content);\n      }\n    } catch (error) {\n      // It's common for clipboard access to fail occasionally (e.g., on VM focus change)\n      // So we log a warning but don't stop the watcher.\n      logger.warn('Could not read from clipboard: ' + getErrorMessage(error));\n    }\n  };\n\n  const start = () => {\n    if (intervalId) {\n      return;\n    }\n    logger.info(`Starting clipboard watcher (polling every ${pollInterval}ms)`);\n    // Immediately check once, then start the interval\n    checkClipboard();\n    intervalId = setInterval(checkClipboard, pollInterval);\n  };\n\n  const stop = () => {\n    if (intervalId) {\n      clearInterval(intervalId);\n      intervalId = null;\n      logger.info('Clipboard watcher stopped.');\n    }\n  };\n\n  start();\n  \n  return { stop };\n};\n\nexport const createBulkClipboardWatcher = (\n  pollInterval: number,\n  bulkCallback: BulkClipboardCallback,\n  bulkSize: number = 5,\n  bulkTimeout: number = 30000,\n  reader?: ClipboardReader,\n) => {\n  // Ensure clipboard executable exists before starting\n  ensureClipboardExecutable();\n  // Check for Linux dependencies. This is fire-and-forget.\n  checkLinuxClipboardDependencies();\n  \n  // On Windows, use the direct Windows reader\n  // Otherwise use the provided reader or clipboardy\n  const clipboardReader = process.platform === 'win32' ? \n    createDirectWindowsClipboardReader() : \n    reader || clipboardy.read;\n  \n  let lastContent = '';\n  let intervalId: NodeJS.Timeout | null = null;\n  let bulkTimer: NodeJS.Timeout | null = null;\n  let clipboardBuffer: string[] = [];\n\n  const processBulk = () => {\n    if (clipboardBuffer.length > 0) {\n      const contentsToProcess = [...clipboardBuffer];\n      clipboardBuffer = [];\n      bulkCallback(contentsToProcess);\n    }\n    if (bulkTimer) {\n      clearTimeout(bulkTimer);\n      bulkTimer = null;\n    }\n  };\n\n  const checkClipboard = async () => {\n    try {\n      const content = await clipboardReader();\n      if (content && content !== lastContent) {\n        lastContent = content;\n        clipboardBuffer.push(content);\n        \n        // Process immediately if we reach the bulk size\n        if (clipboardBuffer.length >= bulkSize) {\n          processBulk();\n        } else {\n          // Set or reset the bulk timer\n          if (bulkTimer) {\n            clearTimeout(bulkTimer);\n          }\n          bulkTimer = setTimeout(processBulk, bulkTimeout);\n        }\n      }\n    } catch (error) {\n      // It's common for clipboard access to fail occasionally (e.g., on VM focus change)\n      // So we log a warning but don't stop the watcher.\n      logger.warn('Could not read from clipboard: ' + getErrorMessage(error));\n    }\n  };\n\n  const start = () => {\n    if (intervalId) {\n      return;\n    }\n    logger.info(`Starting bulk clipboard watcher (polling every ${pollInterval}ms, bulk size: ${bulkSize})`);\n    // Immediately check once, then start the interval\n    checkClipboard();\n    intervalId = setInterval(checkClipboard, pollInterval);\n  };\n\n  const stop = () => {\n    if (intervalId) {\n      clearInterval(intervalId);\n      intervalId = null;\n    }\n    if (bulkTimer) {\n      clearTimeout(bulkTimer);\n      bulkTimer = null;\n    }\n    // Process any remaining items in the buffer\n    processBulk();\n    logger.info('Bulk clipboard watcher stopped.');\n  };\n\n  start();\n  \n  return { stop };\n};"]}