Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .github/swift-warning-budget.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# Reduce counts when warnings are fixed. CI fails if new warnings exceed this budget.
1 CLI/cmux.swift literal value is already handled by previous pattern; consider removing it
2 CLI/cmux.swift variable 'groups' was never mutated; consider changing to 'let' constant
1 Packages/macOS/CmuxSurfaceCatalogModel/Sources/CmuxSurfaceCatalogModel/CmuxTuiSnapshotParser.swift default will never be executed
1 Packages/macOS/CmuxSurfaceCatalogModel/Sources/CmuxSurfaceCatalogModel/SurfaceCatalogModel.swift immutable value 'rowID' was never used; consider replacing with '_' or removing it
1 Sources/App/TerminalDirectoryOpenSupport.swift 'fullPath(forApplication:)' was deprecated in macOS 11.0: Use -[NSWorkspace URLForApplicationWithBundleIdentifier:] instead.
2 Sources/AppDelegate+PaneMemoryGuardrail.swift trailing closure in this context is confusable with the body of the statement; pass as a parenthesized argument to silence this warning
1 Sources/AppDelegate.swift 'accessibilityAttributeValue' was deprecated in macOS 10.10: Use the NSAccessibility protocol methods instead (see NSAccessibilityProtocols.h)
Expand Down Expand Up @@ -78,8 +80,6 @@
1 Sources/SessionIndexTableController.swift main actor-isolated property 'isApplyingRows' can not be referenced from a Sendable closure
2 Sources/SessionIndexView.swift 'onChange(of:perform:)' was deprecated in macOS 14.0: Use `onChange` with a two or zero parameter action closure instead.
1 Sources/Settings/ConfigSettingsView.swift 'onChange(of:perform:)' was deprecated in macOS 14.0: Use `onChange` with a two or zero parameter action closure instead.
1 Sources/Surfaces/CmuxTuiSnapshotParser.swift default will never be executed
1 Sources/Surfaces/SurfaceCatalogModel.swift immutable value 'rowID' was never used; consider replacing with '_' or removing it
17 Sources/TabManager.swift result of call to 'closePanel(_:force:)' is unused
1 Sources/TerminalController.swift 'CGWindowListCreateImage' was deprecated in macOS 14.0: Please use ScreenCaptureKit instead.
2 Sources/TerminalController.swift 'activateIgnoringOtherApps' was deprecated in macOS 14.0: ignoringOtherApps is deprecated in macOS 14 and will have no effect.
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2430,6 +2430,7 @@ jobs:
CmuxNotifications
CmuxSettings
CmuxSettingsUI
CmuxSurfaceCatalogModel
CmuxSudoBroker
CmuxSudoBrokerUI
CmuxTerminal
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cloud-command-deadlines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
paths:
- Sources/Cloud/CloudTuiPersistent*.swift
- Sources/Cloud/CloudTuiManualIO*.swift
- Sources/Cloud/CloudTuiTerminalProjectionTarget.swift
- Packages/macOS/CmuxSurfaceCatalogModel/Sources/CmuxSurfaceCatalogModel/CloudTuiTerminalProjectionTarget.swift
- Sources/Cloud/CloudTuiRemoteColors.swift
- cmuxTests/CloudCommand*.swift
- cmuxTests/CloudTuiManualIOConnectionTests.swift
Expand Down
1 change: 1 addition & 0 deletions CLI/CMUXCLI+VMTransfer.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import CmuxSettings
import CmuxSurfaceCatalogModel
import CryptoKit
import Foundation

Expand Down
1 change: 1 addition & 0 deletions CLI/cmux.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import CmuxSurfaceCatalogModel
import Foundation
import CMUXAgentLaunch
import CmuxAgentJournal
Expand Down
22 changes: 22 additions & 0 deletions Packages/macOS/CmuxSurfaceCatalogModel/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// swift-tools-version: 6.0
import PackageDescription

let package = Package(
name: "CmuxSurfaceCatalogModel",
platforms: [.macOS(.v14)],
products: [.library(name: "CmuxSurfaceCatalogModel", targets: ["CmuxSurfaceCatalogModel"])],
dependencies: [
.package(path: "../CMUXDebugLog"),
.package(path: "../CmuxCore"),
.package(path: "../../Shared/CMUXMobileCore")
],
targets: [
.target(
name: "CmuxSurfaceCatalogModel",
dependencies: ["CMUXDebugLog", "CmuxCore", "CMUXMobileCore"],
// The files moved out of the app target unchanged; keep its language mode.
swiftSettings: [.swiftLanguageMode(.v5)]
),
.testTarget(name: "CmuxSurfaceCatalogModelTests", dependencies: ["CmuxSurfaceCatalogModel"])
]
)
44 changes: 44 additions & 0 deletions Packages/macOS/CmuxSurfaceCatalogModel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# CmuxSurfaceCatalogModel

The surface catalog's value types: the vocabulary shared by `SurfaceCatalog`, the Cloud sidebar, the socket commands and the CLI. Pure `Hashable`/`Codable`/`Sendable` values plus the cmux-tui snapshot parser that produces them. No app imports; depends on `CmuxCore`, `CMUXDebugLog` and `CMUXMobileCore` (for device-ID canonicalization).

```swift
import CmuxSurfaceCatalogModel

let id = SurfaceResourceID(machine: .cloud("vm-1"), kind: .terminal, key: "t1")
assert(SurfaceResourceID(rawValue: id.rawValue) == id)
```

`SurfaceCatalog` itself (the owner, `@MainActor`, app-coupled) stays in the app target.

## Moved files

From `Sources/Surfaces/`: `SurfaceCatalogModel.swift`, `SurfaceCatalogSnapshot.swift`, `SurfaceResourcePlacement.swift`, `CloudVMTabState.swift`, `CloudTabNameAuthority.swift`, `CloudTabNameSource.swift`, `CmuxTuiSnapshotParser.swift`, `CloudVMState+SnapshotComparison.swift` (it holds `CloudVMState`'s `==`), `SurfaceMachineID.swift`, `SurfaceDeviceInstanceID.swift`, `SurfaceDevicePresence.swift`, `SurfaceProjectionIdentity.swift`.
From `Sources/Cloud/`: `VMMachineKind.swift` (was also a member of the `cmux-cli` target, so the CLI links this package), `CloudTuiTerminalProjectionTarget.swift`.

`SurfaceResourceID+Ports.swift` is new: the parser's listening-port helpers (from `SurfaceCatalog+CloudPorts.swift`) and `SurfaceResourceID.portKey`/`desktopDisplayKey` (from `SurfaceSocketCommands.swift`), which the moved parser calls.

## What changed besides the move

- Declarations became `public`. Structs that relied on the synthesized memberwise initializer got an explicit `public init` with the same parameters and defaults.
- `cmuxDebugLog(...)` (an app global) became `CMUXDebugLog.logDebugEvent(...)`, still under `#if DEBUG`.

## Current-main boundary

`SurfaceProjectionIdentity` is also a package value: catalog exports carry stable
surface/workspace ownership metadata beside runtime projection selectors. Its
`Workspace` capture extension stays in the app; the package neither looks up nor
owns live workspaces. Snapshot creation/deletion metadata retains its optional
wire fields and backwards-compatible decoding.

`SurfaceResourceGroup` and `SurfaceProjectionLayout` still live in the app. Their
pure declarations are candidates for a later boundary change; catalog projection
orchestration, provider lookup, and layout application must remain above this
value layer. This extraction does not move the navigation coordinator or establish
a Cloud package.

Run the production value tests without launching the app:

```sh
swift test --package-path Packages/macOS/CmuxSurfaceCatalogModel
```
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import Foundation
/// The daemon persists provenance separately from display text. Legacy named
/// tabs are user-owned; a daemon without revision metadata cannot admit auto names.
/// The extension map keeps snapshots compatible with released strict SDK decoders.
struct CloudTabNameAuthority: Hashable, Codable, Sendable {
let source: CloudTabNameSource
let revision: UInt64
public struct CloudTabNameAuthority: Hashable, Codable, Sendable {
public let source: CloudTabNameSource
public let revision: UInt64

init?(snapshot: [String: Any]) {
public init?(snapshot: [String: Any]) {
guard let metadata = snapshot["extra"] as? [String: Any],
let raw = metadata["name_source"] as? String,
let source = CloudTabNameSource(rawValue: raw),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// The durable writer whose name currently overrides the process title.
enum CloudTabNameSource: String, Codable, Sendable {
public enum CloudTabNameSource: String, Codable, Sendable {
case user
case auto
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// A concrete remote pane location accepted by cmux-tui's `terminal.project` command.
///
/// The public terminal resource can outlive every tab that displays it. When that happens,
/// the native macOS mirror first creates one remote view in an existing pane, then resolves
/// the daemon-local surface id for the byte attachment.
public struct CloudTuiTerminalProjectionTarget: Equatable, Sendable {
public let workspaceID: String
public let screenID: String
public let paneID: String
public let index: Int

public init(workspaceID: String, screenID: String, paneID: String, index: Int) {
self.workspaceID = workspaceID
self.screenID = screenID
self.paneID = paneID
self.index = index
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

extension CloudVMState {
static func == (lhs: CloudVMState, rhs: CloudVMState) -> Bool {
public static func == (lhs: CloudVMState, rhs: CloudVMState) -> Bool {
lhs.hasSameModeledContent(as: rhs) && lhs.document == rhs.document
}

Expand All @@ -10,7 +10,7 @@ extension CloudVMState {
/// them in exports without treating inspection or resize as a conflict.
/// Compare resource rows by identity. Positional keys keep unkeyed arrays
/// strict, and every unknown field inside a row remains part of equality.
func hasSameRevisionedContent(as other: CloudVMState) -> Bool {
public func hasSameRevisionedContent(as other: CloudVMState) -> Bool {
hasSameRevisionedModeledContent(as: other)
&& document.values.filter { $0.key != "clients" && $0.key != "session" }
== other.document.values.filter { $0.key != "clients" && $0.key != "session" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Foundation

/// One accepted daemon tab, including the durable owner and revision of its name.
public struct CloudVMTabState: Hashable, Codable, Sendable {
public var id: String
public var paneID: String
public var name: String?
public var index: Int
public var focused: Bool
public var contentKind: String
public var contentID: String
public var nameAuthority: CloudTabNameAuthority? = nil

public init(
id: String,
paneID: String,
name: String? = nil,
index: Int,
focused: Bool,
contentKind: String,
contentID: String,
nameAuthority: CloudTabNameAuthority? = nil
) {
self.id = id
self.paneID = paneID
self.name = name
self.index = index
self.focused = focused
self.contentKind = contentKind
self.contentID = contentID
self.nameAuthority = nameAuthority
}
}
Loading
Loading