Skip to main content
Glama

Peekaboo MCP

by steipete
cli-ollama-e2e.test.tsβ€’6.86 kB
import * as child_process from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import { describe, test, expect, beforeAll, afterAll } from 'vitest'; // Helper function to run AppleScript const runAppleScript = (script: string): Promise<string> => { return new Promise((resolve, reject) => { const osaScript = child_process.spawn('osascript', ['-e', script]); let stdout = ''; let stderr = ''; osaScript.stdout.on('data', (data) => (stdout += data.toString())); osaScript.stderr.on('data', (data) => (stderr += data.toString())); osaScript.on('close', (code) => { if (code === 0) { resolve(stdout.trim()); } else { reject(new Error(`AppleScript failed with code ${code}: ${stderr}`)); } }); }); }; // Helper function to run Peekaboo CLI commands const runPeekabooCli = (args: string[]): Promise<{ stdout: string; stderr: string; code: number | null }> => { return new Promise((resolve) => { const peekabooPath = path.resolve(__dirname, '../../../../peekaboo'); // Assuming CLI is in project root const process = child_process.spawn(peekabooPath, args); let stdout = ''; let stderr = ''; process.stdout.on('data', (data) => (stdout += data.toString())); process.stderr.on('data', (data) => (stderr += data.toString())); process.on('close', (code) => { resolve({ stdout, stderr, code }); }); process.on('error', (err) => { resolve({ stdout: '', stderr: `Failed to start Peekaboo CLI: ${err.message}`, code: -1 }); }); }); }; const describeAppImageCaptureTest = (appName: string) => { describe(`${appName} CLI Image Capture E2E Test`, () => { let tempImagePath = ''; const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'peekaboo-e2e-')); beforeAll(async () => { try { console.log(`Ensuring ${appName} is running and active...`); await runAppleScript(` tell application "${appName}" if not running then launch end if activate end tell `); await new Promise(resolve => setTimeout(resolve, 3000)); // Wait for app to be visible } catch (error) { console.error(`Error setting up ${appName}:`, error); throw error; } }, 10000); // Increased timeout for app launching afterAll(async () => { try { console.log(`Quitting ${appName}...`); await runAppleScript(` tell application "${appName}" if running then quit end if end tell `); } catch (error) { // Non-critical if quit fails, might be closed already or stuck console.warn(`Could not quit ${appName} gracefully:`, error.message); } if (tempImagePath && fs.existsSync(tempImagePath)) { try { fs.unlinkSync(tempImagePath); } catch (e) { console.warn(`Could not delete temp image ${tempImagePath}: ${e.message}`); } } if (fs.existsSync(tempDir)) { try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch (e) { console.warn(`Could not delete temp dir ${tempDir}: ${e.message}`); } } }, 10000); // Increased timeout for app quitting and cleanup test(`should take a screenshot of ${appName} using the CLI`, async () => { tempImagePath = path.join(tempDir, `${appName.replace(/\\s+/g, '-')}-screenshot-${Date.now()}.png`); console.log(`Taking screenshot of ${appName} to ${tempImagePath} using CLI...`); const imageResult = await runPeekabooCli(['image', '--app', appName, '--path', tempImagePath]); console.log(`${appName} 'image' CLI stdout: ${imageResult.stdout}`); console.error(`${appName} 'image' CLI stderr: ${imageResult.stderr}`); // Check for successful exit code expect(imageResult.code).toBe(0); // Verify stderr is empty or does not contain error indicators (more robust than exact empty string) // Specific error messages from peekaboo CLI can be checked here if known expect(imageResult.stderr.toLowerCase()).not.toContain('error'); expect(imageResult.stderr.toLowerCase()).not.toContain('failed'); // Verify the image file was created expect(fs.existsSync(tempImagePath)).toBe(true); // Verify the image file has a size greater than 0 bytes expect(fs.statSync(tempImagePath).size).toBeGreaterThan(0); // Optional: Check stdout for confirmation message if peekaboo CLI provides one // expect(imageResult.stdout).toContain(`Successfully saved screenshot to ${tempImagePath}`); }, 20000); // Timeout for app interaction and CLI execution // test(`should analyze the screenshot of ${appName} using the CLI`, async () => { // // This test depends on tempImagePath being set by the previous test // expect(fs.existsSync(tempImagePath)).toBe(true); // Ensure image exists before analyzing // console.log(`Analyzing screenshot of ${appName} from ${tempImagePath} using CLI...`); // const question = "Describe this application window in detail."; // const analyzeResult = await runPeekabooCli(['analyze', '--image-path', tempImagePath, '--question', question]); // console.log(`${appName} 'analyze' CLI stdout: ${analyzeResult.stdout}`); // console.error(`${appName} 'analyze' CLI stderr: ${analyzeResult.stderr}`); // expect(analyzeResult.code).toBe(0); // expect(analyzeResult.stderr.toLowerCase()).not.toContain('error'); // expect(analyzeResult.stderr.toLowerCase()).not.toContain('failed'); // // Check for a non-empty stdout, which should contain the analysis // expect(analyzeResult.stdout.trim()).not.toBe(''); // // A more specific check could be to ensure some keywords related to analysis are present, // // but that might make the test brittle depending on the AI model's output. // // For now, a non-empty response is a good indicator. // }, 30000); // Increased timeout for potential AI model processing time }); }; // --- Test Suites --- describeAppImageCaptureTest('Calculator'); describeAppImageCaptureTest('TextEdit'); describeAppImageCaptureTest('System Settings'); describeAppImageCaptureTest('Safari'); describeAppImageCaptureTest('Finder'); describeAppImageCaptureTest('Mail'); describeAppImageCaptureTest('Notes'); describeAppImageCaptureTest('Terminal'); // To run these tests, ensure: // 1. Peekaboo CLI (the Swift executable) is built and accessible at the root of the project. // 2. Screen Recording and Accessibility permissions are granted for the terminal running the tests. // 3. An Ollama server is running locally with a vision model (e.g., llava) available.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/steipete/Peekaboo'

If you have feedback or need assistance with the MCP directory API, please join our Discord server