({ tmpFile, mediaType, text, logLabel = '', onCleanup = null })
| 414 | // Image Upload Handlers |
| 415 | // ============================================================ |
| 416 | async function handlePreparedImageUpload({ tmpFile, mediaType, text, logLabel = '', onCleanup = null }) { |
| 417 | if (!state.claudeProc) throw new Error('Claude not running'); |
| 418 | if (!tmpFile || !fs.existsSync(tmpFile)) throw new Error('Prepared image file missing'); |
| 419 | |
| 420 | const isWin = process.platform === 'win32'; |
| 421 | const isMac = process.platform === 'darwin'; |
| 422 | const isLinux = !isWin && !isMac; |
| 423 | try { |
| 424 | const stat = fs.statSync(tmpFile); |
| 425 | log(`Image ready: ${logLabel || path.basename(tmpFile)} (${stat.size} bytes)`); |
| 426 | if (isLinux) { |
| 427 | const linuxPrompt = buildLinuxImagePrompt(text, tmpFile); |
| 428 | await new Promise((resolve, reject) => { |
| 429 | if (!state.claudeProc) { |
| 430 | reject(new Error('Claude stopped before Linux image submit')); |
| 431 | return; |
| 432 | } |
| 433 | state.claudeProc.write(linuxPrompt); |
| 434 | setTimeout(() => { |
| 435 | if (!state.claudeProc) { |
| 436 | reject(new Error('Claude stopped before Linux image submit')); |
| 437 | return; |
| 438 | } |
| 439 | state.claudeProc.write('\r'); |
| 440 | log(`Sent Linux image prompt via @ref: "${linuxPrompt.substring(0, 120)}"`); |
| 441 | setTimeout(() => { |
| 442 | if (onCleanup) onCleanup(); |
| 443 | else { |
| 444 | try { fs.unlinkSync(tmpFile); } catch {} |
| 445 | } |
| 446 | }, LINUX_AT_IMAGE_CLEANUP_DELAY_MS); |
| 447 | resolve(); |
| 448 | }, LINUX_AT_PROMPT_SUBMIT_DELAY_MS); |
| 449 | }); |
| 450 | return; |
| 451 | } |
| 452 | |
| 453 | if (isWin) { |
| 454 | const psCmd = `Add-Type -AssemblyName System.Drawing; Add-Type -AssemblyName System.Windows.Forms; $img = [System.Drawing.Image]::FromFile('${tmpFile.replace(/'/g, "''")}'); [System.Windows.Forms.Clipboard]::SetImage($img); $img.Dispose()`; |
| 455 | execSync(`powershell -NoProfile -STA -Command "${psCmd}"`, { timeout: 10000 }); |
| 456 | } else if (isMac) { |
| 457 | execSync(`osascript -e 'set the clipboard to (read POSIX file "${tmpFile}" as \u00ABclass PNGf\u00BB)'`, { timeout: 10000 }); |
| 458 | } |
| 459 | log('Clipboard set with image'); |
| 460 | |
| 461 | const pasteDelayMs = isWin || isMac ? 0 : 150; |
| 462 | await new Promise((resolve, reject) => { |
| 463 | setTimeout(() => { |
| 464 | if (!state.claudeProc) { |
| 465 | reject(new Error('Claude stopped before image paste')); |
| 466 | return; |
| 467 | } |
| 468 | if (isWin) state.claudeProc.write('\x1bv'); |
| 469 | else state.claudeProc.write('\x16'); |
| 470 | log('Sent image paste keypress to PTY'); |
| 471 | |
| 472 | setTimeout(() => { |
| 473 | if (!state.claudeProc) { |
no test coverage detected