Skip to content

Commit 25d2e9b

Browse files
DolencLukasteipete
authored andcommitted
fix(macos): keep attach-only from stopping gateway launchd
1 parent ffe67e9 commit 25d2e9b

4 files changed

Lines changed: 65 additions & 16 deletions

File tree

apps/macos/Sources/OpenClaw/DebugSettings.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,6 @@ struct DebugSettings: View {
9292
self.launchAgentWriteDisabled = GatewayLaunchAgentManager.isLaunchAgentWriteDisabled()
9393
return
9494
}
95-
if newValue {
96-
Task {
97-
_ = await GatewayLaunchAgentManager.set(
98-
enabled: false,
99-
bundlePath: Bundle.main.bundlePath,
100-
port: GatewayEnvironment.gatewayPort())
101-
}
102-
}
10395
}
10496

10597
Text(

apps/macos/Sources/OpenClaw/GatewayLaunchAgentManager.swift

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ enum GatewayLaunchAgentManager {
55
private static let disableLaunchAgentMarker = ".openclaw/disable-launchagent"
66

77
private static var disableLaunchAgentMarkerURL: URL {
8-
FileManager().homeDirectoryForCurrentUser
8+
#if DEBUG
9+
if let testingDisableLaunchAgentMarkerURL {
10+
return testingDisableLaunchAgentMarkerURL
11+
}
12+
#endif
13+
return FileManager().homeDirectoryForCurrentUser
914
.appendingPathComponent(self.disableLaunchAgentMarker)
1015
}
1116

@@ -19,6 +24,10 @@ enum GatewayLaunchAgentManager {
1924
return false
2025
}
2126

27+
static func applyAttachOnlyRuntimeOverride() -> String? {
28+
self.setLaunchAgentWriteDisabled(true)
29+
}
30+
2231
static func setLaunchAgentWriteDisabled(_ disabled: Bool) -> String? {
2332
let marker = self.disableLaunchAgentMarkerURL
2433
if disabled {
@@ -144,6 +153,15 @@ extension GatewayLaunchAgentManager {
144153
timeout: Double,
145154
quiet: Bool) async -> CommandResult
146155
{
156+
#if DEBUG
157+
if self.testingInterceptDaemonCommands {
158+
self.testingDaemonCommandCalls.append(args)
159+
return CommandResult(
160+
success: true,
161+
payload: Data("{\"ok\":true}".utf8),
162+
message: nil)
163+
}
164+
#endif
147165
let command = CommandResolver.openclawCommand(
148166
subcommand: "gateway",
149167
extraArgs: self.withJsonFlag(args),
@@ -187,4 +205,26 @@ extension GatewayLaunchAgentManager {
187205
private static func summarize(_ text: String) -> String? {
188206
TextSummarySupport.summarizeLastLine(text)
189207
}
208+
209+
#if DEBUG
210+
nonisolated(unsafe) private static var testingDisableLaunchAgentMarkerURL: URL?
211+
nonisolated(unsafe) private static var testingInterceptDaemonCommands = false
212+
nonisolated(unsafe) private static var testingDaemonCommandCalls: [[String]] = []
213+
214+
static func setTestingDisableLaunchAgentMarkerURL(_ url: URL?) {
215+
self.testingDisableLaunchAgentMarkerURL = url
216+
}
217+
218+
static func setTestingInterceptDaemonCommands(_ intercept: Bool) {
219+
self.testingInterceptDaemonCommands = intercept
220+
}
221+
222+
static func clearTestingDaemonCommandCalls() {
223+
self.testingDaemonCommandCalls.removeAll(keepingCapacity: false)
224+
}
225+
226+
static func testingDaemonCommandCallsSnapshot() -> [[String]] {
227+
self.testingDaemonCommandCalls
228+
}
229+
#endif
190230
}

apps/macos/Sources/OpenClaw/MenuBar.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,10 @@ struct OpenClawApp: App {
9898
private static func applyAttachOnlyOverrideIfNeeded() {
9999
let args = CommandLine.arguments
100100
guard args.contains("--attach-only") || args.contains("--no-launchd") else { return }
101-
if let error = GatewayLaunchAgentManager.setLaunchAgentWriteDisabled(true) {
101+
if let error = GatewayLaunchAgentManager.applyAttachOnlyRuntimeOverride() {
102102
Self.logger.error("attach-only flag failed: \(error, privacy: .public)")
103103
return
104104
}
105-
Task {
106-
_ = await GatewayLaunchAgentManager.set(
107-
enabled: false,
108-
bundlePath: Bundle.main.bundlePath,
109-
port: GatewayEnvironment.gatewayPort())
110-
}
111105
Self.logger.info("attach-only flag enabled")
112106
}
113107

apps/macos/Tests/OpenClawIPCTests/GatewayLaunchAgentManagerTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@ import Testing
33
@testable import OpenClaw
44

55
struct GatewayLaunchAgentManagerTests {
6+
@Test func `attach only runtime override does not uninstall gateway launch agent`() throws {
7+
let dir = FileManager().temporaryDirectory
8+
.appendingPathComponent("openclaw-attach-only-\(UUID().uuidString)", isDirectory: true)
9+
let marker = dir.appendingPathComponent("disable-launchagent")
10+
try FileManager().createDirectory(at: dir, withIntermediateDirectories: true)
11+
defer { try? FileManager().removeItem(at: dir) }
12+
defer {
13+
GatewayLaunchAgentManager.setTestingDisableLaunchAgentMarkerURL(nil)
14+
GatewayLaunchAgentManager.setTestingInterceptDaemonCommands(false)
15+
GatewayLaunchAgentManager.clearTestingDaemonCommandCalls()
16+
}
17+
18+
GatewayLaunchAgentManager.setTestingDisableLaunchAgentMarkerURL(marker)
19+
GatewayLaunchAgentManager.setTestingInterceptDaemonCommands(true)
20+
GatewayLaunchAgentManager.clearTestingDaemonCommandCalls()
21+
22+
let error = GatewayLaunchAgentManager.applyAttachOnlyRuntimeOverride()
23+
24+
#expect(error == nil)
25+
#expect(FileManager().fileExists(atPath: marker.path))
26+
#expect(GatewayLaunchAgentManager.testingDaemonCommandCallsSnapshot().isEmpty)
27+
}
28+
629
@Test func `launch agent plist snapshot parses args and env`() throws {
730
let url = FileManager().temporaryDirectory
831
.appendingPathComponent("openclaw-launchd-\(UUID().uuidString).plist")

0 commit comments

Comments
 (0)