import { execFileSync, spawn } from 'child_process'; import { setTimeout as sleep } from 'timers/promises'; import { find_claude_window } from './find-window.js'; export async function copy_to_clipboard(text) { await new Promise((resolve, reject) => { const proc = spawn('xclip', ['-selection', 'clipboard'], { stdio: ['pipe', 'ignore', 'ignore'] }); proc.on('error', reject); proc.on('close', code => code === 0 ? resolve() : reject(new Error(`xclip exited ${code}`))); proc.stdin.write(text); proc.stdin.end(); }); } export function focus_window(window_id) { execFileSync('xdotool', ['windowactivate', '--sync', window_id]); } export async function paste_to_window(window_id, { submit = true } = {}) { execFileSync('xdotool', ['windowactivate', '--sync', window_id]); execFileSync('xdotool', ['key', '--window', window_id, 'shift+Insert']); if (submit) { await sleep(200); execFileSync('xdotool', ['key', '--window', window_id, 'Return']); } } function normalise_window_id(raw) { // Accept decimal (25165857) or hex (0x1800021) — always return 0x hex string const n = raw.startsWith('0x') ? parseInt(raw, 16) : parseInt(raw, 10); return '0x' + n.toString(16); } export async function send_to_claude(text, options = {}) { const window_id = options.window_id ? normalise_window_id(String(options.window_id)) : find_claude_window({ debug: options.debug }); if (!window_id) { throw new Error('Could not find Claude Code window'); } console.error(`[send] using window ${window_id}`); if (options.focus_only) { focus_window(window_id); return window_id; } await copy_to_clipboard(text); await paste_to_window(window_id, options); return window_id; }