@lattices/cli 0.4.12 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,17 +26,17 @@
26
26
  </dict>
27
27
  </array>
28
28
  <key>CFBundleVersion</key>
29
- <string>0.4.12</string>
29
+ <string>0.4.13</string>
30
30
  <key>CFBundleShortVersionString</key>
31
- <string>0.4.12</string>
31
+ <string>0.4.13</string>
32
32
  <key>LatticesBuildChannel</key>
33
33
  <string>dev</string>
34
34
  <key>LatticesBuildTrack</key>
35
35
  <string>latest</string>
36
36
  <key>LatticesBuildRevision</key>
37
- <string>b84f24f</string>
37
+ <string>42928c7</string>
38
38
  <key>LatticesBuildTimestamp</key>
39
- <string>2026-05-04T16:17:39Z</string>
39
+ <string>2026-05-04T17:39:23Z</string>
40
40
  <key>LSMinimumSystemVersion</key>
41
41
  <string>13.0</string>
42
42
  <key>LSUIElement</key>
@@ -21,11 +21,12 @@ final class KeyboardRemapController: ObservableObject {
21
21
  private var capsLayerLastEventAt: CFAbsoluteTime?
22
22
  private var bypassUntil: CFAbsoluteTime = 0
23
23
  private var lastCapsLayerStaleLogAt: CFAbsoluteTime = 0
24
- private var pressedKeyCodes = Set<Int64>()
24
+ private var pressedKeyCodes: [Int64: CFAbsoluteTime] = [:]
25
25
  private let breaker = EventTapBreaker(label: "KeyboardRemap")
26
26
  private let budgetMeter = TapBudgetMeter(label: "KeyboardRemap")
27
27
  private let maxCapsLayerIdleDuration: TimeInterval = 2.0
28
28
  private let maxCapsLayerHeldDuration: TimeInterval = 20.0
29
+ private let maxTrackedKeyDownDuration: TimeInterval = 120.0
29
30
  private let emergencyBypassDuration: TimeInterval = 3.0
30
31
 
31
32
  private init() {
@@ -182,7 +183,8 @@ final class KeyboardRemapController: ObservableObject {
182
183
  return Unmanaged.passUnretained(event)
183
184
  }
184
185
 
185
- updatePressedKeys(type: type, keyCode: event.getIntegerValueField(.keyboardEventKeycode))
186
+ expireStalePressedKeys(now: started)
187
+ updatePressedKeys(type: type, keyCode: event.getIntegerValueField(.keyboardEventKeycode), now: started)
186
188
  if shouldTriggerEmergencyReset(type: type, event: event) {
187
189
  emergencyClear(now: started)
188
190
  InputCaptureResetCenter.reset(reason: "keyboard emergency chord")
@@ -295,23 +297,32 @@ final class KeyboardRemapController: ObservableObject {
295
297
  DiagnosticLog.shared.warn("KeyboardRemap: emergency bypass via Escape")
296
298
  }
297
299
 
298
- private func updatePressedKeys(type: CGEventType, keyCode: Int64) {
300
+ private func updatePressedKeys(type: CGEventType, keyCode: Int64, now: CFAbsoluteTime) {
299
301
  switch type {
300
302
  case .keyDown:
301
- pressedKeyCodes.insert(keyCode)
303
+ pressedKeyCodes[keyCode] = now
302
304
  case .keyUp:
303
- pressedKeyCodes.remove(keyCode)
305
+ pressedKeyCodes.removeValue(forKey: keyCode)
304
306
  default:
305
307
  break
306
308
  }
307
309
  }
308
310
 
311
+ private func expireStalePressedKeys(now: CFAbsoluteTime) {
312
+ let staleKeys = pressedKeyCodes.filter { now - $0.value > maxTrackedKeyDownDuration }.map(\.key)
313
+ guard !staleKeys.isEmpty else { return }
314
+ for keyCode in staleKeys {
315
+ pressedKeyCodes.removeValue(forKey: keyCode)
316
+ }
317
+ DiagnosticLog.shared.warn("KeyboardRemap: cleared stale key-down state for \(staleKeys.count) key(s)")
318
+ }
319
+
309
320
  private func shouldTriggerEmergencyReset(type: CGEventType, event: CGEvent) -> Bool {
310
321
  guard type == .keyDown else { return false }
311
322
  let keyCode = event.getIntegerValueField(.keyboardEventKeycode)
312
323
  let flags = event.flags
313
324
  return keyCode == 40
314
- && pressedKeyCodes.contains(53)
325
+ && pressedKeyCodes[53] != nil
315
326
  && flags.contains(.maskShift)
316
327
  }
317
328
 
@@ -371,30 +371,19 @@ final class ScreenOverlayCanvasController {
371
371
  let hasAgentLayer = layersByID.values.contains { $0.owner == .agentApi }
372
372
  if hasAgentLayer, globalDismissMonitor == nil {
373
373
  let mask: NSEvent.EventTypeMask = [
374
- .mouseMoved,
375
374
  .leftMouseDown,
376
- .leftMouseUp,
377
375
  .rightMouseDown,
378
376
  .otherMouseDown,
379
- .leftMouseDragged,
380
- .rightMouseDragged,
381
- .otherMouseDragged,
382
377
  ]
383
378
  globalDismissMonitor = NSEvent.addGlobalMonitorForEvents(matching: mask) { [weak self] event in
384
379
  DispatchQueue.main.async {
385
380
  _ = self?.handlePointerEvent(event)
386
381
  }
387
382
  }
388
- localDismissMonitor = NSEvent.addLocalMonitorForEvents(matching: mask.union(.keyDown)) { [weak self] event in
389
- if event.type == .keyDown {
390
- if event.keyCode == 53 {
391
- self?.dismissAgentOverlays()
392
- return nil
393
- }
394
- } else {
395
- if self?.handlePointerEvent(event) == true {
396
- return nil
397
- }
383
+ localDismissMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
384
+ if event.keyCode == 53 {
385
+ self?.dismissAgentOverlays()
386
+ return nil
398
387
  }
399
388
  return event
400
389
  }
@@ -416,35 +405,7 @@ final class ScreenOverlayCanvasController {
416
405
  @discardableResult
417
406
  private func handlePointerEvent(_ event: NSEvent) -> Bool {
418
407
  switch event.type {
419
- case .mouseMoved:
420
- updatePointerCapture(at: NSEvent.mouseLocation)
421
- return false
422
- case .leftMouseDown:
423
- updatePointerCapture(at: NSEvent.mouseLocation)
424
- if beginActorDrag(at: NSEvent.mouseLocation) {
425
- return true
426
- }
427
- dismissAgentOverlays()
428
- return false
429
- case .leftMouseDragged:
430
- if dragActor(to: NSEvent.mouseLocation) {
431
- return true
432
- }
433
- dismissAgentOverlays()
434
- return false
435
- case .leftMouseUp:
436
- let wasDragging = dragState != nil
437
- endActorDrag()
438
- updatePointerCapture(at: NSEvent.mouseLocation)
439
- return wasDragging
440
- case .rightMouseDown:
441
- updatePointerCapture(at: NSEvent.mouseLocation)
442
- if closeActor(at: NSEvent.mouseLocation) {
443
- return true
444
- }
445
- dismissAgentOverlays()
446
- return false
447
- case .otherMouseDown, .rightMouseDragged, .otherMouseDragged:
408
+ case .leftMouseDown, .rightMouseDown, .otherMouseDown:
448
409
  dismissAgentOverlays()
449
410
  return false
450
411
  default:
@@ -453,16 +414,7 @@ final class ScreenOverlayCanvasController {
453
414
  }
454
415
 
455
416
  private func updatePointerCapture(at globalPoint: CGPoint) {
456
- clearStaleActorDragIfNeeded()
457
- let captureWindow: ScreenOverlayWindow?
458
- if let dragState {
459
- captureWindow = windowsByScreenID[dragState.screenID]
460
- } else {
461
- captureWindow = hitActor(at: globalPoint)?.window
462
- }
463
- for window in windowsByScreenID.values {
464
- window.ignoresMouseEvents = window !== captureWindow
465
- }
417
+ resetPointerCapture()
466
418
  }
467
419
 
468
420
  private func beginActorDrag(at globalPoint: CGPoint) -> Bool {
@@ -512,6 +464,7 @@ final class ScreenOverlayCanvasController {
512
464
  let layer = layersByID[dragState.id],
513
465
  case .pet(let payload) = layer.payload else {
514
466
  self.dragState = nil
467
+ cancelActorDragTimeout()
515
468
  resetPointerCapture()
516
469
  return
517
470
  }
@@ -520,7 +473,7 @@ final class ScreenOverlayCanvasController {
520
473
  cancelActorDragTimeout()
521
474
  render()
522
475
  updateLifecycleMonitors()
523
- updatePointerCapture(at: NSEvent.mouseLocation)
476
+ resetPointerCapture()
524
477
  }
525
478
 
526
479
  private func clearStaleActorDragIfNeeded() {
@@ -562,7 +515,7 @@ final class ScreenOverlayCanvasController {
562
515
  }
563
516
  render()
564
517
  updateLifecycleMonitors()
565
- updatePointerCapture(at: globalPoint)
518
+ resetPointerCapture()
566
519
  return true
567
520
  }
568
521
 
@@ -4,7 +4,7 @@ export default {
4
4
  name: 'lattices',
5
5
  tagline: 'macOS developer workspace manager — tmux sessions with a native menu bar app for tiling, navigation, and project management',
6
6
  type: 'cli-tool',
7
- version: '0.4.12',
7
+ version: '0.4.13',
8
8
  },
9
9
 
10
10
  agent: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lattices/cli",
3
- "version": "0.4.12",
3
+ "version": "0.4.13",
4
4
  "description": "The agentic workspace manager for macOS — turn your desktop into a coherent API",
5
5
  "packageManager": "bun@1.3.11",
6
6
  "engines": {