@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.
- package/README.md +155 -0
- package/app/Lattices.app/Contents/Info.plist +24 -0
- package/app/Package.swift +13 -0
- package/app/Sources/AccessibilityTextExtractor.swift +111 -0
- package/app/Sources/ActionRow.swift +61 -0
- package/app/Sources/App.swift +10 -0
- package/app/Sources/AppDelegate.swift +242 -0
- package/app/Sources/AppShellView.swift +62 -0
- package/app/Sources/AppTypeClassifier.swift +70 -0
- package/app/Sources/AppWindowShell.swift +63 -0
- package/app/Sources/CheatSheetHUD.swift +332 -0
- package/app/Sources/CommandModeState.swift +1362 -0
- package/app/Sources/CommandModeView.swift +1405 -0
- package/app/Sources/CommandModeWindow.swift +192 -0
- package/app/Sources/CommandPaletteView.swift +307 -0
- package/app/Sources/CommandPaletteWindow.swift +134 -0
- package/app/Sources/DaemonProtocol.swift +101 -0
- package/app/Sources/DaemonServer.swift +414 -0
- package/app/Sources/DesktopModel.swift +149 -0
- package/app/Sources/DesktopModelTypes.swift +71 -0
- package/app/Sources/DiagnosticLog.swift +271 -0
- package/app/Sources/EventBus.swift +30 -0
- package/app/Sources/HotkeyManager.swift +254 -0
- package/app/Sources/HotkeyStore.swift +338 -0
- package/app/Sources/InventoryManager.swift +35 -0
- package/app/Sources/InventoryPath.swift +43 -0
- package/app/Sources/KeyRecorderView.swift +210 -0
- package/app/Sources/LatticesApi.swift +1234 -0
- package/app/Sources/LayerBezel.swift +203 -0
- package/app/Sources/MainView.swift +479 -0
- package/app/Sources/MainWindow.swift +83 -0
- package/app/Sources/OcrModel.swift +430 -0
- package/app/Sources/OcrStore.swift +329 -0
- package/app/Sources/OmniSearchState.swift +283 -0
- package/app/Sources/OmniSearchView.swift +288 -0
- package/app/Sources/OmniSearchWindow.swift +105 -0
- package/app/Sources/OrphanRow.swift +129 -0
- package/app/Sources/PaletteCommand.swift +419 -0
- package/app/Sources/PermissionChecker.swift +125 -0
- package/app/Sources/Preferences.swift +99 -0
- package/app/Sources/ProcessModel.swift +199 -0
- package/app/Sources/ProcessQuery.swift +151 -0
- package/app/Sources/Project.swift +28 -0
- package/app/Sources/ProjectRow.swift +368 -0
- package/app/Sources/ProjectScanner.swift +128 -0
- package/app/Sources/ScreenMapState.swift +2387 -0
- package/app/Sources/ScreenMapView.swift +2820 -0
- package/app/Sources/ScreenMapWindowController.swift +89 -0
- package/app/Sources/SessionManager.swift +72 -0
- package/app/Sources/SettingsView.swift +1064 -0
- package/app/Sources/SettingsWindow.swift +20 -0
- package/app/Sources/TabGroupRow.swift +178 -0
- package/app/Sources/Terminal.swift +259 -0
- package/app/Sources/TerminalQuery.swift +156 -0
- package/app/Sources/TerminalSynthesizer.swift +200 -0
- package/app/Sources/Theme.swift +163 -0
- package/app/Sources/TilePickerView.swift +209 -0
- package/app/Sources/TmuxModel.swift +53 -0
- package/app/Sources/TmuxQuery.swift +81 -0
- package/app/Sources/WindowTiler.swift +1778 -0
- package/app/Sources/WorkspaceManager.swift +575 -0
- package/bin/client.js +4 -0
- package/bin/daemon-client.js +187 -0
- package/bin/lattices-app.js +221 -0
- package/bin/lattices.js +1551 -0
- package/docs/api.md +924 -0
- package/docs/app.md +297 -0
- package/docs/concepts.md +135 -0
- package/docs/config.md +245 -0
- package/docs/layers.md +410 -0
- package/docs/ocr.md +185 -0
- package/docs/overview.md +94 -0
- package/docs/quickstart.md +75 -0
- 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
|
+
}
|