@lattices/cli 0.4.7 → 0.4.8
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 +8 -6
- package/app/Info.plist +13 -2
- package/app/Lattices.app/Contents/Info.plist +13 -2
- package/app/Lattices.app/Contents/MacOS/Lattices +0 -0
- package/app/Sources/AppShell/App.swift +7 -1
- package/app/Sources/AppShell/AppDelegate.swift +60 -1
- package/app/Sources/AppShell/AppShellView.swift +10 -0
- package/app/Sources/AppShell/CliActionLauncher.swift +2 -2
- package/app/Sources/AppShell/MainView.swift +1 -1
- package/app/Sources/AppShell/Preferences.swift +29 -1
- package/app/Sources/AppShell/SettingsView.swift +498 -58
- package/app/Sources/AppShell/SettingsWindow.swift +4 -0
- package/app/Sources/Core/Companion/LatticesCompanionBridgeServer.swift +23 -7
- package/app/Sources/Core/Companion/LatticesCompanionSecurityCoordinator.swift +35 -0
- package/app/Sources/Core/Companion/LatticesCompanionTrackpadController.swift +1 -1
- package/app/Sources/Core/Input/KeyboardRemapConfig.swift +69 -0
- package/app/Sources/Core/Input/KeyboardRemapController.swift +184 -0
- package/app/Sources/Core/Input/KeyboardRemapStore.swift +84 -0
- package/app/Sources/Core/Workspace/SessionManager.swift +1 -1
- package/app/Sources/Core/Workspace/WorkspaceManager.swift +3 -3
- package/bin/lattices-app.ts +11 -0
- package/bin/lattices-dev +11 -0
- package/bin/lattices.ts +57 -17
- package/docs/app.md +30 -2
- package/docs/companion-deck.md +29 -0
- package/docs/concepts.md +5 -5
- package/docs/config.md +34 -9
- package/docs/layers.md +1 -1
- package/docs/overview.md +1 -1
- package/docs/quickstart.md +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,11 +81,11 @@ Close your laptop, reboot, come back a week later — your editor, dev
|
|
|
81
81
|
server, and test runner are exactly where you left them.
|
|
82
82
|
|
|
83
83
|
```sh
|
|
84
|
-
cd my-project && lattices
|
|
84
|
+
cd my-project && lattices start
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
No config? It
|
|
88
|
-
|
|
87
|
+
No config? It opens a shell in the project and, when it can, starts your
|
|
88
|
+
detected dev command in a second pane.
|
|
89
89
|
|
|
90
90
|
### Configuration
|
|
91
91
|
|
|
@@ -95,7 +95,7 @@ Drop a `.lattices.json` in your project root:
|
|
|
95
95
|
{
|
|
96
96
|
"ensure": true,
|
|
97
97
|
"panes": [
|
|
98
|
-
{ "name": "
|
|
98
|
+
{ "name": "shell", "size": 60 },
|
|
99
99
|
{ "name": "server", "cmd": "pnpm dev" },
|
|
100
100
|
{ "name": "tests", "cmd": "pnpm test --watch" }
|
|
101
101
|
]
|
|
@@ -108,7 +108,7 @@ Drop a `.lattices.json` in your project root:
|
|
|
108
108
|
2 panes 3+ panes
|
|
109
109
|
|
|
110
110
|
┌──────────┬───────┐ ┌──────────┬───────┐
|
|
111
|
-
│
|
|
111
|
+
│ shell │server │ │ shell │server │
|
|
112
112
|
│ (60%) │(40%) │ │ (60%) ├───────┤
|
|
113
113
|
└──────────┴───────┘ │ │tests │
|
|
114
114
|
└──────────┴───────┘
|
|
@@ -193,7 +193,9 @@ desktop the same way you do.
|
|
|
193
193
|
## CLI
|
|
194
194
|
|
|
195
195
|
```
|
|
196
|
-
lattices
|
|
196
|
+
lattices Show workspace status and common commands
|
|
197
|
+
lattices start Create or reattach to current project session
|
|
198
|
+
lattices tmux Alias for lattices start
|
|
197
199
|
lattices init Generate .lattices.json
|
|
198
200
|
lattices ls List active sessions
|
|
199
201
|
lattices kill [name] Kill a session
|
package/app/Info.plist
CHANGED
|
@@ -14,10 +14,21 @@
|
|
|
14
14
|
<string>AppIcon</string>
|
|
15
15
|
<key>CFBundlePackageType</key>
|
|
16
16
|
<string>APPL</string>
|
|
17
|
+
<key>CFBundleURLTypes</key>
|
|
18
|
+
<array>
|
|
19
|
+
<dict>
|
|
20
|
+
<key>CFBundleURLName</key>
|
|
21
|
+
<string>com.arach.lattices</string>
|
|
22
|
+
<key>CFBundleURLSchemes</key>
|
|
23
|
+
<array>
|
|
24
|
+
<string>lattices</string>
|
|
25
|
+
</array>
|
|
26
|
+
</dict>
|
|
27
|
+
</array>
|
|
17
28
|
<key>CFBundleVersion</key>
|
|
18
|
-
<string>0.4.
|
|
29
|
+
<string>0.4.8</string>
|
|
19
30
|
<key>CFBundleShortVersionString</key>
|
|
20
|
-
<string>0.4.
|
|
31
|
+
<string>0.4.8</string>
|
|
21
32
|
<key>LSMinimumSystemVersion</key>
|
|
22
33
|
<string>13.0</string>
|
|
23
34
|
<key>LSUIElement</key>
|
|
@@ -14,10 +14,21 @@
|
|
|
14
14
|
<string>AppIcon</string>
|
|
15
15
|
<key>CFBundlePackageType</key>
|
|
16
16
|
<string>APPL</string>
|
|
17
|
+
<key>CFBundleURLTypes</key>
|
|
18
|
+
<array>
|
|
19
|
+
<dict>
|
|
20
|
+
<key>CFBundleURLName</key>
|
|
21
|
+
<string>com.arach.lattices</string>
|
|
22
|
+
<key>CFBundleURLSchemes</key>
|
|
23
|
+
<array>
|
|
24
|
+
<string>lattices</string>
|
|
25
|
+
</array>
|
|
26
|
+
</dict>
|
|
27
|
+
</array>
|
|
17
28
|
<key>CFBundleVersion</key>
|
|
18
|
-
<string>0.4.
|
|
29
|
+
<string>0.4.8</string>
|
|
19
30
|
<key>CFBundleShortVersionString</key>
|
|
20
|
-
<string>0.4.
|
|
31
|
+
<string>0.4.8</string>
|
|
21
32
|
<key>LSMinimumSystemVersion</key>
|
|
22
33
|
<string>13.0</string>
|
|
23
34
|
<key>LSUIElement</key>
|
|
Binary file
|
|
@@ -5,7 +5,13 @@ struct LatticesApp: App {
|
|
|
5
5
|
@NSApplicationDelegateAdaptor(AppDelegate.self) var delegate
|
|
6
6
|
|
|
7
7
|
var body: some Scene {
|
|
8
|
-
Settings {
|
|
8
|
+
Settings {
|
|
9
|
+
SettingsContentView(
|
|
10
|
+
prefs: Preferences.shared,
|
|
11
|
+
scanner: ProjectScanner.shared
|
|
12
|
+
)
|
|
13
|
+
.frame(width: 900, height: 640)
|
|
14
|
+
}
|
|
9
15
|
.commands {
|
|
10
16
|
CommandGroup(after: .appInfo) {
|
|
11
17
|
Button("Update Lattices…") {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import AppKit
|
|
2
|
+
import Carbon
|
|
2
3
|
import SwiftUI
|
|
3
4
|
|
|
4
5
|
extension Notification.Name {
|
|
@@ -69,6 +70,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|
|
69
70
|
Self.shared = self
|
|
70
71
|
NSApp.setActivationPolicy(.accessory)
|
|
71
72
|
NSApp.appearance = NSAppearance(named: .darkAqua)
|
|
73
|
+
registerDeepLinkHandler()
|
|
72
74
|
|
|
73
75
|
// --- Status item ---
|
|
74
76
|
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
|
|
@@ -124,6 +126,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|
|
124
126
|
store.register(action: .omniSearch) { OmniSearchWindow.shared.toggle() }
|
|
125
127
|
WindowDragSnapController.shared.start()
|
|
126
128
|
MouseGestureController.shared.start()
|
|
129
|
+
KeyboardRemapController.shared.start()
|
|
127
130
|
|
|
128
131
|
// Session layer cycling
|
|
129
132
|
store.register(action: .layerNext) { SessionLayerStore.shared.cycleNext() }
|
|
@@ -183,7 +186,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|
|
183
186
|
ProcessModel.shared.start()
|
|
184
187
|
LatticesApi.setup()
|
|
185
188
|
DaemonServer.shared.start()
|
|
186
|
-
|
|
189
|
+
if Preferences.shared.companionBridgeEnabled {
|
|
190
|
+
LatticesCompanionBridgeServer.shared.start()
|
|
191
|
+
} else {
|
|
192
|
+
diag.info("CompanionBridge: disabled by preference")
|
|
193
|
+
}
|
|
187
194
|
AgentPool.shared.start()
|
|
188
195
|
diag.finish(tBoot)
|
|
189
196
|
|
|
@@ -203,6 +210,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|
|
203
210
|
}
|
|
204
211
|
|
|
205
212
|
func applicationWillTerminate(_ notification: Notification) {
|
|
213
|
+
KeyboardRemapController.shared.stop()
|
|
206
214
|
LatticesCompanionBridgeServer.shared.stop()
|
|
207
215
|
DaemonServer.shared.stop()
|
|
208
216
|
}
|
|
@@ -333,6 +341,57 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|
|
333
341
|
@objc private func menuSettings() { SettingsWindowController.shared.show() }
|
|
334
342
|
@objc private func menuQuit() { NSApp.terminate(nil) }
|
|
335
343
|
|
|
344
|
+
// MARK: - Deep Links
|
|
345
|
+
|
|
346
|
+
private func registerDeepLinkHandler() {
|
|
347
|
+
NSAppleEventManager.shared().setEventHandler(
|
|
348
|
+
self,
|
|
349
|
+
andSelector: #selector(handleGetURLEvent(_:withReplyEvent:)),
|
|
350
|
+
forEventClass: AEEventClass(kInternetEventClass),
|
|
351
|
+
andEventID: AEEventID(kAEGetURL)
|
|
352
|
+
)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
@objc private func handleGetURLEvent(
|
|
356
|
+
_ event: NSAppleEventDescriptor,
|
|
357
|
+
withReplyEvent replyEvent: NSAppleEventDescriptor
|
|
358
|
+
) {
|
|
359
|
+
guard
|
|
360
|
+
let value = event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue,
|
|
361
|
+
let url = URL(string: value)
|
|
362
|
+
else {
|
|
363
|
+
return
|
|
364
|
+
}
|
|
365
|
+
handleDeepLink(url)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
private func handleDeepLink(_ url: URL) {
|
|
369
|
+
guard url.scheme?.localizedCaseInsensitiveCompare("lattices") == .orderedSame else {
|
|
370
|
+
return
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
let host = url.host?.lowercased()
|
|
374
|
+
let action = url.pathComponents
|
|
375
|
+
.first { $0 != "/" }?
|
|
376
|
+
.lowercased()
|
|
377
|
+
|
|
378
|
+
guard host == "companion" else {
|
|
379
|
+
SettingsWindowController.shared.show()
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
switch action {
|
|
384
|
+
case "enable", "start":
|
|
385
|
+
Preferences.shared.companionBridgeEnabled = true
|
|
386
|
+
SettingsWindowController.shared.showCompanion()
|
|
387
|
+
case "disable", "stop":
|
|
388
|
+
Preferences.shared.companionBridgeEnabled = false
|
|
389
|
+
SettingsWindowController.shared.showCompanion()
|
|
390
|
+
default:
|
|
391
|
+
SettingsWindowController.shared.showCompanion()
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
336
395
|
private static func showWorkspaceInspector() {
|
|
337
396
|
guard let entry = DesktopModel.shared.frontmostWindow(),
|
|
338
397
|
entry.app != "Lattices" else {
|
|
@@ -8,6 +8,7 @@ enum AppPage: String, CaseIterable {
|
|
|
8
8
|
case desktopInventory
|
|
9
9
|
case pi
|
|
10
10
|
case settings
|
|
11
|
+
case companionSettings
|
|
11
12
|
case docs
|
|
12
13
|
|
|
13
14
|
var label: String {
|
|
@@ -17,6 +18,7 @@ enum AppPage: String, CaseIterable {
|
|
|
17
18
|
case .desktopInventory: return "Desktop Inventory"
|
|
18
19
|
case .pi: return "Pi"
|
|
19
20
|
case .settings: return "Settings"
|
|
21
|
+
case .companionSettings:return "Settings"
|
|
20
22
|
case .docs: return "Docs"
|
|
21
23
|
}
|
|
22
24
|
}
|
|
@@ -28,6 +30,7 @@ enum AppPage: String, CaseIterable {
|
|
|
28
30
|
case .desktopInventory: return "macwindow.on.rectangle"
|
|
29
31
|
case .pi: return "terminal"
|
|
30
32
|
case .settings: return "gearshape"
|
|
33
|
+
case .companionSettings:return "ipad.and.iphone"
|
|
31
34
|
case .docs: return "book"
|
|
32
35
|
}
|
|
33
36
|
}
|
|
@@ -129,6 +132,13 @@ struct AppShellView: View {
|
|
|
129
132
|
scanner: ProjectScanner.shared,
|
|
130
133
|
onBack: { windowController.activePage = .screenMap; controller.enter() }
|
|
131
134
|
)
|
|
135
|
+
case .companionSettings:
|
|
136
|
+
SettingsContentView(
|
|
137
|
+
page: .companionSettings,
|
|
138
|
+
prefs: Preferences.shared,
|
|
139
|
+
scanner: ProjectScanner.shared,
|
|
140
|
+
onBack: { windowController.activePage = .screenMap; controller.enter() }
|
|
141
|
+
)
|
|
132
142
|
case .docs:
|
|
133
143
|
SettingsContentView(
|
|
134
144
|
page: .docs,
|
|
@@ -24,7 +24,7 @@ enum CliActionLauncher {
|
|
|
24
24
|
) else { return }
|
|
25
25
|
|
|
26
26
|
Preferences.shared.terminal.launch(
|
|
27
|
-
command: "lattices init && lattices",
|
|
27
|
+
command: "lattices init && lattices start",
|
|
28
28
|
in: directory
|
|
29
29
|
)
|
|
30
30
|
}
|
|
@@ -36,7 +36,7 @@ enum CliActionLauncher {
|
|
|
36
36
|
) else { return }
|
|
37
37
|
|
|
38
38
|
Preferences.shared.terminal.launch(
|
|
39
|
-
command: "lattices",
|
|
39
|
+
command: "lattices start",
|
|
40
40
|
in: directory
|
|
41
41
|
)
|
|
42
42
|
}
|
|
@@ -490,7 +490,7 @@ struct MainView: View {
|
|
|
490
490
|
.buttonStyle(.plain)
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
-
Text("Initialize runs lattices init && lattices in the folder you choose.")
|
|
493
|
+
Text("Initialize runs lattices init && lattices start in the folder you choose.")
|
|
494
494
|
.font(Typo.mono(9))
|
|
495
495
|
.foregroundColor(Palette.textMuted)
|
|
496
496
|
.multilineTextAlignment(.center)
|
|
@@ -10,6 +10,7 @@ class Preferences: ObservableObject {
|
|
|
10
10
|
static let shared = Preferences()
|
|
11
11
|
|
|
12
12
|
private enum CompanionDefaultsKey {
|
|
13
|
+
static let bridgeEnabled = "companion.bridge.enabled"
|
|
13
14
|
static let trackpadEnabled = "companion.trackpad.enabled"
|
|
14
15
|
static let cockpitLayout = "companion.cockpit.layout"
|
|
15
16
|
}
|
|
@@ -30,6 +31,17 @@ class Preferences: ObservableObject {
|
|
|
30
31
|
didSet { UserDefaults.standard.set(dragSnapEnabled, forKey: "windowSnap.enabled") }
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
@Published var companionBridgeEnabled: Bool {
|
|
35
|
+
didSet {
|
|
36
|
+
UserDefaults.standard.set(companionBridgeEnabled, forKey: CompanionDefaultsKey.bridgeEnabled)
|
|
37
|
+
if companionBridgeEnabled {
|
|
38
|
+
LatticesCompanionBridgeServer.shared.start()
|
|
39
|
+
} else {
|
|
40
|
+
LatticesCompanionBridgeServer.shared.stop()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
33
45
|
@Published var companionTrackpadEnabled: Bool {
|
|
34
46
|
didSet { UserDefaults.standard.set(companionTrackpadEnabled, forKey: CompanionDefaultsKey.trackpadEnabled) }
|
|
35
47
|
}
|
|
@@ -41,6 +53,10 @@ class Preferences: ObservableObject {
|
|
|
41
53
|
didSet { UserDefaults.standard.set(mouseGesturesEnabled, forKey: "mouseGestures.enabled") }
|
|
42
54
|
}
|
|
43
55
|
|
|
56
|
+
@Published var keyboardRemapsEnabled: Bool {
|
|
57
|
+
didSet { UserDefaults.standard.set(keyboardRemapsEnabled, forKey: "keyboardRemaps.enabled") }
|
|
58
|
+
}
|
|
59
|
+
|
|
44
60
|
// MARK: - AI / Claude
|
|
45
61
|
|
|
46
62
|
@Published var claudePath: String {
|
|
@@ -155,10 +171,16 @@ class Preferences: ObservableObject {
|
|
|
155
171
|
self.dragSnapEnabled = true
|
|
156
172
|
}
|
|
157
173
|
|
|
174
|
+
if UserDefaults.standard.object(forKey: CompanionDefaultsKey.bridgeEnabled) != nil {
|
|
175
|
+
self.companionBridgeEnabled = UserDefaults.standard.bool(forKey: CompanionDefaultsKey.bridgeEnabled)
|
|
176
|
+
} else {
|
|
177
|
+
self.companionBridgeEnabled = false
|
|
178
|
+
}
|
|
179
|
+
|
|
158
180
|
if UserDefaults.standard.object(forKey: CompanionDefaultsKey.trackpadEnabled) != nil {
|
|
159
181
|
self.companionTrackpadEnabled = UserDefaults.standard.bool(forKey: CompanionDefaultsKey.trackpadEnabled)
|
|
160
182
|
} else {
|
|
161
|
-
self.companionTrackpadEnabled =
|
|
183
|
+
self.companionTrackpadEnabled = false
|
|
162
184
|
}
|
|
163
185
|
|
|
164
186
|
self.companionCockpitLayout = Self.loadCompanionCockpitLayout()
|
|
@@ -167,6 +189,12 @@ class Preferences: ObservableObject {
|
|
|
167
189
|
} else {
|
|
168
190
|
self.mouseGesturesEnabled = false
|
|
169
191
|
}
|
|
192
|
+
|
|
193
|
+
if UserDefaults.standard.object(forKey: "keyboardRemaps.enabled") != nil {
|
|
194
|
+
self.keyboardRemapsEnabled = UserDefaults.standard.bool(forKey: "keyboardRemaps.enabled")
|
|
195
|
+
} else {
|
|
196
|
+
self.keyboardRemapsEnabled = true
|
|
197
|
+
}
|
|
170
198
|
// AI / Claude
|
|
171
199
|
self.claudePath = UserDefaults.standard.string(forKey: "claude.path") ?? ""
|
|
172
200
|
self.advisorModel = UserDefaults.standard.string(forKey: "claude.advisorModel") ?? "haiku"
|