Skip to content

Commit 106fa5f

Browse files
committed
fix(macos): prioritize openclaw binary for gateway commands
1 parent d2c031d commit 106fa5f

File tree

2 files changed

+57
-11
lines changed

2 files changed

+57
-11
lines changed

apps/macos/Sources/OpenClaw/CommandResolver.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,17 @@ enum CommandResolver {
246246
return ssh
247247
}
248248

249-
let runtimeResult = self.runtimeResolution(searchPaths: searchPaths)
249+
let root = self.projectRoot()
250+
if let openclawPath = self.projectOpenClawExecutable(projectRoot: root) {
251+
return [openclawPath, subcommand] + extraArgs
252+
}
253+
if let openclawPath = self.openclawExecutable(searchPaths: searchPaths) {
254+
return [openclawPath, subcommand] + extraArgs
255+
}
250256

257+
let runtimeResult = self.runtimeResolution(searchPaths: searchPaths)
251258
switch runtimeResult {
252259
case let .success(runtime):
253-
let root = self.projectRoot()
254-
if let openclawPath = self.projectOpenClawExecutable(projectRoot: root) {
255-
return [openclawPath, subcommand] + extraArgs
256-
}
257-
258260
if let entry = self.gatewayEntrypoint(in: root) {
259261
return self.makeRuntimeCommand(
260262
runtime: runtime,
@@ -266,9 +268,6 @@ enum CommandResolver {
266268
// Use --silent to avoid pnpm lifecycle banners that would corrupt JSON outputs.
267269
return [pnpm, "--silent", "openclaw", subcommand] + extraArgs
268270
}
269-
if let openclawPath = self.openclawExecutable(searchPaths: searchPaths) {
270-
return [openclawPath, subcommand] + extraArgs
271-
}
272271

273272
let missingEntry = """
274273
openclaw entrypoint missing (looked for dist/index.js or openclaw.mjs); run pnpm build.

apps/macos/Tests/OpenClawIPCTests/CommandResolverTests.swift

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,48 @@ import Testing
6666
}
6767
}
6868

69+
@Test func prefersOpenClawBinaryOverPnpm() async throws {
70+
let defaults = self.makeDefaults()
71+
defaults.set(AppState.ConnectionMode.local.rawValue, forKey: connectionModeKey)
72+
73+
let tmp = try makeTempDir()
74+
CommandResolver.setProjectRoot(tmp.path)
75+
76+
let binDir = tmp.appendingPathComponent("bin")
77+
let openclawPath = binDir.appendingPathComponent("openclaw")
78+
let pnpmPath = binDir.appendingPathComponent("pnpm")
79+
try self.makeExec(at: openclawPath)
80+
try self.makeExec(at: pnpmPath)
81+
82+
let cmd = CommandResolver.openclawCommand(
83+
subcommand: "rpc",
84+
defaults: defaults,
85+
configRoot: [:],
86+
searchPaths: [binDir.path])
87+
88+
#expect(cmd.prefix(2).elementsEqual([openclawPath.path, "rpc"]))
89+
}
90+
91+
@Test func usesOpenClawBinaryWithoutNodeRuntime() async throws {
92+
let defaults = self.makeDefaults()
93+
defaults.set(AppState.ConnectionMode.local.rawValue, forKey: connectionModeKey)
94+
95+
let tmp = try makeTempDir()
96+
CommandResolver.setProjectRoot(tmp.path)
97+
98+
let binDir = tmp.appendingPathComponent("bin")
99+
let openclawPath = binDir.appendingPathComponent("openclaw")
100+
try self.makeExec(at: openclawPath)
101+
102+
let cmd = CommandResolver.openclawCommand(
103+
subcommand: "gateway",
104+
defaults: defaults,
105+
configRoot: [:],
106+
searchPaths: [binDir.path])
107+
108+
#expect(cmd.prefix(2).elementsEqual([openclawPath.path, "gateway"]))
109+
}
110+
69111
@Test func fallsBackToPnpm() async throws {
70112
let defaults = self.makeDefaults()
71113
defaults.set(AppState.ConnectionMode.local.rawValue, forKey: connectionModeKey)
@@ -76,7 +118,11 @@ import Testing
76118
let pnpmPath = tmp.appendingPathComponent("node_modules/.bin/pnpm")
77119
try self.makeExec(at: pnpmPath)
78120

79-
let cmd = CommandResolver.openclawCommand(subcommand: "rpc", defaults: defaults, configRoot: [:])
121+
let cmd = CommandResolver.openclawCommand(
122+
subcommand: "rpc",
123+
defaults: defaults,
124+
configRoot: [:],
125+
searchPaths: [tmp.appendingPathComponent("node_modules/.bin").path])
80126

81127
#expect(cmd.prefix(4).elementsEqual([pnpmPath.path, "--silent", "openclaw", "rpc"]))
82128
}
@@ -95,7 +141,8 @@ import Testing
95141
subcommand: "health",
96142
extraArgs: ["--json", "--timeout", "5"],
97143
defaults: defaults,
98-
configRoot: [:])
144+
configRoot: [:],
145+
searchPaths: [tmp.appendingPathComponent("node_modules/.bin").path])
99146

100147
#expect(cmd.prefix(5).elementsEqual([pnpmPath.path, "--silent", "openclaw", "health", "--json"]))
101148
#expect(cmd.suffix(2).elementsEqual(["--timeout", "5"]))

0 commit comments

Comments
 (0)