BigMarc 3d749e8139 feat: Implement LiveMonitor for real-time grammar and spelling checks across applications
- Added LiveMonitor class to scan text areas in the frontmost window for grammar and spelling issues.
- Introduced DetectedField struct to represent text areas with issues, including suggestions for corrections.
- Implemented functionality to apply corrections and dismiss suggestions.
- Added Permissions class to manage Accessibility permissions required for monitoring.
- Created SnippetStore for managing text-expansion snippets, including persistence to UserDefaults.
- Developed TextCapture class to read and write text from the frontmost application using Accessibility API and clipboard fallback.
- Implemented TextFieldScanner to traverse the Accessibility tree and collect editable text elements.
- Added TextReplacementCoordinator to orchestrate the text correction process.
- Integrated UpdaterManager for handling application updates using Sparkle.
- Created comprehensive unit tests for various components, including grammar corrections and entitlement checks.
2026-06-18 16:49:55 +02:00

33 lines
1.1 KiB
Swift

import Foundation
/// A single value object derived from license tier that every paid path checks.
/// Free is deliberately useful (full Harper grammar, system-wide) while the AI
/// superpowers + multi-device are the upgrade triggers (spec §5).
struct Entitlements: Equatable {
let tier: Tier
/// Layer-1 grammar is ALWAYS free + unlimited (the open-source core).
var unlimitedGrammar: Bool { true }
/// Layer-2 AI actions: unlimited when paid; capped per day on free.
var unlimitedAIActions: Bool { tier.isPaid }
var dailyAIActionCap: Int {
tier.isPaid ? Int.max : AppConfig.Limits.freeDailyAIActions
}
/// Writing Modes: free gets Polish only; paid gets all + custom.
var allModes: Bool { tier.isPaid }
/// Paid-only features.
var appAwareSwitching: Bool { tier.isPaid }
var snippets: Bool { tier.isPaid }
var canUseLargeModel: Bool { tier.isPaid }
/// Personal dictionary: 25 entries free, unlimited paid.
var dictionaryCap: Int {
tier.isPaid ? Int.max : AppConfig.Limits.freeDictionaryCap
}
var deviceCap: Int { tier.deviceCap }
}