Skip to content

Commit 6b71fd9

Browse files
committed
fix(kit): avoid @observable macro bug with package-access stored vars
Swift 5.10's @observable macro emits a duplicate access modifier for 'package' tracked stored properties. Those properties (and the enums in their signatures) go public instead — HalenKit is never importable by plugin targets, so nothing leaks into the plugin surface. Also isolate NotchPanelManager's nested PanelController to the main actor. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTBT2mWSqwRv3mRnMhJ2qS
1 parent 44d4450 commit 6b71fd9

8 files changed

Lines changed: 21 additions & 20 deletions

File tree

‎Sources/HalenKit/Accessibility/SystemPermissions.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import HalenPluginAPI
1414
@MainActor
1515
@Observable
1616
package final class SystemPermissionsModel {
17-
package private(set) var grants: [SystemPermission: PermissionGrant] = [:]
17+
public private(set) var grants: [SystemPermission: PermissionGrant] = [:]
1818

1919
package init() {
2020
// Populate synchronously where we can so the Settings view doesn't

‎Sources/HalenKit/Hotkeys/HotkeyRegistrar.swift‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ package enum HotkeyID: UInt32 {
1818
/// were when the conflict was detected. The label is the *attempted* owner
1919
/// — the one we rejected; `existingOwner` is the registration that keeps
2020
/// the chord. Surfaced in Settings so the user can disable or rebind.
21-
package struct HotkeyConflict: Equatable, Identifiable, Sendable {
22-
package let id = UUID()
23-
package let keyCode: UInt32
24-
package let modifiers: UInt32
25-
package let existingOwner: String
26-
package let attemptedOwner: String
21+
public struct HotkeyConflict: Equatable, Identifiable, Sendable {
22+
public let id = UUID()
23+
public let keyCode: UInt32
24+
public let modifiers: UInt32
25+
public let existingOwner: String
26+
public let attemptedOwner: String
2727

28-
package static func == (lhs: HotkeyConflict, rhs: HotkeyConflict) -> Bool {
28+
public static func == (lhs: HotkeyConflict, rhs: HotkeyConflict) -> Bool {
2929
lhs.keyCode == rhs.keyCode
3030
&& lhs.modifiers == rhs.modifiers
3131
&& lhs.existingOwner == rhs.existingOwner
@@ -36,7 +36,7 @@ package struct HotkeyConflict: Equatable, Identifiable, Sendable {
3636
/// bitmask values are stable across macOS versions, so this is a pure
3737
/// lookup. Unknown key codes fall back to their numeric form so the
3838
/// row stays informative even for obscure keys.
39-
package var displayChord: String {
39+
public var displayChord: String {
4040
var s = ""
4141
if modifiers & UInt32(controlKey) != 0 { s += "⌃" }
4242
if modifiers & UInt32(optionKey) != 0 { s += "⌥" }
@@ -106,7 +106,7 @@ package final class HotkeyConflictRegistry {
106106
/// Conflicts collected since launch. Two plugins attempting the same
107107
/// chord at startup append once; the UI uses identity (`UUID`) to
108108
/// stably render rows even if the array is mutated.
109-
package private(set) var conflicts: [HotkeyConflict] = []
109+
public private(set) var conflicts: [HotkeyConflict] = []
110110

111111
private init() {}
112112

‎Sources/HalenKit/Inference/InferenceBackend.swift‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ extension InferenceBackend {
4141
}
4242
}
4343

44-
package enum BackendKind: String, Sendable, Codable, CaseIterable {
44+
public enum BackendKind: String, Sendable, Codable, CaseIterable {
4545
case bundledLlama = "bundled-llama"
4646
case appleFoundationModels = "apple-fm"
4747
case ollama = "ollama"
4848

49-
package var displayName: String {
49+
public var displayName: String {
5050
switch self {
5151
case .bundledLlama: return "Built-in (Gemma 4 E4B)"
5252
case .appleFoundationModels: return "Apple Intelligence"
@@ -72,12 +72,12 @@ package struct BackendCapability: Sendable {
7272
}
7373
}
7474

75-
package enum BackendAvailability: Sendable, Equatable {
75+
public enum BackendAvailability: Sendable, Equatable {
7676
case available
7777
/// Human-readable reason, surfaced in Settings (e.g. "Ollama not reachable").
7878
case unavailable(reason: String)
7979

80-
package var isAvailable: Bool {
80+
public var isAvailable: Bool {
8181
if case .available = self { return true }
8282
return false
8383
}

‎Sources/HalenKit/Inference/InferenceSettings.swift‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ package final class InferenceSettings {
1010
package static let preferenceOrderKey = "halen.inference.backendOrder"
1111

1212
/// Backend priority, highest first. Persisted as raw-value strings.
13-
package var preferenceOrder: [BackendKind] {
13+
public var preferenceOrder: [BackendKind] {
1414
didSet { persist() }
1515
}
1616

1717
/// Last probed availability per backend — drives the Settings status dots.
1818
/// Live state, not persisted.
19-
package var availability: [BackendKind: BackendAvailability] = [:]
19+
public var availability: [BackendKind: BackendAvailability] = [:]
2020

2121
package init() {
2222
if let raw = UserDefaults.standard.array(forKey: Self.preferenceOrderKey) as? [String] {

‎Sources/HalenKit/Inference/LlamaCpp/ModelDownloader.swift‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ package final class ModelDownloader {
3939
/// on even a slow residential link — beyond that we'd rather fail loudly.
4040
private static let resourceTimeout: TimeInterval = 60 * 60
4141

42-
package enum State: Equatable {
42+
public enum State: Equatable {
4343
case notDownloaded
4444
case downloading(fraction: Double, bytes: Int64, total: Int64)
4545
case verifying
@@ -48,7 +48,7 @@ package final class ModelDownloader {
4848
case failed(message: String)
4949
}
5050

51-
package private(set) var state: State
51+
public private(set) var state: State
5252

5353
private var downloadTask: Task<Void, Never>?
5454

‎Sources/HalenKit/Notch/NotchPanelManager.swift‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import HalenPluginAPI
1313
/// throws if another plugin already holds it.
1414
@MainActor
1515
package final class NotchPanelManager {
16+
@MainActor
1617
private final class PanelController {
1718
let panel: NSPanel
1819

‎Sources/HalenKit/PluginHosting/PermissionBroker.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ package final class PermissionBroker {
2727
package let system = SystemPermissionsModel()
2828

2929
/// Bumped on every grant change so SwiftUI dependents refresh.
30-
package private(set) var revision = 0
30+
public private(set) var revision = 0
3131

3232
private let defaults: UserDefaults
3333

‎Sources/HalenKit/PluginHosting/PluginRegistry.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import HalenPluginAPI
88
@Observable
99
@MainActor
1010
package final class PluginRegistry {
11-
package private(set) var plugins: [any HalenPlugin] = []
11+
public private(set) var plugins: [any HalenPlugin] = []
1212
private var enabledStates: [String: Bool] = [:]
1313

1414
private let defaults = UserDefaults.standard

0 commit comments

Comments
 (0)