Adds support for capturing the frontmost window of the frontmost application
instead of falling back to screen capture mode.
Changes:
- Added 'frontmost' case to CaptureMode enum in Swift CLI
- Implemented captureFrontmostWindow() method using NSWorkspace.shared.frontmostApplication
- Updated TypeScript to use --mode frontmost instead of defaulting to screen mode
- Added comprehensive test coverage for frontmost functionality
- Updated existing tests to reflect new behavior
The frontmost mode now:
1. Detects the currently active application
2. Captures only its frontmost window (index 0)
3. Returns a single image file with proper metadata
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes issue where item_type: '' was not properly defaulting to the correct operation.
Empty strings and whitespace-only strings now fall back to the proper default logic:
- If app is provided: defaults to 'application_windows'
- If no app: defaults to 'running_applications'
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix "Cannot convert undefined or null to object" error when provider_config is empty
- Make frontmost target case-insensitive (frontmost, FRONTMOST, Frontmost)
- Make window specifiers case-insensitive (WINDOW_TITLE, window_title, Window_Title)
- Add comprehensive test coverage for empty/null provider_config scenarios
- Improve error handling to prevent spread operator failures on undefined _meta
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Addresses critical edge case where malformed app targets with multiple leading colons
(e.g., "::::::::::::::::Finder") created empty app names that would match ALL system
processes. This could potentially expose sensitive information or cause unintended
system-wide captures.
Key improvements:
- Enhanced app target parsing to validate non-empty app names
- Added fallback logic to extract valid app names from malformed inputs
- Default to screen mode when all parts are empty (security-first approach)
- Comprehensive test coverage for edge cases
- Improved backward compatibility with hidden path parameters
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Invalid screen index (e.g., screen:99) now properly falls back to capturing all screens with unique filenames
- String "null" in path parameter is now correctly treated as undefined instead of literal path
- Added fallback-aware filename generation to prevent file overwrites when screen index is out of bounds
- Comprehensive test coverage for both edge cases
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Automatically correct file extensions when format gets preprocessed/corrected
- When invalid format like 'bmp' is provided with path ending in .bmp,
the path is corrected to end in .png to match the actual output format
- Add Swift CLI path initialization to invalid-format-integration.test.ts
- Add conditional skipping for non-macOS platforms
- Integration tests now pass: files are created with correct .png extensions
This fixes the issue where providing format: "bmp" with path: "test.bmp"
would create a PNG file named "test.bmp", which was confusing for users.
Now it creates "test.png" to match the actual file format.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements robust handling for invalid image formats (like 'bmp', 'gif', 'webp') that bypass schema validation:
- Added defensive format validation in image tool handler
- Automatic path correction to ensure file extensions match actual format used
- Warning messages in response when format fallback occurs
- Comprehensive unit and integration test coverage for edge cases
This ensures invalid formats automatically fall back to PNG as requested, preventing
Swift CLI rejection and incorrect file extensions in output paths.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add preprocessing to handle JSON string arrays from MCP clients
- Support multiple input formats: JSON string, comma-separated, single value
- Handle empty strings and null/undefined values gracefully
- Add comprehensive test coverage for all parsing scenarios
- Fixes "Expected array, received string" error when MCP clients send JSON string arrays
This resolves the issue shown in the test screenshot where include_window_details
was sent as '["ids", "bounds", "off_screen"]' (JSON string) instead of a proper array.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update all test assertions to expect the new three-parameter signature
- Add expect.objectContaining({ timeout: expect.any(Number) }) to all executeSwiftCli assertions
- Fixed 37 test assertions across image.test.ts, image-edge-cases.test.ts, and image-tool.test.ts
- All tests now pass (297 tests passed, 17 skipped)
This completes the integration of PR #2's timeout functionality by ensuring all tests match the new function signature.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Adds configurable timeout support via PEEKABOO_CLI_TIMEOUT env var
- Implements proper SIGTERM/SIGKILL handling for stuck processes
- Updates tests for Linux compatibility
- Fixes hanging issues when permission dialogs appear
Co-authored-by: codegen-sh[bot] <131295404+codegen-sh[bot]@users.noreply.github.com>
The complex JSON parsing logic that handled multiple JSON objects was only
needed because ApplicationFinder was incorrectly outputting errors directly.
Now that the root cause is fixed (ApplicationFinder only throws errors),
we can simplify the TypeScript code to just parse single JSON responses.
This makes the codebase cleaner and error handling more predictable.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed duplicate catch block that was causing compilation errors
- Fixed missing closing brace in timeout handler
- Verified TypeScript tests now run correctly on Linux with Swift tests skipped
- Replace unreliable process.killed check with signal 0 test
- Use try-catch around all process.kill() calls
- Properly detect if process is still running before SIGKILL
- Fixes bug where SIGKILL was never sent to stuck processes
The process.killed property is set immediately when process.kill()
is called, regardless of actual process termination. Using signal 0
to test process existence is the correct approach.
- Add configurable timeout to executeSwiftCli (default 30s)
- Add timeout support to execPeekaboo (default 15s)
- Support PEEKABOO_CLI_TIMEOUT environment variable
- Graceful process termination with SIGTERM then SIGKILL
- Skip E2E tests in CI environments and non-macOS platforms
- Add test timeouts to vitest config (60s tests, 30s hooks)
- Update tool handlers to use appropriate timeouts
- Prevent multiple promise resolutions with isResolved flag
- Enhanced error messages for timeout scenarios
The image tool now properly handles:
- Case-insensitive format values (e.g., "PNG", "Png", "png" all work)
- "jpeg" as an alias for "jpg" format
- Invalid format values gracefully fall back to "png"
This is implemented through Zod schema preprocessing that normalizes
the format parameter before it reaches the Swift CLI, which only
accepts lowercase "png" and "jpg".
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add .trim() to app_target when passing to Swift CLI
- Handles cases like " Spotify " correctly matching "Spotify"
- Applies to all app name formats including window specifiers
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Error messages now include the list of matching applications when multiple apps match an identifier
- Shows bundle IDs alongside app names to help users disambiguate (e.g., Calendar (com.apple.iCal))
- Applies to both image and list tools for consistent user experience
- Added comprehensive tests for error detail handling
This makes it much easier for users to understand which specific application to target when there are multiple matches.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Screen captures with format 'data' now auto-fallback to PNG to prevent stack overflow
- Invalid format values (empty strings, null, unrecognized) gracefully fall back to PNG
- Added comprehensive tests for format validation
- Updated documentation to reflect the new behavior
This provides a better user experience by handling edge cases gracefully instead of returning errors.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Screen captures now reject format: 'data' with clear error message
- Large screen images cause JavaScript stack overflow when base64 encoded
- Application window captures can still use format: 'data'
- Update tests and documentation to reflect this limitation
- Implement Levenshtein distance algorithm for fuzzy app name matching
- Handle common typos like "Chromee" → "Google Chrome"
- Add window-specific labels in analysis results
- Improve error messages with app name suggestions
- Fix TypeScript JSON parsing for error responses
- Update tests for new error message formats
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added new "auto" capture focus mode that intelligently brings windows to foreground only when needed
- Changed default capture_focus from "background" to "auto" for better screenshot success rates
- Fixed list tool server_status validation to allow empty include_window_details arrays
- Added comprehensive tests for new auto mode functionality
- Enhanced error messages for better user experience
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Improved
- The list tool is now more lenient and user-friendly
- item_type parameter is now optional (defaults to 'running_applications')
- Intelligent auto-detection when app parameter is provided
- Enhanced error handling and validation
### Fixed
- Fixed crash when list tool called with empty item_type
- Improved image tool path handling for temporary files
- Better error messages and validation throughout
### Tests
- Added comprehensive test coverage for new list tool features
- Enhanced integration tests for improved scenarios
- Total test count increased from 223 to 228 tests
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update CI configuration to use macOS-15 runner with Xcode 16.3
- Expand test coverage with comprehensive new test suites:
* JSONOutputTests.swift - JSON encoding/decoding and MCP compliance
* LoggerTests.swift - Thread-safe logging functionality
* ImageCaptureLogicTests.swift - Image capture command logic
* TestTags.swift - Centralized test tagging system
- Improve existing tests with Swift Testing patterns and async support
- Make Logger thread-safe with concurrent dispatch queue
- Add performance, concurrency, and edge case testing
- Fix compilation issues and optimize test performance
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add distinct exit codes for different error conditions in Swift CLI
- Map exit codes to clear, actionable error messages in Node.js server
- Replace generic "Swift CLI execution failed" with specific guidance
- Improve permission error messages to guide users to System Settings
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added missing imports for ToolResponse and z in index.ts
- Added missing imports for WindowInfo and TargetApplicationInfo in list.ts
- Fixed type casting for ImageCaptureData in image.ts
- Added proper return type annotations to handlers
- Fixed content array metadata type to Record<string, unknown>
- Added const assertions for all 'text' type literals
- Fixed return types for helper functions in list.ts
- Added minItems and maxItems to JSONSchema interface
All TypeScript compilation errors resolved
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed long lines by splitting template literals
- Replaced all 'any' types with proper types:
- Used ToolResponse type instead of any
- Used z.ZodError for Zod validation errors
- Created JSONSchema interface for zod-to-json-schema
- Added ServerStatusData interface
- Used Record<string, unknown> for metadata
- Created ZodDefAny type for internal Zod properties
- Fixed quote style to use double quotes
- Removed trailing spaces
All ESLint issues resolved (0 errors, 0 warnings)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove unused variables target and mode
- Fix quote style to use double quotes
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix buildSwiftCliArgs import in image tests
- Update buildSwiftCliArgs to match expected behavior (capture-focus default, warning messages)
- Fix image summary builder logic to properly generate summaries
- Update server status test to match new implementation that doesn't use executeSwiftCli
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix all critical ESLint errors (unused variables, wrong types)
- Split image.ts into smaller modules for better maintainability:
- image-analysis.ts: AI provider analysis logic
- image-summary.ts: Summary text generation
- image-cli-args.ts: Swift CLI argument building
- Reduce image.ts from 472 to 246 lines
- Add proper TypeScript types throughout (reduce 'any' usage)
- Fix logger type imports and use proper Pino Logger type
- Update ESLint to ignore test files (handled by vitest)
- Clean up all trailing spaces and formatting issues
- Export buildSwiftCliArgs for test compatibility
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add LICENSE and README.md to npm package files array
- Enhance list tool's server_status as comprehensive info command:
- Shows MCP version, Swift CLI status and version
- Displays system permissions (screen recording, accessibility)
- Lists environment configuration and potential issues
- Checks log file accessibility
- Implement dynamic version injection for Swift CLI via build script
- Add ESLint configuration (.eslintrc.json) and npm scripts
- Fix critical ESLint issues (console.error, unused imports, prefer-const)
- Add Pino fallback logic when log directory is not writable
- Update default log path to ~/Library/Logs/peekaboo-mcp.log (macOS system log directory)
- Update README to document new log path
- Add Version.swift to .gitignore (auto-generated file)
- Create Version.swift.development for local development
- Add execPeekaboo utility function for simple CLI execution
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add npm run inspector script for MCP inspector tool
- Synchronize Swift CLI version with package.json (1.0.0-beta.9)
- Update macOS version requirement to v14 (Sonoma) for n-1 support
- Add Swift compiler warnings check in prepare-release script
- Convert tests/setup.ts from Jest to Vitest syntax
- Update server status tests to match new format
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>