Skip to content

Commit 9c614c6

Browse files
jsonifyclaude
andcommitted
Implement advanced CPS randomization for human-like timing patterns
- Create comprehensive CPSRandomizer with statistical distributions (normal, uniform, exponential, triangular) - Add configurable variance, humanness levels, and anti-detection pattern breakup - Integrate randomization with AutomationConfiguration and ClickCoordinator - Implement dynamic interval scheduling using one-shot timers for randomized timing - Add RandomizationSettings UI with live preview and distribution selection - Extend ClickSettings with timing randomization properties and persistence - Include comprehensive test suite with statistical validation and performance tests - Complete Task 6 of Phase 1 MVP completion spec 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 1390b58 commit 9c614c6

File tree

8 files changed

+1277
-20
lines changed

8 files changed

+1277
-20
lines changed

.agent-os/specs/2025-07-22-phase1-completion/tasks.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ These are the tasks to be completed for the spec detailed in @.agent-os/specs/20
5555
- [x] 5.7 Create performance dashboard for user visibility into timing accuracy
5656
- [x] 5.8 Verify all performance targets met and benchmarks pass consistently
5757

58-
- [ ] 6. **Implement Advanced CPS Randomization**
59-
- [ ] 6.1 Write tests for CPSRandomizer and timing pattern generation
60-
- [ ] 6.2 Create CPSRandomizer with configurable variance and distribution patterns
61-
- [ ] 6.3 Add UI controls for randomization settings and pattern selection
62-
- [ ] 6.4 Implement statistical distributions (normal, uniform) for natural timing variation
63-
- [ ] 6.5 Integrate randomization with AutomationConfiguration and clicking loops
64-
- [ ] 6.6 Add validation to ensure randomization doesn't break timing requirements
65-
- [ ] 6.7 Implement anti-detection patterns to avoid automation signature detection
66-
- [ ] 6.8 Verify all tests pass and randomization produces human-like patterns
58+
- [x] 6. **Implement Advanced CPS Randomization**
59+
- [x] 6.1 Write tests for CPSRandomizer and timing pattern generation
60+
- [x] 6.2 Create CPSRandomizer with configurable variance and distribution patterns
61+
- [x] 6.3 Add UI controls for randomization settings and pattern selection
62+
- [x] 6.4 Implement statistical distributions (normal, uniform) for natural timing variation
63+
- [x] 6.5 Integrate randomization with AutomationConfiguration and clicking loops
64+
- [x] 6.6 Add validation to ensure randomization doesn't break timing requirements
65+
- [x] 6.7 Implement anti-detection patterns to avoid automation signature detection
66+
- [x] 6.8 Verify all tests pass and randomization produces human-like patterns

Sources/ClickIt/Core/Click/ClickCoordinator.swift

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ class ClickCoordinator: ObservableObject {
4242
/// High-precision timer for optimized automation timing
4343
private var automationTimer: HighPrecisionTimer?
4444

45+
/// CPS randomizer for human-like timing patterns
46+
private var cpsRandomizer: CPSRandomizer?
47+
4548
/// Performance monitor for resource optimization
4649
private let performanceMonitor = PerformanceMonitor.shared
4750

@@ -302,17 +305,30 @@ class ClickCoordinator: ObservableObject {
302305
return
303306
}
304307

305-
// Create high-precision timer for automation
306-
automationTimer = HighPrecisionTimer()
308+
// Initialize CPS randomizer with configuration
309+
cpsRandomizer = CPSRandomizer(configuration: configuration.cpsRandomizerConfig)
307310

308-
// Start timer-based automation loop
309-
automationTimer?.startRepeatingTimer(interval: configuration.clickInterval) { [weak self] in
311+
// Start first automation step
312+
scheduleNextAutomationStep(configuration: configuration)
313+
314+
print("ClickCoordinator: Started optimized automation loop with \(configuration.clickInterval * 1000)ms base interval, randomization: \(configuration.cpsRandomizerConfig.enabled)")
315+
}
316+
317+
/// Schedules the next automation step with randomized timing
318+
/// - Parameter configuration: Automation configuration
319+
private func scheduleNextAutomationStep(configuration: AutomationConfiguration) {
320+
guard isActive else { return }
321+
322+
// Calculate next interval with randomization
323+
let nextInterval = cpsRandomizer?.randomizeInterval(configuration.clickInterval) ?? configuration.clickInterval
324+
325+
// Create new one-shot timer for next step (required for dynamic intervals)
326+
automationTimer = HighPrecisionTimer()
327+
automationTimer?.startOneShotTimer(delay: nextInterval) { [weak self] in
310328
Task { @MainActor in
311329
await self?.performOptimizedAutomationStep(configuration: configuration)
312330
}
313331
}
314-
315-
print("ClickCoordinator: Started optimized automation loop with \(configuration.clickInterval * 1000)ms interval")
316332
}
317333

318334
/// Performs a single optimized automation step with minimal overhead
@@ -344,7 +360,11 @@ class ClickCoordinator: ObservableObject {
344360
// Handle failed click with minimal processing
345361
if !result.success && configuration.stopOnError {
346362
stopAutomation()
363+
return
347364
}
365+
366+
// Schedule next automation step with randomized timing
367+
scheduleNextAutomationStep(configuration: configuration)
348368
}
349369

350370
/// Executes a single automation step with error recovery
@@ -602,6 +622,7 @@ struct AutomationConfiguration {
602622
let randomizeLocation: Bool
603623
let locationVariance: CGFloat
604624
let useDynamicMouseTracking: Bool
625+
let cpsRandomizerConfig: CPSRandomizer.Configuration
605626

606627
init(
607628
location: CGPoint,
@@ -613,7 +634,8 @@ struct AutomationConfiguration {
613634
stopOnError: Bool = false,
614635
randomizeLocation: Bool = false,
615636
locationVariance: CGFloat = 0,
616-
useDynamicMouseTracking: Bool = false
637+
useDynamicMouseTracking: Bool = false,
638+
cpsRandomizerConfig: CPSRandomizer.Configuration = CPSRandomizer.Configuration()
617639
) {
618640
self.location = location
619641
self.clickType = clickType
@@ -625,6 +647,7 @@ struct AutomationConfiguration {
625647
self.randomizeLocation = randomizeLocation
626648
self.locationVariance = locationVariance
627649
self.useDynamicMouseTracking = useDynamicMouseTracking
650+
self.cpsRandomizerConfig = cpsRandomizerConfig
628651
}
629652
}
630653

Sources/ClickIt/Core/Models/ClickSettings.swift

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,38 @@ class ClickSettings: ObservableObject {
105105
saveSettings()
106106
}
107107
}
108+
109+
// MARK: - CPS Randomization Properties
110+
111+
/// Whether to enable CPS timing randomization
112+
@Published var randomizeTiming: Bool = false {
113+
didSet {
114+
saveSettings()
115+
}
116+
}
117+
118+
/// Timing variance as percentage (0.0-1.0, representing 0%-100%)
119+
@Published var timingVariancePercentage: Double = 0.1 {
120+
didSet {
121+
// Clamp between 0-100%
122+
timingVariancePercentage = max(0.0, min(1.0, timingVariancePercentage))
123+
saveSettings()
124+
}
125+
}
126+
127+
/// Statistical distribution pattern for randomization
128+
@Published var distributionPattern: CPSRandomizer.DistributionPattern = .normal {
129+
didSet {
130+
saveSettings()
131+
}
132+
}
133+
134+
/// Anti-detection humanness level
135+
@Published var humannessLevel: CPSRandomizer.HumannessLevel = .medium {
136+
didSet {
137+
saveSettings()
138+
}
139+
}
108140

109141
// MARK: - Computed Properties
110142

@@ -156,7 +188,11 @@ class ClickSettings: ObservableObject {
156188
locationVariance: locationVariance,
157189
stopOnError: stopOnError,
158190
showVisualFeedback: showVisualFeedback,
159-
playSoundFeedback: playSoundFeedback
191+
playSoundFeedback: playSoundFeedback,
192+
randomizeTiming: randomizeTiming,
193+
timingVariancePercentage: timingVariancePercentage,
194+
distributionPattern: distributionPattern,
195+
humannessLevel: humannessLevel
160196
)
161197

162198
do {
@@ -188,6 +224,10 @@ class ClickSettings: ObservableObject {
188224
stopOnError = settings.stopOnError
189225
showVisualFeedback = settings.showVisualFeedback
190226
playSoundFeedback = settings.playSoundFeedback
227+
randomizeTiming = settings.randomizeTiming
228+
timingVariancePercentage = settings.timingVariancePercentage
229+
distributionPattern = settings.distributionPattern
230+
humannessLevel = settings.humannessLevel
191231
} catch {
192232
print("ClickSettings: Failed to load settings - \(error.localizedDescription). Using defaults.")
193233
}
@@ -207,8 +247,24 @@ class ClickSettings: ObservableObject {
207247
stopOnError = false
208248
showVisualFeedback = true
209249
playSoundFeedback = false
250+
randomizeTiming = false
251+
timingVariancePercentage = 0.1
252+
distributionPattern = .normal
253+
humannessLevel = .medium
210254
saveSettings()
211255
}
256+
257+
/// Create CPS randomizer configuration from current settings
258+
func createCPSRandomizerConfiguration() -> CPSRandomizer.Configuration {
259+
return CPSRandomizer.Configuration(
260+
enabled: randomizeTiming,
261+
variancePercentage: timingVariancePercentage,
262+
distributionPattern: distributionPattern,
263+
humannessLevel: humannessLevel,
264+
minimumInterval: AppConstants.minClickInterval,
265+
maximumInterval: 10.0 // 10 second maximum
266+
)
267+
}
212268

213269
/// Create automation configuration from current settings
214270
func createAutomationConfiguration() -> AutomationConfiguration {
@@ -226,7 +282,8 @@ class ClickSettings: ObservableObject {
226282
maxDuration: maxDurationValue,
227283
stopOnError: stopOnError,
228284
randomizeLocation: randomizeLocation,
229-
locationVariance: CGFloat(locationVariance)
285+
locationVariance: CGFloat(locationVariance),
286+
cpsRandomizerConfig: createCPSRandomizerConfiguration()
230287
)
231288
}
232289
}
@@ -276,6 +333,10 @@ private struct SettingsData: Codable {
276333
let stopOnError: Bool
277334
let showVisualFeedback: Bool
278335
let playSoundFeedback: Bool
336+
let randomizeTiming: Bool
337+
let timingVariancePercentage: Double
338+
let distributionPattern: CPSRandomizer.DistributionPattern
339+
let humannessLevel: CPSRandomizer.HumannessLevel
279340
}
280341

281342
// MARK: - Extensions

0 commit comments

Comments
 (0)