Moved pino-pretty from devDependencies to dependencies to resolve transport
initialization error when running the published npm package in production.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update to macOS 15.0+ (Sequoia) to match Package.swift
- Fix incorrect version in CHANGELOG.md
- Update README badges and requirements section
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update version to 1.0.0
- Add comprehensive changelog for stable release
- Mark project as production-ready
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Ensure all errors return proper MCP response format
- Prevent 'No result received' when tool execution fails
- Handle special characters and edge cases gracefully
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove problematic AsyncAdapter that was causing continuation leaks
- Use AsyncParsableCommand directly with @main attribute
- Add -parse-as-library flag to Package.swift to enable @main
- This fixes the Swift continuation leak issue
Note: Integration tests still timeout in CI environment, likely due to
screen capture permissions or environment differences. The CLI works
correctly when run directly.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove empty string from item_type enum to prevent undefined values
- Add defensive programming to buildSwiftCliArgs to filter out undefined/null values
- Improve item type determination logic with explicit string checks
- Add debug logging for Swift CLI arguments
- Fix double --json-output flag issue
This fixes the "Unknown operation: undefined" error when calling list with server_status.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Document Swift 6 migration and async/sync adapter implementation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add AsyncAdapter.swift to bridge async/sync execution
- Change AsyncParsableCommand back to ParsableCommand
- Implement AsyncRunnable protocol for async execution
- Use DispatchSemaphore pattern for synchronous blocking
- Make ErrorBox thread-safe with @unchecked Sendable
This fixes the CLI execution issue where commands were showing help
instead of executing, by properly bridging the async/sync worlds
as required by ArgumentParser.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace #expect(throws:) with more expressive error validation pattern
- Use #expect { } throws: { } for better error type checking
- Improve error handling in nonExistentAppThrowsError test
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace XCTSkip with simple return for non-running apps
- This avoids dependency on XCTest framework in Swift Testing
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove redundant bundle ID checks in ApplicationFinderTests
- Replace do-catch with #expect(throws:) for cleaner error testing
- Simplify permission test assertions to avoid false failures
- Remove unnecessary boolean comparisons in permission checks
These changes make the tests more maintainable and less prone to
environment-specific failures.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update to swift-tools-version 6.0 and enable StrictConcurrency
- Make all data models and types Sendable for concurrency safety
- Migrate commands from ParsableCommand to AsyncParsableCommand
- Remove AsyncUtils.swift and synchronous bridging patterns
- Update WindowBounds property names to snake_case for consistency
- Ensure all error types conform to Sendable protocol
- Add comprehensive Swift 6 migration documentation
This migration enables full Swift 6 concurrency checking and data race
safety while maintaining backward compatibility with the existing API.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace problematic DispatchSemaphore usage with NSCondition-based async bridge
- Revert to ParsableCommand for compatibility while maintaining async operations
- Use CGWindowListCopyWindowInfo for sync permission checking instead of async ScreenCaptureKit
- Remove all RunLoop workarounds in favor of proper Task.runBlocking pattern
- Eliminate all deadlock sources while preserving async capture functionality
- Replace DispatchSemaphore usage in checkScreenRecordingPermission with RunLoop pattern
- This was the root cause of CLI hangs affecting all commands that check permissions
- Use same async-to-sync bridging pattern as ImageCommand for consistency
- Replace DispatchSemaphore usage in ScreenshotValidationTests with async/await
- Make test functions async and use Task.sleep instead of RunLoop/Thread.sleep
- Use proper Swift Testing async patterns for better compatibility
Documents the expected behavior and ensures browser helper filtering works correctly:
- Tests browser-specific error messages when main browser isn't running
- Verifies successful capture when main browser is found (not helpers)
- Documents the problem this fixes (no more confusing 'no capturable windows' errors)
- Ensures non-browser applications continue to work normally
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Addresses the issue where searching for 'Chrome' or 'Safari' would incorrectly
match helper processes (like 'Google Chrome Helper (Renderer)') instead of the
main browser application, leading to confusing 'no capturable windows' errors.
Key improvements:
- Added filterBrowserHelpers() method that filters out helper processes for browser searches
- Supports common browsers: chrome, safari, firefox, edge, brave, arc, opera
- Filters out processes containing: helper, renderer, utility, plugin, service, crashpad, gpu, background
- Provides browser-specific error messages when main browser isn't running
- Only applies filtering to browser identifiers, preserves normal matching for other apps
- Comprehensive test coverage for browser filtering scenarios
Example: Searching for 'chrome' now finds 'Google Chrome' instead of
'Google Chrome Helper (Renderer)' which has no capturable windows.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
When users search for windows with URLs containing ports (e.g., 'http://example.com:8080'),
the system now provides much better debugging information when the window isn't found.
Key improvements:
- Enhanced window not found errors now list all available window titles
- Added specific guidance for URL-based searches (try without protocol)
- New CaptureError.windowTitleNotFound with detailed debugging info
- Comprehensive test coverage for colon parsing in app targets
- Better error messages help users understand why matching failed
Example improved error:
"Window with title containing 'http://example.com:8080' not found in Google Chrome.
Available windows: 'example.com:8080 - Google Chrome', 'New Tab - Google Chrome'.
Note: For URLs, try without the protocol (e.g., 'example.com:8080' instead of 'http://example.com:8080')."
This addresses the common issue where browsers display simplified URLs in window titles
without the protocol, making it easier for users to find the correct matching pattern.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Previously, path traversal attempts like `../../../../../../../etc/passwd` were incorrectly
reported as screen recording permission errors instead of file system errors.
Changes:
- Modified ScreenCapture error handling to distinguish between CaptureError types and ScreenCaptureKit errors
- CaptureError.fileWriteError now bypasses screen recording permission detection
- Added path validation in OutputPathResolver to detect and log path traversal attempts
- Added logging for system-sensitive path access attempts
- Comprehensive test coverage for various path traversal patterns and error scenarios
This ensures users get accurate error messages that guide them to the actual problem
(invalid paths, missing directories, file permissions) rather than misleading
screen recording permission prompts.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
When multiple applications have exact matches (e.g., "claude" and "Claude"), the system now:
- Captures all windows from all matching applications instead of throwing an ambiguous match error
- Maintains sequential window indices across all matched applications
- Preserves original application names in saved file metadata
- Only returns errors for truly ambiguous fuzzy matches
This provides more useful behavior for common scenarios where users have multiple apps with
similar names (different case, etc.) and want to capture windows from all of them.
Updates:
- Added `captureWindowsFromMultipleApps` method to handle multi-app capture logic
- Modified error handling in both single window and multi-window capture modes
- Updated documentation (spec.md, CHANGELOG.md) to reflect new behavior
- Comprehensive test suite covering various multiple match scenarios
🤖 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 README.md to clearly explain that screen captures cannot use format: "data"
- Clarify that screen captures always save to files (temp or specified path)
- Update spec.md to distinguish behavior between app window captures and screen captures
- Make it clear that empty format string defaults to PNG file format for screen captures
- Address confusion where documentation suggested format defaults to "data" when path not given
This resolves the apparent contradiction between documentation and actual behavior
shown in the test screenshot where format: "" resulted in file saving rather than
data format for a screen capture.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>