refactor: rename to openclaw

This commit is contained in:
Peter Steinberger
2026-01-30 03:15:10 +01:00
parent 4583f88626
commit 9a7160786a
2357 changed files with 16688 additions and 16788 deletions

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -6,8 +6,8 @@
{
"layers" : [
{
"image-name" : "moltbot-mac.png",
"name" : "moltbot-mac",
"image-name" : "openclaw-mac.png",
"name" : "openclaw-mac",
"position" : {
"scale" : 1.07,
"translation-in-points" : [

View File

@@ -1,18 +1,18 @@
// swift-tools-version: 6.2
// Package manifest for the Moltbot macOS companion (menu bar app + IPC library).
// Package manifest for the OpenClaw macOS companion (menu bar app + IPC library).
import PackageDescription
let package = Package(
name: "Moltbot",
name: "OpenClaw",
platforms: [
.macOS(.v15),
],
products: [
.library(name: "MoltbotIPC", targets: ["MoltbotIPC"]),
.library(name: "MoltbotDiscovery", targets: ["MoltbotDiscovery"]),
.executable(name: "Moltbot", targets: ["Moltbot"]),
.executable(name: "moltbot-mac", targets: ["MoltbotMacCLI"]),
.library(name: "OpenClawIPC", targets: ["OpenClawIPC"]),
.library(name: "OpenClawDiscovery", targets: ["OpenClawDiscovery"]),
.executable(name: "OpenClaw", targets: ["OpenClaw"]),
.executable(name: "openclaw-mac", targets: ["OpenClawMacCLI"]),
],
dependencies: [
.package(url: "https://github.com/orchetect/MenuBarExtraAccess", exact: "1.2.2"),
@@ -20,33 +20,33 @@ let package = Package(
.package(url: "https://github.com/apple/swift-log.git", from: "1.8.0"),
.package(url: "https://github.com/sparkle-project/Sparkle", from: "2.8.1"),
.package(url: "https://github.com/steipete/Peekaboo.git", branch: "main"),
.package(path: "../shared/MoltbotKit"),
.package(path: "../shared/OpenClawKit"),
.package(path: "../../Swabble"),
],
targets: [
.target(
name: "MoltbotIPC",
name: "OpenClawIPC",
dependencies: [],
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
]),
.target(
name: "MoltbotDiscovery",
name: "OpenClawDiscovery",
dependencies: [
.product(name: "MoltbotKit", package: "MoltbotKit"),
.product(name: "OpenClawKit", package: "OpenClawKit"),
],
path: "Sources/MoltbotDiscovery",
path: "Sources/OpenClawDiscovery",
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
]),
.executableTarget(
name: "Moltbot",
name: "OpenClaw",
dependencies: [
"MoltbotIPC",
"MoltbotDiscovery",
.product(name: "MoltbotKit", package: "MoltbotKit"),
.product(name: "MoltbotChatUI", package: "MoltbotKit"),
.product(name: "MoltbotProtocol", package: "MoltbotKit"),
"OpenClawIPC",
"OpenClawDiscovery",
.product(name: "OpenClawKit", package: "OpenClawKit"),
.product(name: "OpenClawChatUI", package: "OpenClawKit"),
.product(name: "OpenClawProtocol", package: "OpenClawKit"),
.product(name: "SwabbleKit", package: "swabble"),
.product(name: "MenuBarExtraAccess", package: "MenuBarExtraAccess"),
.product(name: "Subprocess", package: "swift-subprocess"),
@@ -59,30 +59,30 @@ let package = Package(
"Resources/Info.plist",
],
resources: [
.copy("Resources/Moltbot.icns"),
.copy("Resources/OpenClaw.icns"),
.copy("Resources/DeviceModels"),
],
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
]),
.executableTarget(
name: "MoltbotMacCLI",
name: "OpenClawMacCLI",
dependencies: [
"MoltbotDiscovery",
.product(name: "MoltbotKit", package: "MoltbotKit"),
.product(name: "MoltbotProtocol", package: "MoltbotKit"),
"OpenClawDiscovery",
.product(name: "OpenClawKit", package: "OpenClawKit"),
.product(name: "OpenClawProtocol", package: "OpenClawKit"),
],
path: "Sources/MoltbotMacCLI",
path: "Sources/OpenClawMacCLI",
swiftSettings: [
.enableUpcomingFeature("StrictConcurrency"),
]),
.testTarget(
name: "MoltbotIPCTests",
name: "OpenClawIPCTests",
dependencies: [
"MoltbotIPC",
"Moltbot",
"MoltbotDiscovery",
.product(name: "MoltbotProtocol", package: "MoltbotKit"),
"OpenClawIPC",
"OpenClaw",
"OpenClawDiscovery",
.product(name: "OpenClawProtocol", package: "OpenClawKit"),
.product(name: "SwabbleKit", package: "swabble"),
],
swiftSettings: [

View File

@@ -1,4 +1,4 @@
# Moltbot macOS app (dev + signing)
# OpenClaw macOS app (dev + signing)
## Quick dev run
@@ -20,7 +20,7 @@ scripts/restart-mac.sh --sign # force code signing (requires cert)
scripts/package-mac-app.sh
```
Creates `dist/Moltbot.app` and signs it via `scripts/codesign-mac-app.sh`.
Creates `dist/OpenClaw.app` and signs it via `scripts/codesign-mac-app.sh`.
## Signing behavior

View File

@@ -1,38 +0,0 @@
import Foundation
enum MoltbotEnv {
static func path(_ key: String) -> String? {
// Normalize env overrides once so UI + file IO stay consistent.
guard let raw = getenv(key) else { return nil }
let value = String(cString: raw).trimmingCharacters(in: .whitespacesAndNewlines)
guard !value.isEmpty
else {
return nil
}
return value
}
}
enum MoltbotPaths {
private static let configPathEnv = "CLAWDBOT_CONFIG_PATH"
private static let stateDirEnv = "CLAWDBOT_STATE_DIR"
static var stateDirURL: URL {
if let override = MoltbotEnv.path(self.stateDirEnv) {
return URL(fileURLWithPath: override, isDirectory: true)
}
return FileManager().homeDirectoryForCurrentUser
.appendingPathComponent(".clawdbot", isDirectory: true)
}
static var configURL: URL {
if let override = MoltbotEnv.path(self.configPathEnv) {
return URL(fileURLWithPath: override)
}
return self.stateDirURL.appendingPathComponent("moltbot.json")
}
static var workspaceURL: URL {
self.stateDirURL.appendingPathComponent("workspace", isDirectory: true)
}
}

View File

@@ -1,44 +0,0 @@
import Foundation
let launchdLabel = "bot.molt.mac"
let gatewayLaunchdLabel = "bot.molt.gateway"
let onboardingVersionKey = "moltbot.onboardingVersion"
let currentOnboardingVersion = 7
let pauseDefaultsKey = "moltbot.pauseEnabled"
let iconAnimationsEnabledKey = "moltbot.iconAnimationsEnabled"
let swabbleEnabledKey = "moltbot.swabbleEnabled"
let swabbleTriggersKey = "moltbot.swabbleTriggers"
let voiceWakeTriggerChimeKey = "moltbot.voiceWakeTriggerChime"
let voiceWakeSendChimeKey = "moltbot.voiceWakeSendChime"
let showDockIconKey = "moltbot.showDockIcon"
let defaultVoiceWakeTriggers = ["clawd", "claude"]
let voiceWakeMaxWords = 32
let voiceWakeMaxWordLength = 64
let voiceWakeMicKey = "moltbot.voiceWakeMicID"
let voiceWakeMicNameKey = "moltbot.voiceWakeMicName"
let voiceWakeLocaleKey = "moltbot.voiceWakeLocaleID"
let voiceWakeAdditionalLocalesKey = "moltbot.voiceWakeAdditionalLocaleIDs"
let voicePushToTalkEnabledKey = "moltbot.voicePushToTalkEnabled"
let talkEnabledKey = "moltbot.talkEnabled"
let iconOverrideKey = "moltbot.iconOverride"
let connectionModeKey = "moltbot.connectionMode"
let remoteTargetKey = "moltbot.remoteTarget"
let remoteIdentityKey = "moltbot.remoteIdentity"
let remoteProjectRootKey = "moltbot.remoteProjectRoot"
let remoteCliPathKey = "moltbot.remoteCliPath"
let canvasEnabledKey = "moltbot.canvasEnabled"
let cameraEnabledKey = "moltbot.cameraEnabled"
let systemRunPolicyKey = "moltbot.systemRunPolicy"
let systemRunAllowlistKey = "moltbot.systemRunAllowlist"
let systemRunEnabledKey = "moltbot.systemRunEnabled"
let locationModeKey = "moltbot.locationMode"
let locationPreciseKey = "moltbot.locationPreciseEnabled"
let peekabooBridgeEnabledKey = "moltbot.peekabooBridgeEnabled"
let deepLinkKeyKey = "moltbot.deepLinkKey"
let modelCatalogPathKey = "moltbot.modelCatalogPath"
let modelCatalogReloadKey = "moltbot.modelCatalogReload"
let cliInstallPromptedVersionKey = "moltbot.cliInstallPromptedVersion"
let heartbeatsEnabledKey = "moltbot.heartbeatsEnabled"
let debugFileLogEnabledKey = "moltbot.debug.fileLogEnabled"
let appLogLevelKey = "moltbot.debug.appLogLevel"
let voiceWakeSupported: Bool = ProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 26

View File

@@ -1,5 +0,0 @@
import MoltbotKit
import MoltbotProtocol
typealias ProtoAnyCodable = MoltbotProtocol.AnyCodable
typealias KitAnyCodable = MoltbotKit.AnyCodable

View File

@@ -10,7 +10,7 @@ struct AboutSettings: View {
VStack(spacing: 8) {
let appIcon = NSApplication.shared.applicationIconImage ?? CritterIconRenderer.makeIcon(blink: 0)
Button {
if let url = URL(string: "https://github.com/moltbot/moltbot") {
if let url = URL(string: "https://github.com/openclaw/openclaw") {
NSWorkspace.shared.open(url)
}
} label: {
@@ -29,7 +29,7 @@ struct AboutSettings: View {
}
VStack(spacing: 3) {
Text("Moltbot")
Text("OpenClaw")
.font(.title3.bold())
Text("Version \(self.versionString)")
.foregroundStyle(.secondary)
@@ -49,8 +49,8 @@ struct AboutSettings: View {
AboutLinkRow(
icon: "chevron.left.slash.chevron.right",
title: "GitHub",
url: "https://github.com/moltbot/moltbot")
AboutLinkRow(icon: "globe", title: "Website", url: "https://steipete.me")
url: "https://github.com/openclaw/openclaw")
AboutLinkRow(icon: "globe", title: "Website", url: "https://openclaw.ai")
AboutLinkRow(icon: "bird", title: "Twitter", url: "https://twitter.com/steipete")
AboutLinkRow(icon: "envelope", title: "Email", url: "mailto:peter@steipete.me")
}
@@ -108,7 +108,10 @@ struct AboutSettings: View {
}
private var buildTimestamp: String? {
guard let raw = Bundle.main.object(forInfoDictionaryKey: "MoltbotBuildTimestamp") as? String
guard
let raw =
(Bundle.main.object(forInfoDictionaryKey: "OpenClawBuildTimestamp") as? String) ??
(Bundle.main.object(forInfoDictionaryKey: "OpenClawBuildTimestamp") as? String)
else { return nil }
let parser = ISO8601DateFormatter()
parser.formatOptions = [.withInternetDateTime]
@@ -122,7 +125,9 @@ struct AboutSettings: View {
}
private var gitCommit: String {
Bundle.main.object(forInfoDictionaryKey: "MoltbotGitCommit") as? String ?? "unknown"
(Bundle.main.object(forInfoDictionaryKey: "OpenClawGitCommit") as? String) ??
(Bundle.main.object(forInfoDictionaryKey: "OpenClawGitCommit") as? String) ??
"unknown"
}
private var bundleID: String {

View File

@@ -1,4 +1,4 @@
import MoltbotProtocol
import OpenClawProtocol
import SwiftUI
@MainActor
@@ -81,7 +81,7 @@ private struct EventRow: View {
return f.string(from: date)
}
private func prettyJSON(_ dict: [String: MoltbotProtocol.AnyCodable]) -> String? {
private func prettyJSON(_ dict: [String: OpenClawProtocol.AnyCodable]) -> String? {
let normalized = dict.mapValues { $0.value }
guard JSONSerialization.isValidJSONObject(normalized),
let data = try? JSONSerialization.data(withJSONObject: normalized, options: [.prettyPrinted]),
@@ -99,8 +99,8 @@ struct AgentEventsWindow_Previews: PreviewProvider {
stream: "tool",
ts: Date().timeIntervalSince1970 * 1000,
data: [
"phase": MoltbotProtocol.AnyCodable("start"),
"name": MoltbotProtocol.AnyCodable("bash"),
"phase": OpenClawProtocol.AnyCodable("start"),
"name": OpenClawProtocol.AnyCodable("bash"),
],
summary: nil)
AgentEventStore.shared.append(sample)

View File

@@ -2,7 +2,7 @@ import Foundation
import OSLog
enum AgentWorkspace {
private static let logger = Logger(subsystem: "bot.molt", category: "workspace")
private static let logger = Logger(subsystem: "ai.openclaw", category: "workspace")
static let agentsFilename = "AGENTS.md"
static let soulFilename = "SOUL.md"
static let identityFilename = "IDENTITY.md"
@@ -34,7 +34,7 @@ enum AgentWorkspace {
static func resolveWorkspaceURL(from userInput: String?) -> URL {
let trimmed = userInput?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if trimmed.isEmpty { return MoltbotConfigFile.defaultWorkspaceURL() }
if trimmed.isEmpty { return OpenClawConfigFile.defaultWorkspaceURL() }
let expanded = (trimmed as NSString).expandingTildeInPath
return URL(fileURLWithPath: expanded, isDirectory: true)
}
@@ -154,7 +154,7 @@ enum AgentWorkspace {
static func defaultTemplate() -> String {
let fallback = """
# AGENTS.md - Moltbot Workspace
# AGENTS.md - OpenClaw Workspace
This folder is the assistant's working directory.
@@ -265,7 +265,7 @@ enum AgentWorkspace {
- Timezone (optional)
- Notes
3) ~/.clawdbot/moltbot.json
3) ~/.openclaw/openclaw.json
Set identity.name, identity.theme, identity.emoji to match IDENTITY.md.
## Cleanup

View File

@@ -6,7 +6,7 @@ import SwiftUI
struct AnthropicAuthControls: View {
let connectionMode: AppState.ConnectionMode
@State private var oauthStatus: MoltbotOAuthStore.AnthropicOAuthStatus = MoltbotOAuthStore.anthropicOAuthStatus()
@State private var oauthStatus: OpenClawOAuthStore.AnthropicOAuthStatus = OpenClawOAuthStore.anthropicOAuthStatus()
@State private var pkce: AnthropicOAuth.PKCE?
@State private var code: String = ""
@State private var busy = false
@@ -42,10 +42,10 @@ struct AnthropicAuthControls: View {
.foregroundStyle(.secondary)
Spacer()
Button("Reveal") {
NSWorkspace.shared.activateFileViewerSelecting([MoltbotOAuthStore.oauthURL()])
NSWorkspace.shared.activateFileViewerSelecting([OpenClawOAuthStore.oauthURL()])
}
.buttonStyle(.bordered)
.disabled(!FileManager().fileExists(atPath: MoltbotOAuthStore.oauthURL().path))
.disabled(!FileManager().fileExists(atPath: OpenClawOAuthStore.oauthURL().path))
Button("Refresh") {
self.refresh()
@@ -53,7 +53,7 @@ struct AnthropicAuthControls: View {
.buttonStyle(.bordered)
}
Text(MoltbotOAuthStore.oauthURL().path)
Text(OpenClawOAuthStore.oauthURL().path)
.font(.caption.monospaced())
.foregroundStyle(.secondary)
.lineLimit(1)
@@ -130,8 +130,8 @@ struct AnthropicAuthControls: View {
}
private func refresh() {
let imported = MoltbotOAuthStore.importLegacyAnthropicOAuthIfNeeded()
self.oauthStatus = MoltbotOAuthStore.anthropicOAuthStatus()
let imported = OpenClawOAuthStore.importLegacyAnthropicOAuthIfNeeded()
self.oauthStatus = OpenClawOAuthStore.anthropicOAuthStatus()
if imported != nil {
self.statusText = "Imported existing OAuth credentials."
}
@@ -172,11 +172,11 @@ struct AnthropicAuthControls: View {
code: parsed.code,
state: parsed.state,
verifier: pkce.verifier)
try MoltbotOAuthStore.saveAnthropicOAuth(creds)
try OpenClawOAuthStore.saveAnthropicOAuth(creds)
self.refresh()
self.pkce = nil
self.code = ""
self.statusText = "Connected. Moltbot can now use Claude via OAuth."
self.statusText = "Connected. OpenClaw can now use Claude via OAuth."
} catch {
self.statusText = "OAuth failed: \(error.localizedDescription)"
}
@@ -212,7 +212,7 @@ struct AnthropicAuthControls: View {
extension AnthropicAuthControls {
init(
connectionMode: AppState.ConnectionMode,
oauthStatus: MoltbotOAuthStore.AnthropicOAuthStatus,
oauthStatus: OpenClawOAuthStore.AnthropicOAuthStatus,
pkce: AnthropicOAuth.PKCE? = nil,
code: String = "",
busy: Bool = false,

View File

@@ -18,7 +18,7 @@ enum AnthropicAuthMode: Equatable {
var shortLabel: String {
switch self {
case .oauthFile: "OAuth (Moltbot token file)"
case .oauthFile: "OAuth (OpenClaw token file)"
case .oauthEnv: "OAuth (env var)"
case .apiKeyEnv: "API key (env var)"
case .missing: "Missing credentials"
@@ -36,7 +36,7 @@ enum AnthropicAuthMode: Equatable {
enum AnthropicAuthResolver {
static func resolve(
environment: [String: String] = ProcessInfo.processInfo.environment,
oauthStatus: MoltbotOAuthStore.AnthropicOAuthStatus = MoltbotOAuthStore
oauthStatus: OpenClawOAuthStore.AnthropicOAuthStatus = OpenClawOAuthStore
.anthropicOAuthStatus()) -> AnthropicAuthMode
{
if oauthStatus.isConnected { return .oauthFile }
@@ -58,7 +58,7 @@ enum AnthropicAuthResolver {
}
enum AnthropicOAuth {
private static let logger = Logger(subsystem: "bot.molt", category: "anthropic-oauth")
private static let logger = Logger(subsystem: "ai.openclaw", category: "anthropic-oauth")
private static let clientId = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
private static let authorizeURL = URL(string: "https://claude.ai/oauth/authorize")!
@@ -194,10 +194,10 @@ enum AnthropicOAuth {
}
}
enum MoltbotOAuthStore {
enum OpenClawOAuthStore {
static let oauthFilename = "oauth.json"
private static let providerKey = "anthropic"
private static let moltbotOAuthDirEnv = "CLAWDBOT_OAUTH_DIR"
private static let openclawOAuthDirEnv = "OPENCLAW_OAUTH_DIR"
private static let legacyPiDirEnv = "PI_CODING_AGENT_DIR"
enum AnthropicOAuthStatus: Equatable {
@@ -215,28 +215,28 @@ enum MoltbotOAuthStore {
var shortDescription: String {
switch self {
case .missingFile: "Moltbot OAuth token file not found"
case .unreadableFile: "Moltbot OAuth token file not readable"
case .invalidJSON: "Moltbot OAuth token file invalid"
case .missingProviderEntry: "No Anthropic entry in Moltbot OAuth token file"
case .missingFile: "OpenClaw OAuth token file not found"
case .unreadableFile: "OpenClaw OAuth token file not readable"
case .invalidJSON: "OpenClaw OAuth token file invalid"
case .missingProviderEntry: "No Anthropic entry in OpenClaw OAuth token file"
case .missingTokens: "Anthropic entry missing tokens"
case .connected: "Moltbot OAuth credentials found"
case .connected: "OpenClaw OAuth credentials found"
}
}
}
static func oauthDir() -> URL {
if let override = ProcessInfo.processInfo.environment[self.moltbotOAuthDirEnv]?
if let override = ProcessInfo.processInfo.environment[self.openclawOAuthDirEnv]?
.trimmingCharacters(in: .whitespacesAndNewlines),
!override.isEmpty
{
let expanded = NSString(string: override).expandingTildeInPath
return URL(fileURLWithPath: expanded, isDirectory: true)
}
return FileManager().homeDirectoryForCurrentUser
.appendingPathComponent(".clawdbot", isDirectory: true)
let home = FileManager().homeDirectoryForCurrentUser
let preferred = home.appendingPathComponent(".openclaw", isDirectory: true)
.appendingPathComponent("credentials", isDirectory: true)
return preferred
}
static func oauthURL() -> URL {

View File

@@ -1,10 +1,10 @@
import MoltbotKit
import MoltbotProtocol
import OpenClawKit
import OpenClawProtocol
import Foundation
// Prefer the MoltbotKit wrapper to keep gateway request payloads consistent.
typealias AnyCodable = MoltbotKit.AnyCodable
typealias InstanceIdentity = MoltbotKit.InstanceIdentity
// Prefer the OpenClawKit wrapper to keep gateway request payloads consistent.
typealias AnyCodable = OpenClawKit.AnyCodable
typealias InstanceIdentity = OpenClawKit.InstanceIdentity
extension AnyCodable {
var stringValue: String? { self.value as? String }
@@ -26,19 +26,19 @@ extension AnyCodable {
}
}
extension MoltbotProtocol.AnyCodable {
extension OpenClawProtocol.AnyCodable {
var stringValue: String? { self.value as? String }
var boolValue: Bool? { self.value as? Bool }
var intValue: Int? { self.value as? Int }
var doubleValue: Double? { self.value as? Double }
var dictionaryValue: [String: MoltbotProtocol.AnyCodable]? { self.value as? [String: MoltbotProtocol.AnyCodable] }
var arrayValue: [MoltbotProtocol.AnyCodable]? { self.value as? [MoltbotProtocol.AnyCodable] }
var dictionaryValue: [String: OpenClawProtocol.AnyCodable]? { self.value as? [String: OpenClawProtocol.AnyCodable] }
var arrayValue: [OpenClawProtocol.AnyCodable]? { self.value as? [OpenClawProtocol.AnyCodable] }
var foundationValue: Any {
switch self.value {
case let dict as [String: MoltbotProtocol.AnyCodable]:
case let dict as [String: OpenClawProtocol.AnyCodable]:
dict.mapValues { $0.foundationValue }
case let array as [MoltbotProtocol.AnyCodable]:
case let array as [OpenClawProtocol.AnyCodable]:
array.map(\.foundationValue)
default:
self.value

View File

@@ -41,13 +41,13 @@ final class AppState {
}
var onboardingSeen: Bool {
didSet { self.ifNotPreview { UserDefaults.standard.set(self.onboardingSeen, forKey: "moltbot.onboardingSeen") }
didSet { self.ifNotPreview { UserDefaults.standard.set(self.onboardingSeen, forKey: onboardingSeenKey) }
}
}
var debugPaneEnabled: Bool {
didSet {
self.ifNotPreview { UserDefaults.standard.set(self.debugPaneEnabled, forKey: "moltbot.debugPaneEnabled") }
self.ifNotPreview { UserDefaults.standard.set(self.debugPaneEnabled, forKey: debugPaneEnabledKey) }
CanvasManager.shared.refreshDebugStatus()
}
}
@@ -228,12 +228,16 @@ final class AppState {
private var earBoostTask: Task<Void, Never>?
init(preview: Bool = false) {
self.isPreview = preview || ProcessInfo.processInfo.isRunningTests
let onboardingSeen = UserDefaults.standard.bool(forKey: "moltbot.onboardingSeen")
let isPreview = preview || ProcessInfo.processInfo.isRunningTests
self.isPreview = isPreview
if !isPreview {
migrateLegacyDefaults()
}
let onboardingSeen = UserDefaults.standard.bool(forKey: onboardingSeenKey)
self.isPaused = UserDefaults.standard.bool(forKey: pauseDefaultsKey)
self.launchAtLogin = false
self.onboardingSeen = onboardingSeen
self.debugPaneEnabled = UserDefaults.standard.bool(forKey: "moltbot.debugPaneEnabled")
self.debugPaneEnabled = UserDefaults.standard.bool(forKey: debugPaneEnabledKey)
let savedVoiceWake = UserDefaults.standard.bool(forKey: swabbleEnabledKey)
self.swabbleEnabled = voiceWakeSupported ? savedVoiceWake : false
self.swabbleTriggerWords = UserDefaults.standard
@@ -275,7 +279,7 @@ final class AppState {
UserDefaults.standard.set(IconOverrideSelection.system.rawValue, forKey: iconOverrideKey)
}
let configRoot = MoltbotConfigFile.loadDict()
let configRoot = OpenClawConfigFile.loadDict()
let configRemoteUrl = GatewayRemoteConfig.resolveUrlString(root: configRoot)
let configRemoteTransport = GatewayRemoteConfig.resolveTransport(root: configRoot)
let resolvedConnectionMode = ConnectionModeResolver.resolve(root: configRoot).mode
@@ -353,7 +357,7 @@ final class AppState {
}
private func startConfigWatcher() {
let configUrl = MoltbotConfigFile.url()
let configUrl = OpenClawConfigFile.url()
self.configWatcher = ConfigFileWatcher(url: configUrl) { [weak self] in
Task { @MainActor in
self?.applyConfigFromDisk()
@@ -363,7 +367,7 @@ final class AppState {
}
private func applyConfigFromDisk() {
let root = MoltbotConfigFile.loadDict()
let root = OpenClawConfigFile.loadDict()
self.applyConfigOverrides(root)
}
@@ -451,7 +455,7 @@ final class AppState {
Task { @MainActor in
// Keep app-only connection settings local to avoid overwriting remote gateway config.
var root = MoltbotConfigFile.loadDict()
var root = OpenClawConfigFile.loadDict()
var gateway = root["gateway"] as? [String: Any] ?? [:]
var changed = false
@@ -541,7 +545,7 @@ final class AppState {
} else {
root["gateway"] = gateway
}
MoltbotConfigFile.saveDict(root)
OpenClawConfigFile.saveDict(root)
}
}
@@ -685,7 +689,7 @@ extension AppState {
state.remoteTarget = "user@example.com"
state.remoteUrl = "wss://gateway.example.ts.net"
state.remoteIdentity = "~/.ssh/id_ed25519"
state.remoteProjectRoot = "~/Projects/moltbot"
state.remoteProjectRoot = "~/Projects/openclaw"
state.remoteCliPath = ""
return state
}

View File

@@ -3,7 +3,7 @@ import Foundation
import OSLog
final class AudioInputDeviceObserver {
private let logger = Logger(subsystem: "bot.molt", category: "audio.devices")
private let logger = Logger(subsystem: "ai.openclaw", category: "audio.devices")
private var isActive = false
private var devicesListener: AudioObjectPropertyListenerBlock?
private var defaultInputListener: AudioObjectPropertyListenerBlock?

View File

@@ -5,7 +5,7 @@ import OSLog
@MainActor
final class CLIInstallPrompter {
static let shared = CLIInstallPrompter()
private let logger = Logger(subsystem: "bot.molt", category: "cli.prompt")
private let logger = Logger(subsystem: "ai.openclaw", category: "cli.prompt")
private var isPrompting = false
func checkAndPromptIfNeeded(reason: String) {
@@ -15,7 +15,7 @@ final class CLIInstallPrompter {
UserDefaults.standard.set(version, forKey: cliInstallPromptedVersionKey)
let alert = NSAlert()
alert.messageText = "Install Moltbot CLI?"
alert.messageText = "Install OpenClaw CLI?"
alert.informativeText = "Local mode needs the CLI so launchd can run the gateway."
alert.addButton(withTitle: "Install CLI")
alert.addButton(withTitle: "Not now")
@@ -62,7 +62,7 @@ final class CLIInstallPrompter {
SettingsTabRouter.request(tab)
SettingsWindowOpener.shared.open()
DispatchQueue.main.async {
NotificationCenter.default.post(name: .moltbotSelectSettingsTab, object: tab)
NotificationCenter.default.post(name: .openclawSelectSettingsTab, object: tab)
}
}

View File

@@ -13,7 +13,7 @@ enum CLIInstaller {
fileManager: FileManager) -> String?
{
for basePath in searchPaths {
let candidate = URL(fileURLWithPath: basePath).appendingPathComponent("moltbot").path
let candidate = URL(fileURLWithPath: basePath).appendingPathComponent("openclaw").path
var isDirectory: ObjCBool = false
guard fileManager.fileExists(atPath: candidate, isDirectory: &isDirectory),
@@ -37,14 +37,14 @@ enum CLIInstaller {
static func install(statusHandler: @escaping @MainActor @Sendable (String) async -> Void) async {
let expected = GatewayEnvironment.expectedGatewayVersionString() ?? "latest"
let prefix = Self.installPrefix()
await statusHandler("Installing moltbot CLI…")
await statusHandler("Installing openclaw CLI…")
let cmd = self.installScriptCommand(version: expected, prefix: prefix)
let response = await ShellExecutor.runDetailed(command: cmd, cwd: nil, env: nil, timeout: 900)
if response.success {
let parsed = self.parseInstallEvents(response.stdout)
let installedVersion = parsed.last { $0.event == "done" }?.version
let summary = installedVersion.map { "Installed moltbot \($0)." } ?? "Installed moltbot."
let summary = installedVersion.map { "Installed openclaw \($0)." } ?? "Installed openclaw."
await statusHandler(summary)
return
}
@@ -62,7 +62,7 @@ enum CLIInstaller {
private static func installPrefix() -> String {
FileManager().homeDirectoryForCurrentUser
.appendingPathComponent(".clawdbot")
.appendingPathComponent(".openclaw")
.path
}
@@ -70,7 +70,7 @@ enum CLIInstaller {
let escapedVersion = self.shellEscape(version)
let escapedPrefix = self.shellEscape(prefix)
let script = """
curl -fsSL https://molt.bot/install-cli.sh | \
curl -fsSL https://openclaw.bot/install-cli.sh | \
bash -s -- --json --no-onboard --prefix \(escapedPrefix) --version \(escapedVersion)
"""
return ["/bin/bash", "-lc", script]

View File

@@ -1,6 +1,6 @@
import AVFoundation
import MoltbotIPC
import MoltbotKit
import OpenClawIPC
import OpenClawKit
import CoreGraphics
import Foundation
import OSLog
@@ -36,7 +36,7 @@ actor CameraCaptureService {
}
}
private let logger = Logger(subsystem: "bot.molt", category: "camera")
private let logger = Logger(subsystem: "ai.openclaw", category: "camera")
func listDevices() -> [CameraDeviceInfo] {
Self.availableCameras().map { device in
@@ -168,7 +168,7 @@ actor CameraCaptureService {
await Self.warmUpCaptureSession()
let tmpMovURL = FileManager().temporaryDirectory
.appendingPathComponent("moltbot-camera-\(UUID().uuidString).mov")
.appendingPathComponent("openclaw-camera-\(UUID().uuidString).mov")
defer { try? FileManager().removeItem(at: tmpMovURL) }
let outputURL: URL = {
@@ -176,7 +176,7 @@ actor CameraCaptureService {
return URL(fileURLWithPath: outPath)
}
return FileManager().temporaryDirectory
.appendingPathComponent("moltbot-camera-\(UUID().uuidString).mp4")
.appendingPathComponent("openclaw-camera-\(UUID().uuidString).mp4")
}()
// Ensure we don't fail exporting due to an existing file.

View File

@@ -1,11 +1,12 @@
import AppKit
import MoltbotIPC
import MoltbotKit
import OpenClawIPC
import OpenClawKit
import Foundation
import WebKit
final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
static let messageName = "moltbotCanvasA2UIAction"
static let messageName = "openclawCanvasA2UIAction"
static let allMessageNames = [messageName]
private let sessionKey: String
@@ -15,11 +16,11 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
}
func userContentController(_: WKUserContentController, didReceive message: WKScriptMessage) {
guard message.name == Self.messageName else { return }
guard Self.allMessageNames.contains(message.name) else { return }
// Only accept actions from local Canvas content (not arbitrary web pages).
guard let webView = message.webView, let url = webView.url else { return }
if url.scheme == CanvasScheme.scheme {
if let scheme = url.scheme, CanvasScheme.allSchemes.contains(scheme) {
// ok
} else if Self.isLocalNetworkCanvasURL(url) {
// ok
@@ -52,7 +53,7 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
}()
guard !userAction.isEmpty else { return }
guard let name = MoltbotCanvasA2UIAction.extractActionName(userAction) else { return }
guard let name = OpenClawCanvasA2UIAction.extractActionName(userAction) else { return }
let actionId =
(userAction["id"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
?? UUID().uuidString
@@ -64,15 +65,15 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
let sourceComponentId = (userAction["sourceComponentId"] as? String)?
.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty ?? "-"
let instanceId = InstanceIdentity.instanceId.lowercased()
let contextJSON = MoltbotCanvasA2UIAction.compactJSON(userAction["context"])
let contextJSON = OpenClawCanvasA2UIAction.compactJSON(userAction["context"])
// Token-efficient and unambiguous. The agent should treat this as a UI event and (by default) update Canvas.
let messageContext = MoltbotCanvasA2UIAction.AgentMessageContext(
let messageContext = OpenClawCanvasA2UIAction.AgentMessageContext(
actionName: name,
session: .init(key: self.sessionKey, surfaceId: surfaceId),
component: .init(id: sourceComponentId, host: InstanceIdentity.displayName, instanceId: instanceId),
contextJSON: contextJSON)
let text = MoltbotCanvasA2UIAction.formatAgentMessage(messageContext)
let text = OpenClawCanvasA2UIAction.formatAgentMessage(messageContext)
Task { [weak webView] in
if AppStateStore.shared.connectionMode == .local {
@@ -91,7 +92,7 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
await MainActor.run {
guard let webView else { return }
let js = MoltbotCanvasA2UIAction.jsDispatchA2UIActionStatus(
let js = OpenClawCanvasA2UIAction.jsDispatchA2UIActionStatus(
actionId: actionId,
ok: result.ok,
error: result.error)
@@ -144,5 +145,5 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
return false
}
// Formatting helpers live in MoltbotKit (`MoltbotCanvasA2UIAction`).
// Formatting helpers live in OpenClawKit (`OpenClawCanvasA2UIAction`).
}

View File

@@ -10,7 +10,7 @@ final class CanvasFileWatcher: @unchecked Sendable {
init(url: URL, onChange: @escaping () -> Void) {
self.url = url
self.queue = DispatchQueue(label: "bot.molt.canvaswatcher")
self.queue = DispatchQueue(label: "ai.openclaw.canvaswatcher")
self.onChange = onChange
}

View File

@@ -1,6 +1,6 @@
import AppKit
import MoltbotIPC
import MoltbotKit
import OpenClawIPC
import OpenClawKit
import Foundation
import OSLog
@@ -8,7 +8,7 @@ import OSLog
final class CanvasManager {
static let shared = CanvasManager()
private static let logger = Logger(subsystem: "bot.molt", category: "CanvasManager")
private static let logger = Logger(subsystem: "ai.openclaw", category: "CanvasManager")
private var panelController: CanvasWindowController?
private var panelSessionKey: String?
@@ -26,7 +26,7 @@ final class CanvasManager {
private nonisolated static let canvasRoot: URL = {
let base = FileManager().urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
return base.appendingPathComponent("Moltbot/canvas", isDirectory: true)
return base.appendingPathComponent("OpenClaw/canvas", isDirectory: true)
}()
func show(sessionKey: String, path: String? = nil, placement: CanvasPlacement? = nil) throws -> String {
@@ -231,7 +231,7 @@ final class CanvasManager {
private static func resolveA2UIHostUrl(from raw: String?) -> String? {
let trimmed = raw?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
guard !trimmed.isEmpty, let base = URL(string: trimmed) else { return nil }
return base.appendingPathComponent("__moltbot__/a2ui/").absoluteString + "?platform=macos"
return base.appendingPathComponent("__openclaw__/a2ui/").absoluteString + "?platform=macos"
}
// MARK: - Anchoring

View File

@@ -1,7 +1,8 @@
import Foundation
enum CanvasScheme {
static let scheme = "moltbot-canvas"
static let scheme = "openclaw-canvas"
static let allSchemes = [scheme]
static func makeURL(session: String, path: String? = nil) -> URL? {
var comps = URLComponents()

View File

@@ -1,9 +1,9 @@
import MoltbotKit
import OpenClawKit
import Foundation
import OSLog
import WebKit
private let canvasLogger = Logger(subsystem: "bot.molt", category: "Canvas")
private let canvasLogger = Logger(subsystem: "ai.openclaw", category: "Canvas")
final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
private let root: URL
@@ -45,7 +45,7 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
}
private func response(for url: URL) -> CanvasResponse {
guard url.scheme == CanvasScheme.scheme else {
guard let scheme = url.scheme, CanvasScheme.allSchemes.contains(scheme) else {
return self.html("Invalid scheme.")
}
guard let session = url.host, !session.isEmpty else {
@@ -222,7 +222,7 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
let name = fileURL.deletingPathExtension().lastPathComponent
guard !name.isEmpty, !ext.isEmpty else { return nil }
let bundle = MoltbotKitResources.bundle
let bundle = OpenClawKitResources.bundle
let resourceURL =
bundle.url(forResource: name, withExtension: ext, subdirectory: subdirectory)
?? bundle.url(forResource: name, withExtension: ext)

View File

@@ -1,6 +1,6 @@
import AppKit
let canvasWindowLogger = Logger(subsystem: "bot.molt", category: "Canvas")
let canvasWindowLogger = Logger(subsystem: "ai.openclaw", category: "Canvas")
enum CanvasLayout {
static let panelSize = NSSize(width: 520, height: 680)

View File

@@ -23,7 +23,7 @@ extension CanvasWindowController {
}
static func storedFrameDefaultsKey(sessionKey: String) -> String {
"moltbot.canvas.frame.\(self.sanitizeSessionKey(sessionKey))"
"openclaw.canvas.frame.\(self.sanitizeSessionKey(sessionKey))"
}
static func loadRestoredFrame(sessionKey: String) -> NSRect? {

View File

@@ -17,8 +17,9 @@ extension CanvasWindowController {
let scheme = url.scheme?.lowercased()
// Deep links: allow local Canvas content to invoke the agent without bouncing through NSWorkspace.
if scheme == "moltbot" {
if self.webView.url?.scheme == CanvasScheme.scheme {
if scheme == "openclaw" {
if let currentScheme = self.webView.url?.scheme,
CanvasScheme.allSchemes.contains(currentScheme) {
Task { await DeepLinkHandler.shared.handle(url: url) }
} else {
canvasWindowLogger
@@ -30,7 +31,7 @@ extension CanvasWindowController {
// Keep web content inside the panel when reasonable.
// `about:blank` and friends are common internal navigations for WKWebView; never send them to NSWorkspace.
if scheme == CanvasScheme.scheme
if CanvasScheme.allSchemes.contains(scheme ?? "")
|| scheme == "https"
|| scheme == "http"
|| scheme == "about"

View File

@@ -1,5 +1,5 @@
import AppKit
import MoltbotIPC
import OpenClawIPC
extension CanvasWindowController {
// MARK: - Window
@@ -12,7 +12,7 @@ extension CanvasWindowController {
styleMask: [.titled, .closable, .resizable, .miniaturizable],
backing: .buffered,
defer: false)
window.title = "Moltbot Canvas"
window.title = "OpenClaw Canvas"
window.isReleasedWhenClosed = false
window.contentView = contentView
window.center()

View File

@@ -1,6 +1,6 @@
import AppKit
import MoltbotIPC
import MoltbotKit
import OpenClawIPC
import OpenClawKit
import Foundation
import WebKit
@@ -43,7 +43,9 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
config.preferences.isElementFullscreenEnabled = true
config.preferences.setValue(true, forKey: "developerExtrasEnabled")
canvasWindowLogger.debug("CanvasWindowController init config ready")
config.setURLSchemeHandler(self.schemeHandler, forURLScheme: CanvasScheme.scheme)
for scheme in CanvasScheme.allSchemes {
config.setURLSchemeHandler(self.schemeHandler, forURLScheme: scheme)
}
canvasWindowLogger.debug("CanvasWindowController init scheme handler installed")
// Bridge A2UI "a2uiaction" DOM events back into the native agent loop.
@@ -56,9 +58,11 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
let bridgeScript = """
(() => {
try {
if (location.protocol !== '\(CanvasScheme.scheme):') return;
if (globalThis.__moltbotA2UIBridgeInstalled) return;
globalThis.__moltbotA2UIBridgeInstalled = true;
const allowedSchemes = \(String(describing: CanvasScheme.allSchemes));
const protocol = location.protocol.replace(':', '');
if (!allowedSchemes.includes(protocol)) return;
if (globalThis.__openclawA2UIBridgeInstalled) return;
globalThis.__openclawA2UIBridgeInstalled = true;
const deepLinkKey = \(Self.jsStringLiteral(deepLinkKey));
const sessionKey = \(Self.jsStringLiteral(injectedSessionKey));
@@ -85,11 +89,13 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
...(context.length ? { context } : {}),
};
const handler = globalThis.webkit?.messageHandlers?.clawdbotCanvasA2UIAction;
const handler = globalThis.webkit?.messageHandlers?.openclawCanvasA2UIAction;
// If the bundled A2UI shell is present, let it forward actions so we keep its richer
// context resolution (data model path lookups, surface detection, etc.).
const hasBundledA2UIHost = !!globalThis.clawdbotA2UI || !!document.querySelector('moltbot-a2ui-host');
const hasBundledA2UIHost =
!!globalThis.openclawA2UI ||
!!document.querySelector('openclaw-a2ui-host');
if (hasBundledA2UIHost && handler?.postMessage) return;
// Otherwise, forward directly when possible.
@@ -115,7 +121,7 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
params.set('deliver', 'false');
params.set('channel', 'last');
params.set('key', deepLinkKey);
location.href = 'moltbot://agent?' + params.toString();
location.href = 'openclaw://agent?' + params.toString();
} catch {}
}, true);
} catch {}
@@ -137,7 +143,8 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
guard let webView else { return }
// Only auto-reload when we are showing local canvas content.
guard webView.url?.scheme == CanvasScheme.scheme else { return }
guard let scheme = webView.url?.scheme,
CanvasScheme.allSchemes.contains(scheme) else { return }
let path = webView.url?.path ?? ""
if path == "/" || path.isEmpty {
@@ -161,7 +168,9 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
let handler = CanvasA2UIActionMessageHandler(sessionKey: sessionKey)
self.a2uiActionMessageHandler = handler
self.webView.configuration.userContentController.add(handler, name: CanvasA2UIActionMessageHandler.messageName)
for name in CanvasA2UIActionMessageHandler.allMessageNames {
self.webView.configuration.userContentController.add(handler, name: name)
}
self.webView.navigationDelegate = self
self.window?.delegate = self
@@ -177,8 +186,9 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") }
@MainActor deinit {
self.webView.configuration.userContentController
.removeScriptMessageHandler(forName: CanvasA2UIActionMessageHandler.messageName)
for name in CanvasA2UIActionMessageHandler.allMessageNames {
self.webView.configuration.userContentController.removeScriptMessageHandler(forName: name)
}
self.watcher.stop()
}
@@ -268,7 +278,7 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
let js = """
(() => {
try {
const api = globalThis.__moltbot;
const api = globalThis.__openclaw;
if (!api) return;
if (typeof api.setDebugStatusEnabled === 'function') {
api.setDebugStatusEnabled(\(enabled ? "true" : "false"));
@@ -336,7 +346,7 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
path = outPath
} else {
let ts = Int(Date().timeIntervalSince1970)
path = "/tmp/moltbot-canvas-\(CanvasWindowController.sanitizeSessionKey(self.sessionKey))-\(ts).png"
path = "/tmp/openclaw-canvas-\(CanvasWindowController.sanitizeSessionKey(self.sessionKey))-\(ts).png"
}
try png.write(to: URL(fileURLWithPath: path), options: [.atomic])

View File

@@ -1,4 +1,4 @@
import MoltbotProtocol
import OpenClawProtocol
import SwiftUI
extension ChannelsSettings {

View File

@@ -1,4 +1,4 @@
import MoltbotProtocol
import OpenClawProtocol
import Foundation
extension ChannelsStore {
@@ -28,7 +28,7 @@ extension ChannelsStore {
params: nil,
timeoutMs: 10000)
self.configStatus = snap.valid == false
? "Config invalid; fix it in ~/.clawdbot/moltbot.json."
? "Config invalid; fix it in ~/.openclaw/openclaw.json."
: nil
self.configRoot = snap.config?.mapValues { $0.foundationValue } ?? [:]
self.configDraft = cloneConfigValue(self.configRoot) as? [String: Any] ?? self.configRoot

View File

@@ -1,4 +1,4 @@
import MoltbotProtocol
import OpenClawProtocol
import Foundation
extension ChannelsStore {

View File

@@ -1,4 +1,4 @@
import MoltbotProtocol
import OpenClawProtocol
import Foundation
import Observation

View File

@@ -1,13 +1,15 @@
import Foundation
enum CommandResolver {
private static let projectRootDefaultsKey = "moltbot.gatewayProjectRootPath"
private static let helperName = "moltbot"
private static let projectRootDefaultsKey = "openclaw.gatewayProjectRootPath"
private static let helperName = "openclaw"
static func gatewayEntrypoint(in root: URL) -> String? {
let distEntry = root.appendingPathComponent("dist/index.js").path
if FileManager().isReadableFile(atPath: distEntry) { return distEntry }
let binEntry = root.appendingPathComponent("bin/moltbot.js").path
let openclawEntry = root.appendingPathComponent("openclaw.mjs").path
if FileManager().isReadableFile(atPath: openclawEntry) { return openclawEntry }
let binEntry = root.appendingPathComponent("bin/openclaw.js").path
if FileManager().isReadableFile(atPath: binEntry) { return binEntry }
return nil
}
@@ -36,9 +38,9 @@ enum CommandResolver {
static func errorCommand(with message: String) -> [String] {
let script = """
cat <<'__CLAWDBOT_ERR__' >&2
cat <<'__OPENCLAW_ERR__' >&2
\(message)
__CLAWDBOT_ERR__
__OPENCLAW_ERR__
exit 1
"""
return ["/bin/sh", "-c", script]
@@ -52,7 +54,7 @@ enum CommandResolver {
return url
}
let fallback = FileManager().homeDirectoryForCurrentUser
.appendingPathComponent("Projects/moltbot")
.appendingPathComponent("Projects/openclaw")
if FileManager().fileExists(atPath: fallback.path) {
return fallback
}
@@ -87,26 +89,30 @@ enum CommandResolver {
// Dev-only convenience. Avoid project-local PATH hijacking in release builds.
extras.insert(projectRoot.appendingPathComponent("node_modules/.bin").path, at: 0)
#endif
let moltbotPaths = self.moltbotManagedPaths(home: home)
if !moltbotPaths.isEmpty {
extras.insert(contentsOf: moltbotPaths, at: 1)
let openclawPaths = self.openclawManagedPaths(home: home)
if !openclawPaths.isEmpty {
extras.insert(contentsOf: openclawPaths, at: 1)
}
extras.insert(contentsOf: self.nodeManagerBinPaths(home: home), at: 1 + moltbotPaths.count)
extras.insert(contentsOf: self.nodeManagerBinPaths(home: home), at: 1 + openclawPaths.count)
var seen = Set<String>()
// Preserve order while stripping duplicates so PATH lookups remain deterministic.
return (extras + current).filter { seen.insert($0).inserted }
}
private static func moltbotManagedPaths(home: URL) -> [String] {
let base = home.appendingPathComponent(".clawdbot")
let bin = base.appendingPathComponent("bin")
let nodeBin = base.appendingPathComponent("tools/node/bin")
private static func openclawManagedPaths(home: URL) -> [String] {
let bases = [
home.appendingPathComponent(".openclaw"),
]
var paths: [String] = []
if FileManager().fileExists(atPath: bin.path) {
paths.append(bin.path)
}
if FileManager().fileExists(atPath: nodeBin.path) {
paths.append(nodeBin.path)
for base in bases {
let bin = base.appendingPathComponent("bin")
let nodeBin = base.appendingPathComponent("tools/node/bin")
if FileManager().fileExists(atPath: bin.path) {
paths.append(bin.path)
}
if FileManager().fileExists(atPath: nodeBin.path) {
paths.append(nodeBin.path)
}
}
return paths
}
@@ -187,11 +193,11 @@ enum CommandResolver {
return nil
}
static func moltbotExecutable(searchPaths: [String]? = nil) -> String? {
static func openclawExecutable(searchPaths: [String]? = nil) -> String? {
self.findExecutable(named: self.helperName, searchPaths: searchPaths)
}
static func projectMoltbotExecutable(projectRoot: URL? = nil) -> String? {
static func projectOpenClawExecutable(projectRoot: URL? = nil) -> String? {
#if DEBUG
let root = projectRoot ?? self.projectRoot()
let candidate = root.appendingPathComponent("node_modules/.bin").appendingPathComponent(self.helperName).path
@@ -202,12 +208,19 @@ enum CommandResolver {
}
static func nodeCliPath() -> String? {
let candidate = self.projectRoot().appendingPathComponent("bin/moltbot.js").path
return FileManager().isReadableFile(atPath: candidate) ? candidate : nil
let root = self.projectRoot()
let candidates = [
root.appendingPathComponent("openclaw.mjs").path,
root.appendingPathComponent("bin/openclaw.js").path,
]
for candidate in candidates where FileManager().isReadableFile(atPath: candidate) {
return candidate
}
return nil
}
static func hasAnyMoltbotInvoker(searchPaths: [String]? = nil) -> Bool {
if self.moltbotExecutable(searchPaths: searchPaths) != nil { return true }
static func hasAnyOpenClawInvoker(searchPaths: [String]? = nil) -> Bool {
if self.openclawExecutable(searchPaths: searchPaths) != nil { return true }
if self.findExecutable(named: "pnpm", searchPaths: searchPaths) != nil { return true }
if self.findExecutable(named: "node", searchPaths: searchPaths) != nil,
self.nodeCliPath() != nil
@@ -217,7 +230,7 @@ enum CommandResolver {
return false
}
static func moltbotNodeCommand(
static func openclawNodeCommand(
subcommand: String,
extraArgs: [String] = [],
defaults: UserDefaults = .standard,
@@ -238,8 +251,8 @@ enum CommandResolver {
switch runtimeResult {
case let .success(runtime):
let root = self.projectRoot()
if let moltbotPath = self.projectMoltbotExecutable(projectRoot: root) {
return [moltbotPath, subcommand] + extraArgs
if let openclawPath = self.projectOpenClawExecutable(projectRoot: root) {
return [openclawPath, subcommand] + extraArgs
}
if let entry = self.gatewayEntrypoint(in: root) {
@@ -251,14 +264,14 @@ enum CommandResolver {
}
if let pnpm = self.findExecutable(named: "pnpm", searchPaths: searchPaths) {
// Use --silent to avoid pnpm lifecycle banners that would corrupt JSON outputs.
return [pnpm, "--silent", "moltbot", subcommand] + extraArgs
return [pnpm, "--silent", "openclaw", subcommand] + extraArgs
}
if let moltbotPath = self.moltbotExecutable(searchPaths: searchPaths) {
return [moltbotPath, subcommand] + extraArgs
if let openclawPath = self.openclawExecutable(searchPaths: searchPaths) {
return [openclawPath, subcommand] + extraArgs
}
let missingEntry = """
moltbot entrypoint missing (looked for dist/index.js or bin/moltbot.js); run pnpm build.
openclaw entrypoint missing (looked for dist/index.js or openclaw.mjs); run pnpm build.
"""
return self.errorCommand(with: missingEntry)
@@ -267,15 +280,14 @@ enum CommandResolver {
}
}
// Existing callers still refer to moltbotCommand; keep it as node alias.
static func moltbotCommand(
static func openclawCommand(
subcommand: String,
extraArgs: [String] = [],
defaults: UserDefaults = .standard,
configRoot: [String: Any]? = nil,
searchPaths: [String]? = nil) -> [String]
{
self.moltbotNodeCommand(
self.openclawNodeCommand(
subcommand: subcommand,
extraArgs: extraArgs,
defaults: defaults,
@@ -289,7 +301,7 @@ enum CommandResolver {
guard !settings.target.isEmpty else { return nil }
guard let parsed = self.parseSSHTarget(settings.target) else { return nil }
// Run the real moltbot CLI on the remote host.
// Run the real openclaw CLI on the remote host.
let exportedPath = [
"/opt/homebrew/bin",
"/usr/local/bin",
@@ -306,7 +318,7 @@ enum CommandResolver {
let projectSection = if userPRJ.isEmpty {
"""
DEFAULT_PRJ="$HOME/Projects/moltbot"
DEFAULT_PRJ="$HOME/Projects/openclaw"
if [ -d "$DEFAULT_PRJ" ]; then
PRJ="$DEFAULT_PRJ"
cd "$PRJ" || { echo "Project root not found: $PRJ"; exit 127; }
@@ -345,9 +357,9 @@ enum CommandResolver {
CLI="";
\(cliSection)
\(projectSection)
if command -v moltbot >/dev/null 2>&1; then
CLI="$(command -v moltbot)"
moltbot \(quotedArgs);
if command -v openclaw >/dev/null 2>&1; then
CLI="$(command -v openclaw)"
openclaw \(quotedArgs);
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/dist/index.js" ]; then
if command -v node >/dev/null 2>&1; then
CLI="node $PRJ/dist/index.js"
@@ -355,18 +367,25 @@ enum CommandResolver {
else
echo "Node >=22 required on remote host"; exit 127;
fi
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/bin/moltbot.js" ]; then
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/openclaw.mjs" ]; then
if command -v node >/dev/null 2>&1; then
CLI="node $PRJ/bin/moltbot.js"
node "$PRJ/bin/moltbot.js" \(quotedArgs);
CLI="node $PRJ/openclaw.mjs"
node "$PRJ/openclaw.mjs" \(quotedArgs);
else
echo "Node >=22 required on remote host"; exit 127;
fi
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/bin/openclaw.js" ]; then
if command -v node >/dev/null 2>&1; then
CLI="node $PRJ/bin/openclaw.js"
node "$PRJ/bin/openclaw.js" \(quotedArgs);
else
echo "Node >=22 required on remote host"; exit 127;
fi
elif command -v pnpm >/dev/null 2>&1; then
CLI="pnpm --silent moltbot"
pnpm --silent moltbot \(quotedArgs);
CLI="pnpm --silent openclaw"
pnpm --silent openclaw \(quotedArgs);
else
echo "moltbot CLI missing on remote host"; exit 127;
echo "openclaw CLI missing on remote host"; exit 127;
fi
"""
let options: [String] = [
@@ -394,7 +413,7 @@ enum CommandResolver {
defaults: UserDefaults = .standard,
configRoot: [String: Any]? = nil) -> RemoteSettings
{
let root = configRoot ?? MoltbotConfigFile.loadDict()
let root = configRoot ?? OpenClawConfigFile.loadDict()
let mode = ConnectionModeResolver.resolve(root: root, defaults: defaults).mode
let target = defaults.string(forKey: remoteTargetKey) ?? ""
let identity = defaults.string(forKey: remoteIdentityKey) ?? ""

View File

@@ -13,7 +13,7 @@ final class ConfigFileWatcher: @unchecked Sendable {
init(url: URL, onChange: @escaping () -> Void) {
self.url = url
self.queue = DispatchQueue(label: "bot.molt.configwatcher")
self.queue = DispatchQueue(label: "ai.openclaw.configwatcher")
self.onChange = onChange
self.watchedDir = url.deletingLastPathComponent()
self.targetPath = url.path

View File

@@ -153,7 +153,7 @@ extension ConfigSettings {
.font(.title3.weight(.semibold))
Text(self.isNixMode
? "This tab is read-only in Nix mode. Edit config via Nix and rebuild."
: "Edit ~/.clawdbot/moltbot.json using the schema-driven form.")
: "Edit ~/.openclaw/openclaw.json using the schema-driven form.")
.font(.callout)
.foregroundStyle(.secondary)
}

View File

@@ -1,4 +1,4 @@
import MoltbotProtocol
import OpenClawProtocol
import Foundation
enum ConfigStore {
@@ -44,7 +44,7 @@ enum ConfigStore {
if let gateway = await self.loadFromGateway() {
return gateway
}
return MoltbotConfigFile.loadDict()
return OpenClawConfigFile.loadDict()
}
@MainActor
@@ -63,7 +63,7 @@ enum ConfigStore {
do {
try await self.saveToGateway(root)
} catch {
MoltbotConfigFile.saveDict(root)
OpenClawConfigFile.saveDict(root)
}
}
}

View File

@@ -5,7 +5,7 @@ import OSLog
final class ConnectionModeCoordinator {
static let shared = ConnectionModeCoordinator()
private let logger = Logger(subsystem: "bot.molt", category: "connection")
private let logger = Logger(subsystem: "ai.openclaw", category: "connection")
private var lastMode: AppState.ConnectionMode?
/// Apply the requested connection mode by starting/stopping local gateway,

View File

@@ -43,7 +43,7 @@ enum ConnectionModeResolver {
return EffectiveConnectionMode(mode: storedMode, source: .userDefaults)
}
let seen = defaults.bool(forKey: "moltbot.onboardingSeen")
let seen = defaults.bool(forKey: "openclaw.onboardingSeen")
return EffectiveConnectionMode(mode: seen ? .local : .unconfigured, source: .onboarding)
}
}

View File

@@ -0,0 +1,46 @@
import Foundation
let launchdLabel = "ai.openclaw.mac"
let gatewayLaunchdLabel = "ai.openclaw.gateway"
let onboardingVersionKey = "openclaw.onboardingVersion"
let onboardingSeenKey = "openclaw.onboardingSeen"
let currentOnboardingVersion = 7
let pauseDefaultsKey = "openclaw.pauseEnabled"
let iconAnimationsEnabledKey = "openclaw.iconAnimationsEnabled"
let swabbleEnabledKey = "openclaw.swabbleEnabled"
let swabbleTriggersKey = "openclaw.swabbleTriggers"
let voiceWakeTriggerChimeKey = "openclaw.voiceWakeTriggerChime"
let voiceWakeSendChimeKey = "openclaw.voiceWakeSendChime"
let showDockIconKey = "openclaw.showDockIcon"
let defaultVoiceWakeTriggers = ["openclaw"]
let voiceWakeMaxWords = 32
let voiceWakeMaxWordLength = 64
let voiceWakeMicKey = "openclaw.voiceWakeMicID"
let voiceWakeMicNameKey = "openclaw.voiceWakeMicName"
let voiceWakeLocaleKey = "openclaw.voiceWakeLocaleID"
let voiceWakeAdditionalLocalesKey = "openclaw.voiceWakeAdditionalLocaleIDs"
let voicePushToTalkEnabledKey = "openclaw.voicePushToTalkEnabled"
let talkEnabledKey = "openclaw.talkEnabled"
let iconOverrideKey = "openclaw.iconOverride"
let connectionModeKey = "openclaw.connectionMode"
let remoteTargetKey = "openclaw.remoteTarget"
let remoteIdentityKey = "openclaw.remoteIdentity"
let remoteProjectRootKey = "openclaw.remoteProjectRoot"
let remoteCliPathKey = "openclaw.remoteCliPath"
let canvasEnabledKey = "openclaw.canvasEnabled"
let cameraEnabledKey = "openclaw.cameraEnabled"
let systemRunPolicyKey = "openclaw.systemRunPolicy"
let systemRunAllowlistKey = "openclaw.systemRunAllowlist"
let systemRunEnabledKey = "openclaw.systemRunEnabled"
let locationModeKey = "openclaw.locationMode"
let locationPreciseKey = "openclaw.locationPreciseEnabled"
let peekabooBridgeEnabledKey = "openclaw.peekabooBridgeEnabled"
let deepLinkKeyKey = "openclaw.deepLinkKey"
let modelCatalogPathKey = "openclaw.modelCatalogPath"
let modelCatalogReloadKey = "openclaw.modelCatalogReload"
let cliInstallPromptedVersionKey = "openclaw.cliInstallPromptedVersion"
let heartbeatsEnabledKey = "openclaw.heartbeatsEnabled"
let debugPaneEnabledKey = "openclaw.debugPaneEnabled"
let debugFileLogEnabledKey = "openclaw.debug.fileLogEnabled"
let appLogLevelKey = "openclaw.debug.appLogLevel"
let voiceWakeSupported: Bool = ProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 26

View File

@@ -1,5 +1,5 @@
import MoltbotKit
import MoltbotProtocol
import OpenClawKit
import OpenClawProtocol
import Foundation
import Observation
import SwiftUI
@@ -20,7 +20,7 @@ struct ControlAgentEvent: Codable, Sendable, Identifiable {
let seq: Int
let stream: String
let ts: Double
let data: [String: MoltbotProtocol.AnyCodable]
let data: [String: OpenClawProtocol.AnyCodable]
let summary: String?
}
@@ -76,7 +76,7 @@ final class ControlChannel {
private(set) var lastPingMs: Double?
private(set) var authSourceLabel: String?
private let logger = Logger(subsystem: "bot.molt", category: "control")
private let logger = Logger(subsystem: "ai.openclaw", category: "control")
private var eventTask: Task<Void, Never>?
private var recoveryTask: Task<Void, Never>?
@@ -163,8 +163,8 @@ final class ControlChannel {
timeoutMs: Double? = nil) async throws -> Data
{
do {
let rawParams = params?.reduce(into: [String: MoltbotKit.AnyCodable]()) {
$0[$1.key] = MoltbotKit.AnyCodable($1.value.base)
let rawParams = params?.reduce(into: [String: OpenClawKit.AnyCodable]()) {
$0[$1.key] = OpenClawKit.AnyCodable($1.value.base)
}
let data = try await GatewayConnection.shared.request(
method: method,
@@ -194,9 +194,7 @@ final class ControlChannel {
? "gateway.remote.token"
: "gateway.auth.token"
return
"Gateway rejected token; set \(tokenKey) (or CLAWDBOT_GATEWAY_TOKEN) " +
"or clear it on the gateway. " +
"Reason: \(reason)"
"Gateway rejected token; set \(tokenKey) or clear it on the gateway. Reason: \(reason)"
}
// Common misfire: we connected to the configured localhost port but it is occupied
@@ -400,20 +398,20 @@ final class ControlChannel {
}
private static func bridgeToProtocolArgs(
_ value: MoltbotProtocol.AnyCodable?) -> [String: MoltbotProtocol.AnyCodable]?
_ value: OpenClawProtocol.AnyCodable?) -> [String: OpenClawProtocol.AnyCodable]?
{
guard let value else { return nil }
if let dict = value.value as? [String: MoltbotProtocol.AnyCodable] {
if let dict = value.value as? [String: OpenClawProtocol.AnyCodable] {
return dict
}
if let dict = value.value as? [String: MoltbotKit.AnyCodable],
if let dict = value.value as? [String: OpenClawKit.AnyCodable],
let data = try? JSONEncoder().encode(dict),
let decoded = try? JSONDecoder().decode([String: MoltbotProtocol.AnyCodable].self, from: data)
let decoded = try? JSONDecoder().decode([String: OpenClawProtocol.AnyCodable].self, from: data)
{
return decoded
}
if let data = try? JSONEncoder().encode(value),
let decoded = try? JSONDecoder().decode([String: MoltbotProtocol.AnyCodable].self, from: data)
let decoded = try? JSONDecoder().decode([String: OpenClawProtocol.AnyCodable].self, from: data)
{
return decoded
}
@@ -422,6 +420,6 @@ final class ControlChannel {
}
extension Notification.Name {
static let controlHeartbeat = Notification.Name("moltbot.control.heartbeat")
static let controlAgentEvent = Notification.Name("moltbot.control.agent")
static let controlHeartbeat = Notification.Name("openclaw.control.heartbeat")
static let controlAgentEvent = Notification.Name("openclaw.control.agent")
}

View File

@@ -1,4 +1,4 @@
import MoltbotProtocol
import OpenClawProtocol
import Foundation
import SwiftUI

View File

@@ -1,4 +1,4 @@
import MoltbotProtocol
import OpenClawProtocol
import Observation
import SwiftUI
@@ -12,11 +12,11 @@ struct CronJobEditor: View {
let labelColumnWidth: CGFloat = 160
static let introText =
"Create a schedule that wakes clawd via the Gateway. "
"Create a schedule that wakes OpenClaw via the Gateway. "
+ "Use an isolated session for agent turns so your main chat stays clean."
static let sessionTargetNote =
"Main jobs post a system event into the current main session. "
+ "Isolated jobs run clawd in a dedicated session and can deliver results (WhatsApp/Telegram/Discord/etc)."
+ "Isolated jobs run OpenClaw in a dedicated session and can deliver results (WhatsApp/Telegram/Discord/etc)."
static let scheduleKindNote =
"“At” runs once, “Every” repeats with a duration, “Cron” uses a 5-field Unix expression."
static let isolatedPayloadNote =
@@ -322,7 +322,7 @@ struct CronJobEditor: View {
Grid(alignment: .leadingFirstTextBaseline, horizontalSpacing: 14, verticalSpacing: 10) {
GridRow {
self.gridLabel("Message")
TextField("What should clawd do?", text: self.$agentMessage, axis: .vertical)
TextField("What should OpenClaw do?", text: self.$agentMessage, axis: .vertical)
.textFieldStyle(.roundedBorder)
.lineLimit(3...7)
.frame(maxWidth: .infinity)

View File

@@ -1,5 +1,5 @@
import MoltbotKit
import MoltbotProtocol
import OpenClawKit
import OpenClawProtocol
import Foundation
import Observation
import OSLog
@@ -22,7 +22,7 @@ final class CronJobsStore {
var lastError: String?
var statusMessage: String?
private let logger = Logger(subsystem: "bot.molt", category: "cron.ui")
private let logger = Logger(subsystem: "ai.openclaw", category: "cron.ui")
private var refreshTask: Task<Void, Never>?
private var runsTask: Task<Void, Never>?
private var eventTask: Task<Void, Never>?

View File

@@ -1,4 +1,4 @@
import MoltbotProtocol
import OpenClawProtocol
import Foundation
extension CronSettings {

View File

@@ -57,7 +57,7 @@ extension CronSettings {
static func exerciseForTesting() {
let store = CronJobsStore(isPreview: true)
store.schedulerEnabled = false
store.schedulerStorePath = "/tmp/moltbot-cron-store.json"
store.schedulerStorePath = "/tmp/openclaw-cron-store.json"
let job = CronJob(
id: "job-1",

View File

@@ -3,9 +3,9 @@ import Foundation
import SwiftUI
enum DebugActions {
private static let verboseDefaultsKey = "moltbot.debug.verboseMain"
private static let verboseDefaultsKey = "openclaw.debug.verboseMain"
private static let sessionMenuLimit = 12
private static let onboardingSeenKey = "moltbot.onboardingSeen"
private static let onboardingSeenKey = "openclaw.onboardingSeen"
@MainActor
static func openAgentEventsWindow() {
@@ -38,9 +38,7 @@ enum DebugActions {
@MainActor
static func openConfigFolder() {
let url = FileManager()
.homeDirectoryForCurrentUser
.appendingPathComponent(".clawdbot", isDirectory: true)
let url = OpenClawPaths.stateDirURL
NSWorkspace.shared.activateFileViewerSelecting([url])
}
@@ -63,7 +61,7 @@ enum DebugActions {
}
static func sendTestNotification() async {
_ = await NotificationManager().send(title: "Moltbot", body: "Test notification", sound: nil)
_ = await NotificationManager().send(title: "OpenClaw", body: "Test notification", sound: nil)
}
static func sendDebugVoice() async -> Result<String, DebugActionError> {
@@ -195,8 +193,7 @@ enum DebugActions {
@MainActor
private static func resolveSessionStorePath() -> String {
let defaultPath = SessionLoader.defaultStorePath
let configURL = FileManager().homeDirectoryForCurrentUser
.appendingPathComponent(".clawdbot/moltbot.json")
let configURL = OpenClawPaths.configURL
guard
let data = try? Data(contentsOf: configURL),
let parsed = try? JSONSerialization.jsonObject(with: data) as? [String: Any],

View File

@@ -103,7 +103,7 @@ struct DebugSettings: View {
}
Text(
"When enabled, Moltbot won't install or manage \(gatewayLaunchdLabel). " +
"When enabled, OpenClaw won't install or manage \(gatewayLaunchdLabel). " +
"It will only attach to an existing Gateway.")
.font(.caption)
.foregroundStyle(.secondary)
@@ -203,7 +203,7 @@ struct DebugSettings: View {
Button("Copy sample URL") {
let msg = "Hello from deep link"
let encoded = msg.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? msg
let url = "moltbot://agent?message=\(encoded)&key=\(key)"
let url = "openclaw://agent?message=\(encoded)&key=\(key)"
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(url, forType: .string)
}
@@ -211,7 +211,7 @@ struct DebugSettings: View {
Spacer(minLength: 0)
}
Text("Deep links (moltbot://…) are always enabled; the key controls unattended runs.")
Text("Deep links (openclaw://…) are always enabled; the key controls unattended runs.")
.font(.caption2)
.foregroundStyle(.secondary)
@@ -274,7 +274,7 @@ struct DebugSettings: View {
Toggle("Write rolling diagnostics log (JSONL)", isOn: self.$diagnosticsFileLogEnabled)
.toggleStyle(.checkbox)
.help(
"Writes a rotating, local-only log under ~/Library/Logs/Moltbot/. " +
"Writes a rotating, local-only log under ~/Library/Logs/OpenClaw/. " +
"Enable only while actively debugging.")
HStack(spacing: 8) {
@@ -382,10 +382,10 @@ struct DebugSettings: View {
GroupBox("Paths") {
VStack(alignment: .leading, spacing: 12) {
VStack(alignment: .leading, spacing: 6) {
Text("Moltbot project root")
Text("OpenClaw project root")
.font(.caption.weight(.semibold))
HStack(spacing: 8) {
TextField("Path to moltbot repo", text: self.$gatewayRootInput)
TextField("Path to openclaw repo", text: self.$gatewayRootInput)
.textFieldStyle(.roundedBorder)
.font(.caption.monospaced())
.onSubmit { self.saveRelayRoot() }
@@ -393,7 +393,7 @@ struct DebugSettings: View {
.buttonStyle(.borderedProminent)
Button("Reset") {
let def = FileManager().homeDirectoryForCurrentUser
.appendingPathComponent("Projects/moltbot").path
.appendingPathComponent("Projects/openclaw").path
self.gatewayRootInput = def
self.saveRelayRoot()
}
@@ -423,7 +423,7 @@ struct DebugSettings: View {
.font(.footnote)
.foregroundStyle(.secondary)
} else {
Text("Used by the CLI session loader; stored in ~/.clawdbot/moltbot.json.")
Text("Used by the CLI session loader; stored in ~/.openclaw/openclaw.json.")
.font(.footnote)
.foregroundStyle(.secondary)
}
@@ -524,15 +524,15 @@ struct DebugSettings: View {
VStack(alignment: .leading, spacing: 6) {
Text(
"Note: macOS may require restarting Moltbot after enabling Accessibility or Screen Recording.")
"Note: macOS may require restarting OpenClaw after enabling Accessibility or Screen Recording.")
.font(.caption)
.foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true)
Button {
LaunchdManager.startMoltbot()
LaunchdManager.startOpenClaw()
} label: {
Label("Restart Moltbot", systemImage: "arrow.counterclockwise")
Label("Restart OpenClaw", systemImage: "arrow.counterclockwise")
}
.buttonStyle(.bordered)
.controlSize(.small)
@@ -830,9 +830,7 @@ struct DebugSettings: View {
}
private func configURL() -> URL {
FileManager().homeDirectoryForCurrentUser
.appendingPathComponent(".clawdbot")
.appendingPathComponent("moltbot.json")
OpenClawPaths.configURL
}
}
@@ -981,7 +979,7 @@ extension DebugSettings {
view.modelsCount = 3
view.modelsLoading = false
view.modelsError = "Failed to load models"
view.gatewayRootInput = "/tmp/moltbot"
view.gatewayRootInput = "/tmp/openclaw"
view.sessionStorePath = "/tmp/sessions.json"
view.sessionStoreSaveError = "Save failed"
view.debugSendInFlight = true

View File

@@ -1,10 +1,10 @@
import AppKit
import MoltbotKit
import OpenClawKit
import Foundation
import OSLog
import Security
private let deepLinkLogger = Logger(subsystem: "bot.molt", category: "DeepLink")
private let deepLinkLogger = Logger(subsystem: "ai.openclaw", category: "DeepLink")
@MainActor
final class DeepLinkHandler {
@@ -23,7 +23,7 @@ final class DeepLinkHandler {
return
}
guard !AppStateStore.shared.isPaused else {
self.presentAlert(title: "Moltbot is paused", message: "Unpause Moltbot to run agent actions.")
self.presentAlert(title: "OpenClaw is paused", message: "Unpause OpenClaw to run agent actions.")
return
}
@@ -51,7 +51,7 @@ final class DeepLinkHandler {
let trimmed = messagePreview.count > 240 ? "\(messagePreview.prefix(240))" : messagePreview
let body =
"Run the agent with this message?\n\n\(trimmed)\n\nURL:\n\(originalURL.absoluteString)"
guard self.confirm(title: "Run Moltbot agent?", message: body) else { return }
guard self.confirm(title: "Run OpenClaw agent?", message: body) else { return }
}
if AppStateStore.shared.connectionMode == .local {

View File

@@ -1,6 +1,6 @@
import AppKit
import MoltbotKit
import MoltbotProtocol
import OpenClawKit
import OpenClawProtocol
import Foundation
import Observation
import OSLog
@@ -10,7 +10,7 @@ import OSLog
final class DevicePairingApprovalPrompter {
static let shared = DevicePairingApprovalPrompter()
private let logger = Logger(subsystem: "bot.molt", category: "device-pairing")
private let logger = Logger(subsystem: "ai.openclaw", category: "device-pairing")
private var task: Task<Void, Never>?
private var isStopping = false
private var isPresenting = false

View File

@@ -24,7 +24,7 @@ actor DiagnosticsFileLog {
?? FileManager().homeDirectoryForCurrentUser.appendingPathComponent("Library", isDirectory: true)
return library
.appendingPathComponent("Logs", isDirectory: true)
.appendingPathComponent("Moltbot", isDirectory: true)
.appendingPathComponent("OpenClaw", isDirectory: true)
}
nonisolated static func logFileURL() -> URL {

View File

@@ -6,7 +6,7 @@ final class DockIconManager: NSObject, @unchecked Sendable {
static let shared = DockIconManager()
private var windowsObservation: NSKeyValueObservation?
private let logger = Logger(subsystem: "bot.molt", category: "DockIconManager")
private let logger = Logger(subsystem: "ai.openclaw", category: "DockIconManager")
override private init() {
super.init()

View File

@@ -189,7 +189,7 @@ struct ExecApprovalsResolvedDefaults {
}
enum ExecApprovalsStore {
private static let logger = Logger(subsystem: "bot.molt", category: "exec-approvals")
private static let logger = Logger(subsystem: "ai.openclaw", category: "exec-approvals")
private static let defaultAgentId = "main"
private static let defaultSecurity: ExecSecurity = .deny
private static let defaultAsk: ExecAsk = .onMiss
@@ -197,11 +197,11 @@ enum ExecApprovalsStore {
private static let defaultAutoAllowSkills = false
static func fileURL() -> URL {
MoltbotPaths.stateDirURL.appendingPathComponent("exec-approvals.json")
OpenClawPaths.stateDirURL.appendingPathComponent("exec-approvals.json")
}
static func socketPath() -> String {
MoltbotPaths.stateDirURL.appendingPathComponent("exec-approvals.sock").path
OpenClawPaths.stateDirURL.appendingPathComponent("exec-approvals.sock").path
}
static func normalizeIncoming(_ file: ExecApprovalsFile) -> ExecApprovalsFile {

View File

@@ -1,5 +1,5 @@
import MoltbotKit
import MoltbotProtocol
import OpenClawKit
import OpenClawProtocol
import CoreGraphics
import Foundation
import OSLog
@@ -8,7 +8,7 @@ import OSLog
final class ExecApprovalsGatewayPrompter {
static let shared = ExecApprovalsGatewayPrompter()
private let logger = Logger(subsystem: "bot.molt", category: "exec-approvals.gateway")
private let logger = Logger(subsystem: "ai.openclaw", category: "exec-approvals.gateway")
private var task: Task<Void, Never>?
struct GatewayApprovalRequest: Codable, Sendable {

View File

@@ -1,5 +1,5 @@
import AppKit
import MoltbotKit
import OpenClawKit
import CryptoKit
import Darwin
import Foundation
@@ -589,7 +589,7 @@ private enum ExecHostExecutor {
}
private final class ExecApprovalsSocketServer: @unchecked Sendable {
private let logger = Logger(subsystem: "bot.molt", category: "exec-approvals.socket")
private let logger = Logger(subsystem: "ai.openclaw", category: "exec-approvals.socket")
private let socketPath: String
private let token: String
private let onPrompt: @Sendable (ExecApprovalPromptRequest) async -> ExecApprovalDecision

View File

@@ -1,10 +1,10 @@
import MoltbotChatUI
import MoltbotKit
import MoltbotProtocol
import OpenClawChatUI
import OpenClawKit
import OpenClawProtocol
import Foundation
import OSLog
private let gatewayConnectionLogger = Logger(subsystem: "bot.molt", category: "gateway.connection")
private let gatewayConnectionLogger = Logger(subsystem: "ai.openclaw", category: "gateway.connection")
enum GatewayAgentChannel: String, Codable, CaseIterable, Sendable {
case last
@@ -272,7 +272,7 @@ actor GatewayConnection {
return trimmed.isEmpty ? nil : trimmed
}
private func sessionDefaultString(_ defaults: [String: MoltbotProtocol.AnyCodable]?, key: String) -> String {
private func sessionDefaultString(_ defaults: [String: OpenClawProtocol.AnyCodable]?, key: String) -> String {
let raw = defaults?[key]?.value as? String
return (raw ?? "").trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
@@ -503,7 +503,7 @@ extension GatewayConnection {
func healthOK(timeoutMs: Int = 8000) async throws -> Bool {
let data = try await self.requestRaw(method: .health, timeoutMs: Double(timeoutMs))
return (try? self.decoder.decode(MoltbotGatewayHealthOK.self, from: data))?.ok ?? true
return (try? self.decoder.decode(OpenClawGatewayHealthOK.self, from: data))?.ok ?? true
}
// MARK: - Skills
@@ -548,13 +548,13 @@ extension GatewayConnection {
keys: [String],
limit: Int? = nil,
maxChars: Int? = nil,
timeoutMs: Int? = nil) async throws -> MoltbotSessionsPreviewPayload
timeoutMs: Int? = nil) async throws -> OpenClawSessionsPreviewPayload
{
let resolvedKeys = keys
.map { self.canonicalizeSessionKey($0) }
.filter { !$0.isEmpty }
if resolvedKeys.isEmpty {
return MoltbotSessionsPreviewPayload(ts: 0, previews: [])
return OpenClawSessionsPreviewPayload(ts: 0, previews: [])
}
var params: [String: AnyCodable] = ["keys": AnyCodable(resolvedKeys)]
if let limit { params["limit"] = AnyCodable(limit) }
@@ -571,7 +571,7 @@ extension GatewayConnection {
func chatHistory(
sessionKey: String,
limit: Int? = nil,
timeoutMs: Int? = nil) async throws -> MoltbotChatHistoryPayload
timeoutMs: Int? = nil) async throws -> OpenClawChatHistoryPayload
{
let resolvedKey = self.canonicalizeSessionKey(sessionKey)
var params: [String: AnyCodable] = ["sessionKey": AnyCodable(resolvedKey)]
@@ -588,8 +588,8 @@ extension GatewayConnection {
message: String,
thinking: String,
idempotencyKey: String,
attachments: [MoltbotChatAttachmentPayload],
timeoutMs: Int = 30000) async throws -> MoltbotChatSendResponse
attachments: [OpenClawChatAttachmentPayload],
timeoutMs: Int = 30000) async throws -> OpenClawChatSendResponse
{
let resolvedKey = self.canonicalizeSessionKey(sessionKey)
var params: [String: AnyCodable] = [

View File

@@ -7,7 +7,7 @@ import OSLog
final class GatewayConnectivityCoordinator {
static let shared = GatewayConnectivityCoordinator()
private let logger = Logger(subsystem: "bot.molt", category: "gateway.connectivity")
private let logger = Logger(subsystem: "ai.openclaw", category: "gateway.connectivity")
private var endpointTask: Task<Void, Never>?
private var lastResolvedURL: URL?

View File

@@ -1,4 +1,4 @@
import MoltbotDiscovery
import OpenClawDiscovery
import Foundation
enum GatewayDiscoveryHelpers {

View File

@@ -1,4 +1,4 @@
import MoltbotDiscovery
import OpenClawDiscovery
import SwiftUI
struct GatewayDiscoveryInlineList: View {
@@ -134,6 +134,6 @@ struct GatewayDiscoveryMenu: View {
} label: {
Image(systemName: "dot.radiowaves.left.and.right")
}
.help("Discover Moltbot gateways on your LAN")
.help("Discover OpenClaw gateways on your LAN")
}
}

View File

@@ -23,7 +23,7 @@ actor GatewayEndpointStore {
"custom",
]
private static let remoteConnectingDetail = "Connecting to remote gateway…"
private static let staticLogger = Logger(subsystem: "bot.molt", category: "gateway-endpoint")
private static let staticLogger = Logger(subsystem: "ai.openclaw", category: "gateway-endpoint")
private enum EnvOverrideWarningKind: Sendable {
case token
case password
@@ -43,7 +43,7 @@ actor GatewayEndpointStore {
static let live = Deps(
mode: { await MainActor.run { AppStateStore.shared.connectionMode } },
token: {
let root = MoltbotConfigFile.loadDict()
let root = OpenClawConfigFile.loadDict()
let isRemote = ConnectionModeResolver.resolve(root: root).mode == .remote
return GatewayEndpointStore.resolveGatewayToken(
isRemote: isRemote,
@@ -52,7 +52,7 @@ actor GatewayEndpointStore {
launchdSnapshot: GatewayLaunchAgentManager.launchdConfigSnapshot())
},
password: {
let root = MoltbotConfigFile.loadDict()
let root = OpenClawConfigFile.loadDict()
let isRemote = ConnectionModeResolver.resolve(root: root).mode == .remote
return GatewayEndpointStore.resolveGatewayPassword(
isRemote: isRemote,
@@ -62,7 +62,7 @@ actor GatewayEndpointStore {
},
localPort: { GatewayEnvironment.gatewayPort() },
localHost: {
let root = MoltbotConfigFile.loadDict()
let root = OpenClawConfigFile.loadDict()
let bind = GatewayEndpointStore.resolveGatewayBindMode(
root: root,
env: ProcessInfo.processInfo.environment)
@@ -84,7 +84,7 @@ actor GatewayEndpointStore {
env: [String: String],
launchdSnapshot: LaunchAgentPlistSnapshot?) -> String?
{
let raw = env["CLAWDBOT_GATEWAY_PASSWORD"] ?? ""
let raw = env["OPENCLAW_GATEWAY_PASSWORD"] ?? ""
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
if let configPassword = self.resolveConfigPassword(isRemote: isRemote, root: root),
@@ -92,7 +92,7 @@ actor GatewayEndpointStore {
{
self.warnEnvOverrideOnce(
kind: .password,
envVar: "CLAWDBOT_GATEWAY_PASSWORD",
envVar: "OPENCLAW_GATEWAY_PASSWORD",
configKey: isRemote ? "gateway.remote.password" : "gateway.auth.password")
}
return trimmed
@@ -152,7 +152,7 @@ actor GatewayEndpointStore {
env: [String: String],
launchdSnapshot: LaunchAgentPlistSnapshot?) -> String?
{
let raw = env["CLAWDBOT_GATEWAY_TOKEN"] ?? ""
let raw = env["OPENCLAW_GATEWAY_TOKEN"] ?? ""
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
if let configToken = self.resolveConfigToken(isRemote: isRemote, root: root),
@@ -161,7 +161,7 @@ actor GatewayEndpointStore {
{
self.warnEnvOverrideOnce(
kind: .token,
envVar: "CLAWDBOT_GATEWAY_TOKEN",
envVar: "OPENCLAW_GATEWAY_TOKEN",
configKey: isRemote ? "gateway.remote.token" : "gateway.auth.token")
}
return trimmed
@@ -230,7 +230,7 @@ actor GatewayEndpointStore {
}
private let deps: Deps
private let logger = Logger(subsystem: "bot.molt", category: "gateway-endpoint")
private let logger = Logger(subsystem: "ai.openclaw", category: "gateway-endpoint")
private var state: GatewayEndpointState
private var subscribers: [UUID: AsyncStream<GatewayEndpointState>.Continuation] = [:]
@@ -243,17 +243,17 @@ actor GatewayEndpointStore {
if let modeRaw {
initialMode = AppState.ConnectionMode(rawValue: modeRaw) ?? .local
} else {
let seen = UserDefaults.standard.bool(forKey: "moltbot.onboardingSeen")
let seen = UserDefaults.standard.bool(forKey: "openclaw.onboardingSeen")
initialMode = seen ? .local : .unconfigured
}
let port = deps.localPort()
let bind = GatewayEndpointStore.resolveGatewayBindMode(
root: MoltbotConfigFile.loadDict(),
root: OpenClawConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
let customBindHost = GatewayEndpointStore.resolveGatewayCustomBindHost(root: MoltbotConfigFile.loadDict())
let customBindHost = GatewayEndpointStore.resolveGatewayCustomBindHost(root: OpenClawConfigFile.loadDict())
let scheme = GatewayEndpointStore.resolveGatewayScheme(
root: MoltbotConfigFile.loadDict(),
root: OpenClawConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
let host = GatewayEndpointStore.resolveLocalGatewayHost(
bindMode: bind,
@@ -303,7 +303,7 @@ actor GatewayEndpointStore {
let port = self.deps.localPort()
let host = await self.deps.localHost()
let scheme = GatewayEndpointStore.resolveGatewayScheme(
root: MoltbotConfigFile.loadDict(),
root: OpenClawConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
self.setState(.ready(
mode: .local,
@@ -311,7 +311,7 @@ actor GatewayEndpointStore {
token: token,
password: password))
case .remote:
let root = MoltbotConfigFile.loadDict()
let root = OpenClawConfigFile.loadDict()
if GatewayRemoteConfig.resolveTransport(root: root) == .direct {
guard let url = GatewayRemoteConfig.resolveGatewayUrl(root: root) else {
self.cancelRemoteEnsure()
@@ -332,7 +332,7 @@ actor GatewayEndpointStore {
}
self.cancelRemoteEnsure()
let scheme = GatewayEndpointStore.resolveGatewayScheme(
root: MoltbotConfigFile.loadDict(),
root: OpenClawConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
self.setState(.ready(
mode: .remote,
@@ -354,7 +354,7 @@ actor GatewayEndpointStore {
code: 1,
userInfo: [NSLocalizedDescriptionKey: "Remote mode is not enabled"])
}
let root = MoltbotConfigFile.loadDict()
let root = OpenClawConfigFile.loadDict()
if GatewayRemoteConfig.resolveTransport(root: root) == .direct {
guard let url = GatewayRemoteConfig.resolveGatewayUrl(root: root) else {
throw NSError(
@@ -433,7 +433,7 @@ actor GatewayEndpointStore {
userInfo: [NSLocalizedDescriptionKey: "Remote mode is not enabled"])
}
let root = MoltbotConfigFile.loadDict()
let root = OpenClawConfigFile.loadDict()
if GatewayRemoteConfig.resolveTransport(root: root) == .direct {
guard let url = GatewayRemoteConfig.resolveGatewayUrl(root: root) else {
throw NSError(
@@ -470,7 +470,7 @@ actor GatewayEndpointStore {
let token = self.deps.token()
let password = self.deps.password()
let scheme = GatewayEndpointStore.resolveGatewayScheme(
root: MoltbotConfigFile.loadDict(),
root: OpenClawConfigFile.loadDict(),
env: ProcessInfo.processInfo.environment)
let url = URL(string: "\(scheme)://127.0.0.1:\(Int(forwarded))")!
self.setState(.ready(mode: .remote, url: url, token: token, password: password))
@@ -525,7 +525,7 @@ actor GatewayEndpointStore {
let mode = await self.deps.mode()
guard mode == .local else { return nil }
let root = MoltbotConfigFile.loadDict()
let root = OpenClawConfigFile.loadDict()
let bind = GatewayEndpointStore.resolveGatewayBindMode(
root: root,
env: ProcessInfo.processInfo.environment)
@@ -555,7 +555,7 @@ actor GatewayEndpointStore {
root: [String: Any],
env: [String: String]) -> String?
{
if let envBind = env["CLAWDBOT_GATEWAY_BIND"] {
if let envBind = env["OPENCLAW_GATEWAY_BIND"] {
let trimmed = envBind.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if self.supportedBindModes.contains(trimmed) {
return trimmed
@@ -586,7 +586,7 @@ actor GatewayEndpointStore {
root: [String: Any],
env: [String: String]) -> String
{
if let envValue = env["CLAWDBOT_GATEWAY_TLS"]?.trimmingCharacters(in: .whitespacesAndNewlines),
if let envValue = env["OPENCLAW_GATEWAY_TLS"]?.trimmingCharacters(in: .whitespacesAndNewlines),
!envValue.isEmpty
{
return (envValue == "1" || envValue.lowercased() == "true") ? "wss" : "ws"

View File

@@ -1,4 +1,4 @@
import MoltbotIPC
import OpenClawIPC
import Foundation
import OSLog
@@ -68,15 +68,15 @@ struct GatewayCommandResolution {
}
enum GatewayEnvironment {
private static let logger = Logger(subsystem: "bot.molt", category: "gateway.env")
private static let logger = Logger(subsystem: "ai.openclaw", category: "gateway.env")
private static let supportedBindModes: Set<String> = ["loopback", "tailnet", "lan", "auto"]
static func gatewayPort() -> Int {
if let raw = ProcessInfo.processInfo.environment["CLAWDBOT_GATEWAY_PORT"] {
if let raw = ProcessInfo.processInfo.environment["OPENCLAW_GATEWAY_PORT"] {
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if let parsed = Int(trimmed), parsed > 0 { return parsed }
}
if let configPort = MoltbotConfigFile.gatewayPort(), configPort > 0 {
if let configPort = OpenClawConfigFile.gatewayPort(), configPort > 0 {
return configPort
}
let stored = UserDefaults.standard.integer(forKey: "gatewayPort")
@@ -123,7 +123,7 @@ enum GatewayEnvironment {
requiredGateway: expectedString,
message: RuntimeLocator.describeFailure(err))
case let .success(runtime):
let gatewayBin = CommandResolver.moltbotExecutable()
let gatewayBin = CommandResolver.openclawExecutable()
if gatewayBin == nil, projectEntrypoint == nil {
return GatewayEnvironmentStatus(
@@ -131,7 +131,7 @@ enum GatewayEnvironment {
nodeVersion: runtime.version.description,
gatewayVersion: nil,
requiredGateway: expectedString,
message: "moltbot CLI not found in PATH; install the CLI.")
message: "openclaw CLI not found in PATH; install the CLI.")
}
let installed = gatewayBin.flatMap { self.readGatewayVersion(binary: $0) }
@@ -181,7 +181,7 @@ enum GatewayEnvironment {
let projectRoot = CommandResolver.projectRoot()
let projectEntrypoint = CommandResolver.gatewayEntrypoint(in: projectRoot)
let status = self.check()
let gatewayBin = CommandResolver.moltbotExecutable()
let gatewayBin = CommandResolver.openclawExecutable()
let runtime = RuntimeLocator.resolve(searchPaths: CommandResolver.preferredPaths())
guard case .ok = status.kind else {
@@ -210,14 +210,14 @@ enum GatewayEnvironment {
if CommandResolver.connectionModeIsRemote() {
return nil
}
if let env = ProcessInfo.processInfo.environment["CLAWDBOT_GATEWAY_BIND"] {
if let env = ProcessInfo.processInfo.environment["OPENCLAW_GATEWAY_BIND"] {
let trimmed = env.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if self.supportedBindModes.contains(trimmed) {
return trimmed
}
}
let root = MoltbotConfigFile.loadDict()
let root = OpenClawConfigFile.loadDict()
if let gateway = root["gateway"] as? [String: Any],
let bind = gateway["bind"] as? String
{
@@ -247,16 +247,16 @@ enum GatewayEnvironment {
let bun = CommandResolver.findExecutable(named: "bun")
let (label, cmd): (String, [String]) =
if let npm {
("npm", [npm, "install", "-g", "moltbot@\(target)"])
("npm", [npm, "install", "-g", "openclaw@\(target)"])
} else if let pnpm {
("pnpm", [pnpm, "add", "-g", "moltbot@\(target)"])
("pnpm", [pnpm, "add", "-g", "openclaw@\(target)"])
} else if let bun {
("bun", [bun, "add", "-g", "moltbot@\(target)"])
("bun", [bun, "add", "-g", "openclaw@\(target)"])
} else {
("npm", ["npm", "install", "-g", "moltbot@\(target)"])
("npm", ["npm", "install", "-g", "openclaw@\(target)"])
}
statusHandler("Installing moltbot@\(target) via \(label)")
statusHandler("Installing openclaw@\(target) via \(label)")
func summarize(_ text: String) -> String? {
let lines = text
@@ -270,7 +270,7 @@ enum GatewayEnvironment {
let response = await ShellExecutor.runDetailed(command: cmd, cwd: nil, env: ["PATH": preferred], timeout: 300)
if response.success {
statusHandler("Installed moltbot@\(target)")
statusHandler("Installed openclaw@\(target)")
} else {
if response.timedOut {
statusHandler("Install failed: timed out. Check your internet connection and try again.")

View File

@@ -1,8 +1,8 @@
import Foundation
enum GatewayLaunchAgentManager {
private static let logger = Logger(subsystem: "bot.molt", category: "gateway.launchd")
private static let disableLaunchAgentMarker = ".clawdbot/disable-launchagent"
private static let logger = Logger(subsystem: "ai.openclaw", category: "gateway.launchd")
private static let disableLaunchAgentMarker = ".openclaw/disable-launchagent"
private static var disableLaunchAgentMarkerURL: URL {
FileManager().homeDirectoryForCurrentUser
@@ -15,7 +15,8 @@ enum GatewayLaunchAgentManager {
}
static func isLaunchAgentWriteDisabled() -> Bool {
FileManager().fileExists(atPath: self.disableLaunchAgentMarkerURL.path)
if FileManager().fileExists(atPath: self.disableLaunchAgentMarkerURL.path) { return true }
return false
}
static func setLaunchAgentWriteDisabled(_ disabled: Bool) -> String? {
@@ -143,7 +144,7 @@ extension GatewayLaunchAgentManager {
timeout: Double,
quiet: Bool) async -> CommandResult
{
let command = CommandResolver.moltbotCommand(
let command = CommandResolver.openclawCommand(
subcommand: "gateway",
extraArgs: self.withJsonFlag(args),
// Launchd management must always run locally, even if remote mode is configured.

View File

@@ -45,7 +45,7 @@ final class GatewayProcessManager {
#if DEBUG
private var testingConnection: GatewayConnection?
#endif
private let logger = Logger(subsystem: "bot.molt", category: "gateway.process")
private let logger = Logger(subsystem: "ai.openclaw", category: "gateway.process")
private let logLimit = 20000 // characters to keep in-memory
private let environmentRefreshMinInterval: TimeInterval = 30
@@ -270,8 +270,8 @@ final class GatewayProcessManager {
let lower = message.lowercased()
if self.isGatewayAuthFailure(error) {
return """
Gateway on port \(port) rejected auth. Set gateway.auth.token (or CLAWDBOT_GATEWAY_TOKEN) \
to match the running gateway (or clear it on the gateway) and retry.
Gateway on port \(port) rejected auth. Set gateway.auth.token to match the running gateway \
(or clear it on the gateway) and retry.
"""
}
if lower.contains("protocol mismatch") {

View File

@@ -1,7 +1,7 @@
import AppKit
import MoltbotDiscovery
import MoltbotIPC
import MoltbotKit
import OpenClawDiscovery
import OpenClawIPC
import OpenClawKit
import Observation
import SwiftUI
@@ -24,8 +24,8 @@ struct GeneralSettings: View {
VStack(alignment: .leading, spacing: 18) {
VStack(alignment: .leading, spacing: 12) {
SettingsToggleRow(
title: "Moltbot active",
subtitle: "Pause to stop the Moltbot gateway; no messages will be processed.",
title: "OpenClaw active",
subtitle: "Pause to stop the OpenClaw gateway; no messages will be processed.",
binding: self.activeBinding)
self.connectionSection
@@ -34,12 +34,12 @@ struct GeneralSettings: View {
SettingsToggleRow(
title: "Launch at login",
subtitle: "Automatically start Moltbot after you sign in.",
subtitle: "Automatically start OpenClaw after you sign in.",
binding: self.$state.launchAtLogin)
SettingsToggleRow(
title: "Show Dock icon",
subtitle: "Keep Moltbot visible in the Dock instead of menu-bar-only mode.",
subtitle: "Keep OpenClaw visible in the Dock instead of menu-bar-only mode.",
binding: self.$state.showDockIcon)
SettingsToggleRow(
@@ -71,7 +71,7 @@ struct GeneralSettings: View {
Spacer(minLength: 12)
HStack {
Spacer()
Button("Quit Moltbot") { NSApp.terminate(nil) }
Button("Quit OpenClaw") { NSApp.terminate(nil) }
.buttonStyle(.borderedProminent)
}
}
@@ -98,7 +98,7 @@ struct GeneralSettings: View {
private var connectionSection: some View {
VStack(alignment: .leading, spacing: 10) {
Text("Moltbot runs")
Text("OpenClaw runs")
.font(.title3.weight(.semibold))
.frame(maxWidth: .infinity, alignment: .leading)
@@ -167,12 +167,12 @@ struct GeneralSettings: View {
.frame(width: 280)
}
LabeledContent("Project root") {
TextField("/home/you/Projects/moltbot", text: self.$state.remoteProjectRoot)
TextField("/home/you/Projects/openclaw", text: self.$state.remoteProjectRoot)
.textFieldStyle(.roundedBorder)
.frame(width: 280)
}
LabeledContent("CLI path") {
TextField("/Applications/Moltbot.app/.../moltbot", text: self.$state.remoteCliPath)
TextField("/Applications/OpenClaw.app/.../openclaw", text: self.$state.remoteCliPath)
.textFieldStyle(.roundedBorder)
.frame(width: 280)
}
@@ -659,7 +659,7 @@ extension GeneralSettings {
let alert = NSAlert()
alert.messageText = "Log file not found"
alert.informativeText = """
Looked for moltbot logs in /tmp/moltbot/.
Looked for openclaw logs in /tmp/openclaw/.
Run a health check or send a message to generate activity, then try again.
"""
alert.alertStyle = .informational
@@ -683,7 +683,7 @@ extension GeneralSettings {
host: host,
port: gateway.sshPort)
self.state.remoteCliPath = gateway.cliPath ?? ""
MoltbotConfigFile.setRemoteGatewayUrl(host: host, port: gateway.gatewayPort)
OpenClawConfigFile.setRemoteGatewayUrl(host: host, port: gateway.gatewayPort)
}
}
}
@@ -711,8 +711,8 @@ extension GeneralSettings {
state.remoteTarget = "user@host:2222"
state.remoteUrl = "wss://gateway.example.ts.net"
state.remoteIdentity = "/tmp/id_ed25519"
state.remoteProjectRoot = "/tmp/moltbot"
state.remoteCliPath = "/tmp/moltbot"
state.remoteProjectRoot = "/tmp/openclaw"
state.remoteCliPath = "/tmp/openclaw"
let view = GeneralSettings(state: state)
view.gatewayStatus = GatewayEnvironmentStatus(

View File

@@ -72,7 +72,7 @@ enum HealthState: Equatable {
final class HealthStore {
static let shared = HealthStore()
private static let logger = Logger(subsystem: "bot.molt", category: "health")
private static let logger = Logger(subsystem: "ai.openclaw", category: "health")
private(set) var snapshot: HealthSnapshot?
private(set) var lastSuccess: Date?
@@ -221,9 +221,9 @@ final class HealthStore {
if let fallback = self.resolveFallbackChannel(snap, excluding: link.id) {
let fallbackLabel = snap.channelLabels?[fallback.id] ?? fallback.id.capitalized
let fallbackState = (fallback.summary.probe?.ok ?? true) ? "ok" : "degraded"
return "\(fallbackLabel) \(fallbackState) · Not linked — run moltbot login"
return "\(fallbackLabel) \(fallbackState) · Not linked — run openclaw login"
}
return "Not linked — run moltbot login"
return "Not linked — run openclaw login"
}
let auth = link.summary.authAgeMs.map { msToAge($0) } ?? "unknown"
if let probe = link.summary.probe, probe.ok == false {
@@ -241,7 +241,7 @@ final class HealthStore {
if lower.contains("connection refused") {
let port = GatewayEnvironment.gatewayPort()
let host = GatewayConnectivityCoordinator.shared.localEndpointHostLabel ?? "127.0.0.1:\(port)"
return "The gateway control port (\(host)) isnt listening — restart Moltbot to bring it back."
return "The gateway control port (\(host)) isnt listening — restart OpenClaw to bring it back."
}
if lower.contains("timeout") {
return "Timed out waiting for the control server; the gateway may be crashed or still starting."
@@ -253,7 +253,7 @@ final class HealthStore {
func describeFailure(from snap: HealthSnapshot, fallback: String?) -> String {
if let link = self.resolveLinkChannel(snap), link.summary.linked != true {
return "Not linked — run moltbot login"
return "Not linked — run openclaw login"
}
if let link = self.resolveLinkChannel(snap), let probe = link.summary.probe, probe.ok == false {
return Self.describeProbeFailure(probe)

View File

@@ -38,7 +38,7 @@ struct InstancesSettings: View {
VStack(alignment: .leading, spacing: 4) {
Text("Connected Instances")
.font(.headline)
Text("Latest presence beacons from Moltbot nodes. Updated periodically.")
Text("Latest presence beacons from OpenClaw nodes. Updated periodically.")
.font(.footnote)
.foregroundStyle(.secondary)
}

View File

@@ -1,5 +1,5 @@
import MoltbotKit
import MoltbotProtocol
import OpenClawKit
import OpenClawProtocol
import Cocoa
import Foundation
import Observation
@@ -41,7 +41,7 @@ final class InstancesStore {
var statusMessage: String?
var isLoading = false
private let logger = Logger(subsystem: "bot.molt", category: "instances")
private let logger = Logger(subsystem: "ai.openclaw", category: "instances")
private var task: Task<Void, Never>?
private let interval: TimeInterval = 30
private var eventTask: Task<Void, Never>?
@@ -293,7 +293,7 @@ final class InstancesStore {
}
}
func handlePresenceEventPayload(_ payload: MoltbotProtocol.AnyCodable) {
func handlePresenceEventPayload(_ payload: OpenClawProtocol.AnyCodable) {
do {
let wrapper = try GatewayPayloadDecoding.decode(payload, as: PresenceEventPayload.self)
self.applyPresence(wrapper.presence)

View File

@@ -1,20 +1,9 @@
import Foundation
enum LaunchAgentManager {
private static let legacyLaunchdLabels = [
"com.steipete.clawdbot",
"com.clawdbot.mac",
]
private static var plistURL: URL {
FileManager().homeDirectoryForCurrentUser
.appendingPathComponent("Library/LaunchAgents/bot.molt.mac.plist")
}
private static var legacyPlistURLs: [URL] {
self.legacyLaunchdLabels.map { label in
FileManager().homeDirectoryForCurrentUser
.appendingPathComponent("Library/LaunchAgents/\(label).plist")
}
.appendingPathComponent("Library/LaunchAgents/ai.openclaw.mac.plist")
}
static func status() async -> Bool {
@@ -25,12 +14,6 @@ enum LaunchAgentManager {
static func set(enabled: Bool, bundlePath: String) async {
if enabled {
for legacyLabel in self.legacyLaunchdLabels {
_ = await self.runLaunchctl(["bootout", "gui/\(getuid())/\(legacyLabel)"])
}
for legacyURL in self.legacyPlistURLs {
try? FileManager().removeItem(at: legacyURL)
}
self.writePlist(bundlePath: bundlePath)
_ = await self.runLaunchctl(["bootout", "gui/\(getuid())/\(launchdLabel)"])
_ = await self.runLaunchctl(["bootstrap", "gui/\(getuid())", self.plistURL.path])
@@ -49,10 +32,10 @@ enum LaunchAgentManager {
<plist version="1.0">
<dict>
<key>Label</key>
<string>bot.molt.mac</string>
<string>ai.openclaw.mac</string>
<key>ProgramArguments</key>
<array>
<string>\(bundlePath)/Contents/MacOS/Moltbot</string>
<string>\(bundlePath)/Contents/MacOS/OpenClaw</string>
</array>
<key>WorkingDirectory</key>
<string>\(FileManager().homeDirectoryForCurrentUser.path)</string>

View File

@@ -59,8 +59,8 @@ enum LaunchAgentPlist {
.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
let port = Self.extractFlagInt(programArguments, flag: "--port")
let bind = Self.extractFlagString(programArguments, flag: "--bind")?.lowercased()
let token = env["CLAWDBOT_GATEWAY_TOKEN"]?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
let password = env["CLAWDBOT_GATEWAY_PASSWORD"]?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
let token = env["OPENCLAW_GATEWAY_TOKEN"]?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
let password = env["OPENCLAW_GATEWAY_PASSWORD"]?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
return LaunchAgentPlistSnapshot(
programArguments: programArguments,
environment: env,

View File

@@ -8,12 +8,12 @@ enum LaunchdManager {
try? process.run()
}
static func startMoltbot() {
static func startOpenClaw() {
let userTarget = "gui/\(getuid())/\(launchdLabel)"
self.runLaunchctl(["kickstart", "-k", userTarget])
}
static func stopMoltbot() {
static func stopOpenClaw() {
let userTarget = "gui/\(getuid())/\(launchdLabel)"
self.runLaunchctl(["stop", userTarget])
}

Some files were not shown because too many files have changed in this diff Show More