From f1cd3ea5310fae6e42fdee9f64b88305d3d2373a Mon Sep 17 00:00:00 2001 From: Felix Lu <58391009+lumpinif@users.noreply.github.com> Date: Mon, 2 Mar 2026 23:00:30 +0800 Subject: [PATCH] =?UTF-8?q?fix(app:macos):=20=E3=80=90=20OpenClaw=20?= =?UTF-8?q?=E2=87=84=20clawdbot=20=E3=80=91-=20=20Peekaboo=20Bridge=20disc?= =?UTF-8?q?overy=20after=20the=20OpenClaw=20rename=20(#6033)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(mac): keep OpenClaw bridge socket and harden legacy symlink * fix(mac): add clawdis legacy Peekaboo bridge symlink * macos: include moltbot in PeekabooBridge legacy socket paths * changelog: note peekaboo legacy socket compatibility paths --------- Co-authored-by: Vincent Koc --- CHANGELOG.md | 2 + .../PeekabooBridgeHostCoordinator.swift | 57 ++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2db99bd56a..9bd2d9ea67c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ Docs: https://docs.openclaw.ai ### Fixes +- Agents/Sessions list transcript paths: handle missing/non-string/relative `sessions.list.path` values and per-agent `{agentId}` templates when deriving `transcriptPath`, so cross-agent session listings resolve to concrete agent session files instead of workspace-relative paths. (#24775) Thanks @martinfrancois. +- macOS/PeekabooBridge: add compatibility socket symlinks for legacy `clawdbot`, `clawdis`, and `moltbot` Application Support socket paths so pre-rename clients can still connect. (#6033) Thanks @lumpinif and @vincentkoc. - Webchat/Feishu session continuation: preserve routable `OriginatingChannel`/`OriginatingTo` metadata from session delivery context in `chat.send`, and prefer provider-normalized channel when deciding cross-channel route dispatch so Webchat replies continue on the selected Feishu session instead of falling back to main/internal session routing. (#31573) - Feishu/Duplicate replies: suppress same-target reply dispatch when message-tool sends use generic provider metadata (`provider: "message"`) and normalize `lark`/`feishu` provider aliases during duplicate-target checks, preventing double-delivery in Feishu sessions. (#31526) - Feishu/Plugin sdk compatibility: add safe webhook default fallbacks when loading Feishu monitor state so mixed-version installs no longer crash if older `openclaw/plugin-sdk` builds omit webhook default constants. (#31606) diff --git a/apps/macos/Sources/OpenClaw/PeekabooBridgeHostCoordinator.swift b/apps/macos/Sources/OpenClaw/PeekabooBridgeHostCoordinator.swift index 9f97650b9f2..968931ca33f 100644 --- a/apps/macos/Sources/OpenClaw/PeekabooBridgeHostCoordinator.swift +++ b/apps/macos/Sources/OpenClaw/PeekabooBridgeHostCoordinator.swift @@ -13,14 +13,29 @@ final class PeekabooBridgeHostCoordinator { private var host: PeekabooBridgeHost? private var services: OpenClawPeekabooBridgeServices? + + private static let legacySocketDirectoryNames = ["clawdbot", "clawdis", "moltbot"] + private static var openclawSocketPath: String { let fileManager = FileManager.default let base = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first ?? fileManager.homeDirectoryForCurrentUser.appendingPathComponent("Library/Application Support") - let directory = base.appendingPathComponent("OpenClaw", isDirectory: true) - return directory.appendingPathComponent(PeekabooBridgeConstants.socketName, isDirectory: false).path + return Self.makeSocketPath(for: "OpenClaw", in: base) } + private static func makeSocketPath(for directoryName: String, in baseDirectory: URL) -> String { + baseDirectory + .appendingPathComponent(directoryName, isDirectory: true) + .appendingPathComponent(PeekabooBridgeConstants.socketName, isDirectory: false) + .path + } + + private static var legacySocketPaths: [String] { + let fileManager = FileManager.default + let base = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first + ?? fileManager.homeDirectoryForCurrentUser.appendingPathComponent("Library/Application Support") + return Self.legacySocketDirectoryNames.map { Self.makeSocketPath(for: $0, in: base) } + } func setEnabled(_ enabled: Bool) async { if enabled { await self.startIfNeeded() @@ -46,6 +61,8 @@ final class PeekabooBridgeHostCoordinator { } let allowlistedBundles: Set = [] + self.ensureLegacySocketSymlinks() + let services = OpenClawPeekabooBridgeServices() let server = PeekabooBridgeServer( services: services, @@ -67,6 +84,42 @@ final class PeekabooBridgeHostCoordinator { .info("PeekabooBridge host started at \(Self.openclawSocketPath, privacy: .public)") } + private func ensureLegacySocketSymlinks() { + Self.legacySocketPaths.forEach { legacyPath in + self.ensureLegacySocketSymlink(at: legacyPath) + } + } + + private func ensureLegacySocketSymlink(at legacyPath: String) { + let fileManager = FileManager.default + let legacyDirectory = (legacyPath as NSString).deletingLastPathComponent + do { + let directoryAttributes: [FileAttributeKey: Any] = [ + .posixPermissions: 0o700, + ] + try fileManager.createDirectory( + atPath: legacyDirectory, + withIntermediateDirectories: true, + attributes: directoryAttributes) + let linkURL = URL(fileURLWithPath: legacyPath) + let linkValues = try? linkURL.resourceValues(forKeys: [.isSymbolicLinkKey]) + if linkValues?.isSymbolicLink == true { + let destination = try FileManager.default.destinationOfSymbolicLink(atPath: legacyPath) + let destinationURL = URL(fileURLWithPath: destination, relativeTo: linkURL.deletingLastPathComponent()) + .standardizedFileURL + if destinationURL.path == URL(fileURLWithPath: Self.openclawSocketPath).standardizedFileURL.path { + return + } + try fileManager.removeItem(atPath: legacyPath) + } else if fileManager.fileExists(atPath: legacyPath) { + try fileManager.removeItem(atPath: legacyPath) + } + try fileManager.createSymbolicLink(atPath: legacyPath, withDestinationPath: Self.openclawSocketPath) + } catch { + self.logger.debug("Failed to create legacy PeekabooBridge socket symlink: \(error.localizedDescription, privacy: .public)") + } + } + private static func currentTeamID() -> String? { var code: SecCode? guard SecCodeCopySelf(SecCSFlags(), &code) == errSecSuccess,