@lattices/cli 0.3.0

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.
Files changed (74) hide show
  1. package/README.md +155 -0
  2. package/app/Lattices.app/Contents/Info.plist +24 -0
  3. package/app/Package.swift +13 -0
  4. package/app/Sources/AccessibilityTextExtractor.swift +111 -0
  5. package/app/Sources/ActionRow.swift +61 -0
  6. package/app/Sources/App.swift +10 -0
  7. package/app/Sources/AppDelegate.swift +242 -0
  8. package/app/Sources/AppShellView.swift +62 -0
  9. package/app/Sources/AppTypeClassifier.swift +70 -0
  10. package/app/Sources/AppWindowShell.swift +63 -0
  11. package/app/Sources/CheatSheetHUD.swift +332 -0
  12. package/app/Sources/CommandModeState.swift +1362 -0
  13. package/app/Sources/CommandModeView.swift +1405 -0
  14. package/app/Sources/CommandModeWindow.swift +192 -0
  15. package/app/Sources/CommandPaletteView.swift +307 -0
  16. package/app/Sources/CommandPaletteWindow.swift +134 -0
  17. package/app/Sources/DaemonProtocol.swift +101 -0
  18. package/app/Sources/DaemonServer.swift +414 -0
  19. package/app/Sources/DesktopModel.swift +149 -0
  20. package/app/Sources/DesktopModelTypes.swift +71 -0
  21. package/app/Sources/DiagnosticLog.swift +271 -0
  22. package/app/Sources/EventBus.swift +30 -0
  23. package/app/Sources/HotkeyManager.swift +254 -0
  24. package/app/Sources/HotkeyStore.swift +338 -0
  25. package/app/Sources/InventoryManager.swift +35 -0
  26. package/app/Sources/InventoryPath.swift +43 -0
  27. package/app/Sources/KeyRecorderView.swift +210 -0
  28. package/app/Sources/LatticesApi.swift +1234 -0
  29. package/app/Sources/LayerBezel.swift +203 -0
  30. package/app/Sources/MainView.swift +479 -0
  31. package/app/Sources/MainWindow.swift +83 -0
  32. package/app/Sources/OcrModel.swift +430 -0
  33. package/app/Sources/OcrStore.swift +329 -0
  34. package/app/Sources/OmniSearchState.swift +283 -0
  35. package/app/Sources/OmniSearchView.swift +288 -0
  36. package/app/Sources/OmniSearchWindow.swift +105 -0
  37. package/app/Sources/OrphanRow.swift +129 -0
  38. package/app/Sources/PaletteCommand.swift +419 -0
  39. package/app/Sources/PermissionChecker.swift +125 -0
  40. package/app/Sources/Preferences.swift +99 -0
  41. package/app/Sources/ProcessModel.swift +199 -0
  42. package/app/Sources/ProcessQuery.swift +151 -0
  43. package/app/Sources/Project.swift +28 -0
  44. package/app/Sources/ProjectRow.swift +368 -0
  45. package/app/Sources/ProjectScanner.swift +128 -0
  46. package/app/Sources/ScreenMapState.swift +2387 -0
  47. package/app/Sources/ScreenMapView.swift +2820 -0
  48. package/app/Sources/ScreenMapWindowController.swift +89 -0
  49. package/app/Sources/SessionManager.swift +72 -0
  50. package/app/Sources/SettingsView.swift +1064 -0
  51. package/app/Sources/SettingsWindow.swift +20 -0
  52. package/app/Sources/TabGroupRow.swift +178 -0
  53. package/app/Sources/Terminal.swift +259 -0
  54. package/app/Sources/TerminalQuery.swift +156 -0
  55. package/app/Sources/TerminalSynthesizer.swift +200 -0
  56. package/app/Sources/Theme.swift +163 -0
  57. package/app/Sources/TilePickerView.swift +209 -0
  58. package/app/Sources/TmuxModel.swift +53 -0
  59. package/app/Sources/TmuxQuery.swift +81 -0
  60. package/app/Sources/WindowTiler.swift +1778 -0
  61. package/app/Sources/WorkspaceManager.swift +575 -0
  62. package/bin/client.js +4 -0
  63. package/bin/daemon-client.js +187 -0
  64. package/bin/lattices-app.js +221 -0
  65. package/bin/lattices.js +1551 -0
  66. package/docs/api.md +924 -0
  67. package/docs/app.md +297 -0
  68. package/docs/concepts.md +135 -0
  69. package/docs/config.md +245 -0
  70. package/docs/layers.md +410 -0
  71. package/docs/ocr.md +185 -0
  72. package/docs/overview.md +94 -0
  73. package/docs/quickstart.md +75 -0
  74. package/package.json +42 -0
@@ -0,0 +1,89 @@
1
+ import AppKit
2
+ import SwiftUI
3
+
4
+ /// Manages the unified app window (Screen Map + Settings).
5
+ /// Singleton with show/close/toggle, plus showPage() for navigation.
6
+ final class ScreenMapWindowController: ObservableObject {
7
+ static let shared = ScreenMapWindowController()
8
+
9
+ private var window: NSWindow?
10
+ private var controller: ScreenMapController?
11
+ @Published var activePage: AppPage = .screenMap
12
+
13
+ var isVisible: Bool { window?.isVisible ?? false }
14
+
15
+ /// Exposed for event monitor filtering
16
+ var nsWindow: NSWindow? { window }
17
+
18
+ func toggle() {
19
+ if let w = window, w.isVisible {
20
+ close()
21
+ } else {
22
+ show()
23
+ }
24
+ }
25
+
26
+ /// Show the window on the current page (defaults to Screen Map).
27
+ func show() {
28
+ if let existing = window {
29
+ if activePage == .screenMap {
30
+ controller?.enter()
31
+ }
32
+ existing.makeKeyAndOrderFront(nil)
33
+ NSApp.activate(ignoringOtherApps: true)
34
+ return
35
+ }
36
+
37
+ let ctrl = ScreenMapController()
38
+ ctrl.onDismiss = { [weak self] in
39
+ self?.close()
40
+ }
41
+ if activePage == .screenMap {
42
+ ctrl.enter()
43
+ }
44
+
45
+ let screens = NSScreen.screens
46
+ let primaryHeight = screens.first?.frame.height ?? 0
47
+ var bbox = CGRect.zero
48
+ for (i, screen) in screens.enumerated() {
49
+ let cgY = primaryHeight - screen.frame.maxY
50
+ let cgRect = CGRect(x: screen.frame.origin.x, y: cgY,
51
+ width: screen.frame.width, height: screen.frame.height)
52
+ bbox = i == 0 ? cgRect : bbox.union(cgRect)
53
+ }
54
+ let aspectRatio = bbox.width / max(bbox.height, 1)
55
+ let windowWidth = max(860, CGFloat(620) * aspectRatio + 100)
56
+
57
+ let view = AppShellView(controller: ctrl)
58
+
59
+ let w = AppWindowShell.makeWindow(
60
+ config: .init(
61
+ title: "Lattices",
62
+ initialSize: NSSize(width: windowWidth, height: 620),
63
+ minSize: NSSize(width: 600, height: 400),
64
+ maxSize: NSSize(width: 2400, height: 1600)
65
+ ),
66
+ rootView: view
67
+ )
68
+ AppWindowShell.positionCentered(w)
69
+ AppWindowShell.present(w)
70
+
71
+ self.window = w
72
+ self.controller = ctrl
73
+ }
74
+
75
+ /// Navigate to a specific page, opening the window if needed.
76
+ func showPage(_ page: AppPage) {
77
+ activePage = page
78
+ show()
79
+ }
80
+
81
+ func close() {
82
+ controller?.endPreview()
83
+ window?.orderOut(nil)
84
+ window = nil
85
+ controller = nil
86
+ activePage = .screenMap
87
+ AppDelegate.updateActivationPolicy()
88
+ }
89
+ }
@@ -0,0 +1,72 @@
1
+ import AppKit
2
+
3
+ enum SessionManager {
4
+ private static let latticesPath = "/opt/homebrew/bin/lattices"
5
+ private static let tmuxPath = "/opt/homebrew/bin/tmux"
6
+
7
+ /// Launch or reattach — if session is running, find and focus the existing window
8
+ static func launch(project: Project) {
9
+ let terminal = Preferences.shared.terminal
10
+ if project.isRunning {
11
+ terminal.focusOrAttach(session: project.sessionName)
12
+ } else {
13
+ terminal.launch(command: latticesPath, in: project.path)
14
+ }
15
+ }
16
+
17
+ /// Detach all clients from a tmux session (keeps it running)
18
+ static func detach(project: Project) {
19
+ detachByName(project.sessionName)
20
+ }
21
+
22
+ /// Detach all clients by session name string (for layer switching without a Project object)
23
+ static func detachByName(_ sessionName: String) {
24
+ let task = Process()
25
+ task.executableURL = URL(fileURLWithPath: tmuxPath)
26
+ task.arguments = ["detach-client", "-s", sessionName]
27
+ task.standardOutput = FileHandle.nullDevice
28
+ task.standardError = FileHandle.nullDevice
29
+ try? task.run()
30
+ task.waitUntilExit()
31
+ }
32
+
33
+ /// Kill a tmux session
34
+ static func kill(project: Project) {
35
+ killByName(project.sessionName)
36
+ }
37
+
38
+ /// Kill a tmux session by name string (for orphan sessions without a Project object)
39
+ static func killByName(_ sessionName: String) {
40
+ let task = Process()
41
+ task.executableURL = URL(fileURLWithPath: tmuxPath)
42
+ task.arguments = ["kill-session", "-t", sessionName]
43
+ task.standardOutput = FileHandle.nullDevice
44
+ task.standardError = FileHandle.nullDevice
45
+ try? task.run()
46
+ task.waitUntilExit()
47
+ }
48
+
49
+ /// Reconcile session state to match declared config (recreate missing panes)
50
+ static func sync(project: Project) {
51
+ let task = Process()
52
+ task.executableURL = URL(fileURLWithPath: latticesPath)
53
+ task.arguments = ["sync"]
54
+ task.currentDirectoryURL = URL(fileURLWithPath: project.path)
55
+ task.standardOutput = FileHandle.nullDevice
56
+ task.standardError = FileHandle.nullDevice
57
+ try? task.run()
58
+ task.waitUntilExit()
59
+ }
60
+
61
+ /// Restart a specific pane's process (kill + re-run declared command)
62
+ static func restart(project: Project, paneName: String? = nil) {
63
+ let task = Process()
64
+ task.executableURL = URL(fileURLWithPath: latticesPath)
65
+ task.arguments = paneName != nil ? ["restart", paneName!] : ["restart"]
66
+ task.currentDirectoryURL = URL(fileURLWithPath: project.path)
67
+ task.standardOutput = FileHandle.nullDevice
68
+ task.standardError = FileHandle.nullDevice
69
+ try? task.run()
70
+ task.waitUntilExit()
71
+ }
72
+ }